react-native-awesome-stories
v0.3.1
Published
A fast and optimized library for rendering stories with smooth animations and gestures. Supports story lists and an integrated player with full customization.
Maintainers
Readme
react-native-awesome-stories
A fast, highly customizable, and optimized library for rendering stories in React Native. Features smooth 3D animations, gesture controls, and fully custom rendering using Reanimated.
Features
- 🚀 60 FPS Animations powered by
react-native-reanimated. - 🎨 100% Customizable UI: You have full control over how steps are rendered.
- 📱 3D Cube Transitions between user stories.
- 👆 Gestures: Tap to navigate, long press to pause.
- 🕹 State Control: Imperative API and state hooks to control playback.
- 🛠 TypeScript ready with generic data support.
Installation
npm install react-native-awesome-stories
# or
yarn add react-native-awesome-storiesPeer Dependencies
This library relies on the following peer dependencies. Make sure they are installed:
npm install react-native-gesture-handler react-native-reanimated react-native-safe-area-context react-native-svg(Note: Don't forget to wrap your app with GestureHandlerRootView and SafeAreaProvider)
Quick Start
1. Wrap your app with Providers
You need to wrap your application with GestureHandlerRootView, SafeAreaProvider, and the StoriesProvider.
// App.tsx
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { StoriesProvider } from 'react-native-awesome-stories';
export default function App() {
return (
<SafeAreaProvider>
<GestureHandlerRootView style={{ flex: 1 }}>
<StoriesProvider
theme={{
viewedBorderColor: 'gray',
listItemStyle: {
width: 80,
height: 80,
borderWidth: 3,
borderColor: '#4A90E2',
borderRadius: 40,
},
}}
>
<YourApp />
</StoriesProvider>
</GestureHandlerRootView>
</SafeAreaProvider>
);
}2. Render the Stories List
Use the StoriesList component to display the avatars list. You must provide a renderContent function to describe how a full-screen story step should look.
// Stories.tsx
import { View, Image, Text, StyleSheet } from 'react-native';
import { StoriesList, StoryRenderProps } from 'react-native-awesome-stories';
const stories = [
{
id: '1',
image: 'https://example.com/avatar.jpg',
title: 'User 1',
isViewed: false,
steps: [
{
id: '1-1',
image: 'https://example.com/story1.jpg',
title: 'Morning',
duration: 5000,
},
{
id: '1-2',
image: 'https://example.com/story2.jpg',
title: 'Work',
duration: 3000,
},
],
},
];
export function Stories() {
const renderContent = ({ step, storyIndex, stepIndex }: StoryRenderProps) => (
<View style={styles.storyContainer}>
<Image
source={{ uri: step.image }}
style={StyleSheet.absoluteFill}
resizeMode="cover"
/>
<View style={styles.footer}>
<Text style={styles.text}>{step.title}</Text>
</View>
</View>
);
return (
<View style={{ flex: 1 }}>
<StoriesList
stories={stories}
renderContent={renderContent}
onStepChange={({ storyIndex, stepIndex }) =>
console.log(storyIndex, stepIndex)
}
/>
</View>
);
}
const styles = StyleSheet.create({
storyContainer: { flex: 1, backgroundColor: '#000' },
footer: { flex: 1, justifyContent: 'flex-end', padding: 20 },
text: { color: 'white', fontSize: 18 },
});API Reference
StoriesList Props
| Prop | Type | Description |
| ---------------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| stories | StoryListItemType<T>[] | Array of stories to display in the horizontal list. |
| renderContent | (props: StoryRenderProps<T>) => ReactNode | Required. A function that renders the full-screen content for each story step. |
| HeaderComponent | ReactNode | (Optional) A custom React node to render as a header overlay (rendered above renderContent, alongside the progress bars). |
| onStoryPress | (story, index) => Promise<void> | Callback when an avatar is pressed. Wait for the promise to resolve before the player opens (useful for preloading data/images). |
| onStepChange | (props: { step, story, storyIndex, stepIndex }) => void | Callback triggered when the active step or story changes. |
| preloadImagesEnabled | boolean | If true, the library will automatically try to prefetch the image prop of neighboring story steps. |
| flatListProps | FlatListProps | Additional props passed directly to the underlying React Native FlatList. |
StoryRenderProps<T>
This object is passed into your renderContent function. It gives you complete context and animated values.
| Property | Type | Description |
| ------------ | ---------------------- | ----------------------------------------------------------------------------------------------------------- |
| step | StoryStepType<T> | The current story step object to render. |
| story | StoryListItemType<T> | The parent story object containing the current step. |
| storyIndex | number | The index of the current active story. |
| stepIndex | number | The index of the current active step within the story. |
| stepsCount | number | The total number of steps in the current story. |
| isPaused | boolean | true if the user is holding the screen (paused). |
| progress | SharedValue<number> | A Reanimated shared value (0 to 100) representing the step playback progress. Use it for custom animations! |
Data Types
You can pass a generic type <T> to extend StoryStepType with your own custom properties (e.g., video URLs, rich text objects).
export type StoryListItemType<T = {}> = {
id: string;
image?: string; // Avatar preview
title?: string; // Avatar title
isViewed?: boolean;
steps: StoryStepType<T>[];
};
export type StoryStepType<T = {}> = {
id: string;
image?: string; // Default image URL
title?: string;
duration?: number; // Duration in milliseconds (default: 5000)
} & T;Hooks
useStoriesState
Provides read-only state of the active player and exposes methods to control playback directly from your custom components (like inside renderContent or HeaderComponent).
import { useStoriesState } from 'react-native-awesome-stories';
const CustomStoryOverlay = () => {
const { isPaused, pause, resume, close, goToStep } = useStoriesState();
return (
<Button onPress={isPaused ? resume : pause}>
{isPaused ? 'Play' : 'Pause'}
</Button>
);
};State Properties:
isOpen: booleancurrentStoryIndex: numbercurrentStepIndex: numberisPaused: boolean
Methods:
pause()/resume()close()goToStep(index: number)goToStory(index: number)
useStoriesController
Allows you to imperatively open or close the story player from anywhere in your app (even if you don't use StoriesList).
import { useStoriesController } from 'react-native-awesome-stories';
const ExternalComponent = () => {
const { openPlayer, closePlayer, isPlayerOpened } = useStoriesController();
const handleOpen = () => {
openPlayer({
stories: myStoriesArray,
storyIndex: 0,
stepIndex: 0,
config: {
renderContent: ({ step }) => <MyCustomStep step={step} />,
preloadImagesEnabled: true,
},
});
};
return <Button onPress={handleOpen}>Open Player manually</Button>;
};Theming (StoriesProvider)
You can customize the appearance of the StoriesList avatars via the theme prop on StoriesProvider:
export type StoriesThemeConfigType = {
borderColor?: string;
viewedBorderColor?: string;
skeletonBg?: string;
skeletonTintColor?: string;
listItemStyle?: {
width: number;
height: number;
borderRadius?: number;
// ...other ViewStyle props
};
};License
MIT
