ai-design-system 0.1.100 → 0.1.102
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/components/composites/ScenePlayer/ScenePlayer.stories.tsx +2 -0
- package/components/composites/ScenePlayer/ScenePlayer.tsx +74 -40
- package/dist/index.cjs +75 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +12 -39
- package/dist/index.d.ts +108 -97
- package/dist/index.js +75 -50
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
|
+
import type { FormEvent } from "react";
|
|
4
5
|
import { Button } from "@/components/primitives/Button";
|
|
5
6
|
import { Icon } from "@/components/primitives/Icon";
|
|
7
|
+
import { PromptInput } from "@/components/composites/PromptInput";
|
|
8
|
+
import type { PromptInputMessage } from "@/components/ai-elements/prompt-input";
|
|
6
9
|
import { cn } from "@/lib/utils";
|
|
7
10
|
|
|
8
11
|
export interface SceneItem {
|
|
@@ -18,15 +21,26 @@ export interface SceneItem {
|
|
|
18
21
|
[key: string]: unknown;
|
|
19
22
|
}
|
|
20
23
|
|
|
21
|
-
export interface ScenePlayerProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
24
|
+
export interface ScenePlayerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onSubmit"> {
|
|
22
25
|
scenes: SceneItem[];
|
|
23
26
|
title?: string;
|
|
24
27
|
avatarInitials?: string;
|
|
25
28
|
avatarColor?: string;
|
|
26
29
|
initialSceneIndex?: number;
|
|
27
30
|
isMuted?: boolean;
|
|
31
|
+
onBack?: () => void;
|
|
28
32
|
onClose?: () => void;
|
|
29
|
-
|
|
33
|
+
placeholder?: string;
|
|
34
|
+
promptValue?: string;
|
|
35
|
+
onPromptValueChange?: (value: string) => void;
|
|
36
|
+
onSubmit?: (
|
|
37
|
+
message: PromptInputMessage,
|
|
38
|
+
event: FormEvent<HTMLFormElement>
|
|
39
|
+
) => void | Promise<void>;
|
|
40
|
+
loading?: boolean;
|
|
41
|
+
onStop?: () => void;
|
|
42
|
+
enableSpeech?: boolean;
|
|
43
|
+
onPublish?: (currentScene: SceneItem, text?: string) => void;
|
|
30
44
|
publishPlaceholder?: string;
|
|
31
45
|
onSceneChange?: (sceneIndex: number, scene: SceneItem) => void;
|
|
32
46
|
}
|
|
@@ -40,15 +54,25 @@ export const ScenePlayer = React.forwardRef<HTMLDivElement, ScenePlayerProps>(
|
|
|
40
54
|
avatarColor = "bg-indigo-600",
|
|
41
55
|
initialSceneIndex = 0,
|
|
42
56
|
isMuted: initialMuted = false,
|
|
57
|
+
onBack,
|
|
43
58
|
onClose,
|
|
59
|
+
placeholder,
|
|
60
|
+
promptValue,
|
|
61
|
+
onPromptValueChange,
|
|
62
|
+
onSubmit,
|
|
63
|
+
loading = false,
|
|
64
|
+
onStop,
|
|
65
|
+
enableSpeech = true,
|
|
44
66
|
onPublish,
|
|
45
|
-
publishPlaceholder = "
|
|
67
|
+
publishPlaceholder = "Ask a question or provide instructions...",
|
|
46
68
|
onSceneChange,
|
|
47
69
|
className,
|
|
48
70
|
...props
|
|
49
71
|
},
|
|
50
72
|
ref
|
|
51
73
|
) => {
|
|
74
|
+
const handleBack = onBack || onClose;
|
|
75
|
+
|
|
52
76
|
const [currentSceneIndex, setCurrentSceneIndex] = React.useState<number>(() => {
|
|
53
77
|
if (initialSceneIndex >= 0 && initialSceneIndex < scenes.length) {
|
|
54
78
|
return initialSceneIndex;
|
|
@@ -61,6 +85,19 @@ export const ScenePlayer = React.forwardRef<HTMLDivElement, ScenePlayerProps>(
|
|
|
61
85
|
|
|
62
86
|
const activeScene = scenes[currentSceneIndex] || scenes[0];
|
|
63
87
|
|
|
88
|
+
const handlePromptSubmit = React.useCallback(
|
|
89
|
+
(message: PromptInputMessage, event: FormEvent<HTMLFormElement>) => {
|
|
90
|
+
if (onSubmit) {
|
|
91
|
+
onSubmit(message, event);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (onPublish) {
|
|
95
|
+
onPublish(activeScene, message.text);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
[onSubmit, onPublish, activeScene]
|
|
99
|
+
);
|
|
100
|
+
|
|
64
101
|
const handlePrev = React.useCallback(() => {
|
|
65
102
|
if (!scenes.length) return;
|
|
66
103
|
setCurrentSceneIndex((prev) => {
|
|
@@ -117,7 +154,7 @@ export const ScenePlayer = React.forwardRef<HTMLDivElement, ScenePlayerProps>(
|
|
|
117
154
|
handleNext();
|
|
118
155
|
} else if (e.key === "Escape") {
|
|
119
156
|
e.preventDefault();
|
|
120
|
-
|
|
157
|
+
handleBack?.();
|
|
121
158
|
} else if (e.key === "m" || e.key === "M") {
|
|
122
159
|
e.preventDefault();
|
|
123
160
|
setIsMuted((prev) => !prev);
|
|
@@ -126,7 +163,7 @@ export const ScenePlayer = React.forwardRef<HTMLDivElement, ScenePlayerProps>(
|
|
|
126
163
|
|
|
127
164
|
window.addEventListener("keydown", handleKeyDown);
|
|
128
165
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
129
|
-
}, [handlePrev, handleNext,
|
|
166
|
+
}, [handlePrev, handleNext, handleBack]);
|
|
130
167
|
|
|
131
168
|
if (!scenes || scenes.length === 0) {
|
|
132
169
|
return (
|
|
@@ -137,14 +174,14 @@ export const ScenePlayer = React.forwardRef<HTMLDivElement, ScenePlayerProps>(
|
|
|
137
174
|
{...props}
|
|
138
175
|
>
|
|
139
176
|
<p className="text-white/70 text-sm">No scenes available</p>
|
|
140
|
-
{
|
|
177
|
+
{handleBack && (
|
|
141
178
|
<Button
|
|
142
179
|
variant="ghost"
|
|
143
|
-
onClick={
|
|
180
|
+
onClick={handleBack}
|
|
144
181
|
className="mt-4 text-white hover:bg-white/20"
|
|
145
|
-
data-testid="btn-
|
|
182
|
+
data-testid="btn-back"
|
|
146
183
|
>
|
|
147
|
-
|
|
184
|
+
Back
|
|
148
185
|
</Button>
|
|
149
186
|
)}
|
|
150
187
|
</div>
|
|
@@ -183,8 +220,22 @@ export const ScenePlayer = React.forwardRef<HTMLDivElement, ScenePlayerProps>(
|
|
|
183
220
|
</div>
|
|
184
221
|
|
|
185
222
|
{/* Story Header Overlay */}
|
|
186
|
-
<div className="flex items-center justify-between px-
|
|
187
|
-
<div className="flex items-center gap-2
|
|
223
|
+
<div className="flex items-center justify-between px-3 py-2.5 z-20 shrink-0">
|
|
224
|
+
<div className="flex items-center gap-2 min-w-0">
|
|
225
|
+
{/* Back Button */}
|
|
226
|
+
{handleBack && (
|
|
227
|
+
<Button
|
|
228
|
+
variant="ghost"
|
|
229
|
+
size="icon"
|
|
230
|
+
data-testid="btn-back"
|
|
231
|
+
aria-label="Back"
|
|
232
|
+
onClick={handleBack}
|
|
233
|
+
className="h-8 w-8 rounded-full bg-black/40 hover:bg-white/20 text-white p-0 cursor-pointer shrink-0"
|
|
234
|
+
>
|
|
235
|
+
<Icon name="arrow-left" className="w-5 h-5 text-white" />
|
|
236
|
+
</Button>
|
|
237
|
+
)}
|
|
238
|
+
|
|
188
239
|
<div
|
|
189
240
|
className={cn(
|
|
190
241
|
"w-9 h-9 rounded-full flex items-center justify-center font-bold text-sm text-white shrink-0 ring-1.5 ring-white/80 overflow-hidden",
|
|
@@ -215,20 +266,6 @@ export const ScenePlayer = React.forwardRef<HTMLDivElement, ScenePlayerProps>(
|
|
|
215
266
|
>
|
|
216
267
|
<Icon name={isMuted ? "volume-x" : "volume-2"} className="w-4 h-4" />
|
|
217
268
|
</Button>
|
|
218
|
-
|
|
219
|
-
{/* Close Button */}
|
|
220
|
-
{onClose && (
|
|
221
|
-
<Button
|
|
222
|
-
variant="ghost"
|
|
223
|
-
size="icon"
|
|
224
|
-
data-testid="btn-close"
|
|
225
|
-
aria-label="Close scenes view"
|
|
226
|
-
onClick={onClose}
|
|
227
|
-
className="h-8 w-8 rounded-full bg-black/40 hover:bg-white/20 text-white p-0 cursor-pointer"
|
|
228
|
-
>
|
|
229
|
-
<Icon name="x" className="w-4 h-4" />
|
|
230
|
-
</Button>
|
|
231
|
-
)}
|
|
232
269
|
</div>
|
|
233
270
|
</div>
|
|
234
271
|
|
|
@@ -265,21 +302,18 @@ export const ScenePlayer = React.forwardRef<HTMLDivElement, ScenePlayerProps>(
|
|
|
265
302
|
</div>
|
|
266
303
|
</div>
|
|
267
304
|
|
|
268
|
-
{/* Bottom
|
|
269
|
-
<div className="
|
|
270
|
-
<
|
|
271
|
-
{publishPlaceholder}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
>
|
|
281
|
-
<Icon name="send" className="w-4 h-4 text-white" />
|
|
282
|
-
</Button>
|
|
305
|
+
{/* Bottom PromptInput Composite from Design System */}
|
|
306
|
+
<div className="p-3 bg-gradient-to-t from-black via-black/90 to-transparent pt-4 z-20 shrink-0">
|
|
307
|
+
<PromptInput
|
|
308
|
+
placeholder={placeholder || publishPlaceholder}
|
|
309
|
+
value={promptValue}
|
|
310
|
+
onChange={onPromptValueChange}
|
|
311
|
+
onSubmit={handlePromptSubmit}
|
|
312
|
+
loading={loading}
|
|
313
|
+
onStop={onStop}
|
|
314
|
+
enableSpeech={enableSpeech}
|
|
315
|
+
className="border border-border bg-background shadow-md overflow-hidden rounded-2xl"
|
|
316
|
+
/>
|
|
283
317
|
</div>
|
|
284
318
|
</div>
|
|
285
319
|
);
|
package/dist/index.cjs
CHANGED
|
@@ -14575,9 +14575,17 @@ var ScenePlayer = React3__namespace.forwardRef(
|
|
|
14575
14575
|
avatarColor = "bg-indigo-600",
|
|
14576
14576
|
initialSceneIndex = 0,
|
|
14577
14577
|
isMuted: initialMuted = false,
|
|
14578
|
+
onBack,
|
|
14578
14579
|
onClose,
|
|
14580
|
+
placeholder,
|
|
14581
|
+
promptValue,
|
|
14582
|
+
onPromptValueChange,
|
|
14583
|
+
onSubmit,
|
|
14584
|
+
loading = false,
|
|
14585
|
+
onStop,
|
|
14586
|
+
enableSpeech = true,
|
|
14579
14587
|
onPublish,
|
|
14580
|
-
publishPlaceholder = "
|
|
14588
|
+
publishPlaceholder = "Ask a question or provide instructions...",
|
|
14581
14589
|
onSceneChange,
|
|
14582
14590
|
className
|
|
14583
14591
|
} = _b, props = __objRest(_b, [
|
|
@@ -14587,13 +14595,22 @@ var ScenePlayer = React3__namespace.forwardRef(
|
|
|
14587
14595
|
"avatarColor",
|
|
14588
14596
|
"initialSceneIndex",
|
|
14589
14597
|
"isMuted",
|
|
14598
|
+
"onBack",
|
|
14590
14599
|
"onClose",
|
|
14600
|
+
"placeholder",
|
|
14601
|
+
"promptValue",
|
|
14602
|
+
"onPromptValueChange",
|
|
14603
|
+
"onSubmit",
|
|
14604
|
+
"loading",
|
|
14605
|
+
"onStop",
|
|
14606
|
+
"enableSpeech",
|
|
14591
14607
|
"onPublish",
|
|
14592
14608
|
"publishPlaceholder",
|
|
14593
14609
|
"onSceneChange",
|
|
14594
14610
|
"className"
|
|
14595
14611
|
]);
|
|
14596
14612
|
var _a2;
|
|
14613
|
+
const handleBack = onBack || onClose;
|
|
14597
14614
|
const [currentSceneIndex, setCurrentSceneIndex] = React3__namespace.useState(() => {
|
|
14598
14615
|
if (initialSceneIndex >= 0 && initialSceneIndex < scenes.length) {
|
|
14599
14616
|
return initialSceneIndex;
|
|
@@ -14603,6 +14620,18 @@ var ScenePlayer = React3__namespace.forwardRef(
|
|
|
14603
14620
|
const [isMuted, setIsMuted] = React3__namespace.useState(initialMuted);
|
|
14604
14621
|
const videoRef = React3__namespace.useRef(null);
|
|
14605
14622
|
const activeScene = scenes[currentSceneIndex] || scenes[0];
|
|
14623
|
+
const handlePromptSubmit = React3__namespace.useCallback(
|
|
14624
|
+
(message, event) => {
|
|
14625
|
+
if (onSubmit) {
|
|
14626
|
+
onSubmit(message, event);
|
|
14627
|
+
return;
|
|
14628
|
+
}
|
|
14629
|
+
if (onPublish) {
|
|
14630
|
+
onPublish(activeScene, message.text);
|
|
14631
|
+
}
|
|
14632
|
+
},
|
|
14633
|
+
[onSubmit, onPublish, activeScene]
|
|
14634
|
+
);
|
|
14606
14635
|
const handlePrev = React3__namespace.useCallback(() => {
|
|
14607
14636
|
if (!scenes.length) return;
|
|
14608
14637
|
setCurrentSceneIndex((prev) => {
|
|
@@ -14653,7 +14682,7 @@ var ScenePlayer = React3__namespace.forwardRef(
|
|
|
14653
14682
|
handleNext();
|
|
14654
14683
|
} else if (e.key === "Escape") {
|
|
14655
14684
|
e.preventDefault();
|
|
14656
|
-
|
|
14685
|
+
handleBack == null ? void 0 : handleBack();
|
|
14657
14686
|
} else if (e.key === "m" || e.key === "M") {
|
|
14658
14687
|
e.preventDefault();
|
|
14659
14688
|
setIsMuted((prev) => !prev);
|
|
@@ -14661,7 +14690,7 @@ var ScenePlayer = React3__namespace.forwardRef(
|
|
|
14661
14690
|
};
|
|
14662
14691
|
window.addEventListener("keydown", handleKeyDown);
|
|
14663
14692
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
14664
|
-
}, [handlePrev, handleNext,
|
|
14693
|
+
}, [handlePrev, handleNext, handleBack]);
|
|
14665
14694
|
if (!scenes || scenes.length === 0) {
|
|
14666
14695
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
14667
14696
|
"div",
|
|
@@ -14672,14 +14701,14 @@ var ScenePlayer = React3__namespace.forwardRef(
|
|
|
14672
14701
|
}, props), {
|
|
14673
14702
|
children: [
|
|
14674
14703
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-white/70 text-sm", children: "No scenes available" }),
|
|
14675
|
-
|
|
14704
|
+
handleBack && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14676
14705
|
Button2,
|
|
14677
14706
|
{
|
|
14678
14707
|
variant: "ghost",
|
|
14679
|
-
onClick:
|
|
14708
|
+
onClick: handleBack,
|
|
14680
14709
|
className: "mt-4 text-white hover:bg-white/20",
|
|
14681
|
-
"data-testid": "btn-
|
|
14682
|
-
children: "
|
|
14710
|
+
"data-testid": "btn-back",
|
|
14711
|
+
children: "Back"
|
|
14683
14712
|
}
|
|
14684
14713
|
)
|
|
14685
14714
|
]
|
|
@@ -14717,8 +14746,20 @@ var ScenePlayer = React3__namespace.forwardRef(
|
|
|
14717
14746
|
scene.id || `scene-${idx}`
|
|
14718
14747
|
);
|
|
14719
14748
|
}) }),
|
|
14720
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-
|
|
14721
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2
|
|
14749
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-3 py-2.5 z-20 shrink-0", children: [
|
|
14750
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
14751
|
+
handleBack && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14752
|
+
Button2,
|
|
14753
|
+
{
|
|
14754
|
+
variant: "ghost",
|
|
14755
|
+
size: "icon",
|
|
14756
|
+
"data-testid": "btn-back",
|
|
14757
|
+
"aria-label": "Back",
|
|
14758
|
+
onClick: handleBack,
|
|
14759
|
+
className: "h-8 w-8 rounded-full bg-black/40 hover:bg-white/20 text-white p-0 cursor-pointer shrink-0",
|
|
14760
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "arrow-left", className: "w-5 h-5 text-white" })
|
|
14761
|
+
}
|
|
14762
|
+
),
|
|
14722
14763
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14723
14764
|
"div",
|
|
14724
14765
|
{
|
|
@@ -14739,32 +14780,18 @@ var ScenePlayer = React3__namespace.forwardRef(
|
|
|
14739
14780
|
] })
|
|
14740
14781
|
] })
|
|
14741
14782
|
] }),
|
|
14742
|
-
/* @__PURE__ */ jsxRuntime.
|
|
14743
|
-
|
|
14744
|
-
|
|
14745
|
-
|
|
14746
|
-
|
|
14747
|
-
|
|
14748
|
-
|
|
14749
|
-
|
|
14750
|
-
|
|
14751
|
-
|
|
14752
|
-
|
|
14753
|
-
|
|
14754
|
-
),
|
|
14755
|
-
onClose && /* @__PURE__ */ jsxRuntime.jsx(
|
|
14756
|
-
Button2,
|
|
14757
|
-
{
|
|
14758
|
-
variant: "ghost",
|
|
14759
|
-
size: "icon",
|
|
14760
|
-
"data-testid": "btn-close",
|
|
14761
|
-
"aria-label": "Close scenes view",
|
|
14762
|
-
onClick: onClose,
|
|
14763
|
-
className: "h-8 w-8 rounded-full bg-black/40 hover:bg-white/20 text-white p-0 cursor-pointer",
|
|
14764
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "x", className: "w-4 h-4" })
|
|
14765
|
-
}
|
|
14766
|
-
)
|
|
14767
|
-
] })
|
|
14783
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14784
|
+
Button2,
|
|
14785
|
+
{
|
|
14786
|
+
variant: "ghost",
|
|
14787
|
+
size: "icon",
|
|
14788
|
+
"data-testid": "btn-toggle-mute",
|
|
14789
|
+
"aria-label": isMuted ? "Unmute audio" : "Mute audio",
|
|
14790
|
+
onClick: () => setIsMuted((prev) => !prev),
|
|
14791
|
+
className: "h-8 w-8 rounded-full bg-black/40 hover:bg-white/20 text-white p-0 cursor-pointer",
|
|
14792
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: isMuted ? "volume-x" : "volume-2", className: "w-4 h-4" })
|
|
14793
|
+
}
|
|
14794
|
+
) })
|
|
14768
14795
|
] }),
|
|
14769
14796
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 relative flex items-center justify-center bg-black overflow-hidden min-h-0", children: [
|
|
14770
14797
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -14804,21 +14831,19 @@ var ScenePlayer = React3__namespace.forwardRef(
|
|
|
14804
14831
|
)
|
|
14805
14832
|
] })
|
|
14806
14833
|
] }),
|
|
14807
|
-
/* @__PURE__ */ jsxRuntime.
|
|
14808
|
-
|
|
14809
|
-
|
|
14810
|
-
|
|
14811
|
-
|
|
14812
|
-
|
|
14813
|
-
|
|
14814
|
-
|
|
14815
|
-
|
|
14816
|
-
|
|
14817
|
-
|
|
14818
|
-
|
|
14819
|
-
|
|
14820
|
-
)
|
|
14821
|
-
] })
|
|
14834
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3 bg-gradient-to-t from-black via-black/90 to-transparent pt-4 z-20 shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
14835
|
+
PromptInput2,
|
|
14836
|
+
{
|
|
14837
|
+
placeholder: placeholder || publishPlaceholder,
|
|
14838
|
+
value: promptValue,
|
|
14839
|
+
onChange: onPromptValueChange,
|
|
14840
|
+
onSubmit: handlePromptSubmit,
|
|
14841
|
+
loading,
|
|
14842
|
+
onStop,
|
|
14843
|
+
enableSpeech,
|
|
14844
|
+
className: "border border-border bg-background shadow-md overflow-hidden rounded-2xl"
|
|
14845
|
+
}
|
|
14846
|
+
) })
|
|
14822
14847
|
]
|
|
14823
14848
|
})
|
|
14824
14849
|
);
|