@seams/voice-capture 0.68.1 → 0.69.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/README.md +41 -0
- package/dist/browser/card.js +252 -19
- package/dist/esm/card/index.js +1 -1
- package/dist/esm/card/phraseCard.js +2 -2
- package/dist/esm/card/prompt.js +314 -20
- package/dist/esm/card/ribbon.js +92 -2
- package/dist/esm/card/rowMotion.js +3 -3
- package/dist/esm/card/surface.js +113 -5
- package/dist/esm/card/visual.js +1 -1
- package/dist/esm/chunks/{visual-CeEQ8QkM.js → visual-DU1OVwCA.js} +4 -0
- package/dist/types/card/index.d.ts +2 -2
- package/dist/types/card/prompt.d.ts +13 -1
- package/dist/types/card/ribbon.d.ts +17 -0
- package/dist/types/card/rowMotion.d.ts +3 -3
- package/dist/types/card/surface.d.ts +63 -0
- package/dist/types/card/visual.d.ts +3 -1
- package/package.json +1 -1
package/dist/esm/card/surface.js
CHANGED
|
@@ -8,7 +8,29 @@ import { VoicePrompt, leaveSurface } from "./prompt.js";
|
|
|
8
8
|
//#region src/card/surface.ts
|
|
9
9
|
const LABEL = "Say this with your voice";
|
|
10
10
|
const PROMPT_LABEL = "Say this sentence";
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* The status line before a recording: empty, so the sentence is the one text to read. It holds
|
|
13
|
+
* "Opening microphone…", a loading line or a problem with the recording.
|
|
14
|
+
*/
|
|
15
|
+
const PROMPT_MESSAGE = "";
|
|
16
|
+
/** The colours that a phrase card reads. */
|
|
17
|
+
const PHRASE_CARD_COLORS = [
|
|
18
|
+
"colorBackground",
|
|
19
|
+
"textPrimary",
|
|
20
|
+
"textSecondary",
|
|
21
|
+
"textMuted",
|
|
22
|
+
"borderPrimary",
|
|
23
|
+
"surface",
|
|
24
|
+
"buttonBackground",
|
|
25
|
+
"textButton",
|
|
26
|
+
"error",
|
|
27
|
+
"info",
|
|
28
|
+
"voiceLine",
|
|
29
|
+
"voiceEcho",
|
|
30
|
+
"voiceEchoDeep",
|
|
31
|
+
"voiceFill",
|
|
32
|
+
"voicePixelBackground"
|
|
33
|
+
];
|
|
12
34
|
/**
|
|
13
35
|
* Shows the given sentence in the prompt. The surface records clips with the quality check, and
|
|
14
36
|
* stays open so the caller can show its check and the result in the same card. A too quiet or
|
|
@@ -27,6 +49,14 @@ var CardSurface = class {
|
|
|
27
49
|
pressed;
|
|
28
50
|
/** Back, when the card shows it apart from Close. */
|
|
29
51
|
back;
|
|
52
|
+
/** Minimize, when the host can hide the card. */
|
|
53
|
+
minimize;
|
|
54
|
+
minimizedHook;
|
|
55
|
+
progressedHook;
|
|
56
|
+
/** The person pressed Minimize, and the card has not asked to show again since. */
|
|
57
|
+
minimized = false;
|
|
58
|
+
/** The last stage that the host heard, as a key. */
|
|
59
|
+
progress = "";
|
|
30
60
|
recorder = null;
|
|
31
61
|
recording = null;
|
|
32
62
|
choice = null;
|
|
@@ -55,8 +85,10 @@ var CardSurface = class {
|
|
|
55
85
|
this.element.setAttribute("role", "dialog");
|
|
56
86
|
this.element.setAttribute("aria-modal", "true");
|
|
57
87
|
this.element.setAttribute("aria-label", LABEL);
|
|
88
|
+
paintColors(this.element, input.colors);
|
|
58
89
|
this.prompt = new VoicePrompt(document, LABEL, sentence);
|
|
59
|
-
|
|
90
|
+
const promptLabel = input.context?.sentenceLabel ?? PROMPT_LABEL;
|
|
91
|
+
this.prompt.title.textContent = promptLabel;
|
|
60
92
|
const shown = /[.!?]$/.test(sentence) ? sentence : `${sentence}.`;
|
|
61
93
|
this.prompt.phrase.textContent = shown;
|
|
62
94
|
delete this.prompt.phrase.dataset.voiceidPhrase;
|
|
@@ -65,7 +97,11 @@ var CardSurface = class {
|
|
|
65
97
|
const controls = frame.controls ?? "close";
|
|
66
98
|
this.pressed = frame.pressed;
|
|
67
99
|
const back = controls === "close" ? null : this.prompt.showBack(controls === "back_and_close");
|
|
100
|
+
if (input.context) this.prompt.showContext(input.context.label, input.context.text);
|
|
68
101
|
this.back = back === this.prompt.cancel ? null : back;
|
|
102
|
+
this.minimizedHook = frame.minimized;
|
|
103
|
+
this.progressedHook = frame.progressed;
|
|
104
|
+
this.minimize = frame.minimized ? this.prompt.showMinimize() : null;
|
|
69
105
|
const handedOverPrompt = handedOver?.querySelector(":scope > .seams-voiceid-prompt") ?? null;
|
|
70
106
|
const rows = handedOverPrompt ? handedOverRows(handedOverPrompt) : null;
|
|
71
107
|
if (handedOverPrompt) {
|
|
@@ -74,7 +110,7 @@ var CardSurface = class {
|
|
|
74
110
|
this.autoStart = false;
|
|
75
111
|
}
|
|
76
112
|
this.card = new PhraseCard(this.prompt, {
|
|
77
|
-
label:
|
|
113
|
+
label: promptLabel,
|
|
78
114
|
sentence: shown,
|
|
79
115
|
message: PROMPT_MESSAGE,
|
|
80
116
|
action: "Record"
|
|
@@ -89,10 +125,13 @@ var CardSurface = class {
|
|
|
89
125
|
const corner = controls === "back" ? this.pressBack : this.pressClose;
|
|
90
126
|
this.prompt.cancel.addEventListener("click", corner);
|
|
91
127
|
this.back?.addEventListener("click", this.pressBack);
|
|
128
|
+
this.minimize?.addEventListener("click", this.pressMinimize);
|
|
92
129
|
this.element.addEventListener("cancel", this.cancel);
|
|
93
130
|
outer.addEventListener("abort", this.cancel);
|
|
94
131
|
if (handedOver) handedOver.replaceWith(this.element);
|
|
95
132
|
else parent.appendChild(this.element);
|
|
133
|
+
const voiceLine = input.voiceLine ?? themeVoiceLine(this.prompt.element);
|
|
134
|
+
if (voiceLine === "pixels") this.prompt.useVoiceLine(voiceLine);
|
|
96
135
|
if (frame.hugged) this.element.classList.add("seams-voiceid-hugged");
|
|
97
136
|
this.unmounted = frame.mounted?.(this.element);
|
|
98
137
|
if (rows || this.autoStart) this.prompt.element.focus({ preventScroll: true });
|
|
@@ -107,6 +146,11 @@ var CardSurface = class {
|
|
|
107
146
|
this.recording = recording;
|
|
108
147
|
if (this.view) {
|
|
109
148
|
this.view = null;
|
|
149
|
+
this.report({
|
|
150
|
+
stage: "recording",
|
|
151
|
+
done: 0,
|
|
152
|
+
total: 0
|
|
153
|
+
});
|
|
110
154
|
this.card.showPrompt();
|
|
111
155
|
} else if (this.autoStart) this.begin(recording);
|
|
112
156
|
this.autoStart = false;
|
|
@@ -117,6 +161,21 @@ var CardSurface = class {
|
|
|
117
161
|
if (this.closed) return Promise.resolve("closed");
|
|
118
162
|
this.settleChoice("replaced");
|
|
119
163
|
this.view = view;
|
|
164
|
+
if (view.kind === "check") {
|
|
165
|
+
const done = view.segments.filter((state) => state === "done" || state === "skip").length;
|
|
166
|
+
this.report({
|
|
167
|
+
stage: "checking",
|
|
168
|
+
done,
|
|
169
|
+
total: view.segments.length
|
|
170
|
+
});
|
|
171
|
+
} else {
|
|
172
|
+
this.report({
|
|
173
|
+
stage: "result",
|
|
174
|
+
done: 0,
|
|
175
|
+
total: 0
|
|
176
|
+
});
|
|
177
|
+
this.needPerson();
|
|
178
|
+
}
|
|
120
179
|
this.card.show(view);
|
|
121
180
|
return new Promise((resolve) => {
|
|
122
181
|
this.choice = resolve;
|
|
@@ -135,6 +194,7 @@ var CardSurface = class {
|
|
|
135
194
|
this.prompt.cancel.removeEventListener("click", this.pressBack);
|
|
136
195
|
this.prompt.cancel.removeEventListener("click", this.pressClose);
|
|
137
196
|
this.back?.removeEventListener("click", this.pressBack);
|
|
197
|
+
this.minimize?.removeEventListener("click", this.pressMinimize);
|
|
138
198
|
this.card.dispose();
|
|
139
199
|
this.prompt.dispose();
|
|
140
200
|
leaveSurface(this.element);
|
|
@@ -150,6 +210,11 @@ var CardSurface = class {
|
|
|
150
210
|
};
|
|
151
211
|
begin(recording) {
|
|
152
212
|
this.started = true;
|
|
213
|
+
this.report({
|
|
214
|
+
stage: "recording",
|
|
215
|
+
done: 0,
|
|
216
|
+
total: 0
|
|
217
|
+
});
|
|
153
218
|
this.prompt.record.disabled = true;
|
|
154
219
|
this.prompt.status.textContent = this.speechDetectorReady ? "Opening microphone…" : `Loading ${captureConfig().label}…`;
|
|
155
220
|
this.attempt(recording, this.autoStart);
|
|
@@ -198,8 +263,14 @@ var CardSurface = class {
|
|
|
198
263
|
};
|
|
199
264
|
/** The end of speech starts the check in place; every other capture event is the prompt's. */
|
|
200
265
|
capture = (event) => {
|
|
201
|
-
if (event.kind === "processing")
|
|
202
|
-
|
|
266
|
+
if (event.kind === "processing") {
|
|
267
|
+
this.report({
|
|
268
|
+
stage: "checking",
|
|
269
|
+
done: 0,
|
|
270
|
+
total: 0
|
|
271
|
+
});
|
|
272
|
+
this.card.beginCheck();
|
|
273
|
+
} else this.prompt.capture(event);
|
|
203
274
|
};
|
|
204
275
|
retry(message, action = "Try again") {
|
|
205
276
|
this.started = false;
|
|
@@ -207,6 +278,31 @@ var CardSurface = class {
|
|
|
207
278
|
this.prompt.record.textContent = action;
|
|
208
279
|
this.prompt.ready(message);
|
|
209
280
|
this.prompt.record.focus();
|
|
281
|
+
this.report({
|
|
282
|
+
stage: "recording",
|
|
283
|
+
done: 0,
|
|
284
|
+
total: 0
|
|
285
|
+
});
|
|
286
|
+
this.needPerson();
|
|
287
|
+
}
|
|
288
|
+
/** Tells the host each new stage of the card. */
|
|
289
|
+
report(progress) {
|
|
290
|
+
const key = `${progress.stage}:${progress.done}:${progress.total}`;
|
|
291
|
+
if (key === this.progress || this.closed) return;
|
|
292
|
+
this.progress = key;
|
|
293
|
+
this.progressedHook?.(progress);
|
|
294
|
+
}
|
|
295
|
+
/** The person asks the host to hide the card. A host that showed it again can hide it again. */
|
|
296
|
+
pressMinimize = () => {
|
|
297
|
+
if (this.closed) return;
|
|
298
|
+
this.minimized = true;
|
|
299
|
+
this.minimizedHook?.(true);
|
|
300
|
+
};
|
|
301
|
+
/** The card needs the person: the host shows the card that it hid. */
|
|
302
|
+
needPerson() {
|
|
303
|
+
if (!this.minimized) return;
|
|
304
|
+
this.minimized = false;
|
|
305
|
+
this.minimizedHook?.(false);
|
|
210
306
|
}
|
|
211
307
|
settleChoice(choice) {
|
|
212
308
|
const settle = this.choice;
|
|
@@ -233,6 +329,18 @@ var CardSurface = class {
|
|
|
233
329
|
if (this.outer.aborted) this.close();
|
|
234
330
|
};
|
|
235
331
|
};
|
|
332
|
+
/** Sets the card's own colours. Keys that a card does not read are left out. */
|
|
333
|
+
function paintColors(element, colors) {
|
|
334
|
+
if (!colors) return;
|
|
335
|
+
for (const key of PHRASE_CARD_COLORS) {
|
|
336
|
+
const value = colors[key];
|
|
337
|
+
if (value) element.style.setProperty(`--seams-colors-${key}`, value);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/** The theme's `--seams-shape-voiceLine`: `pixels`, or else the wave lines. */
|
|
341
|
+
function themeVoiceLine(element) {
|
|
342
|
+
return getComputedStyle(element).getPropertyValue("--seams-shape-voiceLine").trim() === "pixels" ? "pixels" : "wave";
|
|
343
|
+
}
|
|
236
344
|
/** A failed early load runs again when Record needs the detector, and shows its error there. */
|
|
237
345
|
function ignoreEarlyLoad() {}
|
|
238
346
|
/** The rows that the handed-over card shows now. */
|
package/dist/esm/card/visual.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as beamPalette, t as VoiceVisual } from "../chunks/visual-
|
|
1
|
+
import { n as beamPalette, t as VoiceVisual } from "../chunks/visual-DU1OVwCA.js";
|
|
2
2
|
export { VoiceVisual, beamPalette };
|
|
@@ -1484,6 +1484,10 @@ var VoiceVisual = class {
|
|
|
1484
1484
|
attributeFilter: ["data-theme"]
|
|
1485
1485
|
});
|
|
1486
1486
|
}
|
|
1487
|
+
/** Draws the voice as wave lines (the default) or as columns of pixels. */
|
|
1488
|
+
setLineStyle(style) {
|
|
1489
|
+
this.ribbon.setLineStyle(style);
|
|
1490
|
+
}
|
|
1487
1491
|
listen() {
|
|
1488
1492
|
this.setPhase("listening");
|
|
1489
1493
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { openPhraseCard, type PhraseCardControl, type PhraseCardControls, type PhraseCardFrame, type PhraseCardInput, } from './surface';
|
|
1
|
+
export { openPhraseCard, type PhraseCardColor, type PhraseCardColors, type PhraseCardContext, type PhraseCardControl, type PhraseCardControls, type PhraseCardFrame, type PhraseCardInput, type PhraseCardProgress, } from './surface';
|
|
2
2
|
export type { PhraseCheckView, PhraseChoice, PhraseRecording, PhraseResultView, PhraseSegmentState, PhraseSurface, PhraseText, PhraseView, } from './types';
|
|
3
3
|
export { leaveSurface, VoicePrompt, type PhraseDisplay, type PromptChange } from './prompt';
|
|
4
4
|
export { PhraseCard, type HandedOverRows, type PromptCopy } from './phraseCard';
|
|
5
|
-
export { VoiceRibbon, type VoiceCheckingStyle } from './ribbon';
|
|
5
|
+
export { VoiceRibbon, type VoiceCheckingStyle, type VoiceLineStyle } from './ribbon';
|
|
6
6
|
export { VoiceVisual } from './visual';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { VoiceCaptureEvent } from '../microphone';
|
|
2
|
-
import type { VoiceCheckingStyle } from './ribbon';
|
|
2
|
+
import type { VoiceCheckingStyle, VoiceLineStyle } from './ribbon';
|
|
3
3
|
/** How the card shows a phrase: by default as it is, with a capital letter and a full stop. */
|
|
4
4
|
export type PhraseDisplay = (phrase: string) => string;
|
|
5
5
|
/** A new state of the card's rows. Rows that it leaves out keep their content. */
|
|
@@ -45,12 +45,24 @@ export declare class VoicePrompt {
|
|
|
45
45
|
constructor(document: Document, label: string, phrase: string, checking?: VoiceCheckingStyle,
|
|
46
46
|
/** The text to show for a phrase, such as the phrase with its commas. */
|
|
47
47
|
display?: PhraseDisplay);
|
|
48
|
+
/** Draws the voice as wave lines (the default) or as columns of pixels. */
|
|
49
|
+
useVoiceLine(style: VoiceLineStyle): void;
|
|
50
|
+
/**
|
|
51
|
+
* Shows the text that the sentence speaks for, such as the note that a spoken summary signs,
|
|
52
|
+
* above the sentence. It stays for the check and the result.
|
|
53
|
+
*/
|
|
54
|
+
showContext(label: string, text: string): void;
|
|
48
55
|
/**
|
|
49
56
|
* In an app's dialog with a step before this card, Back in the leading corner returns to that
|
|
50
57
|
* step. With `close`, Close stays in the trailing corner and ends the whole dialog; without it,
|
|
51
58
|
* Back takes Close's place. Each one ends the card as cancelled. The result is the Back control.
|
|
52
59
|
*/
|
|
53
60
|
showBack(close: boolean): HTMLButtonElement;
|
|
61
|
+
/**
|
|
62
|
+
* Minimize in the trailing corner, beside Close. It stays in the check, where Close is hidden,
|
|
63
|
+
* so the person can hide the card while the check goes on. The result is the control.
|
|
64
|
+
*/
|
|
65
|
+
showMinimize(): HTMLButtonElement;
|
|
54
66
|
/**
|
|
55
67
|
* Moves the rows to a new state. The rows whose content changes fade out together, take their
|
|
56
68
|
* new content and fade in one after another; the other rows stay still. A change that comes
|
|
@@ -2,6 +2,8 @@ import type { VoiceActivityEvent } from '../microphone';
|
|
|
2
2
|
type RibbonPhase = 'idle' | 'listening' | 'processing';
|
|
3
3
|
/** How the line shows that the voice is being checked. */
|
|
4
4
|
export type VoiceCheckingStyle = 'ring' | 'segments';
|
|
5
|
+
/** How the card draws the voice while it listens: sine wave lines, or columns of pixels. */
|
|
6
|
+
export type VoiceLineStyle = 'wave' | 'pixels';
|
|
5
7
|
/** Visual feedback from recorder activity. Never opens or retains an audio stream. */
|
|
6
8
|
export declare class VoiceRibbon {
|
|
7
9
|
private readonly checking;
|
|
@@ -25,8 +27,19 @@ export declare class VoiceRibbon {
|
|
|
25
27
|
private target;
|
|
26
28
|
private level;
|
|
27
29
|
private stopped;
|
|
30
|
+
private lineStyle;
|
|
31
|
+
/** The pixel style's dots by column, top row first. Made when the style is first chosen. */
|
|
32
|
+
private pixels;
|
|
33
|
+
/** The level of each column, the newest at the right end. */
|
|
34
|
+
private readonly pixelLevels;
|
|
35
|
+
/** The rows that each column shows now, above and below the middle row. */
|
|
36
|
+
private readonly pixelHeights;
|
|
37
|
+
private pixelClock;
|
|
28
38
|
constructor(document: Document, checking?: VoiceCheckingStyle);
|
|
29
39
|
readonly readLevel: () => number;
|
|
40
|
+
/** Draws the voice as wave lines (the default) or as columns of pixels. */
|
|
41
|
+
setLineStyle(style: VoiceLineStyle): void;
|
|
42
|
+
private makePixels;
|
|
30
43
|
/** The voice line's width now: 1, or the theme's `voiceLineWidth`. */
|
|
31
44
|
private lineWidth;
|
|
32
45
|
setPhase(phase: RibbonPhase): void;
|
|
@@ -43,8 +56,12 @@ export declare class VoiceRibbon {
|
|
|
43
56
|
private wake;
|
|
44
57
|
private readonly draw;
|
|
45
58
|
private idleAmplitude;
|
|
59
|
+
/** Adds the level of each step at the right end; the older columns move left. */
|
|
60
|
+
private stepPixels;
|
|
46
61
|
private paint;
|
|
47
62
|
private paintLine;
|
|
63
|
+
/** Each column shows the middle dot and as many rows above and below it as its level. */
|
|
64
|
+
private paintPixels;
|
|
48
65
|
private paintSegments;
|
|
49
66
|
/** Each segment brightens one beat after the one before it, from the resting line's opacity. */
|
|
50
67
|
private segmentOpacity;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const ROW_OUT_MS = 150;
|
|
2
|
-
export declare const ROW_IN_MS =
|
|
3
|
-
export declare const ROW_IN_DELAY_MS =
|
|
4
|
-
export declare const ROW_STAGGER_MS =
|
|
2
|
+
export declare const ROW_IN_MS = 140;
|
|
3
|
+
export declare const ROW_IN_DELAY_MS = 0;
|
|
4
|
+
export declare const ROW_STAGGER_MS = 20;
|
|
5
5
|
export declare const ROW_EASE = "cubic-bezier(0.2, 0, 0, 1)";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type VoiceRecordingOptions } from '../microphone';
|
|
2
|
+
import type { VoiceLineStyle } from './ribbon';
|
|
2
3
|
import type { PhraseSurface } from './types';
|
|
3
4
|
/** What the host page adds around the card. Every field is optional. */
|
|
4
5
|
export type PhraseCardFrame = Readonly<{
|
|
@@ -14,6 +15,16 @@ export type PhraseCardFrame = Readonly<{
|
|
|
14
15
|
controls?: PhraseCardControls;
|
|
15
16
|
/** Runs when the person presses Back or Close, before the card ends. Escape is not a press. */
|
|
16
17
|
pressed?(control: PhraseCardControl): void;
|
|
18
|
+
/**
|
|
19
|
+
* With it, the card draws Minimize in the trailing corner, beside Close, also in the check.
|
|
20
|
+
* A press runs `minimized(true)`. The card does not hide itself: the host hides it, and the
|
|
21
|
+
* recording, the check and the caller's work go on. The card runs `minimized(false)` when it
|
|
22
|
+
* needs the person again: on a result, and when a recording needs another try. The host can
|
|
23
|
+
* show the card again before that.
|
|
24
|
+
*/
|
|
25
|
+
minimized?(minimized: boolean): void;
|
|
26
|
+
/** Runs on each new stage of the card, so the host can show the progress of a hidden card. */
|
|
27
|
+
progressed?(progress: PhraseCardProgress): void;
|
|
17
28
|
/** The host sizes its frame to the surface, so the card follows the frame. */
|
|
18
29
|
hugged?: boolean;
|
|
19
30
|
/** Runs when the surface is in the document. Its return value runs when the surface closes. */
|
|
@@ -23,6 +34,16 @@ export type PhraseCardFrame = Readonly<{
|
|
|
23
34
|
export type PhraseCardControls = 'close' | 'back' | 'back_and_close';
|
|
24
35
|
/** One corner control of a phrase card. */
|
|
25
36
|
export type PhraseCardControl = 'back' | 'close';
|
|
37
|
+
/**
|
|
38
|
+
* The stage of a phrase card: it records the sentence (or waits for Record), it checks the
|
|
39
|
+
* recording, or it shows a result.
|
|
40
|
+
*/
|
|
41
|
+
export type PhraseCardProgress = Readonly<{
|
|
42
|
+
stage: 'recording' | 'checking' | 'result';
|
|
43
|
+
/** The parts of the check that are over, of `total`. Both are 0 outside a check. */
|
|
44
|
+
done: number;
|
|
45
|
+
total: number;
|
|
46
|
+
}>;
|
|
26
47
|
export type PhraseCardInput = Readonly<{
|
|
27
48
|
sentence: string;
|
|
28
49
|
signal: AbortSignal;
|
|
@@ -35,6 +56,47 @@ export type PhraseCardInput = Readonly<{
|
|
|
35
56
|
* start audio without a press, the card stays with its Record button.
|
|
36
57
|
*/
|
|
37
58
|
autoStart?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* The text that the sentence speaks for, such as the note that a spoken summary signs. With
|
|
61
|
+
* it, the card is a form: the text in a soft box under its label, the sentence centred in a
|
|
62
|
+
* box under its own label, and one button at the foot that is the voice line while the card
|
|
63
|
+
* records. The text stays for the check and the result.
|
|
64
|
+
*/
|
|
65
|
+
context?: PhraseCardContext;
|
|
66
|
+
/**
|
|
67
|
+
* How the card draws the voice while it listens: `wave`, sine wave lines (the default), or
|
|
68
|
+
* `pixels`, columns of dots in blue tones. Without it, the theme value `--seams-shape-voiceLine`
|
|
69
|
+
* (`wave` or `pixels`) decides, so a Wallet host can choose it with its theme.
|
|
70
|
+
*/
|
|
71
|
+
voiceLine?: VoiceLineStyle;
|
|
72
|
+
/**
|
|
73
|
+
* The card's colours, as CSS colours, for example `{ buttonBackground: '#1d9bf0' }`. Each one
|
|
74
|
+
* sets the CSS variable `--seams-colors-<key>` on this card, over the page's own value. A
|
|
75
|
+
* Seams Wallet app sets the same keys in `appearance.theme.colors`.
|
|
76
|
+
*/
|
|
77
|
+
colors?: PhraseCardColors;
|
|
78
|
+
}>;
|
|
79
|
+
/** The colours that a phrase card reads. */
|
|
80
|
+
declare const PHRASE_CARD_COLORS: readonly [
|
|
81
|
+
/** The card, its text, its lines and its soft boxes. */
|
|
82
|
+
'colorBackground', 'textPrimary', 'textSecondary', 'textMuted', 'borderPrimary', 'surface',
|
|
83
|
+
/** The main button (Record, the voice line of a form card, Done) and its text. */
|
|
84
|
+
'buttonBackground', 'textButton',
|
|
85
|
+
/** A failed check, and a held one. */
|
|
86
|
+
'error', 'info',
|
|
87
|
+
/** The voice line, its echoes, and the bands of the pixel style. */
|
|
88
|
+
'voiceLine', 'voiceEcho', 'voiceEchoDeep',
|
|
89
|
+
/** A form card: the fill of the sentence's box, and the button behind the pixels. */
|
|
90
|
+
'voiceFill', 'voicePixelBackground'];
|
|
91
|
+
export type PhraseCardColor = (typeof PHRASE_CARD_COLORS)[number];
|
|
92
|
+
export type PhraseCardColors = Partial<Readonly<Record<PhraseCardColor, string>>>;
|
|
93
|
+
/** The text that a phrase card shows above its sentence. */
|
|
94
|
+
export type PhraseCardContext = Readonly<{
|
|
95
|
+
/** The label above the text, such as "Your note on @alice". */
|
|
96
|
+
label: string;
|
|
97
|
+
text: string;
|
|
98
|
+
/** The label above the sentence, such as "Read this aloud to post". Default: "Say this sentence". */
|
|
99
|
+
sentenceLabel?: string;
|
|
38
100
|
}>;
|
|
39
101
|
/**
|
|
40
102
|
* Shows the given sentence in the prompt. The surface records clips with the quality check, and
|
|
@@ -42,3 +104,4 @@ export type PhraseCardInput = Readonly<{
|
|
|
42
104
|
* interrupted recording stays on the surface for another try.
|
|
43
105
|
*/
|
|
44
106
|
export declare function openPhraseCard(input: PhraseCardInput): PhraseSurface;
|
|
107
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type VoiceBeamColorVariant } from 'voice-glow';
|
|
2
2
|
import type { VoiceActivityEvent } from '../microphone';
|
|
3
|
-
import { type VoiceCheckingStyle } from './ribbon';
|
|
3
|
+
import { type VoiceCheckingStyle, type VoiceLineStyle } from './ribbon';
|
|
4
4
|
/** The theme's `voiceBeam`, the name of a Beam palette, or the default one. */
|
|
5
5
|
export declare function beamPalette(value: string): VoiceBeamColorVariant;
|
|
6
6
|
/** Shared by enrollment, unlock and signing. The recorder remains the only audio owner. */
|
|
@@ -13,6 +13,8 @@ export declare class VoiceVisual {
|
|
|
13
13
|
private phase;
|
|
14
14
|
private disposed;
|
|
15
15
|
constructor(document: Document, prompt: HTMLElement, checking: VoiceCheckingStyle);
|
|
16
|
+
/** Draws the voice as wave lines (the default) or as columns of pixels. */
|
|
17
|
+
setLineStyle(style: VoiceLineStyle): void;
|
|
16
18
|
listen(): void;
|
|
17
19
|
add(event: VoiceActivityEvent): void;
|
|
18
20
|
checking(): void;
|
package/package.json
CHANGED