@vanillaskyai/video 0.8.0 → 0.8.2
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/CHANGELOG.md +8 -0
- package/README.md +4 -0
- package/dist/assets/vanillasky-logo.svg +151 -0
- package/dist/react.js +397 -152
- package/docs/customization.md +11 -6
- package/docs/immersive-interface.md +87 -0
- package/docs/reference/design-system.html +123 -0
- package/package.json +1 -1
- package/starters/video-chat/index.html +2 -1
- package/starters/video-chat/package.json +1 -1
- package/styles/video-chat.css +659 -246
package/dist/react.js
CHANGED
|
@@ -2255,6 +2255,17 @@ function reducer(state, action) {
|
|
|
2255
2255
|
error: void 0
|
|
2256
2256
|
};
|
|
2257
2257
|
}
|
|
2258
|
+
case "restore": {
|
|
2259
|
+
const restored = {
|
|
2260
|
+
...initialState(state.muted),
|
|
2261
|
+
capabilities: state.capabilities,
|
|
2262
|
+
welcome: state.welcome,
|
|
2263
|
+
turns: action.turns,
|
|
2264
|
+
playerKey: state.playerKey
|
|
2265
|
+
};
|
|
2266
|
+
const latest = action.turns.at(-1);
|
|
2267
|
+
return latest ? reducer(restored, { type: "select", id: latest.id }) : restored;
|
|
2268
|
+
}
|
|
2258
2269
|
case "reset":
|
|
2259
2270
|
return { ...initialState(state.muted), capabilities: state.capabilities, welcome: state.welcome };
|
|
2260
2271
|
}
|
|
@@ -2338,6 +2349,9 @@ function prepareVisualScene(scene, mode) {
|
|
|
2338
2349
|
return overMedia ? { ...shown, textArchetype: "subtle" } : shown;
|
|
2339
2350
|
}
|
|
2340
2351
|
function useVideoChat(options = {}) {
|
|
2352
|
+
return useVideoChatSession(options).chat;
|
|
2353
|
+
}
|
|
2354
|
+
function useVideoChatSession(options = {}) {
|
|
2341
2355
|
const optionsRef = useRef3(options);
|
|
2342
2356
|
optionsRef.current = options;
|
|
2343
2357
|
const voiceWarningRef = useRef3(() => void 0);
|
|
@@ -2861,6 +2875,12 @@ function useVideoChat(options = {}) {
|
|
|
2861
2875
|
voiceRef.current.resume();
|
|
2862
2876
|
dispatch({ type: "reset" });
|
|
2863
2877
|
}, [cancel]);
|
|
2878
|
+
const restoreSession = useCallback2((turns) => {
|
|
2879
|
+
cancel("Restoring session");
|
|
2880
|
+
heldRef.current = false;
|
|
2881
|
+
voiceRef.current.resume();
|
|
2882
|
+
dispatch({ type: "restore", turns: turns.filter((turn) => turn.completed && turn.video).slice(-100) });
|
|
2883
|
+
}, [cancel]);
|
|
2864
2884
|
const setMuted = useCallback2((muted) => dispatch({ type: "mute", value: muted }), []);
|
|
2865
2885
|
const currentTurn = state.turns.at(-1);
|
|
2866
2886
|
const shownTurn = state.turns.find((turn) => turn.id === state.shownTurnId) ?? currentTurn;
|
|
@@ -2907,7 +2927,7 @@ function useVideoChat(options = {}) {
|
|
|
2907
2927
|
if (id) dispatch({ type: "error", id, error: errorFrom(cause) });
|
|
2908
2928
|
}
|
|
2909
2929
|
} : void 0;
|
|
2910
|
-
|
|
2930
|
+
const chat = {
|
|
2911
2931
|
ask,
|
|
2912
2932
|
cancel,
|
|
2913
2933
|
pause,
|
|
@@ -2934,15 +2954,16 @@ function useVideoChat(options = {}) {
|
|
|
2934
2954
|
playerKey: state.playerKey,
|
|
2935
2955
|
playerProps
|
|
2936
2956
|
};
|
|
2957
|
+
return { chat, restoreSession };
|
|
2937
2958
|
}
|
|
2938
2959
|
|
|
2939
2960
|
// src/video-chat/video-chat.tsx
|
|
2940
|
-
import { useCallback as
|
|
2961
|
+
import { useCallback as useCallback6, useEffect as useEffect9, useId, useLayoutEffect, useMemo as useMemo2, useRef as useRef7, useState as useState6 } from "react";
|
|
2941
2962
|
|
|
2942
2963
|
// src/video-chat/modes.ts
|
|
2943
2964
|
var visualModes = [
|
|
2944
|
-
{ id: "templates", label: "Templates only", note: "
|
|
2945
|
-
{ id: "full", label: "Full AI video", note: "
|
|
2965
|
+
{ id: "templates", label: "Templates only", note: "Animated text, diagrams and charts" },
|
|
2966
|
+
{ id: "full", label: "Full AI video", note: "AI-generated footage \xB7 billed per clip" }
|
|
2946
2967
|
];
|
|
2947
2968
|
var defaultMode = visualModes[0];
|
|
2948
2969
|
var modeById = (id) => visualModes.find((mode) => mode.id === id) ?? defaultMode;
|
|
@@ -3406,14 +3427,77 @@ function useVoiceInput(onTranscript, transcriptionAvailable = false, options = {
|
|
|
3406
3427
|
return { supported, listening, thinking, error, toggle, stop };
|
|
3407
3428
|
}
|
|
3408
3429
|
|
|
3430
|
+
// src/video-chat/use-immersive-controls.ts
|
|
3431
|
+
import { useCallback as useCallback5, useEffect as useEffect8, useRef as useRef6, useState as useState5 } from "react";
|
|
3432
|
+
function useImmersiveControls(playing, pinned, hasCaptions = false) {
|
|
3433
|
+
const [visible, setVisible] = useState5(true);
|
|
3434
|
+
const hovered = useRef6(false);
|
|
3435
|
+
const focused = useRef6(false);
|
|
3436
|
+
const previousCaptions = useRef6(false);
|
|
3437
|
+
const timer = useRef6(null);
|
|
3438
|
+
const clearTimer = useCallback5(() => {
|
|
3439
|
+
if (timer.current !== null) clearTimeout(timer.current);
|
|
3440
|
+
timer.current = null;
|
|
3441
|
+
}, []);
|
|
3442
|
+
const reveal = useCallback5(() => {
|
|
3443
|
+
clearTimer();
|
|
3444
|
+
setVisible(true);
|
|
3445
|
+
if (playing && !pinned && !hovered.current && !focused.current) {
|
|
3446
|
+
timer.current = setTimeout(() => {
|
|
3447
|
+
timer.current = null;
|
|
3448
|
+
setVisible(false);
|
|
3449
|
+
}, 2e3);
|
|
3450
|
+
}
|
|
3451
|
+
}, [clearTimer, playing, pinned]);
|
|
3452
|
+
useEffect8(() => {
|
|
3453
|
+
const firstCaption = hasCaptions && !previousCaptions.current;
|
|
3454
|
+
previousCaptions.current = hasCaptions;
|
|
3455
|
+
if (firstCaption && playing && !pinned && !focused.current) {
|
|
3456
|
+
hovered.current = false;
|
|
3457
|
+
clearTimer();
|
|
3458
|
+
setVisible(false);
|
|
3459
|
+
} else {
|
|
3460
|
+
reveal();
|
|
3461
|
+
}
|
|
3462
|
+
return clearTimer;
|
|
3463
|
+
}, [hasCaptions, playing, pinned, reveal, clearTimer]);
|
|
3464
|
+
const onPointerEnter = useCallback5((event) => {
|
|
3465
|
+
if (event?.pointerType === "touch") return;
|
|
3466
|
+
hovered.current = true;
|
|
3467
|
+
reveal();
|
|
3468
|
+
}, [reveal]);
|
|
3469
|
+
const onPointerLeave = useCallback5(() => {
|
|
3470
|
+
if (!hovered.current) return;
|
|
3471
|
+
hovered.current = false;
|
|
3472
|
+
reveal();
|
|
3473
|
+
}, [reveal]);
|
|
3474
|
+
const onFocusCapture = useCallback5((event) => {
|
|
3475
|
+
focused.current = event.target.matches(":focus-visible");
|
|
3476
|
+
reveal();
|
|
3477
|
+
}, [reveal]);
|
|
3478
|
+
const onBlurCapture = useCallback5((event) => {
|
|
3479
|
+
if (focused.current && !event.currentTarget.contains(event.relatedTarget)) {
|
|
3480
|
+
focused.current = false;
|
|
3481
|
+
reveal();
|
|
3482
|
+
}
|
|
3483
|
+
}, [reveal]);
|
|
3484
|
+
return { visible, reveal, onPointerEnter, onPointerLeave, onFocusCapture, onBlurCapture };
|
|
3485
|
+
}
|
|
3486
|
+
|
|
3487
|
+
// src/video-chat/logo.tsx
|
|
3488
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
3489
|
+
function Logo() {
|
|
3490
|
+
return /* @__PURE__ */ jsx6("img", { className: "brand-logo", src: new URL("./assets/vanillasky-logo.svg", import.meta.url).href, alt: "VanillaSky", width: 144, height: 36 });
|
|
3491
|
+
}
|
|
3492
|
+
|
|
3409
3493
|
// src/video-chat/video-chat.tsx
|
|
3410
|
-
import { Fragment as Fragment4, jsx as
|
|
3494
|
+
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
3411
3495
|
var DESKTOP_WIDTH = 900;
|
|
3412
3496
|
function useViewportOrientation() {
|
|
3413
|
-
const [portrait, setPortrait] =
|
|
3414
|
-
|
|
3497
|
+
const [portrait, setPortrait] = useState6(() => typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia(`(max-width: ${DESKTOP_WIDTH - 1}px) and (orientation: portrait)`).matches : false);
|
|
3498
|
+
useEffect9(() => {
|
|
3415
3499
|
if (typeof window.matchMedia !== "function") return;
|
|
3416
|
-
const query = window.matchMedia(`(max-width: ${DESKTOP_WIDTH - 1}px)`);
|
|
3500
|
+
const query = window.matchMedia(`(max-width: ${DESKTOP_WIDTH - 1}px) and (orientation: portrait)`);
|
|
3417
3501
|
const update = () => setPortrait(query.matches);
|
|
3418
3502
|
update();
|
|
3419
3503
|
query.addEventListener("change", update);
|
|
@@ -3428,8 +3512,8 @@ var STEPS = [
|
|
|
3428
3512
|
"Still filming\u2026"
|
|
3429
3513
|
];
|
|
3430
3514
|
function useFilmingStep(active, key) {
|
|
3431
|
-
const [step, setStep] =
|
|
3432
|
-
|
|
3515
|
+
const [step, setStep] = useState6(0);
|
|
3516
|
+
useEffect9(() => {
|
|
3433
3517
|
if (!active) return;
|
|
3434
3518
|
setStep(0);
|
|
3435
3519
|
const stepper = window.setInterval(() => setStep((current) => current + 1), 3e3);
|
|
@@ -3438,22 +3522,29 @@ function useFilmingStep(active, key) {
|
|
|
3438
3522
|
return STEPS[Math.min(step, STEPS.length - 1)];
|
|
3439
3523
|
}
|
|
3440
3524
|
function Waveform({ active, listening }) {
|
|
3441
|
-
return /* @__PURE__ */
|
|
3525
|
+
return /* @__PURE__ */ jsx7("span", { className: `waveform${active ? " on" : ""}${listening ? " hearing" : ""}`, "aria-hidden": "true", children: [0, 1, 2, 3, 4].map((bar) => /* @__PURE__ */ jsx7("span", { style: { animationDelay: `${bar * 140}ms`, animationDuration: `${900 + bar * 130}ms` } }, bar)) });
|
|
3442
3526
|
}
|
|
3443
3527
|
function VideoChat({ options = {}, className, welcomeTitle }) {
|
|
3444
|
-
const [draft, setDraft] =
|
|
3445
|
-
const [
|
|
3446
|
-
const [
|
|
3447
|
-
const [
|
|
3448
|
-
const [
|
|
3449
|
-
const [
|
|
3528
|
+
const [draft, setDraft] = useState6("");
|
|
3529
|
+
const [savedSessions, setSavedSessions] = useState6([]);
|
|
3530
|
+
const [themeId, setThemeId] = useState6(defaultTheme.id);
|
|
3531
|
+
const [modeId, setModeId] = useState6(options.mode ?? defaultMode.id);
|
|
3532
|
+
const [historyOpen, setHistoryOpen] = useState6(false);
|
|
3533
|
+
const [settingsOpen, setSettingsOpen] = useState6(false);
|
|
3534
|
+
const [aboutOpen, setAboutOpen] = useState6(false);
|
|
3535
|
+
const [captionsOn, setCaptionsOn] = useState6(true);
|
|
3536
|
+
const [captionsExpanded, setCaptionsExpanded] = useState6(false);
|
|
3537
|
+
const [alwaysShowControls, setAlwaysShowControls] = useState6(false);
|
|
3538
|
+
const [editing, setEditing] = useState6(false);
|
|
3539
|
+
const resumeAfterInput = useRef7(false);
|
|
3540
|
+
const panelRef = useRef7(null);
|
|
3541
|
+
const composerRef = useRef7(null);
|
|
3450
3542
|
const viewportOrientation = useViewportOrientation();
|
|
3451
|
-
const [themeChoice, setThemeChoice] = useState5("system");
|
|
3452
3543
|
const theme = themeById(themeId);
|
|
3453
3544
|
const sessionOrientation = options.orientation ?? viewportOrientation;
|
|
3454
3545
|
const { brand: configuredBrand, style: configuredStyle, ...sessionOptions } = options;
|
|
3455
3546
|
const presentationBrand = configuredBrand ?? theme.brand;
|
|
3456
|
-
const chat =
|
|
3547
|
+
const { chat, restoreSession } = useVideoChatSession({
|
|
3457
3548
|
...sessionOptions,
|
|
3458
3549
|
mode: modeId,
|
|
3459
3550
|
orientation: sessionOrientation,
|
|
@@ -3464,16 +3555,13 @@ function VideoChat({ options = {}, className, welcomeTitle }) {
|
|
|
3464
3555
|
const historyId = `${instanceId}-history`;
|
|
3465
3556
|
const settingsId = `${instanceId}-settings`;
|
|
3466
3557
|
const promptId = `${instanceId}-prompt`;
|
|
3467
|
-
const responseTitleId = `${instanceId}-response-title`;
|
|
3468
|
-
const appearanceName = `${instanceId}-appearance`;
|
|
3469
3558
|
const visualsName = `${instanceId}-visuals`;
|
|
3470
3559
|
const styleName = `${instanceId}-style`;
|
|
3471
|
-
const inputRef =
|
|
3472
|
-
const historyRef =
|
|
3473
|
-
const historyButtonRef =
|
|
3474
|
-
const settingsRef =
|
|
3475
|
-
const settingsButtonRef =
|
|
3476
|
-
const sheetRef = useRef6(null);
|
|
3560
|
+
const inputRef = useRef7(null);
|
|
3561
|
+
const historyRef = useRef7(null);
|
|
3562
|
+
const historyButtonRef = useRef7(null);
|
|
3563
|
+
const settingsRef = useRef7(null);
|
|
3564
|
+
const settingsButtonRef = useRef7(null);
|
|
3477
3565
|
const listen = useVoiceInput(setDraft, chat.capabilities?.transcription ?? false, {
|
|
3478
3566
|
endpoint: options.endpoint,
|
|
3479
3567
|
headers: options.headers,
|
|
@@ -3482,40 +3570,49 @@ function VideoChat({ options = {}, className, welcomeTitle }) {
|
|
|
3482
3570
|
});
|
|
3483
3571
|
const historySurfaces = useMemo2(() => [historyRef, historyButtonRef], []);
|
|
3484
3572
|
const settingsSurfaces = useMemo2(() => [settingsRef, settingsButtonRef], []);
|
|
3485
|
-
const
|
|
3486
|
-
const
|
|
3487
|
-
const closeSettings = useCallback5(() => setSettingsOpen(false), []);
|
|
3488
|
-
const closeSheet = useCallback5(() => setSheetOpen(false), []);
|
|
3573
|
+
const closeHistory = useCallback6(() => setHistoryOpen(false), []);
|
|
3574
|
+
const closeSettings = useCallback6(() => setSettingsOpen(false), []);
|
|
3489
3575
|
useDismiss(historyOpen, closeHistory, historySurfaces);
|
|
3490
3576
|
useDismiss(settingsOpen, closeSettings, settingsSurfaces);
|
|
3491
|
-
|
|
3492
|
-
useFocusTrap(
|
|
3493
|
-
const ask =
|
|
3577
|
+
useFocusTrap(settingsOpen, settingsRef);
|
|
3578
|
+
useFocusTrap(historyOpen, historyRef);
|
|
3579
|
+
const ask = useCallback6((value) => {
|
|
3494
3580
|
const prompt = (typeof value === "string" ? value : value.prompt).trim();
|
|
3495
3581
|
if (!prompt) return;
|
|
3496
3582
|
setDraft("");
|
|
3497
3583
|
listen.stop();
|
|
3498
3584
|
setHistoryOpen(false);
|
|
3499
3585
|
setSettingsOpen(false);
|
|
3500
|
-
|
|
3586
|
+
setCaptionsExpanded(false);
|
|
3587
|
+
setEditing(false);
|
|
3588
|
+
resumeAfterInput.current = false;
|
|
3589
|
+
inputRef.current?.blur();
|
|
3501
3590
|
void chat.ask(prompt, typeof value === "string" ? void 0 : {
|
|
3502
3591
|
openingMedia: value.media,
|
|
3503
3592
|
opening: value.opening
|
|
3504
3593
|
});
|
|
3505
3594
|
}, [chat, listen]);
|
|
3506
|
-
const newSession =
|
|
3595
|
+
const newSession = useCallback6(() => {
|
|
3507
3596
|
if (chat.turns.length === 0) {
|
|
3508
3597
|
inputRef.current?.focus();
|
|
3509
3598
|
return;
|
|
3510
3599
|
}
|
|
3600
|
+
listen.stop();
|
|
3601
|
+
setDraft("");
|
|
3602
|
+
const completed = chat.turns.filter((turn) => turn.completed && turn.video);
|
|
3603
|
+
if (completed.length) setSavedSessions((sessions) => [{ id: completed[0].id, turns: completed }, ...sessions].slice(0, 10));
|
|
3511
3604
|
chat.reset();
|
|
3512
3605
|
setHistoryOpen(false);
|
|
3513
3606
|
setSettingsOpen(false);
|
|
3514
|
-
|
|
3515
|
-
|
|
3607
|
+
setCaptionsExpanded(false);
|
|
3608
|
+
setEditing(false);
|
|
3609
|
+
resumeAfterInput.current = false;
|
|
3610
|
+
inputRef.current?.blur();
|
|
3611
|
+
}, [chat, listen]);
|
|
3516
3612
|
const current = chat.currentTurn;
|
|
3517
3613
|
const shown = chat.shownTurn;
|
|
3518
3614
|
const showing = chat.playerProps != null;
|
|
3615
|
+
const ambientPoster = shown?.openingMedia?.type === "image" ? shown.openingMedia.url : shown?.openingMedia?.posterUrl;
|
|
3519
3616
|
const waitingForPicture = chat.turns.length > 0 && !showing && (chat.status === "composing" || chat.status === "playing" || chat.status === "paused");
|
|
3520
3617
|
const filmingStep = useFilmingStep(waitingForPicture, current?.id);
|
|
3521
3618
|
const status = chat.turns.length === 0 ? "idle" : chat.status === "composing" ? "drawing" : chat.status === "playing" ? "narrating" : chat.status === "error" || chat.status === "cancelled" ? "ended" : chat.status;
|
|
@@ -3524,47 +3621,99 @@ function VideoChat({ options = {}, className, welcomeTitle }) {
|
|
|
3524
3621
|
const availableModes = visualModes.filter((option) => chat.availableModes.includes(option.id));
|
|
3525
3622
|
const selectedMode = modeById(modeId);
|
|
3526
3623
|
const line = chat.caption ?? "";
|
|
3527
|
-
const
|
|
3624
|
+
const fullTranscript = shown?.video ? [shown.opening, ...shown.video.scenes.map((scene) => scene.narration)].filter((entry) => Boolean(entry)) : chat.transcript;
|
|
3625
|
+
const transport = status === "narrating" ? { label: "Pause", action: chat.pause, icon: /* @__PURE__ */ jsx7(Stop, {}) } : status === "paused" ? { label: "Continue", action: chat.resume, icon: /* @__PURE__ */ jsx7(Play, {}) } : status === "ended" && shown?.completed && shown.video ? { label: "Play again", action: chat.replay, icon: /* @__PURE__ */ jsx7(Replay, {}) } : void 0;
|
|
3626
|
+
const cancelInput = useCallback6(() => {
|
|
3627
|
+
listen.stop();
|
|
3628
|
+
setDraft("");
|
|
3629
|
+
setEditing(false);
|
|
3630
|
+
inputRef.current?.blur();
|
|
3631
|
+
if (resumeAfterInput.current) chat.resume();
|
|
3632
|
+
resumeAfterInput.current = false;
|
|
3633
|
+
}, [listen, chat]);
|
|
3634
|
+
const beginInput = (speak = false) => {
|
|
3635
|
+
if (!editing) {
|
|
3636
|
+
resumeAfterInput.current = chat.status === "playing" || chat.status === "composing";
|
|
3637
|
+
if (resumeAfterInput.current) chat.pause();
|
|
3638
|
+
}
|
|
3639
|
+
setEditing(true);
|
|
3640
|
+
setSettingsOpen(false);
|
|
3641
|
+
setHistoryOpen(false);
|
|
3642
|
+
if (speak) listen.toggle();
|
|
3643
|
+
};
|
|
3644
|
+
const controls = useImmersiveControls(
|
|
3645
|
+
status === "narrating" || Boolean(line) && status !== "paused",
|
|
3646
|
+
alwaysShowControls || captionsExpanded || editing || historyOpen || settingsOpen || listen.listening || listen.thinking || Boolean(chat.error || listen.error),
|
|
3647
|
+
captionsOn && Boolean(line)
|
|
3648
|
+
);
|
|
3649
|
+
const captionControls = useImmersiveControls(Boolean(line), captionsExpanded, false);
|
|
3650
|
+
const controlEvents = {
|
|
3651
|
+
onPointerEnter: controls.onPointerEnter,
|
|
3652
|
+
onPointerLeave: controls.onPointerLeave,
|
|
3653
|
+
onFocusCapture: controls.onFocusCapture,
|
|
3654
|
+
onBlurCapture: controls.onBlurCapture
|
|
3655
|
+
};
|
|
3656
|
+
useLayoutEffect(() => {
|
|
3657
|
+
const composer = composerRef.current;
|
|
3658
|
+
if (!composer) return;
|
|
3659
|
+
const measure = () => panelRef.current?.style.setProperty("--composer-height", `${composer.getBoundingClientRect().height}px`);
|
|
3660
|
+
measure();
|
|
3661
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
3662
|
+
const observer = new ResizeObserver(measure);
|
|
3663
|
+
observer.observe(composer);
|
|
3664
|
+
return () => observer.disconnect();
|
|
3665
|
+
}, []);
|
|
3528
3666
|
return /* @__PURE__ */ jsxs6(
|
|
3529
3667
|
"div",
|
|
3530
3668
|
{
|
|
3531
3669
|
className: `vanillasky-video-chat${className ? ` ${className}` : ""}`,
|
|
3532
3670
|
"data-orientation": stageOrientation,
|
|
3533
|
-
"data-
|
|
3671
|
+
"data-controls-visible": controls.visible,
|
|
3672
|
+
tabIndex: 0,
|
|
3673
|
+
"aria-label": "Video conversation",
|
|
3674
|
+
onPointerMove: controls.reveal,
|
|
3675
|
+
onPointerDown: controls.reveal,
|
|
3676
|
+
onKeyDownCapture: controls.reveal,
|
|
3534
3677
|
children: [
|
|
3535
|
-
/* @__PURE__ */ jsxs6("header", { className: "chrome", children: [
|
|
3678
|
+
/* @__PURE__ */ jsxs6("header", { className: "chrome", ...controlEvents, children: [
|
|
3679
|
+
/* @__PURE__ */ jsx7("div", { className: "session-brand", children: /* @__PURE__ */ jsx7(Logo, {}) }),
|
|
3536
3680
|
/* @__PURE__ */ jsxs6("div", { className: "group", children: [
|
|
3537
|
-
/* @__PURE__ */
|
|
3681
|
+
/* @__PURE__ */ jsxs6(
|
|
3538
3682
|
"button",
|
|
3539
3683
|
{
|
|
3540
3684
|
type: "button",
|
|
3541
3685
|
className: "round",
|
|
3542
|
-
"aria-label":
|
|
3686
|
+
"aria-label": "New session",
|
|
3543
3687
|
onClick: newSession,
|
|
3544
|
-
children:
|
|
3688
|
+
children: [
|
|
3689
|
+
/* @__PURE__ */ jsx7(Plus, {}),
|
|
3690
|
+
/* @__PURE__ */ jsx7("span", { className: "nav-label", children: "New session" })
|
|
3691
|
+
]
|
|
3545
3692
|
}
|
|
3546
3693
|
),
|
|
3547
|
-
|
|
3694
|
+
/* @__PURE__ */ jsxs6(
|
|
3548
3695
|
"button",
|
|
3549
3696
|
{
|
|
3550
3697
|
ref: historyButtonRef,
|
|
3551
3698
|
type: "button",
|
|
3552
3699
|
className: "pill",
|
|
3553
3700
|
"aria-expanded": historyOpen,
|
|
3701
|
+
"aria-label": "History",
|
|
3702
|
+
"aria-haspopup": "dialog",
|
|
3554
3703
|
"aria-controls": historyId,
|
|
3555
3704
|
onClick: () => {
|
|
3556
3705
|
setHistoryOpen((open) => !open);
|
|
3557
3706
|
setSettingsOpen(false);
|
|
3558
3707
|
},
|
|
3559
3708
|
children: [
|
|
3560
|
-
|
|
3561
|
-
"
|
|
3709
|
+
/* @__PURE__ */ jsx7(Replay, {}),
|
|
3710
|
+
/* @__PURE__ */ jsx7("span", { className: "nav-label", children: "History" })
|
|
3562
3711
|
]
|
|
3563
3712
|
}
|
|
3564
3713
|
)
|
|
3565
3714
|
] }),
|
|
3566
3715
|
/* @__PURE__ */ jsxs6("div", { className: "group", children: [
|
|
3567
|
-
/* @__PURE__ */
|
|
3716
|
+
/* @__PURE__ */ jsx7(
|
|
3568
3717
|
"button",
|
|
3569
3718
|
{
|
|
3570
3719
|
ref: settingsButtonRef,
|
|
@@ -3578,10 +3727,10 @@ function VideoChat({ options = {}, className, welcomeTitle }) {
|
|
|
3578
3727
|
setSettingsOpen((open) => !open);
|
|
3579
3728
|
setHistoryOpen(false);
|
|
3580
3729
|
},
|
|
3581
|
-
children: /* @__PURE__ */
|
|
3730
|
+
children: /* @__PURE__ */ jsx7(Gear, {})
|
|
3582
3731
|
}
|
|
3583
3732
|
),
|
|
3584
|
-
/* @__PURE__ */
|
|
3733
|
+
/* @__PURE__ */ jsx7(
|
|
3585
3734
|
"button",
|
|
3586
3735
|
{
|
|
3587
3736
|
type: "button",
|
|
@@ -3589,60 +3738,102 @@ function VideoChat({ options = {}, className, welcomeTitle }) {
|
|
|
3589
3738
|
"aria-label": chat.muted ? "Turn the voice on" : "Turn the voice off",
|
|
3590
3739
|
"aria-pressed": chat.muted,
|
|
3591
3740
|
onClick: () => chat.setMuted(!chat.muted),
|
|
3592
|
-
children: chat.muted ? /* @__PURE__ */
|
|
3741
|
+
children: chat.muted ? /* @__PURE__ */ jsx7(Muted, {}) : /* @__PURE__ */ jsx7(Sound, {})
|
|
3593
3742
|
}
|
|
3594
3743
|
)
|
|
3595
3744
|
] })
|
|
3596
3745
|
] }),
|
|
3597
3746
|
/* @__PURE__ */ jsxs6("div", { className: "stage-area", children: [
|
|
3598
3747
|
/* @__PURE__ */ jsxs6("div", { className: "stage", style: { background: themeBackground(presentationBrand) }, children: [
|
|
3748
|
+
showing && /* @__PURE__ */ jsx7("div", { className: "ambient-media", "aria-hidden": "true", children: ambientPoster && /* @__PURE__ */ jsx7("img", { className: "frame-media", src: ambientPoster, alt: "" }) }),
|
|
3599
3749
|
!showing && /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
3600
|
-
/* @__PURE__ */
|
|
3750
|
+
/* @__PURE__ */ jsx7("div", { className: "ground", "aria-hidden": "true" }),
|
|
3601
3751
|
shown?.openingMedia && /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
3602
|
-
/* @__PURE__ */
|
|
3603
|
-
/* @__PURE__ */
|
|
3752
|
+
/* @__PURE__ */ jsx7(Frame, { media: shown.openingMedia, poster: true }),
|
|
3753
|
+
/* @__PURE__ */ jsx7("div", { className: "opening-wash", "aria-hidden": "true" })
|
|
3604
3754
|
] }),
|
|
3605
|
-
chat.turns.length === 0 && /* @__PURE__ */
|
|
3755
|
+
chat.turns.length === 0 && /* @__PURE__ */ jsx7(Welcome, { data: chat.welcome, onAsk: ask, title: welcomeTitle }),
|
|
3606
3756
|
shown?.prompt && /* @__PURE__ */ jsxs6("div", { className: "asked", children: [
|
|
3607
|
-
/* @__PURE__ */
|
|
3608
|
-
waitingForPicture && /* @__PURE__ */
|
|
3757
|
+
/* @__PURE__ */ jsx7("p", { className: "asked-prompt", children: shown.prompt }),
|
|
3758
|
+
waitingForPicture && /* @__PURE__ */ jsx7("p", { className: "asked-step", "aria-live": "polite", children: filmingStep })
|
|
3609
3759
|
] })
|
|
3610
3760
|
] }),
|
|
3611
|
-
chat.playerProps && /* @__PURE__ */
|
|
3761
|
+
chat.playerProps && /* @__PURE__ */ jsx7("div", { className: "player-fit", style: { width: stageOrientation === "portrait" ? "min(100cqw, 56.25cqh)" : "min(100cqw, 177.7778cqh)" }, children: /* @__PURE__ */ jsx7(
|
|
3612
3762
|
VideoPlayer,
|
|
3613
3763
|
{
|
|
3614
3764
|
...chat.playerProps,
|
|
3615
3765
|
templates: options.templates,
|
|
3766
|
+
orientation: stageOrientation,
|
|
3616
3767
|
responsiveBreakpoint: DESKTOP_WIDTH,
|
|
3617
3768
|
ariaLabel: chat.playerProps.video ? "Replay" : "The response"
|
|
3618
3769
|
},
|
|
3619
3770
|
chat.playerKey
|
|
3620
|
-
),
|
|
3771
|
+
) }),
|
|
3621
3772
|
showing && chat.playbackEnded && chat.suggestions.length > 0 && /* @__PURE__ */ jsxs6("div", { className: "ending", children: [
|
|
3622
|
-
/* @__PURE__ */
|
|
3773
|
+
/* @__PURE__ */ jsx7("div", { className: "ending-wash", "aria-hidden": "true" }),
|
|
3623
3774
|
/* @__PURE__ */ jsxs6("div", { className: "ending-body", children: [
|
|
3624
|
-
/* @__PURE__ */
|
|
3625
|
-
/* @__PURE__ */
|
|
3775
|
+
/* @__PURE__ */ jsx7("p", { className: "ending-label", children: "Ask next" }),
|
|
3776
|
+
/* @__PURE__ */ jsx7(SuggestionCards, { suggestions: [...chat.suggestions], label: "Follow-up prompts", onAsk: ask })
|
|
3626
3777
|
] })
|
|
3627
3778
|
] })
|
|
3628
3779
|
] }),
|
|
3629
|
-
historyOpen && /* @__PURE__ */
|
|
3630
|
-
"
|
|
3631
|
-
|
|
3632
|
-
type: "button",
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3780
|
+
historyOpen && /* @__PURE__ */ jsxs6("nav", { ref: historyRef, id: historyId, className: "sheet-popover history", role: "dialog", "aria-modal": "true", "aria-label": "History", children: [
|
|
3781
|
+
/* @__PURE__ */ jsxs6("div", { className: "popover-heading", children: [
|
|
3782
|
+
/* @__PURE__ */ jsx7("h2", { children: "History" }),
|
|
3783
|
+
/* @__PURE__ */ jsx7("button", { type: "button", className: "round", "aria-label": "Close history", onClick: closeHistory, children: /* @__PURE__ */ jsx7(Close, {}) })
|
|
3784
|
+
] }),
|
|
3785
|
+
/* @__PURE__ */ jsx7("h3", { className: "section-label", children: "Current session" }),
|
|
3786
|
+
chat.turns.length === 0 && /* @__PURE__ */ jsx7("p", { className: "history-empty", children: "Your questions will appear here." }),
|
|
3787
|
+
chat.turns.map((turn, index) => /* @__PURE__ */ jsxs6(
|
|
3788
|
+
"button",
|
|
3789
|
+
{
|
|
3790
|
+
type: "button",
|
|
3791
|
+
className: `history-row${turn.id === shown?.id ? " current" : ""}`,
|
|
3792
|
+
"aria-current": turn.id === shown?.id ? true : void 0,
|
|
3793
|
+
disabled: !turn.completed || !turn.video,
|
|
3794
|
+
onClick: () => {
|
|
3795
|
+
listen.stop();
|
|
3796
|
+
setDraft("");
|
|
3797
|
+
setEditing(false);
|
|
3798
|
+
resumeAfterInput.current = false;
|
|
3799
|
+
chat.selectTurn(turn.id);
|
|
3800
|
+
setHistoryOpen(false);
|
|
3801
|
+
},
|
|
3802
|
+
children: [
|
|
3803
|
+
/* @__PURE__ */ jsx7("span", { className: "index", children: String(index + 1).padStart(2, "0") }),
|
|
3804
|
+
/* @__PURE__ */ jsxs6("span", { className: "prompt", children: [
|
|
3805
|
+
turn.prompt,
|
|
3806
|
+
/* @__PURE__ */ jsx7("small", { children: turn.id === shown?.id ? "Now showing" : turn.completed ? "Play answer" : "Unfinished answer" })
|
|
3807
|
+
] })
|
|
3808
|
+
]
|
|
3638
3809
|
},
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3810
|
+
turn.id
|
|
3811
|
+
)),
|
|
3812
|
+
savedSessions.length > 0 && /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
3813
|
+
/* @__PURE__ */ jsx7("h3", { className: "section-label", children: "Earlier sessions" }),
|
|
3814
|
+
savedSessions.map((session) => /* @__PURE__ */ jsxs6("button", { type: "button", className: "history-row", onClick: () => {
|
|
3815
|
+
listen.stop();
|
|
3816
|
+
setDraft("");
|
|
3817
|
+
setEditing(false);
|
|
3818
|
+
resumeAfterInput.current = false;
|
|
3819
|
+
const completed = chat.turns.filter((turn) => turn.completed && turn.video);
|
|
3820
|
+
setSavedSessions((sessions) => [...completed.length ? [{ id: completed[0].id, turns: completed }] : [], ...sessions.filter((entry) => entry.id !== session.id)].slice(0, 10));
|
|
3821
|
+
restoreSession(session.turns);
|
|
3822
|
+
setHistoryOpen(false);
|
|
3823
|
+
setCaptionsExpanded(false);
|
|
3824
|
+
}, children: [
|
|
3825
|
+
/* @__PURE__ */ jsx7(Replay, {}),
|
|
3826
|
+
/* @__PURE__ */ jsxs6("span", { className: "prompt", children: [
|
|
3827
|
+
session.turns[0]?.prompt,
|
|
3828
|
+
/* @__PURE__ */ jsxs6("small", { children: [
|
|
3829
|
+
session.turns.length,
|
|
3830
|
+
" ",
|
|
3831
|
+
session.turns.length === 1 ? "answer" : "answers"
|
|
3832
|
+
] })
|
|
3833
|
+
] })
|
|
3834
|
+
] }, session.id))
|
|
3835
|
+
] })
|
|
3836
|
+
] }),
|
|
3646
3837
|
settingsOpen && /* @__PURE__ */ jsxs6(
|
|
3647
3838
|
"div",
|
|
3648
3839
|
{
|
|
@@ -3651,97 +3842,151 @@ function VideoChat({ options = {}, className, welcomeTitle }) {
|
|
|
3651
3842
|
className: "sheet-popover settings",
|
|
3652
3843
|
role: "dialog",
|
|
3653
3844
|
"aria-label": "Settings",
|
|
3845
|
+
"aria-modal": "true",
|
|
3654
3846
|
children: [
|
|
3655
|
-
/* @__PURE__ */ jsxs6("
|
|
3656
|
-
/* @__PURE__ */
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3847
|
+
/* @__PURE__ */ jsxs6("div", { className: "popover-heading", children: [
|
|
3848
|
+
/* @__PURE__ */ jsx7("h2", { children: "Settings" }),
|
|
3849
|
+
/* @__PURE__ */ jsx7("button", { type: "button", className: "round", "aria-label": "Close settings", onClick: closeSettings, children: /* @__PURE__ */ jsx7(Close, {}) })
|
|
3850
|
+
] }),
|
|
3851
|
+
/* @__PURE__ */ jsxs6("fieldset", { className: "playback-options", children: [
|
|
3852
|
+
/* @__PURE__ */ jsx7("legend", { children: "Watching" }),
|
|
3853
|
+
/* @__PURE__ */ jsxs6("label", { className: "switch-row", children: [
|
|
3854
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
3855
|
+
/* @__PURE__ */ jsx7("strong", { children: "Subtitles" }),
|
|
3856
|
+
/* @__PURE__ */ jsx7("small", { children: "Read along with the answer" })
|
|
3857
|
+
] }),
|
|
3858
|
+
/* @__PURE__ */ jsx7("input", { type: "checkbox", role: "switch", checked: captionsOn, onChange: (event) => {
|
|
3859
|
+
setCaptionsOn(event.target.checked);
|
|
3860
|
+
setCaptionsExpanded(false);
|
|
3861
|
+
} })
|
|
3862
|
+
] }),
|
|
3863
|
+
/* @__PURE__ */ jsxs6("label", { className: "switch-row", children: [
|
|
3864
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
3865
|
+
/* @__PURE__ */ jsx7("strong", { children: "Keep controls visible" }),
|
|
3866
|
+
/* @__PURE__ */ jsx7("small", { children: "Keep the input bar on screen" })
|
|
3867
|
+
] }),
|
|
3868
|
+
/* @__PURE__ */ jsx7("input", { type: "checkbox", role: "switch", checked: alwaysShowControls, onChange: (event) => setAlwaysShowControls(event.target.checked) })
|
|
3869
|
+
] })
|
|
3661
3870
|
] }),
|
|
3662
|
-
/* @__PURE__ */
|
|
3663
|
-
|
|
3664
|
-
/* @__PURE__ */
|
|
3665
|
-
|
|
3666
|
-
/* @__PURE__ */ jsx6("input", { type: "radio", name: visualsName, checked: option.id === selectedMode.id, onChange: () => setModeId(option.id) }),
|
|
3871
|
+
/* @__PURE__ */ jsxs6("fieldset", { className: "visual-options", children: [
|
|
3872
|
+
/* @__PURE__ */ jsx7("legend", { children: "Video creation" }),
|
|
3873
|
+
availableModes.map((option) => /* @__PURE__ */ jsxs6("label", { className: "choice-row", children: [
|
|
3874
|
+
/* @__PURE__ */ jsx7("input", { type: "radio", name: visualsName, checked: option.id === selectedMode.id, onChange: () => setModeId(option.id) }),
|
|
3667
3875
|
/* @__PURE__ */ jsxs6("span", { children: [
|
|
3668
|
-
/* @__PURE__ */
|
|
3669
|
-
option.note
|
|
3876
|
+
/* @__PURE__ */ jsx7("strong", { children: option.label }),
|
|
3877
|
+
/* @__PURE__ */ jsx7("small", { children: option.note })
|
|
3670
3878
|
] })
|
|
3671
3879
|
] }, option.id))
|
|
3672
3880
|
] }),
|
|
3673
|
-
/* @__PURE__ */ jsxs6("fieldset", { children: [
|
|
3674
|
-
/* @__PURE__ */
|
|
3881
|
+
/* @__PURE__ */ jsxs6("fieldset", { className: "style-options", children: [
|
|
3882
|
+
/* @__PURE__ */ jsx7("legend", { children: "Video style" }),
|
|
3675
3883
|
themes.map((option) => /* @__PURE__ */ jsxs6("label", { children: [
|
|
3676
|
-
/* @__PURE__ */
|
|
3677
|
-
/* @__PURE__ */
|
|
3884
|
+
/* @__PURE__ */ jsx7("input", { type: "radio", name: styleName, checked: option.id === themeId, onChange: () => setThemeId(option.id) }),
|
|
3885
|
+
/* @__PURE__ */ jsx7("span", { children: /* @__PURE__ */ jsx7("strong", { children: option.label }) })
|
|
3678
3886
|
] }, option.id))
|
|
3887
|
+
] }),
|
|
3888
|
+
/* @__PURE__ */ jsx7("p", { className: "settings-note", children: "Creation and style changes apply to your next question." }),
|
|
3889
|
+
/* @__PURE__ */ jsxs6("nav", { className: "developer-links", "aria-label": "Build with VanillaSky", children: [
|
|
3890
|
+
/* @__PURE__ */ jsx7("p", { className: "section-label", children: "Build with VanillaSky" }),
|
|
3891
|
+
/* @__PURE__ */ jsxs6("a", { href: "https://github.com/VanillaSkyAi/video/blob/main/docs/getting-started.md", target: "_blank", rel: "noopener noreferrer", children: [
|
|
3892
|
+
"Docs",
|
|
3893
|
+
/* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\u2197" })
|
|
3894
|
+
] }),
|
|
3895
|
+
/* @__PURE__ */ jsxs6("button", { type: "button", "aria-expanded": aboutOpen, "aria-controls": `${instanceId}-about`, onClick: () => setAboutOpen((open) => !open), children: [
|
|
3896
|
+
"About",
|
|
3897
|
+
/* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: aboutOpen ? "\u2212" : "+" })
|
|
3898
|
+
] }),
|
|
3899
|
+
/* @__PURE__ */ jsx7("div", { id: `${instanceId}-about`, className: "developer-about", role: "region", "aria-label": "About VanillaSky", hidden: !aboutOpen, children: /* @__PURE__ */ jsx7("p", { children: "VanillaSky is an open-source SDK for conversations that answer in video. Developers connect their own AI providers through their application server." }) }),
|
|
3900
|
+
/* @__PURE__ */ jsxs6("a", { href: "https://github.com/VanillaSkyAi/video", target: "_blank", rel: "noopener noreferrer", children: [
|
|
3901
|
+
"GitHub",
|
|
3902
|
+
/* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\u2197" })
|
|
3903
|
+
] })
|
|
3679
3904
|
] })
|
|
3680
3905
|
]
|
|
3681
3906
|
}
|
|
3682
3907
|
)
|
|
3683
3908
|
] }),
|
|
3684
|
-
/* @__PURE__ */
|
|
3685
|
-
/* @__PURE__ */
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3909
|
+
/* @__PURE__ */ jsx7("div", { ref: panelRef, className: "panel", "data-input-visible": controls.visible || !captionsOn || !line, children: /* @__PURE__ */ jsxs6("div", { className: "panel-inner", children: [
|
|
3910
|
+
/* @__PURE__ */ jsx7("div", { className: "caption-slot", "data-captions": captionsOn && Boolean(line), "aria-hidden": !captionsOn || !line, children: /* @__PURE__ */ jsx7("div", { className: "caption-clip", children: /* @__PURE__ */ jsxs6(
|
|
3911
|
+
"div",
|
|
3912
|
+
{
|
|
3913
|
+
className: "line-row",
|
|
3914
|
+
"data-expanded": captionsExpanded,
|
|
3915
|
+
"data-actions-visible": captionControls.visible,
|
|
3916
|
+
onPointerMove: captionControls.onPointerEnter,
|
|
3917
|
+
onPointerLeave: captionControls.onPointerLeave,
|
|
3918
|
+
onPointerDown: captionControls.reveal,
|
|
3919
|
+
onFocusCapture: captionControls.onFocusCapture,
|
|
3920
|
+
onBlurCapture: captionControls.onBlurCapture,
|
|
3921
|
+
children: [
|
|
3922
|
+
captionsOn && line && /* @__PURE__ */ jsxs6("div", { className: "caption-actions", children: [
|
|
3923
|
+
/* @__PURE__ */ jsxs6("button", { type: "button", className: "caption-action", "aria-label": captionsExpanded ? "Collapse subtitles" : "Expand subtitles", "aria-expanded": captionsExpanded, onClick: () => setCaptionsExpanded((open) => !open), children: [
|
|
3924
|
+
captionsExpanded ? "Collapse" : "Expand",
|
|
3925
|
+
/* @__PURE__ */ jsx7(ChevronUp, {})
|
|
3926
|
+
] }),
|
|
3927
|
+
/* @__PURE__ */ jsx7("button", { type: "button", className: "caption-action", "aria-label": "Hide subtitles", onClick: () => {
|
|
3928
|
+
setCaptionsOn(false);
|
|
3929
|
+
setCaptionsExpanded(false);
|
|
3930
|
+
}, children: /* @__PURE__ */ jsx7(Close, {}) })
|
|
3931
|
+
] }),
|
|
3932
|
+
captionsExpanded ? /* @__PURE__ */ jsx7("div", { className: "expanded-captions", role: "region", tabIndex: 0, "aria-label": "Expanded subtitles", children: fullTranscript.map((entry, index) => /* @__PURE__ */ jsx7("p", { children: entry }, index)) }) : /* @__PURE__ */ jsx7("p", { className: "line", "aria-live": "polite", children: line })
|
|
3933
|
+
]
|
|
3934
|
+
}
|
|
3935
|
+
) }) }),
|
|
3692
3936
|
(chat.error || listen.error) && /* @__PURE__ */ jsxs6("p", { className: "error", role: "status", children: [
|
|
3693
|
-
/* @__PURE__ */
|
|
3694
|
-
/* @__PURE__ */
|
|
3937
|
+
/* @__PURE__ */ jsx7(Warning, {}),
|
|
3938
|
+
/* @__PURE__ */ jsx7("span", { children: chat.error?.message ?? listen.error })
|
|
3695
3939
|
] }),
|
|
3696
|
-
/* @__PURE__ */ jsxs6("
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3940
|
+
/* @__PURE__ */ jsxs6("div", { ref: composerRef, className: "conversation-composer", "data-editing": editing, ...controlEvents, children: [
|
|
3941
|
+
(listen.listening || listen.thinking) && /* @__PURE__ */ jsx7("div", { className: "composer-meta", children: /* @__PURE__ */ jsx7("span", { role: "status", children: listen.listening ? "Listening\u2026 Tap the mic to finish, then review and send." : "Turning your words into a draft\u2026" }) }),
|
|
3942
|
+
/* @__PURE__ */ jsxs6("form", { className: "composer", "aria-label": "Ask a question", onSubmit: (event) => {
|
|
3943
|
+
event.preventDefault();
|
|
3944
|
+
ask(draft);
|
|
3945
|
+
}, children: [
|
|
3946
|
+
transport && /* @__PURE__ */ jsx7("button", { type: "button", className: "ghost transport", "aria-label": transport.label, onClick: () => {
|
|
3947
|
+
listen.stop();
|
|
3948
|
+
setEditing(false);
|
|
3949
|
+
resumeAfterInput.current = false;
|
|
3950
|
+
inputRef.current?.blur();
|
|
3951
|
+
transport.action();
|
|
3952
|
+
}, children: transport.icon }),
|
|
3953
|
+
/* @__PURE__ */ jsx7(Waveform, { active: listen.listening || chat.speaking && !chat.muted && status !== "paused", listening: listen.listening }),
|
|
3954
|
+
/* @__PURE__ */ jsx7("label", { className: "sr-only", htmlFor: promptId, children: "Prompt" }),
|
|
3955
|
+
/* @__PURE__ */ jsx7(
|
|
3956
|
+
"textarea",
|
|
3957
|
+
{
|
|
3958
|
+
id: promptId,
|
|
3959
|
+
ref: inputRef,
|
|
3960
|
+
rows: 1,
|
|
3961
|
+
value: draft,
|
|
3962
|
+
placeholder: listen.listening ? "Listening\u2026" : chat.turns.length ? "Ask a follow-up\u2026" : "Ask anything\u2026",
|
|
3963
|
+
onFocus: () => {
|
|
3964
|
+
if (!editing) beginInput();
|
|
3965
|
+
},
|
|
3966
|
+
onChange: (event) => {
|
|
3967
|
+
setDraft(event.target.value);
|
|
3968
|
+
event.target.style.height = "auto";
|
|
3969
|
+
event.target.style.height = `${Math.min(event.target.scrollHeight, 120)}px`;
|
|
3970
|
+
},
|
|
3971
|
+
onKeyDown: (event) => {
|
|
3972
|
+
if (event.key === "Escape") {
|
|
3973
|
+
event.stopPropagation();
|
|
3974
|
+
cancelInput();
|
|
3975
|
+
}
|
|
3976
|
+
if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
|
|
3977
|
+
event.preventDefault();
|
|
3978
|
+
ask(draft);
|
|
3979
|
+
}
|
|
3715
3980
|
}
|
|
3716
3981
|
}
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
"aria-label": listen.listening ? "Stop listening" : "Ask by voice",
|
|
3726
|
-
"aria-pressed": listen.listening,
|
|
3727
|
-
disabled: listen.thinking,
|
|
3728
|
-
onClick: listen.toggle,
|
|
3729
|
-
children: /* @__PURE__ */ jsx6(Mic, {})
|
|
3730
|
-
}
|
|
3731
|
-
),
|
|
3732
|
-
/* @__PURE__ */ jsx6("button", { type: "submit", className: "send", "aria-label": "Ask", disabled: !draft.trim() || status === "drawing", children: /* @__PURE__ */ jsx6(Send, {}) })
|
|
3733
|
-
] })
|
|
3734
|
-
] }) }),
|
|
3735
|
-
sheetOpen && shown && /* @__PURE__ */ jsxs6("div", { className: "sheet-layer", children: [
|
|
3736
|
-
/* @__PURE__ */ jsx6("button", { type: "button", className: "scrim", tabIndex: -1, "aria-hidden": "true", onClick: () => setSheetOpen(false) }),
|
|
3737
|
-
/* @__PURE__ */ jsxs6("article", { ref: sheetRef, className: "sheet", role: "dialog", "aria-modal": "true", "aria-labelledby": responseTitleId, children: [
|
|
3738
|
-
/* @__PURE__ */ jsxs6("header", { children: [
|
|
3739
|
-
/* @__PURE__ */ jsx6("h1", { id: responseTitleId, children: shown.prompt }),
|
|
3740
|
-
/* @__PURE__ */ jsx6("button", { type: "button", className: "round", "aria-label": "Close the full response", onClick: () => setSheetOpen(false), children: /* @__PURE__ */ jsx6(Close, {}) })
|
|
3741
|
-
] }),
|
|
3742
|
-
/* @__PURE__ */ jsx6("div", { className: "sheet-body", children: chat.transcript.map((entry, index) => /* @__PURE__ */ jsx6("p", { children: entry }, `${index}-${entry}`)) })
|
|
3743
|
-
] })
|
|
3744
|
-
] })
|
|
3982
|
+
),
|
|
3983
|
+
listen.supported && /* @__PURE__ */ jsx7("button", { type: "button", className: `ghost${listen.listening ? " listening" : ""}`, "aria-label": listen.listening ? "Stop listening" : "Ask by voice", "aria-pressed": listen.listening, disabled: listen.thinking, onClick: () => beginInput(true), children: /* @__PURE__ */ jsx7(Mic, {}) }),
|
|
3984
|
+
/* @__PURE__ */ jsx7("button", { type: "submit", className: "send", "aria-label": "Ask", disabled: !draft.trim() || listen.thinking, children: /* @__PURE__ */ jsx7(Send, {}) }),
|
|
3985
|
+
editing && /* @__PURE__ */ jsx7("button", { type: "button", className: "ghost", "aria-label": "Cancel question", onClick: cancelInput, children: /* @__PURE__ */ jsx7(Close, {}) })
|
|
3986
|
+
] })
|
|
3987
|
+
] }),
|
|
3988
|
+
!showing && chat.turns.length === 0 && /* @__PURE__ */ jsx7("p", { className: "dock-hint", children: "Speak or type. See where it takes you." })
|
|
3989
|
+
] }) })
|
|
3745
3990
|
]
|
|
3746
3991
|
}
|
|
3747
3992
|
);
|