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