react-instagram-stories 1.0.5 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +230 -85
- package/dist/index.cjs +9 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -4
- package/dist/index.d.ts +47 -4
- package/dist/index.js +9 -9
- package/dist/index.js.map +1 -1
- package/dist/styles.css +59 -388
- package/package.json +3 -5
package/README.md
CHANGED
|
@@ -14,11 +14,14 @@ A high-performance, fully customizable Instagram-style Stories component for Rea
|
|
|
14
14
|
- **Keyboard Navigation**: Full keyboard support for accessibility
|
|
15
15
|
- **TypeScript**: Complete type definitions included
|
|
16
16
|
- **Accessible**: ARIA labels and keyboard navigation
|
|
17
|
+
- **Tailwind CSS Support**: Customize every sub-element via `classNames` prop with Tailwind or custom CSS classes
|
|
18
|
+
- **3D Cube Transition**: Instagram-style 3D cube drag transition when switching between users
|
|
19
|
+
- **Story Resume**: Dragging back to a previous user resumes their story from where you left off
|
|
17
20
|
- **Lightweight**: ~30 KB with zero runtime dependencies
|
|
18
21
|
- **No Router Required**: Works with native browser history API
|
|
19
22
|
- **URL Navigation**: Built-in query parameter support (`?user=userId&story=storyId`)
|
|
20
23
|
- **Auto Progress**: Smart progress bar that pauses during video buffering
|
|
21
|
-
- **Smooth Transitions**:
|
|
24
|
+
- **Smooth Transitions**: 3D cube drag transitions between users, smooth animations between stories
|
|
22
25
|
|
|
23
26
|
## Installation
|
|
24
27
|
|
|
@@ -37,8 +40,8 @@ pnpm add react-instagram-stories
|
|
|
37
40
|
### Simple Usage (Recommended)
|
|
38
41
|
|
|
39
42
|
```tsx
|
|
40
|
-
import { Stories, demoUsers } from
|
|
41
|
-
import
|
|
43
|
+
import { Stories, demoUsers } from "react-instagram-stories";
|
|
44
|
+
import "react-instagram-stories/styles.css";
|
|
42
45
|
|
|
43
46
|
function App() {
|
|
44
47
|
return <Stories users={demoUsers} />;
|
|
@@ -52,8 +55,13 @@ That's it! Click on any avatar to open the story viewer. The URL automatically u
|
|
|
52
55
|
### Using Separate Components
|
|
53
56
|
|
|
54
57
|
```tsx
|
|
55
|
-
import {
|
|
56
|
-
|
|
58
|
+
import {
|
|
59
|
+
AvatarList,
|
|
60
|
+
StoryViewer,
|
|
61
|
+
demoUsers,
|
|
62
|
+
navigateWithParams,
|
|
63
|
+
} from "react-instagram-stories";
|
|
64
|
+
import "react-instagram-stories/styles.css";
|
|
57
65
|
|
|
58
66
|
function App() {
|
|
59
67
|
const handleAvatarClick = (userIndex: number) => {
|
|
@@ -76,20 +84,20 @@ function App() {
|
|
|
76
84
|
|
|
77
85
|
The StoryViewer supports URL-based navigation using query parameters with **user ID** and **story ID**:
|
|
78
86
|
|
|
79
|
-
| URL
|
|
80
|
-
|
|
81
|
-
| `?user=user-travel&story=travel-1` | Opens Travel user's first story
|
|
82
|
-
| `?user=user-polls&story=poll-1`
|
|
83
|
-
| `?user=user-launch&story=launch-2` | Opens Events user's second story
|
|
84
|
-
| No query params
|
|
87
|
+
| URL | Result |
|
|
88
|
+
| ---------------------------------- | ----------------------------------- |
|
|
89
|
+
| `?user=user-travel&story=travel-1` | Opens Travel user's first story |
|
|
90
|
+
| `?user=user-polls&story=poll-1` | Opens Interactive user's poll story |
|
|
91
|
+
| `?user=user-launch&story=launch-2` | Opens Events user's second story |
|
|
92
|
+
| No query params | Viewer stays closed |
|
|
85
93
|
|
|
86
94
|
### Navigation Helpers
|
|
87
95
|
|
|
88
96
|
```tsx
|
|
89
|
-
import { navigateWithParams, clearQueryParams } from
|
|
97
|
+
import { navigateWithParams, clearQueryParams } from "react-instagram-stories";
|
|
90
98
|
|
|
91
99
|
// Open story viewer with user ID and story ID
|
|
92
|
-
navigateWithParams({ user:
|
|
100
|
+
navigateWithParams({ user: "user-travel", story: "travel-1" });
|
|
93
101
|
|
|
94
102
|
// Close story viewer (clear params)
|
|
95
103
|
clearQueryParams();
|
|
@@ -102,20 +110,22 @@ clearQueryParams();
|
|
|
102
110
|
The all-in-one component with avatar list and story viewer.
|
|
103
111
|
|
|
104
112
|
```tsx
|
|
105
|
-
import { Stories } from
|
|
113
|
+
import { Stories } from "react-instagram-stories";
|
|
106
114
|
|
|
107
|
-
<Stories users={myUsers}
|
|
115
|
+
<Stories users={myUsers} />;
|
|
108
116
|
```
|
|
109
117
|
|
|
110
|
-
| Prop
|
|
111
|
-
|
|
112
|
-
| `users`
|
|
118
|
+
| Prop | Type | Default | Description |
|
|
119
|
+
| ------------ | ------------------- | ------------ | ---------------------------------------------------------------- |
|
|
120
|
+
| `users` | `User[]` | **required** | Array of user objects with their stories |
|
|
121
|
+
| `classNames` | `StoriesClassNames` | - | Object to customize sub-element CSS classes (Tailwind or custom) |
|
|
113
122
|
|
|
114
123
|
### `<StoryViewer />` Component
|
|
115
124
|
|
|
116
125
|
The story viewer component. Supports two modes:
|
|
117
126
|
|
|
118
127
|
#### Query Param Mode (Default)
|
|
128
|
+
|
|
119
129
|
When `isOpen` is not provided, reads from URL query params:
|
|
120
130
|
|
|
121
131
|
```tsx
|
|
@@ -123,6 +133,7 @@ When `isOpen` is not provided, reads from URL query params:
|
|
|
123
133
|
```
|
|
124
134
|
|
|
125
135
|
#### Controlled Mode
|
|
136
|
+
|
|
126
137
|
When `isOpen` is provided, you control the viewer state:
|
|
127
138
|
|
|
128
139
|
```tsx
|
|
@@ -131,19 +142,20 @@ When `isOpen` is provided, you control the viewer state:
|
|
|
131
142
|
isOpen={true}
|
|
132
143
|
initialUserIndex={0}
|
|
133
144
|
initialStoryIndex={0}
|
|
134
|
-
onClose={() => console.log(
|
|
145
|
+
onClose={() => console.log("closed")}
|
|
135
146
|
onStoryChange={(userIndex, storyIndex) => console.log(userIndex, storyIndex)}
|
|
136
147
|
/>
|
|
137
148
|
```
|
|
138
149
|
|
|
139
|
-
| Prop
|
|
140
|
-
|
|
141
|
-
| `users`
|
|
142
|
-
| `isOpen`
|
|
143
|
-
| `initialUserIndex`
|
|
144
|
-
| `initialStoryIndex` | `number`
|
|
145
|
-
| `onClose`
|
|
146
|
-
| `onStoryChange`
|
|
150
|
+
| Prop | Type | Default | Description |
|
|
151
|
+
| ------------------- | --------------------------------- | ------------ | ---------------------------------------------------------------- |
|
|
152
|
+
| `users` | `User[]` | **required** | Array of user objects |
|
|
153
|
+
| `isOpen` | `boolean` | - | Controls viewer visibility (enables controlled mode) |
|
|
154
|
+
| `initialUserIndex` | `number` | `0` | Starting user index |
|
|
155
|
+
| `initialStoryIndex` | `number` | `0` | Starting story index |
|
|
156
|
+
| `onClose` | `() => void` | - | Called when viewer closes |
|
|
157
|
+
| `onStoryChange` | `(userIndex, storyIndex) => void` | - | Called when story changes |
|
|
158
|
+
| `classNames` | `StoryViewerClassNames` | - | Object to customize sub-element CSS classes (Tailwind or custom) |
|
|
147
159
|
|
|
148
160
|
### `<AvatarList />` Component
|
|
149
161
|
|
|
@@ -156,10 +168,11 @@ The horizontal scrollable avatar list.
|
|
|
156
168
|
/>
|
|
157
169
|
```
|
|
158
170
|
|
|
159
|
-
| Prop
|
|
160
|
-
|
|
161
|
-
| `users`
|
|
162
|
-
| `onAvatarClick` | `(userIndex: number) => void` | Called when avatar is clicked
|
|
171
|
+
| Prop | Type | Description |
|
|
172
|
+
| --------------- | ----------------------------- | ---------------------------------------------------------------- |
|
|
173
|
+
| `users` | `User[]` | Array of user objects |
|
|
174
|
+
| `onAvatarClick` | `(userIndex: number) => void` | Called when avatar is clicked |
|
|
175
|
+
| `classNames` | `AvatarListClassNames` | Object to customize sub-element CSS classes (Tailwind or custom) |
|
|
163
176
|
|
|
164
177
|
## Story Types
|
|
165
178
|
|
|
@@ -187,6 +200,7 @@ The horizontal scrollable avatar list.
|
|
|
187
200
|
```
|
|
188
201
|
|
|
189
202
|
**Features:**
|
|
203
|
+
|
|
190
204
|
- Audio enabled by default
|
|
191
205
|
- Progress bar pauses during buffering
|
|
192
206
|
- Auto-detects video duration
|
|
@@ -234,6 +248,7 @@ const MyCustomStory: React.FC<StoryItemControls> = ({
|
|
|
234
248
|
```
|
|
235
249
|
|
|
236
250
|
**Control Methods Available:**
|
|
251
|
+
|
|
237
252
|
- `pause()` - Pause the story timer
|
|
238
253
|
- `resume()` - Resume the story timer
|
|
239
254
|
- `next()` - Go to next story
|
|
@@ -247,10 +262,14 @@ Build interactive experiences! Here are examples included in `demoUsers`:
|
|
|
247
262
|
### Poll Component
|
|
248
263
|
|
|
249
264
|
```tsx
|
|
250
|
-
const PollComponent: React.FC<StoryItemControls> = ({
|
|
265
|
+
const PollComponent: React.FC<StoryItemControls> = ({
|
|
266
|
+
pause,
|
|
267
|
+
resume,
|
|
268
|
+
next,
|
|
269
|
+
}) => {
|
|
251
270
|
const [selected, setSelected] = React.useState<number | null>(null);
|
|
252
271
|
const [votes, setVotes] = React.useState([42, 28, 18, 12]);
|
|
253
|
-
const options = [
|
|
272
|
+
const options = ["React", "Vue", "Angular", "Svelte"];
|
|
254
273
|
|
|
255
274
|
React.useEffect(() => {
|
|
256
275
|
pause(); // Pause timer during interaction
|
|
@@ -272,14 +291,16 @@ const PollComponent: React.FC<StoryItemControls> = ({ pause, resume, next }) =>
|
|
|
272
291
|
const total = votes.reduce((a, b) => a + b, 0);
|
|
273
292
|
|
|
274
293
|
return (
|
|
275
|
-
<div
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
294
|
+
<div
|
|
295
|
+
style={{
|
|
296
|
+
display: "flex",
|
|
297
|
+
flexDirection: "column",
|
|
298
|
+
height: "100%",
|
|
299
|
+
background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
|
|
300
|
+
padding: "20px",
|
|
301
|
+
}}
|
|
302
|
+
>
|
|
303
|
+
<h2 style={{ color: "white", marginBottom: "20px" }}>
|
|
283
304
|
What's your favorite framework?
|
|
284
305
|
</h2>
|
|
285
306
|
{options.map((option, index) => (
|
|
@@ -288,17 +309,18 @@ const PollComponent: React.FC<StoryItemControls> = ({ pause, resume, next }) =>
|
|
|
288
309
|
onClick={() => handleVote(index)}
|
|
289
310
|
disabled={selected !== null}
|
|
290
311
|
style={{
|
|
291
|
-
margin:
|
|
292
|
-
padding:
|
|
293
|
-
background:
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
312
|
+
margin: "8px 0",
|
|
313
|
+
padding: "15px",
|
|
314
|
+
background:
|
|
315
|
+
selected === index ? "#4CAF50" : "rgba(255,255,255,0.2)",
|
|
316
|
+
color: "white",
|
|
317
|
+
border: "none",
|
|
318
|
+
borderRadius: "12px",
|
|
319
|
+
fontSize: "16px",
|
|
320
|
+
cursor: selected !== null ? "default" : "pointer",
|
|
299
321
|
}}
|
|
300
322
|
>
|
|
301
|
-
<div style={{ display:
|
|
323
|
+
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
|
302
324
|
<span>{option}</span>
|
|
303
325
|
{selected !== null && (
|
|
304
326
|
<span>{((votes[index] / total) * 100).toFixed(0)}%</span>
|
|
@@ -318,7 +340,26 @@ const PollComponent: React.FC<StoryItemControls> = ({ pause, resume, next }) =>
|
|
|
318
340
|
Import the default styles:
|
|
319
341
|
|
|
320
342
|
```tsx
|
|
321
|
-
import
|
|
343
|
+
import "react-instagram-stories/styles.css";
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
**With Tailwind CSS**: Import the library styles **before** your Tailwind CSS so that utility classes can override them:
|
|
347
|
+
|
|
348
|
+
```css
|
|
349
|
+
/* Your global CSS file */
|
|
350
|
+
@import "react-instagram-stories/styles.css";
|
|
351
|
+
|
|
352
|
+
@tailwind base;
|
|
353
|
+
@tailwind components;
|
|
354
|
+
@tailwind utilities;
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
Or in JS, import the library CSS before your app's CSS:
|
|
358
|
+
|
|
359
|
+
```tsx
|
|
360
|
+
// main.tsx
|
|
361
|
+
import "react-instagram-stories/styles.css"; // first
|
|
362
|
+
import "./index.css"; // your Tailwind CSS — after
|
|
322
363
|
```
|
|
323
364
|
|
|
324
365
|
Override with custom CSS:
|
|
@@ -350,13 +391,60 @@ Override with custom CSS:
|
|
|
350
391
|
}
|
|
351
392
|
```
|
|
352
393
|
|
|
394
|
+
## Customization with classNames
|
|
395
|
+
|
|
396
|
+
Every component accepts a `classNames` prop for fine-grained styling using Tailwind CSS or custom CSS classes. The prop is a typed object that maps to specific sub-elements.
|
|
397
|
+
|
|
398
|
+
```tsx
|
|
399
|
+
<Stories
|
|
400
|
+
users={users}
|
|
401
|
+
classNames={{
|
|
402
|
+
avatarList: {
|
|
403
|
+
root: "bg-gray-900 p-4",
|
|
404
|
+
avatar: { ring: "border-pink-500", username: "text-xs text-gray-400" },
|
|
405
|
+
},
|
|
406
|
+
storyViewer: {
|
|
407
|
+
overlay: "bg-black/90",
|
|
408
|
+
closeButton: "hover:text-gray-300",
|
|
409
|
+
progressBars: {
|
|
410
|
+
bar: { fill: "bg-gradient-to-r from-pink-500 to-purple-500" },
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
}}
|
|
414
|
+
/>
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
You can also pass `classNames` directly to `StoryViewer` or `AvatarList` when using them separately:
|
|
418
|
+
|
|
419
|
+
```tsx
|
|
420
|
+
<AvatarList
|
|
421
|
+
users={users}
|
|
422
|
+
onAvatarClick={handleClick}
|
|
423
|
+
classNames={{
|
|
424
|
+
root: "bg-gray-900 p-4",
|
|
425
|
+
avatar: { ring: "border-pink-500", username: "text-xs text-gray-400" },
|
|
426
|
+
}}
|
|
427
|
+
/>
|
|
428
|
+
|
|
429
|
+
<StoryViewer
|
|
430
|
+
users={users}
|
|
431
|
+
classNames={{
|
|
432
|
+
overlay: "bg-black/90",
|
|
433
|
+
closeButton: "hover:text-gray-300",
|
|
434
|
+
progressBars: { bar: { fill: "bg-gradient-to-r from-pink-500 to-purple-500" } },
|
|
435
|
+
}}
|
|
436
|
+
/>
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
All `classNames` types are exported from the package. See the [TypeScript Types](#typescript-types) section for the full list.
|
|
440
|
+
|
|
353
441
|
## Advanced Usage
|
|
354
442
|
|
|
355
443
|
### Using Demo Data
|
|
356
444
|
|
|
357
445
|
```tsx
|
|
358
|
-
import { Stories, demoUsers } from
|
|
359
|
-
import
|
|
446
|
+
import { Stories, demoUsers } from "react-instagram-stories";
|
|
447
|
+
import "react-instagram-stories/styles.css";
|
|
360
448
|
|
|
361
449
|
function App() {
|
|
362
450
|
return <Stories users={demoUsers} />;
|
|
@@ -368,7 +456,7 @@ The `demoUsers` includes examples of all story types including interactive polls
|
|
|
368
456
|
### Generate Demo Users
|
|
369
457
|
|
|
370
458
|
```tsx
|
|
371
|
-
import { generateDemoUsers } from
|
|
459
|
+
import { generateDemoUsers } from "react-instagram-stories";
|
|
372
460
|
|
|
373
461
|
const users = generateDemoUsers(10); // 10 users with random stories
|
|
374
462
|
```
|
|
@@ -376,39 +464,39 @@ const users = generateDemoUsers(10); // 10 users with random stories
|
|
|
376
464
|
### Create Custom Stories
|
|
377
465
|
|
|
378
466
|
```tsx
|
|
379
|
-
import type { User } from
|
|
467
|
+
import type { User } from "react-instagram-stories";
|
|
380
468
|
|
|
381
469
|
const myUsers: User[] = [
|
|
382
470
|
{
|
|
383
|
-
id:
|
|
384
|
-
username:
|
|
385
|
-
avatarUrl:
|
|
471
|
+
id: "1",
|
|
472
|
+
username: "johndoe",
|
|
473
|
+
avatarUrl: "https://example.com/avatar.jpg",
|
|
386
474
|
hasUnreadStories: true, // Shows ring around avatar
|
|
387
475
|
stories: [
|
|
388
476
|
{
|
|
389
|
-
id:
|
|
390
|
-
type:
|
|
391
|
-
src:
|
|
392
|
-
alt:
|
|
477
|
+
id: "story-1",
|
|
478
|
+
type: "image",
|
|
479
|
+
src: "https://example.com/photo.jpg",
|
|
480
|
+
alt: "Beach sunset",
|
|
393
481
|
duration: 5000,
|
|
394
482
|
},
|
|
395
483
|
{
|
|
396
|
-
id:
|
|
397
|
-
type:
|
|
398
|
-
src:
|
|
484
|
+
id: "story-2",
|
|
485
|
+
type: "video",
|
|
486
|
+
src: "https://example.com/video.mp4",
|
|
399
487
|
// duration auto-detected
|
|
400
488
|
},
|
|
401
489
|
{
|
|
402
|
-
id:
|
|
403
|
-
type:
|
|
404
|
-
text:
|
|
405
|
-
backgroundColor:
|
|
406
|
-
textColor:
|
|
490
|
+
id: "story-3",
|
|
491
|
+
type: "text",
|
|
492
|
+
text: "Hello from my story!",
|
|
493
|
+
backgroundColor: "#FF6B6B",
|
|
494
|
+
textColor: "#FFFFFF",
|
|
407
495
|
duration: 5000,
|
|
408
496
|
},
|
|
409
497
|
{
|
|
410
|
-
id:
|
|
411
|
-
type:
|
|
498
|
+
id: "story-4",
|
|
499
|
+
type: "custom_component",
|
|
412
500
|
component: MyPollComponent,
|
|
413
501
|
duration: 10000,
|
|
414
502
|
},
|
|
@@ -422,8 +510,8 @@ const myUsers: User[] = [
|
|
|
422
510
|
If you don't want URL navigation, use controlled mode:
|
|
423
511
|
|
|
424
512
|
```tsx
|
|
425
|
-
import { useState } from
|
|
426
|
-
import { AvatarList, StoryViewer } from
|
|
513
|
+
import { useState } from "react";
|
|
514
|
+
import { AvatarList, StoryViewer } from "react-instagram-stories";
|
|
427
515
|
|
|
428
516
|
function App() {
|
|
429
517
|
const [viewerState, setViewerState] = useState({
|
|
@@ -435,7 +523,9 @@ function App() {
|
|
|
435
523
|
<>
|
|
436
524
|
<AvatarList
|
|
437
525
|
users={myUsers}
|
|
438
|
-
onAvatarClick={(index) =>
|
|
526
|
+
onAvatarClick={(index) =>
|
|
527
|
+
setViewerState({ isOpen: true, userIndex: index })
|
|
528
|
+
}
|
|
439
529
|
/>
|
|
440
530
|
<StoryViewer
|
|
441
531
|
users={myUsers}
|
|
@@ -458,6 +548,7 @@ function App() {
|
|
|
458
548
|
|
|
459
549
|
- **Tap Left/Right** - Navigate stories
|
|
460
550
|
- **Swipe Left/Right** - Change users
|
|
551
|
+
- **Drag Left/Right** - 3D cube transition between users (peek at next/previous user, snaps on release)
|
|
461
552
|
- **Swipe Down** - Close
|
|
462
553
|
- **Hold/Hover** - Pause
|
|
463
554
|
|
|
@@ -472,11 +563,18 @@ import type {
|
|
|
472
563
|
ImageStoryItem,
|
|
473
564
|
VideoStoryItem,
|
|
474
565
|
TextStoryItem,
|
|
475
|
-
CustomComponentStoryItem
|
|
476
|
-
|
|
566
|
+
CustomComponentStoryItem,
|
|
567
|
+
StoriesClassNames,
|
|
568
|
+
StoryViewerClassNames,
|
|
569
|
+
AvatarListClassNames,
|
|
570
|
+
AvatarClassNames,
|
|
571
|
+
StoryProgressBarsClassNames,
|
|
572
|
+
ProgressBarClassNames,
|
|
573
|
+
StoryItemClassNames,
|
|
574
|
+
} from "react-instagram-stories";
|
|
477
575
|
|
|
478
576
|
// Core Types
|
|
479
|
-
type StoryItemType =
|
|
577
|
+
type StoryItemType = "image" | "video" | "text" | "custom_component";
|
|
480
578
|
|
|
481
579
|
interface StoryItemControls {
|
|
482
580
|
pause: () => void;
|
|
@@ -493,19 +591,58 @@ interface User {
|
|
|
493
591
|
stories: StoryItem[];
|
|
494
592
|
hasUnreadStories?: boolean;
|
|
495
593
|
}
|
|
594
|
+
|
|
595
|
+
// ClassNames Types (for Tailwind / custom CSS customization)
|
|
596
|
+
interface StoriesClassNames {
|
|
597
|
+
avatarList?: AvatarListClassNames;
|
|
598
|
+
storyViewer?: StoryViewerClassNames;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
interface AvatarListClassNames {
|
|
602
|
+
root?: string;
|
|
603
|
+
avatar?: AvatarClassNames;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
interface AvatarClassNames {
|
|
607
|
+
root?: string;
|
|
608
|
+
ring?: string;
|
|
609
|
+
image?: string;
|
|
610
|
+
username?: string;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
interface StoryViewerClassNames {
|
|
614
|
+
overlay?: string;
|
|
615
|
+
closeButton?: string;
|
|
616
|
+
progressBars?: StoryProgressBarsClassNames;
|
|
617
|
+
storyItem?: StoryItemClassNames;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
interface StoryProgressBarsClassNames {
|
|
621
|
+
root?: string;
|
|
622
|
+
bar?: ProgressBarClassNames;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
interface ProgressBarClassNames {
|
|
626
|
+
root?: string;
|
|
627
|
+
fill?: string;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
interface StoryItemClassNames {
|
|
631
|
+
root?: string;
|
|
632
|
+
}
|
|
496
633
|
```
|
|
497
634
|
|
|
498
635
|
## Package Exports
|
|
499
636
|
|
|
500
637
|
```tsx
|
|
501
638
|
// Components
|
|
502
|
-
import { Stories, StoryViewer, AvatarList } from
|
|
639
|
+
import { Stories, StoryViewer, AvatarList } from "react-instagram-stories";
|
|
503
640
|
|
|
504
641
|
// Navigation helpers
|
|
505
|
-
import { navigateWithParams, clearQueryParams } from
|
|
642
|
+
import { navigateWithParams, clearQueryParams } from "react-instagram-stories";
|
|
506
643
|
|
|
507
644
|
// Demo data
|
|
508
|
-
import { demoUsers, generateDemoUsers } from
|
|
645
|
+
import { demoUsers, generateDemoUsers } from "react-instagram-stories";
|
|
509
646
|
|
|
510
647
|
// Types
|
|
511
648
|
import type {
|
|
@@ -516,18 +653,25 @@ import type {
|
|
|
516
653
|
ImageStoryItem,
|
|
517
654
|
VideoStoryItem,
|
|
518
655
|
TextStoryItem,
|
|
519
|
-
CustomComponentStoryItem
|
|
520
|
-
|
|
656
|
+
CustomComponentStoryItem,
|
|
657
|
+
StoriesClassNames,
|
|
658
|
+
StoryViewerClassNames,
|
|
659
|
+
AvatarListClassNames,
|
|
660
|
+
AvatarClassNames,
|
|
661
|
+
StoryProgressBarsClassNames,
|
|
662
|
+
ProgressBarClassNames,
|
|
663
|
+
StoryItemClassNames,
|
|
664
|
+
} from "react-instagram-stories";
|
|
521
665
|
|
|
522
666
|
// Styles
|
|
523
|
-
import
|
|
667
|
+
import "react-instagram-stories/styles.css";
|
|
524
668
|
```
|
|
525
669
|
|
|
526
670
|
## Performance
|
|
527
671
|
|
|
528
672
|
- **Bundle Size**: ~30 KB (minified)
|
|
529
673
|
- **Gzipped**: ~10 KB
|
|
530
|
-
- **Zero Runtime Dependencies
|
|
674
|
+
- **Zero Runtime Dependencies**: No production dependencies at all (framer-motion and tailwindcss-animate are dev-only)
|
|
531
675
|
- **Smart Preloading**: Preloads adjacent stories
|
|
532
676
|
- **Optimized Rendering**: Uses React.memo
|
|
533
677
|
- **Video Buffering Detection**: Pauses progress during buffering
|
|
@@ -536,6 +680,7 @@ import 'react-instagram-stories/styles.css';
|
|
|
536
680
|
|
|
537
681
|
- React 18+
|
|
538
682
|
- TypeScript
|
|
683
|
+
- CSS 3D Transforms (cube transition between users)
|
|
539
684
|
- Native Browser History API (no router needed)
|
|
540
685
|
- tsup (bundler)
|
|
541
686
|
|