@vanillaskyai/video 0.8.0 → 0.8.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/CHANGELOG.md +4 -0
- package/README.md +4 -0
- package/dist/assets/vanillasky-logo.svg +151 -0
- package/dist/react.js +381 -153
- package/docs/customization.md +11 -6
- package/docs/immersive-interface.md +87 -0
- package/docs/reference/design-system.html +115 -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 +650 -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,28 @@ 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 [captionsOn, setCaptionsOn] = useState6(true);
|
|
3535
|
+
const [captionsExpanded, setCaptionsExpanded] = useState6(false);
|
|
3536
|
+
const [alwaysShowControls, setAlwaysShowControls] = useState6(false);
|
|
3537
|
+
const [editing, setEditing] = useState6(false);
|
|
3538
|
+
const resumeAfterInput = useRef7(false);
|
|
3539
|
+
const panelRef = useRef7(null);
|
|
3540
|
+
const composerRef = useRef7(null);
|
|
3450
3541
|
const viewportOrientation = useViewportOrientation();
|
|
3451
|
-
const [themeChoice, setThemeChoice] = useState5("system");
|
|
3452
3542
|
const theme = themeById(themeId);
|
|
3453
3543
|
const sessionOrientation = options.orientation ?? viewportOrientation;
|
|
3454
3544
|
const { brand: configuredBrand, style: configuredStyle, ...sessionOptions } = options;
|
|
3455
3545
|
const presentationBrand = configuredBrand ?? theme.brand;
|
|
3456
|
-
const chat =
|
|
3546
|
+
const { chat, restoreSession } = useVideoChatSession({
|
|
3457
3547
|
...sessionOptions,
|
|
3458
3548
|
mode: modeId,
|
|
3459
3549
|
orientation: sessionOrientation,
|
|
@@ -3464,16 +3554,13 @@ function VideoChat({ options = {}, className, welcomeTitle }) {
|
|
|
3464
3554
|
const historyId = `${instanceId}-history`;
|
|
3465
3555
|
const settingsId = `${instanceId}-settings`;
|
|
3466
3556
|
const promptId = `${instanceId}-prompt`;
|
|
3467
|
-
const responseTitleId = `${instanceId}-response-title`;
|
|
3468
|
-
const appearanceName = `${instanceId}-appearance`;
|
|
3469
3557
|
const visualsName = `${instanceId}-visuals`;
|
|
3470
3558
|
const styleName = `${instanceId}-style`;
|
|
3471
|
-
const inputRef =
|
|
3472
|
-
const historyRef =
|
|
3473
|
-
const historyButtonRef =
|
|
3474
|
-
const settingsRef =
|
|
3475
|
-
const settingsButtonRef =
|
|
3476
|
-
const sheetRef = useRef6(null);
|
|
3559
|
+
const inputRef = useRef7(null);
|
|
3560
|
+
const historyRef = useRef7(null);
|
|
3561
|
+
const historyButtonRef = useRef7(null);
|
|
3562
|
+
const settingsRef = useRef7(null);
|
|
3563
|
+
const settingsButtonRef = useRef7(null);
|
|
3477
3564
|
const listen = useVoiceInput(setDraft, chat.capabilities?.transcription ?? false, {
|
|
3478
3565
|
endpoint: options.endpoint,
|
|
3479
3566
|
headers: options.headers,
|
|
@@ -3482,40 +3569,49 @@ function VideoChat({ options = {}, className, welcomeTitle }) {
|
|
|
3482
3569
|
});
|
|
3483
3570
|
const historySurfaces = useMemo2(() => [historyRef, historyButtonRef], []);
|
|
3484
3571
|
const settingsSurfaces = useMemo2(() => [settingsRef, settingsButtonRef], []);
|
|
3485
|
-
const
|
|
3486
|
-
const
|
|
3487
|
-
const closeSettings = useCallback5(() => setSettingsOpen(false), []);
|
|
3488
|
-
const closeSheet = useCallback5(() => setSheetOpen(false), []);
|
|
3572
|
+
const closeHistory = useCallback6(() => setHistoryOpen(false), []);
|
|
3573
|
+
const closeSettings = useCallback6(() => setSettingsOpen(false), []);
|
|
3489
3574
|
useDismiss(historyOpen, closeHistory, historySurfaces);
|
|
3490
3575
|
useDismiss(settingsOpen, closeSettings, settingsSurfaces);
|
|
3491
|
-
|
|
3492
|
-
useFocusTrap(
|
|
3493
|
-
const ask =
|
|
3576
|
+
useFocusTrap(settingsOpen, settingsRef);
|
|
3577
|
+
useFocusTrap(historyOpen, historyRef);
|
|
3578
|
+
const ask = useCallback6((value) => {
|
|
3494
3579
|
const prompt = (typeof value === "string" ? value : value.prompt).trim();
|
|
3495
3580
|
if (!prompt) return;
|
|
3496
3581
|
setDraft("");
|
|
3497
3582
|
listen.stop();
|
|
3498
3583
|
setHistoryOpen(false);
|
|
3499
3584
|
setSettingsOpen(false);
|
|
3500
|
-
|
|
3585
|
+
setCaptionsExpanded(false);
|
|
3586
|
+
setEditing(false);
|
|
3587
|
+
resumeAfterInput.current = false;
|
|
3588
|
+
inputRef.current?.blur();
|
|
3501
3589
|
void chat.ask(prompt, typeof value === "string" ? void 0 : {
|
|
3502
3590
|
openingMedia: value.media,
|
|
3503
3591
|
opening: value.opening
|
|
3504
3592
|
});
|
|
3505
3593
|
}, [chat, listen]);
|
|
3506
|
-
const newSession =
|
|
3594
|
+
const newSession = useCallback6(() => {
|
|
3507
3595
|
if (chat.turns.length === 0) {
|
|
3508
3596
|
inputRef.current?.focus();
|
|
3509
3597
|
return;
|
|
3510
3598
|
}
|
|
3599
|
+
listen.stop();
|
|
3600
|
+
setDraft("");
|
|
3601
|
+
const completed = chat.turns.filter((turn) => turn.completed && turn.video);
|
|
3602
|
+
if (completed.length) setSavedSessions((sessions) => [{ id: completed[0].id, turns: completed }, ...sessions].slice(0, 10));
|
|
3511
3603
|
chat.reset();
|
|
3512
3604
|
setHistoryOpen(false);
|
|
3513
3605
|
setSettingsOpen(false);
|
|
3514
|
-
|
|
3515
|
-
|
|
3606
|
+
setCaptionsExpanded(false);
|
|
3607
|
+
setEditing(false);
|
|
3608
|
+
resumeAfterInput.current = false;
|
|
3609
|
+
inputRef.current?.blur();
|
|
3610
|
+
}, [chat, listen]);
|
|
3516
3611
|
const current = chat.currentTurn;
|
|
3517
3612
|
const shown = chat.shownTurn;
|
|
3518
3613
|
const showing = chat.playerProps != null;
|
|
3614
|
+
const ambientPoster = shown?.openingMedia?.type === "image" ? shown.openingMedia.url : shown?.openingMedia?.posterUrl;
|
|
3519
3615
|
const waitingForPicture = chat.turns.length > 0 && !showing && (chat.status === "composing" || chat.status === "playing" || chat.status === "paused");
|
|
3520
3616
|
const filmingStep = useFilmingStep(waitingForPicture, current?.id);
|
|
3521
3617
|
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 +3620,99 @@ function VideoChat({ options = {}, className, welcomeTitle }) {
|
|
|
3524
3620
|
const availableModes = visualModes.filter((option) => chat.availableModes.includes(option.id));
|
|
3525
3621
|
const selectedMode = modeById(modeId);
|
|
3526
3622
|
const line = chat.caption ?? "";
|
|
3527
|
-
const
|
|
3623
|
+
const fullTranscript = shown?.video ? [shown.opening, ...shown.video.scenes.map((scene) => scene.narration)].filter((entry) => Boolean(entry)) : chat.transcript;
|
|
3624
|
+
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;
|
|
3625
|
+
const cancelInput = useCallback6(() => {
|
|
3626
|
+
listen.stop();
|
|
3627
|
+
setDraft("");
|
|
3628
|
+
setEditing(false);
|
|
3629
|
+
inputRef.current?.blur();
|
|
3630
|
+
if (resumeAfterInput.current) chat.resume();
|
|
3631
|
+
resumeAfterInput.current = false;
|
|
3632
|
+
}, [listen, chat]);
|
|
3633
|
+
const beginInput = (speak = false) => {
|
|
3634
|
+
if (!editing) {
|
|
3635
|
+
resumeAfterInput.current = chat.status === "playing" || chat.status === "composing";
|
|
3636
|
+
if (resumeAfterInput.current) chat.pause();
|
|
3637
|
+
}
|
|
3638
|
+
setEditing(true);
|
|
3639
|
+
setSettingsOpen(false);
|
|
3640
|
+
setHistoryOpen(false);
|
|
3641
|
+
if (speak) listen.toggle();
|
|
3642
|
+
};
|
|
3643
|
+
const controls = useImmersiveControls(
|
|
3644
|
+
status === "narrating" || Boolean(line) && status !== "paused",
|
|
3645
|
+
alwaysShowControls || captionsExpanded || editing || historyOpen || settingsOpen || listen.listening || listen.thinking || Boolean(chat.error || listen.error),
|
|
3646
|
+
captionsOn && Boolean(line)
|
|
3647
|
+
);
|
|
3648
|
+
const captionControls = useImmersiveControls(Boolean(line), captionsExpanded, false);
|
|
3649
|
+
const controlEvents = {
|
|
3650
|
+
onPointerEnter: controls.onPointerEnter,
|
|
3651
|
+
onPointerLeave: controls.onPointerLeave,
|
|
3652
|
+
onFocusCapture: controls.onFocusCapture,
|
|
3653
|
+
onBlurCapture: controls.onBlurCapture
|
|
3654
|
+
};
|
|
3655
|
+
useLayoutEffect(() => {
|
|
3656
|
+
const composer = composerRef.current;
|
|
3657
|
+
if (!composer) return;
|
|
3658
|
+
const measure = () => panelRef.current?.style.setProperty("--composer-height", `${composer.getBoundingClientRect().height}px`);
|
|
3659
|
+
measure();
|
|
3660
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
3661
|
+
const observer = new ResizeObserver(measure);
|
|
3662
|
+
observer.observe(composer);
|
|
3663
|
+
return () => observer.disconnect();
|
|
3664
|
+
}, []);
|
|
3528
3665
|
return /* @__PURE__ */ jsxs6(
|
|
3529
3666
|
"div",
|
|
3530
3667
|
{
|
|
3531
3668
|
className: `vanillasky-video-chat${className ? ` ${className}` : ""}`,
|
|
3532
3669
|
"data-orientation": stageOrientation,
|
|
3533
|
-
"data-
|
|
3670
|
+
"data-controls-visible": controls.visible,
|
|
3671
|
+
tabIndex: 0,
|
|
3672
|
+
"aria-label": "Video conversation",
|
|
3673
|
+
onPointerMove: controls.reveal,
|
|
3674
|
+
onPointerDown: controls.reveal,
|
|
3675
|
+
onKeyDownCapture: controls.reveal,
|
|
3534
3676
|
children: [
|
|
3535
|
-
/* @__PURE__ */ jsxs6("header", { className: "chrome", children: [
|
|
3677
|
+
/* @__PURE__ */ jsxs6("header", { className: "chrome", ...controlEvents, children: [
|
|
3678
|
+
/* @__PURE__ */ jsx7("div", { className: "session-brand", children: /* @__PURE__ */ jsx7(Logo, {}) }),
|
|
3536
3679
|
/* @__PURE__ */ jsxs6("div", { className: "group", children: [
|
|
3537
|
-
/* @__PURE__ */
|
|
3680
|
+
/* @__PURE__ */ jsxs6(
|
|
3538
3681
|
"button",
|
|
3539
3682
|
{
|
|
3540
3683
|
type: "button",
|
|
3541
3684
|
className: "round",
|
|
3542
|
-
"aria-label":
|
|
3685
|
+
"aria-label": "New session",
|
|
3543
3686
|
onClick: newSession,
|
|
3544
|
-
children:
|
|
3687
|
+
children: [
|
|
3688
|
+
/* @__PURE__ */ jsx7(Plus, {}),
|
|
3689
|
+
/* @__PURE__ */ jsx7("span", { className: "nav-label", children: "New session" })
|
|
3690
|
+
]
|
|
3545
3691
|
}
|
|
3546
3692
|
),
|
|
3547
|
-
|
|
3693
|
+
/* @__PURE__ */ jsxs6(
|
|
3548
3694
|
"button",
|
|
3549
3695
|
{
|
|
3550
3696
|
ref: historyButtonRef,
|
|
3551
3697
|
type: "button",
|
|
3552
3698
|
className: "pill",
|
|
3553
3699
|
"aria-expanded": historyOpen,
|
|
3700
|
+
"aria-label": "History",
|
|
3701
|
+
"aria-haspopup": "dialog",
|
|
3554
3702
|
"aria-controls": historyId,
|
|
3555
3703
|
onClick: () => {
|
|
3556
3704
|
setHistoryOpen((open) => !open);
|
|
3557
3705
|
setSettingsOpen(false);
|
|
3558
3706
|
},
|
|
3559
3707
|
children: [
|
|
3560
|
-
|
|
3561
|
-
"
|
|
3708
|
+
/* @__PURE__ */ jsx7(Replay, {}),
|
|
3709
|
+
/* @__PURE__ */ jsx7("span", { className: "nav-label", children: "History" })
|
|
3562
3710
|
]
|
|
3563
3711
|
}
|
|
3564
3712
|
)
|
|
3565
3713
|
] }),
|
|
3566
3714
|
/* @__PURE__ */ jsxs6("div", { className: "group", children: [
|
|
3567
|
-
/* @__PURE__ */
|
|
3715
|
+
/* @__PURE__ */ jsx7(
|
|
3568
3716
|
"button",
|
|
3569
3717
|
{
|
|
3570
3718
|
ref: settingsButtonRef,
|
|
@@ -3578,10 +3726,10 @@ function VideoChat({ options = {}, className, welcomeTitle }) {
|
|
|
3578
3726
|
setSettingsOpen((open) => !open);
|
|
3579
3727
|
setHistoryOpen(false);
|
|
3580
3728
|
},
|
|
3581
|
-
children: /* @__PURE__ */
|
|
3729
|
+
children: /* @__PURE__ */ jsx7(Gear, {})
|
|
3582
3730
|
}
|
|
3583
3731
|
),
|
|
3584
|
-
/* @__PURE__ */
|
|
3732
|
+
/* @__PURE__ */ jsx7(
|
|
3585
3733
|
"button",
|
|
3586
3734
|
{
|
|
3587
3735
|
type: "button",
|
|
@@ -3589,60 +3737,102 @@ function VideoChat({ options = {}, className, welcomeTitle }) {
|
|
|
3589
3737
|
"aria-label": chat.muted ? "Turn the voice on" : "Turn the voice off",
|
|
3590
3738
|
"aria-pressed": chat.muted,
|
|
3591
3739
|
onClick: () => chat.setMuted(!chat.muted),
|
|
3592
|
-
children: chat.muted ? /* @__PURE__ */
|
|
3740
|
+
children: chat.muted ? /* @__PURE__ */ jsx7(Muted, {}) : /* @__PURE__ */ jsx7(Sound, {})
|
|
3593
3741
|
}
|
|
3594
3742
|
)
|
|
3595
3743
|
] })
|
|
3596
3744
|
] }),
|
|
3597
3745
|
/* @__PURE__ */ jsxs6("div", { className: "stage-area", children: [
|
|
3598
3746
|
/* @__PURE__ */ jsxs6("div", { className: "stage", style: { background: themeBackground(presentationBrand) }, children: [
|
|
3747
|
+
showing && /* @__PURE__ */ jsx7("div", { className: "ambient-media", "aria-hidden": "true", children: ambientPoster && /* @__PURE__ */ jsx7("img", { className: "frame-media", src: ambientPoster, alt: "" }) }),
|
|
3599
3748
|
!showing && /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
3600
|
-
/* @__PURE__ */
|
|
3749
|
+
/* @__PURE__ */ jsx7("div", { className: "ground", "aria-hidden": "true" }),
|
|
3601
3750
|
shown?.openingMedia && /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
3602
|
-
/* @__PURE__ */
|
|
3603
|
-
/* @__PURE__ */
|
|
3751
|
+
/* @__PURE__ */ jsx7(Frame, { media: shown.openingMedia, poster: true }),
|
|
3752
|
+
/* @__PURE__ */ jsx7("div", { className: "opening-wash", "aria-hidden": "true" })
|
|
3604
3753
|
] }),
|
|
3605
|
-
chat.turns.length === 0 && /* @__PURE__ */
|
|
3754
|
+
chat.turns.length === 0 && /* @__PURE__ */ jsx7(Welcome, { data: chat.welcome, onAsk: ask, title: welcomeTitle }),
|
|
3606
3755
|
shown?.prompt && /* @__PURE__ */ jsxs6("div", { className: "asked", children: [
|
|
3607
|
-
/* @__PURE__ */
|
|
3608
|
-
waitingForPicture && /* @__PURE__ */
|
|
3756
|
+
/* @__PURE__ */ jsx7("p", { className: "asked-prompt", children: shown.prompt }),
|
|
3757
|
+
waitingForPicture && /* @__PURE__ */ jsx7("p", { className: "asked-step", "aria-live": "polite", children: filmingStep })
|
|
3609
3758
|
] })
|
|
3610
3759
|
] }),
|
|
3611
|
-
chat.playerProps && /* @__PURE__ */
|
|
3760
|
+
chat.playerProps && /* @__PURE__ */ jsx7("div", { className: "player-fit", style: { width: stageOrientation === "portrait" ? "min(100cqw, 56.25cqh)" : "min(100cqw, 177.7778cqh)" }, children: /* @__PURE__ */ jsx7(
|
|
3612
3761
|
VideoPlayer,
|
|
3613
3762
|
{
|
|
3614
3763
|
...chat.playerProps,
|
|
3615
3764
|
templates: options.templates,
|
|
3765
|
+
orientation: stageOrientation,
|
|
3616
3766
|
responsiveBreakpoint: DESKTOP_WIDTH,
|
|
3617
3767
|
ariaLabel: chat.playerProps.video ? "Replay" : "The response"
|
|
3618
3768
|
},
|
|
3619
3769
|
chat.playerKey
|
|
3620
|
-
),
|
|
3770
|
+
) }),
|
|
3621
3771
|
showing && chat.playbackEnded && chat.suggestions.length > 0 && /* @__PURE__ */ jsxs6("div", { className: "ending", children: [
|
|
3622
|
-
/* @__PURE__ */
|
|
3772
|
+
/* @__PURE__ */ jsx7("div", { className: "ending-wash", "aria-hidden": "true" }),
|
|
3623
3773
|
/* @__PURE__ */ jsxs6("div", { className: "ending-body", children: [
|
|
3624
|
-
/* @__PURE__ */
|
|
3625
|
-
/* @__PURE__ */
|
|
3774
|
+
/* @__PURE__ */ jsx7("p", { className: "ending-label", children: "Ask next" }),
|
|
3775
|
+
/* @__PURE__ */ jsx7(SuggestionCards, { suggestions: [...chat.suggestions], label: "Follow-up prompts", onAsk: ask })
|
|
3626
3776
|
] })
|
|
3627
3777
|
] })
|
|
3628
3778
|
] }),
|
|
3629
|
-
historyOpen && /* @__PURE__ */
|
|
3630
|
-
"
|
|
3631
|
-
|
|
3632
|
-
type: "button",
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3779
|
+
historyOpen && /* @__PURE__ */ jsxs6("nav", { ref: historyRef, id: historyId, className: "sheet-popover history", role: "dialog", "aria-modal": "true", "aria-label": "History", children: [
|
|
3780
|
+
/* @__PURE__ */ jsxs6("div", { className: "popover-heading", children: [
|
|
3781
|
+
/* @__PURE__ */ jsx7("h2", { children: "History" }),
|
|
3782
|
+
/* @__PURE__ */ jsx7("button", { type: "button", className: "round", "aria-label": "Close history", onClick: closeHistory, children: /* @__PURE__ */ jsx7(Close, {}) })
|
|
3783
|
+
] }),
|
|
3784
|
+
/* @__PURE__ */ jsx7("h3", { className: "section-label", children: "Current session" }),
|
|
3785
|
+
chat.turns.length === 0 && /* @__PURE__ */ jsx7("p", { className: "history-empty", children: "Your questions will appear here." }),
|
|
3786
|
+
chat.turns.map((turn, index) => /* @__PURE__ */ jsxs6(
|
|
3787
|
+
"button",
|
|
3788
|
+
{
|
|
3789
|
+
type: "button",
|
|
3790
|
+
className: `history-row${turn.id === shown?.id ? " current" : ""}`,
|
|
3791
|
+
"aria-current": turn.id === shown?.id ? true : void 0,
|
|
3792
|
+
disabled: !turn.completed || !turn.video,
|
|
3793
|
+
onClick: () => {
|
|
3794
|
+
listen.stop();
|
|
3795
|
+
setDraft("");
|
|
3796
|
+
setEditing(false);
|
|
3797
|
+
resumeAfterInput.current = false;
|
|
3798
|
+
chat.selectTurn(turn.id);
|
|
3799
|
+
setHistoryOpen(false);
|
|
3800
|
+
},
|
|
3801
|
+
children: [
|
|
3802
|
+
/* @__PURE__ */ jsx7("span", { className: "index", children: String(index + 1).padStart(2, "0") }),
|
|
3803
|
+
/* @__PURE__ */ jsxs6("span", { className: "prompt", children: [
|
|
3804
|
+
turn.prompt,
|
|
3805
|
+
/* @__PURE__ */ jsx7("small", { children: turn.id === shown?.id ? "Now showing" : turn.completed ? "Play answer" : "Unfinished answer" })
|
|
3806
|
+
] })
|
|
3807
|
+
]
|
|
3638
3808
|
},
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3809
|
+
turn.id
|
|
3810
|
+
)),
|
|
3811
|
+
savedSessions.length > 0 && /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
3812
|
+
/* @__PURE__ */ jsx7("h3", { className: "section-label", children: "Earlier sessions" }),
|
|
3813
|
+
savedSessions.map((session) => /* @__PURE__ */ jsxs6("button", { type: "button", className: "history-row", onClick: () => {
|
|
3814
|
+
listen.stop();
|
|
3815
|
+
setDraft("");
|
|
3816
|
+
setEditing(false);
|
|
3817
|
+
resumeAfterInput.current = false;
|
|
3818
|
+
const completed = chat.turns.filter((turn) => turn.completed && turn.video);
|
|
3819
|
+
setSavedSessions((sessions) => [...completed.length ? [{ id: completed[0].id, turns: completed }] : [], ...sessions.filter((entry) => entry.id !== session.id)].slice(0, 10));
|
|
3820
|
+
restoreSession(session.turns);
|
|
3821
|
+
setHistoryOpen(false);
|
|
3822
|
+
setCaptionsExpanded(false);
|
|
3823
|
+
}, children: [
|
|
3824
|
+
/* @__PURE__ */ jsx7(Replay, {}),
|
|
3825
|
+
/* @__PURE__ */ jsxs6("span", { className: "prompt", children: [
|
|
3826
|
+
session.turns[0]?.prompt,
|
|
3827
|
+
/* @__PURE__ */ jsxs6("small", { children: [
|
|
3828
|
+
session.turns.length,
|
|
3829
|
+
" ",
|
|
3830
|
+
session.turns.length === 1 ? "answer" : "answers"
|
|
3831
|
+
] })
|
|
3832
|
+
] })
|
|
3833
|
+
] }, session.id))
|
|
3834
|
+
] })
|
|
3835
|
+
] }),
|
|
3646
3836
|
settingsOpen && /* @__PURE__ */ jsxs6(
|
|
3647
3837
|
"div",
|
|
3648
3838
|
{
|
|
@@ -3651,97 +3841,135 @@ function VideoChat({ options = {}, className, welcomeTitle }) {
|
|
|
3651
3841
|
className: "sheet-popover settings",
|
|
3652
3842
|
role: "dialog",
|
|
3653
3843
|
"aria-label": "Settings",
|
|
3844
|
+
"aria-modal": "true",
|
|
3654
3845
|
children: [
|
|
3655
|
-
/* @__PURE__ */ jsxs6("
|
|
3656
|
-
/* @__PURE__ */
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3846
|
+
/* @__PURE__ */ jsxs6("div", { className: "popover-heading", children: [
|
|
3847
|
+
/* @__PURE__ */ jsx7("h2", { children: "Settings" }),
|
|
3848
|
+
/* @__PURE__ */ jsx7("button", { type: "button", className: "round", "aria-label": "Close settings", onClick: closeSettings, children: /* @__PURE__ */ jsx7(Close, {}) })
|
|
3849
|
+
] }),
|
|
3850
|
+
/* @__PURE__ */ jsxs6("fieldset", { className: "playback-options", children: [
|
|
3851
|
+
/* @__PURE__ */ jsx7("legend", { children: "Watching" }),
|
|
3852
|
+
/* @__PURE__ */ jsxs6("label", { className: "switch-row", children: [
|
|
3853
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
3854
|
+
/* @__PURE__ */ jsx7("strong", { children: "Subtitles" }),
|
|
3855
|
+
/* @__PURE__ */ jsx7("small", { children: "Read along with the answer" })
|
|
3856
|
+
] }),
|
|
3857
|
+
/* @__PURE__ */ jsx7("input", { type: "checkbox", role: "switch", checked: captionsOn, onChange: (event) => {
|
|
3858
|
+
setCaptionsOn(event.target.checked);
|
|
3859
|
+
setCaptionsExpanded(false);
|
|
3860
|
+
} })
|
|
3861
|
+
] }),
|
|
3862
|
+
/* @__PURE__ */ jsxs6("label", { className: "switch-row", children: [
|
|
3863
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
3864
|
+
/* @__PURE__ */ jsx7("strong", { children: "Keep controls visible" }),
|
|
3865
|
+
/* @__PURE__ */ jsx7("small", { children: "Keep the input bar on screen" })
|
|
3866
|
+
] }),
|
|
3867
|
+
/* @__PURE__ */ jsx7("input", { type: "checkbox", role: "switch", checked: alwaysShowControls, onChange: (event) => setAlwaysShowControls(event.target.checked) })
|
|
3868
|
+
] })
|
|
3661
3869
|
] }),
|
|
3662
|
-
/* @__PURE__ */
|
|
3663
|
-
|
|
3664
|
-
/* @__PURE__ */
|
|
3665
|
-
|
|
3666
|
-
/* @__PURE__ */ jsx6("input", { type: "radio", name: visualsName, checked: option.id === selectedMode.id, onChange: () => setModeId(option.id) }),
|
|
3870
|
+
/* @__PURE__ */ jsxs6("fieldset", { className: "visual-options", children: [
|
|
3871
|
+
/* @__PURE__ */ jsx7("legend", { children: "Video creation" }),
|
|
3872
|
+
availableModes.map((option) => /* @__PURE__ */ jsxs6("label", { className: "choice-row", children: [
|
|
3873
|
+
/* @__PURE__ */ jsx7("input", { type: "radio", name: visualsName, checked: option.id === selectedMode.id, onChange: () => setModeId(option.id) }),
|
|
3667
3874
|
/* @__PURE__ */ jsxs6("span", { children: [
|
|
3668
|
-
/* @__PURE__ */
|
|
3669
|
-
option.note
|
|
3875
|
+
/* @__PURE__ */ jsx7("strong", { children: option.label }),
|
|
3876
|
+
/* @__PURE__ */ jsx7("small", { children: option.note })
|
|
3670
3877
|
] })
|
|
3671
3878
|
] }, option.id))
|
|
3672
3879
|
] }),
|
|
3673
|
-
/* @__PURE__ */ jsxs6("fieldset", { children: [
|
|
3674
|
-
/* @__PURE__ */
|
|
3880
|
+
/* @__PURE__ */ jsxs6("fieldset", { className: "style-options", children: [
|
|
3881
|
+
/* @__PURE__ */ jsx7("legend", { children: "Video style" }),
|
|
3675
3882
|
themes.map((option) => /* @__PURE__ */ jsxs6("label", { children: [
|
|
3676
|
-
/* @__PURE__ */
|
|
3677
|
-
/* @__PURE__ */
|
|
3883
|
+
/* @__PURE__ */ jsx7("input", { type: "radio", name: styleName, checked: option.id === themeId, onChange: () => setThemeId(option.id) }),
|
|
3884
|
+
/* @__PURE__ */ jsx7("span", { children: /* @__PURE__ */ jsx7("strong", { children: option.label }) })
|
|
3678
3885
|
] }, option.id))
|
|
3679
|
-
] })
|
|
3886
|
+
] }),
|
|
3887
|
+
/* @__PURE__ */ jsx7("p", { className: "settings-note", children: "Creation and style changes apply to your next question." })
|
|
3680
3888
|
]
|
|
3681
3889
|
}
|
|
3682
3890
|
)
|
|
3683
3891
|
] }),
|
|
3684
|
-
/* @__PURE__ */
|
|
3685
|
-
/* @__PURE__ */
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3892
|
+
/* @__PURE__ */ jsx7("div", { ref: panelRef, className: "panel", "data-input-visible": controls.visible || !captionsOn || !line, children: /* @__PURE__ */ jsxs6("div", { className: "panel-inner", children: [
|
|
3893
|
+
/* @__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(
|
|
3894
|
+
"div",
|
|
3895
|
+
{
|
|
3896
|
+
className: "line-row",
|
|
3897
|
+
"data-expanded": captionsExpanded,
|
|
3898
|
+
"data-actions-visible": captionControls.visible,
|
|
3899
|
+
onPointerMove: captionControls.onPointerEnter,
|
|
3900
|
+
onPointerLeave: captionControls.onPointerLeave,
|
|
3901
|
+
onPointerDown: captionControls.reveal,
|
|
3902
|
+
onFocusCapture: captionControls.onFocusCapture,
|
|
3903
|
+
onBlurCapture: captionControls.onBlurCapture,
|
|
3904
|
+
children: [
|
|
3905
|
+
captionsOn && line && /* @__PURE__ */ jsxs6("div", { className: "caption-actions", children: [
|
|
3906
|
+
/* @__PURE__ */ jsxs6("button", { type: "button", className: "caption-action", "aria-label": captionsExpanded ? "Collapse subtitles" : "Expand subtitles", "aria-expanded": captionsExpanded, onClick: () => setCaptionsExpanded((open) => !open), children: [
|
|
3907
|
+
captionsExpanded ? "Collapse" : "Expand",
|
|
3908
|
+
/* @__PURE__ */ jsx7(ChevronUp, {})
|
|
3909
|
+
] }),
|
|
3910
|
+
/* @__PURE__ */ jsx7("button", { type: "button", className: "caption-action", "aria-label": "Hide subtitles", onClick: () => {
|
|
3911
|
+
setCaptionsOn(false);
|
|
3912
|
+
setCaptionsExpanded(false);
|
|
3913
|
+
}, children: /* @__PURE__ */ jsx7(Close, {}) })
|
|
3914
|
+
] }),
|
|
3915
|
+
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 })
|
|
3916
|
+
]
|
|
3917
|
+
}
|
|
3918
|
+
) }) }),
|
|
3692
3919
|
(chat.error || listen.error) && /* @__PURE__ */ jsxs6("p", { className: "error", role: "status", children: [
|
|
3693
|
-
/* @__PURE__ */
|
|
3694
|
-
/* @__PURE__ */
|
|
3920
|
+
/* @__PURE__ */ jsx7(Warning, {}),
|
|
3921
|
+
/* @__PURE__ */ jsx7("span", { children: chat.error?.message ?? listen.error })
|
|
3695
3922
|
] }),
|
|
3696
|
-
/* @__PURE__ */ jsxs6("
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3923
|
+
/* @__PURE__ */ jsxs6("div", { ref: composerRef, className: "conversation-composer", "data-editing": editing, ...controlEvents, children: [
|
|
3924
|
+
(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" }) }),
|
|
3925
|
+
/* @__PURE__ */ jsxs6("form", { className: "composer", "aria-label": "Ask a question", onSubmit: (event) => {
|
|
3926
|
+
event.preventDefault();
|
|
3927
|
+
ask(draft);
|
|
3928
|
+
}, children: [
|
|
3929
|
+
transport && /* @__PURE__ */ jsx7("button", { type: "button", className: "ghost transport", "aria-label": transport.label, onClick: () => {
|
|
3930
|
+
listen.stop();
|
|
3931
|
+
setEditing(false);
|
|
3932
|
+
resumeAfterInput.current = false;
|
|
3933
|
+
inputRef.current?.blur();
|
|
3934
|
+
transport.action();
|
|
3935
|
+
}, children: transport.icon }),
|
|
3936
|
+
/* @__PURE__ */ jsx7(Waveform, { active: listen.listening || chat.speaking && !chat.muted && status !== "paused", listening: listen.listening }),
|
|
3937
|
+
/* @__PURE__ */ jsx7("label", { className: "sr-only", htmlFor: promptId, children: "Prompt" }),
|
|
3938
|
+
/* @__PURE__ */ jsx7(
|
|
3939
|
+
"textarea",
|
|
3940
|
+
{
|
|
3941
|
+
id: promptId,
|
|
3942
|
+
ref: inputRef,
|
|
3943
|
+
rows: 1,
|
|
3944
|
+
value: draft,
|
|
3945
|
+
placeholder: listen.listening ? "Listening\u2026" : chat.turns.length ? "Ask a follow-up\u2026" : "Ask anything\u2026",
|
|
3946
|
+
onFocus: () => {
|
|
3947
|
+
if (!editing) beginInput();
|
|
3948
|
+
},
|
|
3949
|
+
onChange: (event) => {
|
|
3950
|
+
setDraft(event.target.value);
|
|
3951
|
+
event.target.style.height = "auto";
|
|
3952
|
+
event.target.style.height = `${Math.min(event.target.scrollHeight, 120)}px`;
|
|
3953
|
+
},
|
|
3954
|
+
onKeyDown: (event) => {
|
|
3955
|
+
if (event.key === "Escape") {
|
|
3956
|
+
event.stopPropagation();
|
|
3957
|
+
cancelInput();
|
|
3958
|
+
}
|
|
3959
|
+
if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
|
|
3960
|
+
event.preventDefault();
|
|
3961
|
+
ask(draft);
|
|
3962
|
+
}
|
|
3715
3963
|
}
|
|
3716
3964
|
}
|
|
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
|
-
] })
|
|
3965
|
+
),
|
|
3966
|
+
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, {}) }),
|
|
3967
|
+
/* @__PURE__ */ jsx7("button", { type: "submit", className: "send", "aria-label": "Ask", disabled: !draft.trim() || listen.thinking, children: /* @__PURE__ */ jsx7(Send, {}) }),
|
|
3968
|
+
editing && /* @__PURE__ */ jsx7("button", { type: "button", className: "ghost", "aria-label": "Cancel question", onClick: cancelInput, children: /* @__PURE__ */ jsx7(Close, {}) })
|
|
3969
|
+
] })
|
|
3970
|
+
] }),
|
|
3971
|
+
!showing && chat.turns.length === 0 && /* @__PURE__ */ jsx7("p", { className: "dock-hint", children: "Speak or type. See where it takes you." })
|
|
3972
|
+
] }) })
|
|
3745
3973
|
]
|
|
3746
3974
|
}
|
|
3747
3975
|
);
|