@k2b/ui 0.40.0 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/chat/ChatComposer.js +759 -570
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/inputs/ChoiceGroups.js +30 -18
- package/dist/browser/inputs/ChoiceGroups.js.map +1 -1
- package/dist/browser/inputs/Select.js +32 -19
- package/dist/browser/inputs/Select.js.map +1 -1
- package/dist/browser/inputs/SpecialInputs.js +54 -25
- package/dist/browser/inputs/SpecialInputs.js.map +1 -1
- package/dist/browser/inputs/choice.js +4 -1
- package/dist/browser/inputs/choice.js.map +1 -1
- package/dist/browser/inputs/dictation/Dictation.js +546 -0
- package/dist/browser/inputs/dictation/Dictation.js.map +1 -0
- package/dist/browser/inputs/dictation/create-dictation.js +324 -0
- package/dist/browser/inputs/dictation/create-dictation.js.map +1 -0
- package/dist/browser/inputs/dictation/dictation-messages.js +115 -0
- package/dist/browser/inputs/dictation/dictation-messages.js.map +1 -0
- package/dist/browser/inputs/dictation/text-dictation.js +152 -0
- package/dist/browser/inputs/dictation/text-dictation.js.map +1 -0
- package/dist/browser/inputs/dictation/types.js +2 -0
- package/dist/browser/inputs/dictation/types.js.map +1 -0
- package/dist/browser/inputs/icon-messages.js +29 -2
- package/dist/browser/inputs/icon-messages.js.map +1 -1
- package/dist/browser/inputs/icon-texts.js +172 -0
- package/dist/browser/inputs/icon-texts.js.map +1 -0
- package/dist/browser/inputs/index.js +2 -0
- package/dist/browser/inputs/index.js.map +1 -1
- package/dist/browser/layout/AnchoredPopover.js +1 -1
- package/dist/browser/layout/AnchoredPopover.js.map +1 -1
- package/dist/browser/layout/SettingsModal.js +10 -5
- package/dist/browser/layout/SettingsModal.js.map +1 -1
- package/dist/browser/text-editor/TextEditor.js +74 -25
- package/dist/browser/text-editor/TextEditor.js.map +1 -1
- package/dist/browser/text-editor/dictation.js +166 -0
- package/dist/browser/text-editor/dictation.js.map +1 -0
- package/dist/browser/text-editor.js +1 -0
- package/dist/browser/text-editor.js.map +1 -1
- package/dist/ssr/chat/ChatComposer.js +271 -99
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/inputs/ChoiceGroups.js +12 -3
- package/dist/ssr/inputs/ChoiceGroups.js.map +1 -1
- package/dist/ssr/inputs/Select.js +8 -2
- package/dist/ssr/inputs/Select.js.map +1 -1
- package/dist/ssr/inputs/SpecialInputs.js +54 -25
- package/dist/ssr/inputs/SpecialInputs.js.map +1 -1
- package/dist/ssr/inputs/choice.js +4 -1
- package/dist/ssr/inputs/choice.js.map +1 -1
- package/dist/ssr/inputs/dictation/Dictation.js +386 -0
- package/dist/ssr/inputs/dictation/Dictation.js.map +1 -0
- package/dist/ssr/inputs/dictation/create-dictation.js +324 -0
- package/dist/ssr/inputs/dictation/create-dictation.js.map +1 -0
- package/dist/ssr/inputs/dictation/dictation-messages.js +115 -0
- package/dist/ssr/inputs/dictation/dictation-messages.js.map +1 -0
- package/dist/ssr/inputs/dictation/text-dictation.js +152 -0
- package/dist/ssr/inputs/dictation/text-dictation.js.map +1 -0
- package/dist/ssr/inputs/dictation/types.js +2 -0
- package/dist/ssr/inputs/dictation/types.js.map +1 -0
- package/dist/ssr/inputs/icon-messages.js +29 -2
- package/dist/ssr/inputs/icon-messages.js.map +1 -1
- package/dist/ssr/inputs/icon-texts.js +172 -0
- package/dist/ssr/inputs/icon-texts.js.map +1 -0
- package/dist/ssr/inputs/index.js +2 -0
- package/dist/ssr/inputs/index.js.map +1 -1
- package/dist/ssr/layout/AnchoredPopover.js +1 -1
- package/dist/ssr/layout/AnchoredPopover.js.map +1 -1
- package/dist/ssr/layout/SettingsModal.js +10 -5
- package/dist/ssr/layout/SettingsModal.js.map +1 -1
- package/dist/ssr/text-editor/TextEditor.js +74 -25
- package/dist/ssr/text-editor/TextEditor.js.map +1 -1
- package/dist/ssr/text-editor/dictation.js +166 -0
- package/dist/ssr/text-editor/dictation.js.map +1 -0
- package/dist/ssr/text-editor.js +1 -0
- package/dist/ssr/text-editor.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/chat/ChatComposer.d.ts +9 -0
- package/dist/types/inputs/SpecialInputs.d.ts +8 -0
- package/dist/types/inputs/dictation/Dictation.d.ts +26 -0
- package/dist/types/inputs/dictation/create-dictation.d.ts +77 -0
- package/dist/types/inputs/dictation/dictation-messages.d.ts +54 -0
- package/dist/types/inputs/dictation/text-dictation.d.ts +36 -0
- package/dist/types/inputs/dictation/types.d.ts +74 -0
- package/dist/types/inputs/icon-messages.d.ts +14 -0
- package/dist/types/inputs/icon-texts.d.ts +13 -0
- package/dist/types/inputs/index.d.ts +5 -0
- package/dist/types/layout/AnchoredPopover.d.ts +5 -0
- package/dist/types/text-editor/TextEditor.d.ts +10 -1
- package/dist/types/text-editor/dictation.d.ts +20 -0
- package/dist/types/text-editor.d.ts +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["inputs/dictation/Dictation.tsx"],"sourcesContent":["import { createEffect, createSignal, Index, type JSX, Match, onCleanup, Show, Switch } from \"solid-js\";\nimport { Button, IconButton } from \"../../actions/Button\";\nimport { Dropdown } from \"../../actions/Dropdown\";\nimport { useLocale } from \"../../intl/locale\";\nimport { AnchoredPopover } from \"../../layout/AnchoredPopover\";\nimport { type DictationController, type DictationNotice, isBarNotice } from \"./create-dictation\";\nimport { dictationMessages } from \"./dictation-messages\";\nimport type { DictationDevice } from \"./types\";\n\nconst useDictationMessages = () => {\n const locale = useLocale();\n return () => dictationMessages.resolve([locale()]).t;\n};\n\n/** Whether the bar stands in for the host's controls: while dictating, finishing, or showing a bar notice. */\nexport const dictationBarShown = (dictation: DictationController) => dictation.active() || isBarNotice(dictation.notice());\n\nconst clock = (ms: number) => {\n const seconds = Math.max(0, Math.floor(ms / 1000));\n return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, \"0\")}`;\n};\n\n/** The quiet countdown starts one minute before the end. */\nconst warnMs = 60_000;\n\nconst deviceIcon = (device: DictationDevice | undefined) => {\n const label = device?.label ?? \"\";\n if (/airpods|buds|headset|headphone|kopfhörer/i.test(label)) return \"ti-headphones\";\n if (/iphone|android|phone|handy|mobile/i.test(label)) return \"ti-device-mobile\";\n if (/macbook|laptop|built-in|internal|intern/i.test(label) || !label) return \"ti-device-laptop\";\n return \"ti-microphone\";\n};\n\nexport type DictationButtonProps = {\n dictation: DictationController;\n size?: \"xs\" | \"sm\";\n class?: string;\n /** The box the notice cards line up with, such as the whole composer; defaults to the button. */\n cardAnchor?: () => HTMLElement | undefined;\n};\n\n/**\n * The microphone at its fixed place. A press starts live dictation; offline it stays focusable and says why it waits.\n * Notices that need a decision, such as a blocked microphone or a used-up allowance, open as cards above it.\n */\nexport function DictationButton(props: DictationButtonProps): JSX.Element {\n const t = useDictationMessages();\n const [button, setButton] = createSignal<HTMLButtonElement>();\n const card = () => {\n const notice = props.dictation.notice();\n return notice && !isBarNotice(notice) ? notice : null;\n };\n createEffect(() => props.dictation.bind(\"microphone\", button()));\n onCleanup(() => props.dictation.bind(\"microphone\", undefined));\n return (\n <>\n <IconButton\n ref={setButton}\n size={props.size ?? \"sm\"}\n class={`k2b-dictation-button ${props.class ?? \"\"}`}\n label={props.dictation.offline() ? t().dictateOffline : t().dictate}\n tooltip={props.dictation.offline() ? t().offline : t().dictate}\n aria-pressed={props.dictation.active() ? \"true\" : \"false\"}\n aria-disabled={props.dictation.offline() || (!props.dictation.active() && props.dictation.disabled()) ? \"true\" : undefined}\n data-notice={card()?.kind}\n onClick={() => {\n if (props.dictation.offline() || (!props.dictation.active() && props.dictation.disabled())) return;\n if (props.dictation.active()) void props.dictation.stop();\n else props.dictation.start();\n }}\n >\n <i class={`ti ${card()?.kind === \"blocked\" ? \"ti-microphone-off\" : \"ti-microphone\"}`} aria-hidden=\"true\" />\n </IconButton>\n <Show when={card()}>\n {(notice) => <DictationCard dictation={props.dictation} notice={notice()} anchor={props.cardAnchor?.() ?? button()} />}\n </Show>\n </>\n );\n}\n\nfunction DictationCard(props: { dictation: DictationController; notice: DictationNotice; anchor: HTMLElement | undefined }) {\n const t = useDictationMessages();\n const locale = useLocale();\n const resetTime = () => {\n const notice = props.notice;\n const at = notice.kind === \"quota\" && notice.resetsAt ? new Date(notice.resetsAt) : null;\n const time = (at ?? new Date(new Date().setHours(24, 0, 0, 0))).toLocaleTimeString(locale(), { hour: \"2-digit\", minute: \"2-digit\" });\n const today = new Date();\n const tomorrow = !at || at.toDateString() !== today.toDateString();\n return tomorrow ? t().quotaBodyTomorrow({ time }) : t().quotaBody({ time });\n };\n const content = (): { icon: string; title: string; body: JSX.Element; retry: boolean } => {\n switch (props.notice.kind) {\n case \"blocked\":\n return {\n icon: \"ti-microphone-off\",\n title: t().blockedTitle,\n body: (\n <>\n <p>{t().blockedBody}</p>\n <ol>\n <li>{t().blockedStep1}</li>\n <li>{t().blockedStep2}</li>\n </ol>\n </>\n ),\n retry: true,\n };\n case \"quota\":\n return { icon: \"ti-hourglass\", title: t().quotaTitle, body: <p>{resetTime()}</p>, retry: false };\n case \"overloaded\":\n return {\n icon: \"ti-hourglass\",\n title: t().overloadedTitle,\n body: <p>{props.dictation.alternative?.note ?? t().overloadedBody}</p>,\n retry: true,\n };\n case \"elsewhere\":\n return { icon: \"ti-microphone\", title: t().elsewhereTitle, body: <p>{t().elsewhereBody}</p>, retry: false };\n case \"unavailable\":\n return { icon: \"ti-microphone-off\", title: t().unavailableTitle, body: <p>{t().unavailableBody}</p>, retry: true };\n default:\n return { icon: \"ti-microphone-off\", title: t().notAvailableTitle, body: <p>{t().notAvailableBody}</p>, retry: false };\n }\n };\n return (\n <AnchoredPopover\n anchor={props.anchor}\n onClose={() => props.dictation.dismiss()}\n label={content().title}\n side=\"above\"\n align=\"end\"\n width=\"20rem\"\n sheet={false}\n class=\"k2b-dictation-card\"\n >\n <h3 class=\"k2b-dictation-card__title\">\n <i class={`ti ${content().icon}`} aria-hidden=\"true\" />\n {content().title}\n </h3>\n <div class=\"k2b-dictation-card__body\">{content().body}</div>\n <div class=\"k2b-dictation-card__actions\">\n <Show when={props.notice.kind === \"overloaded\" ? props.dictation.alternative : undefined}>\n {(alternative) => (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => {\n props.dictation.dismiss();\n alternative().run();\n }}\n >\n {alternative().label}\n </Button>\n )}\n </Show>\n <Show\n when={content().retry}\n fallback={\n <Button\n size=\"sm\"\n variant=\"ghost\"\n class={props.notice.kind === \"elsewhere\" ? \"k2b-dictation-card__primary\" : undefined}\n onClick={() => props.dictation.dismiss()}\n >\n {t().ok}\n </Button>\n }\n >\n <Button size=\"sm\" variant=\"ghost\" class=\"k2b-dictation-card__primary\" onClick={() => props.dictation.start()}>\n {t().retry}\n </Button>\n </Show>\n </div>\n </AnchoredPopover>\n );\n}\n\nexport type DictationBarProps = {\n dictation: DictationController;\n class?: string;\n};\n\n/**\n * The row that stands in for the host's controls while dictating, at the same place and height: Discard, level, time,\n * microphone and Stop; then \"Finishing …\" until the last words arrived; and a notice with \"Continue\" when the session\n * ended early. Render it where `dictationBarShown()` is true. Escape stops, after closing an open menu.\n */\nexport function DictationBar(props: DictationBarProps): JSX.Element {\n const t = useDictationMessages();\n const status = () => props.dictation.status();\n const remaining = () => props.dictation.maxMs() - props.dictation.elapsedMs();\n const warning = () => status() === \"live\" && remaining() <= warnMs;\n const time = () => (warning() ? t().timeLeft({ time: clock(remaining()) }) : clock(props.dictation.elapsedMs()));\n const slots = 160;\n const bars = () => {\n const levels = props.dictation.levels();\n return Array.from({ length: slots }, (_, index) => levels[levels.length - slots + index] ?? 0);\n };\n const deviceLabel = () => props.dictation.device()?.label || t().microphone;\n\n const onKey = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\" || event.defaultPrevented || status() !== \"live\") return;\n event.preventDefault();\n void props.dictation.stop();\n };\n createEffect(() => {\n if (status() !== \"live\") return;\n document.addEventListener(\"keydown\", onKey);\n onCleanup(() => document.removeEventListener(\"keydown\", onKey));\n });\n const bindStop = (element: HTMLElement) => {\n props.dictation.bind(\"stop\", element);\n onCleanup(() => props.dictation.bind(\"stop\", undefined));\n };\n const bindContinue = (element: HTMLElement) => {\n props.dictation.bind(\"continue\", element);\n onCleanup(() => props.dictation.bind(\"continue\", undefined));\n };\n\n const deviceItems = () => [\n {\n sectionLabel: t().microphone,\n items: (props.dictation.devices().length\n ? props.dictation.devices()\n : props.dictation.device()\n ? [props.dictation.device()!]\n : []\n ).map((device) => ({\n choice: \"radio\" as const,\n icon: `ti ${deviceIcon(device)}`,\n label: device.id === \"default\" ? `${device.label || t().microphone} · ${t().systemDefault}` : device.label || t().microphone,\n checked: () => (props.dictation.deviceId() ?? props.dictation.device()?.id) === device.id,\n action: () => props.dictation.chooseDevice(device.id),\n })),\n },\n ];\n\n return (\n <div class={`k2b-dictation-bar ${props.class ?? \"\"}`}>\n <Switch>\n <Match when={status() === \"finishing\"}>\n <div class=\"k2b-dictation-bar__row\" data-state=\"finishing\" role=\"group\" aria-label={t().finishingGroup}>\n <IconButton size=\"sm\" label={t().discard} aria-disabled=\"true\" class=\"k2b-dictation-bar__icon\">\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </IconButton>\n <div class=\"k2b-dictation-bar__status\" role=\"status\">\n <i class=\"ti ti-loader-2 k2b-spin\" aria-hidden=\"true\" />\n <span class=\"k2b-dictation-bar__message\">{t().finishing}</span>\n </div>\n <span class=\"k2b-dictation-bar__time\">{clock(props.dictation.elapsedMs())}</span>\n <span class=\"k2b-dictation-bar__stop\" data-disabled=\"true\" aria-hidden=\"true\">\n <span />\n </span>\n </div>\n </Match>\n <Match when={status() === \"live\" || status() === \"starting\"}>\n <div class=\"k2b-dictation-bar__row\" data-state={status()} role=\"group\" aria-label={t().running}>\n <IconButton size=\"sm\" label={t().discard} class=\"k2b-dictation-bar__icon\" onClick={() => props.dictation.discard()}>\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </IconButton>\n <span class=\"k2b-dictation-bar__dot\" data-live={status() === \"live\" ? \"true\" : undefined} aria-hidden=\"true\" />\n <div class=\"k2b-dictation-bar__wave\" aria-hidden=\"true\">\n <Index each={bars()}>{(level) => <span style={{ \"--k2b-dictation-level\": String(0.1 + level() * 0.9) }} />}</Index>\n </div>\n <span class=\"k2b-dictation-bar__time\" data-warning={warning() ? \"true\" : undefined}>\n {status() === \"starting\" ? clock(0) : time()}\n </span>\n <Dropdown\n items={deviceItems()}\n position=\"top-left\"\n width=\"16.25rem\"\n onOpenChange={(open) => {\n if (open) void props.dictation.loadDevices();\n }}\n >\n <Dropdown.Trigger appearance=\"plain\" class=\"k2b-dictation-bar__device\" label={t().microphoneNamed({ name: deviceLabel() })}>\n <i class={`ti ${deviceIcon(props.dictation.device())}`} aria-hidden=\"true\" />\n <span class=\"k2b-dictation-bar__device-name\">{deviceLabel()}</span>\n <i class=\"ti ti-chevron-down k2b-dictation-bar__device-chevron\" aria-hidden=\"true\" />\n </Dropdown.Trigger>\n </Dropdown>\n <button\n ref={bindStop}\n type=\"button\"\n class=\"k2b-dictation-bar__stop\"\n aria-label={t().stop}\n title={t().stop}\n onClick={() => void props.dictation.stop()}\n >\n <span aria-hidden=\"true\" />\n </button>\n </div>\n </Match>\n <Match when={isBarNotice(props.dictation.notice()) ? props.dictation.notice() : undefined}>\n {(notice) => {\n const ended = () => {\n const value = notice();\n return value.kind === \"ended\" ? value : undefined;\n };\n const minutes = () => Math.round((ended()?.maxMs ?? 600_000) / 60_000);\n const long = () =>\n !ended() ? t().interrupted : ended()!.reason === \"silence\" ? t().silenceDone : t().maxDone({ minutes: minutes() });\n const short = () =>\n !ended()\n ? t().interruptedShort\n : ended()!.reason === \"silence\"\n ? t().silenceDoneShort\n : t().maxDoneShort({ minutes: minutes() });\n return (\n <div class=\"k2b-dictation-bar__row\" data-state=\"notice\">\n <div class=\"k2b-dictation-bar__status\" data-tone={ended() ? undefined : \"danger\"} role=\"status\">\n <i class={`ti ${ended() ? \"ti-clock\" : \"ti-alert-circle\"}`} aria-hidden=\"true\" />\n {/* The full message is read on every width; the visible text shortens on narrow rows. */}\n <span class=\"k2b-sr-only\">{long()}</span>\n <span class=\"k2b-dictation-bar__message k2b-dictation-bar__message--long\" aria-hidden=\"true\">\n {long()}\n </span>\n <span class=\"k2b-dictation-bar__message k2b-dictation-bar__message--short\" aria-hidden=\"true\">\n {short()}\n </span>\n </div>\n <Button\n ref={bindContinue}\n size=\"sm\"\n variant=\"ghost\"\n class=\"k2b-dictation-bar__continue\"\n onClick={() => props.dictation.start()}\n >\n {t().continue}\n </Button>\n <IconButton size=\"sm\" label={t().dismiss} class=\"k2b-dictation-bar__icon\" onClick={() => props.dictation.dismiss()}>\n <i class=\"ti ti-x\" aria-hidden=\"true\" />\n </IconButton>\n </div>\n );\n }}\n </Match>\n </Switch>\n </div>\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { createSignal, getOwner, onCleanup } from "solid-js";
|
|
2
|
+
import { isServer } from "solid-js/web";
|
|
3
|
+
import { announce } from "../../feedback/announce";
|
|
4
|
+
import { useLocale } from "../../intl/locale";
|
|
5
|
+
import { dictationMessages } from "./dictation-messages";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* What stays visible after a session could not start or ended on its own. `interrupted` and `ended` replace the bar,
|
|
9
|
+
* so "Continue" writes on at the same mark; the others are cards at the microphone.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const deviceKey = "k2b.dictation.deviceId";
|
|
13
|
+
const levelCount = 160;
|
|
14
|
+
/** A stop waits this long for the source's last words before it gives up the connection. */
|
|
15
|
+
const stopGraceMs = 8_000;
|
|
16
|
+
const defaultMaxMs = 600_000;
|
|
17
|
+
const readDevice = () => {
|
|
18
|
+
try {
|
|
19
|
+
return localStorage.getItem(deviceKey) ?? undefined;
|
|
20
|
+
} catch {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const writeDevice = id => {
|
|
25
|
+
try {
|
|
26
|
+
localStorage.setItem(deviceKey, id);
|
|
27
|
+
} catch {
|
|
28
|
+
// A private window may refuse storage; the choice then lasts for this page.
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const noticeFor = (code, resetsAt) => {
|
|
32
|
+
switch (code) {
|
|
33
|
+
case "microphone_blocked":
|
|
34
|
+
return {
|
|
35
|
+
kind: "blocked"
|
|
36
|
+
};
|
|
37
|
+
case "microphone_unavailable":
|
|
38
|
+
return {
|
|
39
|
+
kind: "unavailable"
|
|
40
|
+
};
|
|
41
|
+
case "not_configured":
|
|
42
|
+
case "no_access":
|
|
43
|
+
return {
|
|
44
|
+
kind: "not_available"
|
|
45
|
+
};
|
|
46
|
+
case "daily_limit":
|
|
47
|
+
return {
|
|
48
|
+
kind: "quota",
|
|
49
|
+
resetsAt
|
|
50
|
+
};
|
|
51
|
+
case "overloaded":
|
|
52
|
+
return {
|
|
53
|
+
kind: "overloaded"
|
|
54
|
+
};
|
|
55
|
+
case "busy_elsewhere":
|
|
56
|
+
return {
|
|
57
|
+
kind: "elsewhere"
|
|
58
|
+
};
|
|
59
|
+
default:
|
|
60
|
+
return {
|
|
61
|
+
kind: "interrupted"
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/** Bar notices stand where the bar was; card notices open at the microphone. */
|
|
67
|
+
export const isBarNotice = notice => notice?.kind === "interrupted" || notice?.kind === "ended";
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The state of one dictation place: which session runs, what its bar shows, and the notice it leaves. Render it with
|
|
71
|
+
* `DictationButton` and `DictationBar`; the target decides where text lands. One controller runs one session at a time.
|
|
72
|
+
*/
|
|
73
|
+
export function createDictation(options) {
|
|
74
|
+
const [status, setStatus] = createSignal("idle");
|
|
75
|
+
const [notice, setNotice] = createSignal(null);
|
|
76
|
+
const [levels, setLevels] = createSignal([]);
|
|
77
|
+
const [elapsedMs, setElapsedMs] = createSignal(0);
|
|
78
|
+
const [maxMs, setMaxMs] = createSignal(defaultMaxMs);
|
|
79
|
+
const [device, setDevice] = createSignal();
|
|
80
|
+
const [deviceId, setDeviceId] = createSignal(isServer ? undefined : readDevice());
|
|
81
|
+
const [devices, setDevices] = createSignal([]);
|
|
82
|
+
const [offline, setOffline] = createSignal(!isServer && typeof navigator !== "undefined" && navigator.onLine === false);
|
|
83
|
+
const elements = {};
|
|
84
|
+
let session;
|
|
85
|
+
let abort;
|
|
86
|
+
/** The target's mark stays open while a notice offers to continue. */
|
|
87
|
+
let open = false;
|
|
88
|
+
let timer;
|
|
89
|
+
let liveSince = 0;
|
|
90
|
+
let disposed = false;
|
|
91
|
+
let grace;
|
|
92
|
+
const locale = useLocale();
|
|
93
|
+
const t = () => dictationMessages.resolve([locale()]).t;
|
|
94
|
+
/** Set while a new microphone takes over, so the mark stays where the words go on. */
|
|
95
|
+
let restarting = false;
|
|
96
|
+
const focusLater = role => queueMicrotask(() => requestAnimationFrame(() => elements[role]?.focus({
|
|
97
|
+
preventScroll: true
|
|
98
|
+
})));
|
|
99
|
+
const clearTimer = () => {
|
|
100
|
+
if (timer) clearInterval(timer);
|
|
101
|
+
timer = undefined;
|
|
102
|
+
};
|
|
103
|
+
const close = () => {
|
|
104
|
+
if (!open) return;
|
|
105
|
+
open = false;
|
|
106
|
+
options.target.end();
|
|
107
|
+
};
|
|
108
|
+
const settle = (next, message) => {
|
|
109
|
+
clearTimer();
|
|
110
|
+
if (grace) clearTimeout(grace);
|
|
111
|
+
grace = undefined;
|
|
112
|
+
session = undefined;
|
|
113
|
+
abort = undefined;
|
|
114
|
+
setStatus("idle");
|
|
115
|
+
setNotice(next);
|
|
116
|
+
if (restarting && !next) {
|
|
117
|
+
// A new microphone takes over at the same mark.
|
|
118
|
+
queueMicrotask(start);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
restarting = false;
|
|
122
|
+
if (!next) close();
|
|
123
|
+
if (message) announce(message);
|
|
124
|
+
// A card takes the focus itself and returns it to the microphone when it closes.
|
|
125
|
+
if (!next || isBarNotice(next)) focusLater(next ? "continue" : "microphone");
|
|
126
|
+
};
|
|
127
|
+
const run = async (current, signal) => {
|
|
128
|
+
let finished = false;
|
|
129
|
+
try {
|
|
130
|
+
for await (const event of current.events) {
|
|
131
|
+
if (signal.aborted || disposed) return;
|
|
132
|
+
switch (event.type) {
|
|
133
|
+
case "state":
|
|
134
|
+
if (event.state === "connecting") setStatus("starting");else if (event.state === "live") {
|
|
135
|
+
setMaxMs(event.maxMs || defaultMaxMs);
|
|
136
|
+
if (event.device) setDevice(event.device);
|
|
137
|
+
liveSince = performance.now();
|
|
138
|
+
setElapsedMs(0);
|
|
139
|
+
clearTimer();
|
|
140
|
+
timer = setInterval(() => setElapsedMs(performance.now() - liveSince), 250);
|
|
141
|
+
const resumed = restarting;
|
|
142
|
+
restarting = false;
|
|
143
|
+
setStatus("live");
|
|
144
|
+
if (!resumed) {
|
|
145
|
+
announce(t().running);
|
|
146
|
+
focusLater("stop");
|
|
147
|
+
}
|
|
148
|
+
} else if (event.state === "finishing") setStatus("finishing");else {
|
|
149
|
+
finished = true;
|
|
150
|
+
if (event.reason === "daily_limit") settle({
|
|
151
|
+
kind: "quota"
|
|
152
|
+
}, t().ended);else if (event.reason) settle({
|
|
153
|
+
kind: "ended",
|
|
154
|
+
reason: event.reason,
|
|
155
|
+
maxMs: maxMs()
|
|
156
|
+
}, t().ended);else settle(null, t().ended);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
break;
|
|
160
|
+
case "level":
|
|
161
|
+
setLevels(previous => [...previous.slice(1 - levelCount), Math.max(0, Math.min(1, event.level))]);
|
|
162
|
+
break;
|
|
163
|
+
case "text":
|
|
164
|
+
if (event.text) options.target.insert(event.text);
|
|
165
|
+
break;
|
|
166
|
+
case "error":
|
|
167
|
+
finished = true;
|
|
168
|
+
settle(noticeFor(event.code, event.resetsAt));
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
} catch {
|
|
173
|
+
if (signal.aborted || disposed) return;
|
|
174
|
+
finished = true;
|
|
175
|
+
settle({
|
|
176
|
+
kind: "interrupted"
|
|
177
|
+
});
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (!finished && !signal.aborted && !disposed) settle({
|
|
181
|
+
kind: "interrupted"
|
|
182
|
+
});
|
|
183
|
+
};
|
|
184
|
+
const start = () => {
|
|
185
|
+
if (disposed || offline() || options.disabled?.() || status() !== "idle") return;
|
|
186
|
+
setNotice(null);
|
|
187
|
+
if (!restarting) setDevice(undefined);
|
|
188
|
+
options.target.begin();
|
|
189
|
+
open = true;
|
|
190
|
+
setLevels([]);
|
|
191
|
+
setElapsedMs(0);
|
|
192
|
+
setStatus("starting");
|
|
193
|
+
const controller = new AbortController();
|
|
194
|
+
abort = controller;
|
|
195
|
+
try {
|
|
196
|
+
session = options.source.start({
|
|
197
|
+
deviceId: deviceId(),
|
|
198
|
+
signal: controller.signal
|
|
199
|
+
});
|
|
200
|
+
} catch {
|
|
201
|
+
settle({
|
|
202
|
+
kind: "interrupted"
|
|
203
|
+
});
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
void run(session, controller.signal);
|
|
207
|
+
};
|
|
208
|
+
const stop = async () => {
|
|
209
|
+
const current = session;
|
|
210
|
+
const controller = abort;
|
|
211
|
+
if (!current || !controller || status() !== "live" && status() !== "starting") return;
|
|
212
|
+
if (status() === "starting") {
|
|
213
|
+
// Nothing was said yet: end it like a discard, without removing anything.
|
|
214
|
+
controller.abort();
|
|
215
|
+
settle(null);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
setStatus("finishing");
|
|
219
|
+
clearTimer();
|
|
220
|
+
// The deadline stays until the session settled, also when stop() itself fails, so "Finishing" always ends.
|
|
221
|
+
grace = setTimeout(() => {
|
|
222
|
+
if (abort !== controller) return;
|
|
223
|
+
controller.abort();
|
|
224
|
+
settle({
|
|
225
|
+
kind: "interrupted"
|
|
226
|
+
});
|
|
227
|
+
}, stopGraceMs);
|
|
228
|
+
try {
|
|
229
|
+
await current.stop();
|
|
230
|
+
} catch {
|
|
231
|
+
// The event stream reports how it ended; the deadline covers a stream that stalls.
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
const discard = () => {
|
|
235
|
+
restarting = false;
|
|
236
|
+
abort?.abort();
|
|
237
|
+
if (open) options.target.discard();
|
|
238
|
+
settle(null, t().discarded);
|
|
239
|
+
};
|
|
240
|
+
if (!isServer && typeof window !== "undefined") {
|
|
241
|
+
const online = () => setOffline(false);
|
|
242
|
+
const lost = () => setOffline(true);
|
|
243
|
+
window.addEventListener("online", online);
|
|
244
|
+
window.addEventListener("offline", lost);
|
|
245
|
+
if (getOwner()) onCleanup(() => {
|
|
246
|
+
window.removeEventListener("online", online);
|
|
247
|
+
window.removeEventListener("offline", lost);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
if (getOwner()) onCleanup(() => {
|
|
251
|
+
disposed = true;
|
|
252
|
+
clearTimer();
|
|
253
|
+
abort?.abort();
|
|
254
|
+
if (open) {
|
|
255
|
+
open = false;
|
|
256
|
+
options.target.end();
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
return {
|
|
260
|
+
status,
|
|
261
|
+
active: () => status() !== "idle",
|
|
262
|
+
notice,
|
|
263
|
+
levels,
|
|
264
|
+
elapsedMs,
|
|
265
|
+
maxMs,
|
|
266
|
+
offline,
|
|
267
|
+
device,
|
|
268
|
+
deviceId,
|
|
269
|
+
devices,
|
|
270
|
+
loadDevices: async () => {
|
|
271
|
+
try {
|
|
272
|
+
setDevices(await options.source.devices());
|
|
273
|
+
} catch {
|
|
274
|
+
setDevices([]);
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
chooseDevice: id => {
|
|
278
|
+
writeDevice(id);
|
|
279
|
+
setDeviceId(id);
|
|
280
|
+
const chosen = devices().find(item => item.id === id);
|
|
281
|
+
if (chosen) setDevice(chosen);
|
|
282
|
+
// A running session keeps its microphone; the next words come from the new one after a short finish.
|
|
283
|
+
if (status() !== "live") return;
|
|
284
|
+
restarting = true;
|
|
285
|
+
void stop();
|
|
286
|
+
},
|
|
287
|
+
get alternative() {
|
|
288
|
+
return options.alternative;
|
|
289
|
+
},
|
|
290
|
+
start: () => start(),
|
|
291
|
+
stop,
|
|
292
|
+
discard,
|
|
293
|
+
dismiss: () => {
|
|
294
|
+
const card = notice() && !isBarNotice(notice());
|
|
295
|
+
setNotice(null);
|
|
296
|
+
close();
|
|
297
|
+
// A closed card gives the focus back to the microphone, unless the person moved it elsewhere meanwhile.
|
|
298
|
+
if (card) queueMicrotask(() => requestAnimationFrame(() => {
|
|
299
|
+
const active = document.activeElement;
|
|
300
|
+
if (!active || active === document.body || !active.isConnected) elements.microphone?.focus({
|
|
301
|
+
preventScroll: true
|
|
302
|
+
});
|
|
303
|
+
}));
|
|
304
|
+
},
|
|
305
|
+
end: () => {
|
|
306
|
+
restarting = false;
|
|
307
|
+
if (status() === "idle" && !notice() && !open) return;
|
|
308
|
+
abort?.abort();
|
|
309
|
+
clearTimer();
|
|
310
|
+
if (grace) clearTimeout(grace);
|
|
311
|
+
grace = undefined;
|
|
312
|
+
session = undefined;
|
|
313
|
+
abort = undefined;
|
|
314
|
+
setStatus("idle");
|
|
315
|
+
setNotice(null);
|
|
316
|
+
close();
|
|
317
|
+
},
|
|
318
|
+
disabled: () => Boolean(options.disabled?.()),
|
|
319
|
+
bind: (role, element) => {
|
|
320
|
+
if (element) elements[role] = element;else delete elements[role];
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
//# sourceMappingURL=create-dictation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["inputs/dictation/create-dictation.ts"],"sourcesContent":["import { type Accessor, createSignal, getOwner, onCleanup } from \"solid-js\";\nimport { isServer } from \"solid-js/web\";\nimport { announce } from \"../../feedback/announce\";\nimport { useLocale } from \"../../intl/locale\";\nimport { dictationMessages } from \"./dictation-messages\";\nimport type {\n DictationAlternative,\n DictationDevice,\n DictationErrorCode,\n DictationEvent,\n DictationSession,\n DictationSource,\n DictationTarget,\n} from \"./types\";\n\nexport type DictationStatus = \"idle\" | \"starting\" | \"live\" | \"finishing\";\n\n/**\n * What stays visible after a session could not start or ended on its own. `interrupted` and `ended` replace the bar,\n * so \"Continue\" writes on at the same mark; the others are cards at the microphone.\n */\nexport type DictationNotice =\n | { kind: \"blocked\" }\n | { kind: \"unavailable\" }\n | { kind: \"not_available\" }\n | { kind: \"quota\"; resetsAt?: string }\n | { kind: \"overloaded\" }\n | { kind: \"elsewhere\" }\n | { kind: \"interrupted\" }\n | { kind: \"ended\"; reason: \"max_duration\" | \"silence\"; maxMs: number };\n\nexport type DictationOptions = {\n source: DictationSource;\n target: DictationTarget;\n /** Offered beside \"Try again\" when live dictation is busy. */\n alternative?: DictationAlternative;\n /** While true, dictation cannot start, such as in a read-only field; the host calls `end()` when it turns true. */\n disabled?: () => boolean;\n};\n\nexport type DictationController = {\n status: Accessor<DictationStatus>;\n /** Dictating, starting, or finishing: the bar stands in for the host's controls. */\n active: Accessor<boolean>;\n notice: Accessor<DictationNotice | null>;\n /** Recent levels from 0 to 1, newest last. */\n levels: Accessor<readonly number[]>;\n elapsedMs: Accessor<number>;\n maxMs: Accessor<number>;\n offline: Accessor<boolean>;\n device: Accessor<DictationDevice | undefined>;\n deviceId: Accessor<string | undefined>;\n devices: Accessor<readonly DictationDevice[]>;\n loadDevices(): Promise<void>;\n chooseDevice(id: string): void;\n alternative?: DictationAlternative;\n start(): void;\n stop(): Promise<void>;\n /** Ends the session at once and removes only the text it inserted. */\n discard(): void;\n /** Closes a notice; the text stays. */\n dismiss(): void;\n /** Ends any session at once and closes the dictation; the text stays. For a field that changes or turns read-only. */\n end(): void;\n /** Whether dictation may start now. */\n disabled: Accessor<boolean>;\n /** Elements that receive focus: the microphone after the end, the stop button after the start. */\n bind(role: \"microphone\" | \"stop\" | \"continue\", element: HTMLElement | undefined): void;\n};\n\nconst deviceKey = \"k2b.dictation.deviceId\";\nconst levelCount = 160;\n/** A stop waits this long for the source's last words before it gives up the connection. */\nconst stopGraceMs = 8_000;\nconst defaultMaxMs = 600_000;\n\nconst readDevice = () => {\n try {\n return localStorage.getItem(deviceKey) ?? undefined;\n } catch {\n return undefined;\n }\n};\nconst writeDevice = (id: string) => {\n try {\n localStorage.setItem(deviceKey, id);\n } catch {\n // A private window may refuse storage; the choice then lasts for this page.\n }\n};\n\nconst noticeFor = (code: DictationErrorCode, resetsAt?: string): DictationNotice => {\n switch (code) {\n case \"microphone_blocked\":\n return { kind: \"blocked\" };\n case \"microphone_unavailable\":\n return { kind: \"unavailable\" };\n case \"not_configured\":\n case \"no_access\":\n return { kind: \"not_available\" };\n case \"daily_limit\":\n return { kind: \"quota\", resetsAt };\n case \"overloaded\":\n return { kind: \"overloaded\" };\n case \"busy_elsewhere\":\n return { kind: \"elsewhere\" };\n default:\n return { kind: \"interrupted\" };\n }\n};\n\n/** Bar notices stand where the bar was; card notices open at the microphone. */\nexport const isBarNotice = (notice: DictationNotice | null) => notice?.kind === \"interrupted\" || notice?.kind === \"ended\";\n\n/**\n * The state of one dictation place: which session runs, what its bar shows, and the notice it leaves. Render it with\n * `DictationButton` and `DictationBar`; the target decides where text lands. One controller runs one session at a time.\n */\nexport function createDictation(options: DictationOptions): DictationController {\n const [status, setStatus] = createSignal<DictationStatus>(\"idle\");\n const [notice, setNotice] = createSignal<DictationNotice | null>(null);\n const [levels, setLevels] = createSignal<readonly number[]>([]);\n const [elapsedMs, setElapsedMs] = createSignal(0);\n const [maxMs, setMaxMs] = createSignal(defaultMaxMs);\n const [device, setDevice] = createSignal<DictationDevice>();\n const [deviceId, setDeviceId] = createSignal<string | undefined>(isServer ? undefined : readDevice());\n const [devices, setDevices] = createSignal<readonly DictationDevice[]>([]);\n const [offline, setOffline] = createSignal(!isServer && typeof navigator !== \"undefined\" && navigator.onLine === false);\n const elements: Partial<Record<\"microphone\" | \"stop\" | \"continue\", HTMLElement>> = {};\n let session: DictationSession | undefined;\n let abort: AbortController | undefined;\n /** The target's mark stays open while a notice offers to continue. */\n let open = false;\n let timer: ReturnType<typeof setInterval> | undefined;\n let liveSince = 0;\n let disposed = false;\n let grace: ReturnType<typeof setTimeout> | undefined;\n\n const locale = useLocale();\n const t = () => dictationMessages.resolve([locale()]).t;\n /** Set while a new microphone takes over, so the mark stays where the words go on. */\n let restarting = false;\n const focusLater = (role: \"microphone\" | \"stop\" | \"continue\") =>\n queueMicrotask(() => requestAnimationFrame(() => elements[role]?.focus({ preventScroll: true })));\n const clearTimer = () => {\n if (timer) clearInterval(timer);\n timer = undefined;\n };\n const close = () => {\n if (!open) return;\n open = false;\n options.target.end();\n };\n const settle = (next: DictationNotice | null, message?: string) => {\n clearTimer();\n if (grace) clearTimeout(grace);\n grace = undefined;\n session = undefined;\n abort = undefined;\n setStatus(\"idle\");\n setNotice(next);\n if (restarting && !next) {\n // A new microphone takes over at the same mark.\n queueMicrotask(start);\n return;\n }\n restarting = false;\n if (!next) close();\n if (message) announce(message);\n // A card takes the focus itself and returns it to the microphone when it closes.\n if (!next || isBarNotice(next)) focusLater(next ? \"continue\" : \"microphone\");\n };\n\n const run = async (current: DictationSession, signal: AbortSignal) => {\n let finished = false;\n try {\n for await (const event of current.events as AsyncIterable<DictationEvent>) {\n if (signal.aborted || disposed) return;\n switch (event.type) {\n case \"state\":\n if (event.state === \"connecting\") setStatus(\"starting\");\n else if (event.state === \"live\") {\n setMaxMs(event.maxMs || defaultMaxMs);\n if (event.device) setDevice(event.device);\n liveSince = performance.now();\n setElapsedMs(0);\n clearTimer();\n timer = setInterval(() => setElapsedMs(performance.now() - liveSince), 250);\n const resumed = restarting;\n restarting = false;\n setStatus(\"live\");\n if (!resumed) {\n announce(t().running);\n focusLater(\"stop\");\n }\n } else if (event.state === \"finishing\") setStatus(\"finishing\");\n else {\n finished = true;\n if (event.reason === \"daily_limit\") settle({ kind: \"quota\" }, t().ended);\n else if (event.reason) settle({ kind: \"ended\", reason: event.reason, maxMs: maxMs() }, t().ended);\n else settle(null, t().ended);\n return;\n }\n break;\n case \"level\":\n setLevels((previous) => [...previous.slice(1 - levelCount), Math.max(0, Math.min(1, event.level))]);\n break;\n case \"text\":\n if (event.text) options.target.insert(event.text);\n break;\n case \"error\":\n finished = true;\n settle(noticeFor(event.code, event.resetsAt));\n return;\n }\n }\n } catch {\n if (signal.aborted || disposed) return;\n finished = true;\n settle({ kind: \"interrupted\" });\n return;\n }\n if (!finished && !signal.aborted && !disposed) settle({ kind: \"interrupted\" });\n };\n\n const start = () => {\n if (disposed || offline() || options.disabled?.() || status() !== \"idle\") return;\n setNotice(null);\n if (!restarting) setDevice(undefined);\n options.target.begin();\n open = true;\n setLevels([]);\n setElapsedMs(0);\n setStatus(\"starting\");\n const controller = new AbortController();\n abort = controller;\n try {\n session = options.source.start({ deviceId: deviceId(), signal: controller.signal });\n } catch {\n settle({ kind: \"interrupted\" });\n return;\n }\n void run(session, controller.signal);\n };\n\n const stop = async () => {\n const current = session;\n const controller = abort;\n if (!current || !controller || (status() !== \"live\" && status() !== \"starting\")) return;\n if (status() === \"starting\") {\n // Nothing was said yet: end it like a discard, without removing anything.\n controller.abort();\n settle(null);\n return;\n }\n setStatus(\"finishing\");\n clearTimer();\n // The deadline stays until the session settled, also when stop() itself fails, so \"Finishing\" always ends.\n grace = setTimeout(() => {\n if (abort !== controller) return;\n controller.abort();\n settle({ kind: \"interrupted\" });\n }, stopGraceMs);\n try {\n await current.stop();\n } catch {\n // The event stream reports how it ended; the deadline covers a stream that stalls.\n }\n };\n\n const discard = () => {\n restarting = false;\n abort?.abort();\n if (open) options.target.discard();\n settle(null, t().discarded);\n };\n\n if (!isServer && typeof window !== \"undefined\") {\n const online = () => setOffline(false);\n const lost = () => setOffline(true);\n window.addEventListener(\"online\", online);\n window.addEventListener(\"offline\", lost);\n if (getOwner())\n onCleanup(() => {\n window.removeEventListener(\"online\", online);\n window.removeEventListener(\"offline\", lost);\n });\n }\n if (getOwner())\n onCleanup(() => {\n disposed = true;\n clearTimer();\n abort?.abort();\n if (open) {\n open = false;\n options.target.end();\n }\n });\n\n return {\n status,\n active: () => status() !== \"idle\",\n notice,\n levels,\n elapsedMs,\n maxMs,\n offline,\n device,\n deviceId,\n devices,\n loadDevices: async () => {\n try {\n setDevices(await options.source.devices());\n } catch {\n setDevices([]);\n }\n },\n chooseDevice: (id) => {\n writeDevice(id);\n setDeviceId(id);\n const chosen = devices().find((item) => item.id === id);\n if (chosen) setDevice(chosen);\n // A running session keeps its microphone; the next words come from the new one after a short finish.\n if (status() !== \"live\") return;\n restarting = true;\n void stop();\n },\n get alternative() {\n return options.alternative;\n },\n start: () => start(),\n stop,\n discard,\n dismiss: () => {\n const card = notice() && !isBarNotice(notice());\n setNotice(null);\n close();\n // A closed card gives the focus back to the microphone, unless the person moved it elsewhere meanwhile.\n if (card)\n queueMicrotask(() =>\n requestAnimationFrame(() => {\n const active = document.activeElement;\n if (!active || active === document.body || !active.isConnected) elements.microphone?.focus({ preventScroll: true });\n }),\n );\n },\n end: () => {\n restarting = false;\n if (status() === \"idle\" && !notice() && !open) return;\n abort?.abort();\n clearTimer();\n if (grace) clearTimeout(grace);\n grace = undefined;\n session = undefined;\n abort = undefined;\n setStatus(\"idle\");\n setNotice(null);\n close();\n },\n disabled: () => Boolean(options.disabled?.()),\n bind: (role, element) => {\n if (element) elements[role] = element;\n else delete elements[role];\n },\n };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { i18n } from "@k2b/stdlib";
|
|
2
|
+
export const dictationMessages = i18n.define({
|
|
3
|
+
baseLocale: "en",
|
|
4
|
+
messages: {
|
|
5
|
+
en: {
|
|
6
|
+
dictate: "Dictate",
|
|
7
|
+
dictateOffline: "Dictate, not available offline",
|
|
8
|
+
offline: "Offline. Dictation needs a connection.",
|
|
9
|
+
discard: "Discard dictation",
|
|
10
|
+
stop: "Stop dictation",
|
|
11
|
+
running: "Dictating",
|
|
12
|
+
finishingGroup: "Finishing dictation",
|
|
13
|
+
finishing: "Finishing …",
|
|
14
|
+
starting: "Starting …",
|
|
15
|
+
ended: "Dictation ended",
|
|
16
|
+
discarded: "Dictation discarded",
|
|
17
|
+
microphone: "Microphone",
|
|
18
|
+
microphoneNamed: ({
|
|
19
|
+
name
|
|
20
|
+
}) => `Microphone: ${name}`,
|
|
21
|
+
systemDefault: "Default",
|
|
22
|
+
interrupted: "Dictation interrupted. The text so far stays.",
|
|
23
|
+
interruptedShort: "Interrupted. Text stays.",
|
|
24
|
+
maxDone: ({
|
|
25
|
+
minutes
|
|
26
|
+
}) => `Ended after ${minutes} minutes. The text stays.`,
|
|
27
|
+
maxDoneShort: ({
|
|
28
|
+
minutes
|
|
29
|
+
}) => `Ended after ${minutes} min.`,
|
|
30
|
+
silenceDone: "Ended after a long silence. The text stays.",
|
|
31
|
+
silenceDoneShort: "Ended after silence.",
|
|
32
|
+
continue: "Continue dictating",
|
|
33
|
+
dismiss: "Close notice",
|
|
34
|
+
blockedTitle: "Microphone blocked",
|
|
35
|
+
blockedBody: "The browser does not let this page use the microphone. To allow it:",
|
|
36
|
+
blockedStep1: "Tap the lock on the left of the address bar.",
|
|
37
|
+
blockedStep2: "Choose “Allow” for “Microphone”.",
|
|
38
|
+
retry: "Try again",
|
|
39
|
+
quotaTitle: "Your dictation allowance for today is used up",
|
|
40
|
+
quotaBody: ({
|
|
41
|
+
time
|
|
42
|
+
}) => `You can dictate again from ${time}. Typing works as always.`,
|
|
43
|
+
quotaBodyTomorrow: ({
|
|
44
|
+
time
|
|
45
|
+
}) => `You can dictate again from tomorrow, ${time}. Typing works as always.`,
|
|
46
|
+
overloadedTitle: "Live dictation is busy right now",
|
|
47
|
+
overloadedBody: "Try again in a moment.",
|
|
48
|
+
elsewhereTitle: "You are dictating in another tab",
|
|
49
|
+
elsewhereBody: "End it there, then you can dictate here.",
|
|
50
|
+
unavailableTitle: "No microphone found",
|
|
51
|
+
unavailableBody: "Connect a microphone or choose another one, then try again.",
|
|
52
|
+
notAvailableTitle: "Dictation is not available here",
|
|
53
|
+
notAvailableBody: "Typing works as always.",
|
|
54
|
+
ok: "OK",
|
|
55
|
+
timeLeft: ({
|
|
56
|
+
time
|
|
57
|
+
}) => `${time} left`
|
|
58
|
+
},
|
|
59
|
+
de: {
|
|
60
|
+
dictate: "Diktieren",
|
|
61
|
+
dictateOffline: "Diktieren, offline nicht verfügbar",
|
|
62
|
+
offline: "Offline. Diktieren braucht eine Verbindung.",
|
|
63
|
+
discard: "Diktat verwerfen",
|
|
64
|
+
stop: "Diktat beenden",
|
|
65
|
+
running: "Diktat läuft",
|
|
66
|
+
finishingGroup: "Diktat wird abgeschlossen",
|
|
67
|
+
finishing: "Wird abgeschlossen …",
|
|
68
|
+
starting: "Wird gestartet …",
|
|
69
|
+
ended: "Diktat beendet",
|
|
70
|
+
discarded: "Diktat verworfen",
|
|
71
|
+
microphone: "Mikrofon",
|
|
72
|
+
microphoneNamed: ({
|
|
73
|
+
name
|
|
74
|
+
}) => `Mikrofon: ${name}`,
|
|
75
|
+
systemDefault: "Standard",
|
|
76
|
+
interrupted: "Diktat unterbrochen. Der Text bis hier bleibt.",
|
|
77
|
+
interruptedShort: "Unterbrochen. Text bleibt.",
|
|
78
|
+
maxDone: ({
|
|
79
|
+
minutes
|
|
80
|
+
}) => `Nach ${minutes} Minuten beendet. Der Text bleibt.`,
|
|
81
|
+
maxDoneShort: ({
|
|
82
|
+
minutes
|
|
83
|
+
}) => `Nach ${minutes} Min. beendet.`,
|
|
84
|
+
silenceDone: "Nach langer Stille beendet. Der Text bleibt.",
|
|
85
|
+
silenceDoneShort: "Nach Stille beendet.",
|
|
86
|
+
continue: "Weiter diktieren",
|
|
87
|
+
dismiss: "Hinweis schließen",
|
|
88
|
+
blockedTitle: "Mikrofon blockiert",
|
|
89
|
+
blockedBody: "Der Browser lässt diese Seite nicht an das Mikrofon. So erlaubst du es:",
|
|
90
|
+
blockedStep1: "Links in der Adressleiste auf das Schloss tippen.",
|
|
91
|
+
blockedStep2: "Bei „Mikrofon“ „Erlauben“ wählen.",
|
|
92
|
+
retry: "Erneut versuchen",
|
|
93
|
+
quotaTitle: "Dein Diktat-Kontingent für heute ist aufgebraucht",
|
|
94
|
+
quotaBody: ({
|
|
95
|
+
time
|
|
96
|
+
}) => `Ab ${time} kannst du wieder diktieren. Tippen geht natürlich weiter.`,
|
|
97
|
+
quotaBodyTomorrow: ({
|
|
98
|
+
time
|
|
99
|
+
}) => `Ab morgen, ${time}, kannst du wieder diktieren. Tippen geht natürlich weiter.`,
|
|
100
|
+
overloadedTitle: "Live-Diktat ist gerade ausgelastet",
|
|
101
|
+
overloadedBody: "Versuch es in einem Moment noch mal.",
|
|
102
|
+
elsewhereTitle: "Du diktierst gerade in einem anderen Tab",
|
|
103
|
+
elsewhereBody: "Beende es dort, dann kannst du hier diktieren.",
|
|
104
|
+
unavailableTitle: "Kein Mikrofon gefunden",
|
|
105
|
+
unavailableBody: "Schließ ein Mikrofon an oder wähl ein anderes, dann versuch es noch mal.",
|
|
106
|
+
notAvailableTitle: "Diktieren ist hier nicht verfügbar",
|
|
107
|
+
notAvailableBody: "Tippen geht natürlich weiter.",
|
|
108
|
+
ok: "OK",
|
|
109
|
+
timeLeft: ({
|
|
110
|
+
time
|
|
111
|
+
}) => `noch ${time}`
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
//# sourceMappingURL=dictation-messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["inputs/dictation/dictation-messages.ts"],"sourcesContent":["import { i18n } from \"@k2b/stdlib\";\n\nexport const dictationMessages = i18n.define({\n baseLocale: \"en\",\n messages: {\n en: {\n dictate: \"Dictate\",\n dictateOffline: \"Dictate, not available offline\",\n offline: \"Offline. Dictation needs a connection.\",\n discard: \"Discard dictation\",\n stop: \"Stop dictation\",\n running: \"Dictating\",\n finishingGroup: \"Finishing dictation\",\n finishing: \"Finishing …\",\n starting: \"Starting …\",\n ended: \"Dictation ended\",\n discarded: \"Dictation discarded\",\n microphone: \"Microphone\",\n microphoneNamed: ({ name }: { name: string }) => `Microphone: ${name}`,\n systemDefault: \"Default\",\n interrupted: \"Dictation interrupted. The text so far stays.\",\n interruptedShort: \"Interrupted. Text stays.\",\n maxDone: ({ minutes }: { minutes: number }) => `Ended after ${minutes} minutes. The text stays.`,\n maxDoneShort: ({ minutes }: { minutes: number }) => `Ended after ${minutes} min.`,\n silenceDone: \"Ended after a long silence. The text stays.\",\n silenceDoneShort: \"Ended after silence.\",\n continue: \"Continue dictating\",\n dismiss: \"Close notice\",\n blockedTitle: \"Microphone blocked\",\n blockedBody: \"The browser does not let this page use the microphone. To allow it:\",\n blockedStep1: \"Tap the lock on the left of the address bar.\",\n blockedStep2: \"Choose “Allow” for “Microphone”.\",\n retry: \"Try again\",\n quotaTitle: \"Your dictation allowance for today is used up\",\n quotaBody: ({ time }: { time: string }) => `You can dictate again from ${time}. Typing works as always.`,\n quotaBodyTomorrow: ({ time }: { time: string }) => `You can dictate again from tomorrow, ${time}. Typing works as always.`,\n overloadedTitle: \"Live dictation is busy right now\",\n overloadedBody: \"Try again in a moment.\",\n elsewhereTitle: \"You are dictating in another tab\",\n elsewhereBody: \"End it there, then you can dictate here.\",\n unavailableTitle: \"No microphone found\",\n unavailableBody: \"Connect a microphone or choose another one, then try again.\",\n notAvailableTitle: \"Dictation is not available here\",\n notAvailableBody: \"Typing works as always.\",\n ok: \"OK\",\n timeLeft: ({ time }: { time: string }) => `${time} left`,\n },\n de: {\n dictate: \"Diktieren\",\n dictateOffline: \"Diktieren, offline nicht verfügbar\",\n offline: \"Offline. Diktieren braucht eine Verbindung.\",\n discard: \"Diktat verwerfen\",\n stop: \"Diktat beenden\",\n running: \"Diktat läuft\",\n finishingGroup: \"Diktat wird abgeschlossen\",\n finishing: \"Wird abgeschlossen …\",\n starting: \"Wird gestartet …\",\n ended: \"Diktat beendet\",\n discarded: \"Diktat verworfen\",\n microphone: \"Mikrofon\",\n microphoneNamed: ({ name }: { name: string }) => `Mikrofon: ${name}`,\n systemDefault: \"Standard\",\n interrupted: \"Diktat unterbrochen. Der Text bis hier bleibt.\",\n interruptedShort: \"Unterbrochen. Text bleibt.\",\n maxDone: ({ minutes }: { minutes: number }) => `Nach ${minutes} Minuten beendet. Der Text bleibt.`,\n maxDoneShort: ({ minutes }: { minutes: number }) => `Nach ${minutes} Min. beendet.`,\n silenceDone: \"Nach langer Stille beendet. Der Text bleibt.\",\n silenceDoneShort: \"Nach Stille beendet.\",\n continue: \"Weiter diktieren\",\n dismiss: \"Hinweis schließen\",\n blockedTitle: \"Mikrofon blockiert\",\n blockedBody: \"Der Browser lässt diese Seite nicht an das Mikrofon. So erlaubst du es:\",\n blockedStep1: \"Links in der Adressleiste auf das Schloss tippen.\",\n blockedStep2: \"Bei „Mikrofon“ „Erlauben“ wählen.\",\n retry: \"Erneut versuchen\",\n quotaTitle: \"Dein Diktat-Kontingent für heute ist aufgebraucht\",\n quotaBody: ({ time }: { time: string }) => `Ab ${time} kannst du wieder diktieren. Tippen geht natürlich weiter.`,\n quotaBodyTomorrow: ({ time }: { time: string }) => `Ab morgen, ${time}, kannst du wieder diktieren. Tippen geht natürlich weiter.`,\n overloadedTitle: \"Live-Diktat ist gerade ausgelastet\",\n overloadedBody: \"Versuch es in einem Moment noch mal.\",\n elsewhereTitle: \"Du diktierst gerade in einem anderen Tab\",\n elsewhereBody: \"Beende es dort, dann kannst du hier diktieren.\",\n unavailableTitle: \"Kein Mikrofon gefunden\",\n unavailableBody: \"Schließ ein Mikrofon an oder wähl ein anderes, dann versuch es noch mal.\",\n notAvailableTitle: \"Diktieren ist hier nicht verfügbar\",\n notAvailableBody: \"Tippen geht natürlich weiter.\",\n ok: \"OK\",\n timeLeft: ({ time }: { time: string }) => `noch ${time}`,\n },\n },\n});\n"],"mappings":"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","ignoreList":[]}
|