UNPKG

ranui

Version:

A framework-agnostic Web Components UI library built on native custom elements, with TypeScript types, light/dark theming, SSR and PWA support.

117 lines (116 loc) 5.15 kB
import { EventManager } from '../../utils/builder'; import { RanElement } from '../../utils'; /** * `<r-voice-button>` — dictation for a text composer. * * A microphone button, and nothing else. It owns the capture and reports what was heard; * where that text goes is the caller's decision, because a component that also wrote into * an input would have to know which input, whether to append or replace, and what to do * about the caret — three answers that differ per app. * * ```ts * const mic = document.querySelector('r-voice-button'); * let base = ''; * mic.addEventListener('voicestart', () => { base = input.value; }); * mic.addEventListener('voiceresult', (e) => { * input.value = base + e.detail.transcript; // the whole capture, revised as it firms up * }); * ``` * * **It does not send.** Recognition is wrong often enough that committing on its behalf * takes away the review the speaker needs, so this fills the box and stops there. * * **It hides itself where speech recognition does not exist** — Firefox, and any browser * with the API absent. A button that cannot work is worse than no button: it invites a tap * and then explains itself. * * **Two gestures, because two devices want different ones.** With a mouse or pen it is a * toggle: click to start, click to stop, Escape to discard — the desktop pattern, and the * only one available to a keyboard. Under a finger it is push-to-talk: hold to record, * slide away to cancel, release to keep. That is the gesture a decade of voice messaging * has taught people, and it costs a touch user nothing to learn. * * Attributes: `lang` (BCP 47; defaults to the document's), `continuous`, `disabled`, * `label`, `active-label`, `hold-hint`, `cancel-hint`, `sheet`. `listening` is reflected * while capturing; `holding` and `cancelling` while a press-and-hold is in progress. * * Events: `voicestart`, `voiceresult` (`{ transcript, isFinal }`), `voiceerror` * (`{ kind, detail }`), `voiceend`. */ export declare class VoiceButton extends RanElement { _events: EventManager; _shadowDom: ShadowRoot; _button: HTMLButtonElement; _icon: HTMLElement; _hint: HTMLElement; private _recognizer; /** Pointer id of a press-and-hold in progress, so a second finger cannot end the first. */ private _holdPointer; /** Where the holding pointer went down, to measure the slide that cancels. */ private _holdOrigin; static get observedAttributes(): string[]; constructor(); /** Whether a capture is running. Reflected, so `:host([listening])` can style it. */ get listening(): boolean; /** Whether this platform can recognize speech at all. */ get supported(): boolean; /** * Language being spoken, as a BCP 47 tag. * * Read per capture rather than once, and defaulting to the document's own language, so an * app that switches locale mid-session dictates in the language it is showing. */ get lang(): string; set lang(value: string); /** Keep listening across pauses instead of stopping at the first one. */ get continuous(): boolean; set continuous(value: boolean); get disabled(): boolean; set disabled(value: boolean); /** Accessible name while idle. */ get label(): string; set label(value: string); /** Accessible name while listening; the name has to change, not only the icon. */ get activeLabel(): string; set activeLabel(value: string); /** Shown above the button while a finger is held down. */ get holdHint(): string; set holdHint(value: string); /** Replaces {@link holdHint} once the finger has slid far enough to discard. */ get cancelHint(): string; set cancelHint(value: string); get sheet(): string; set sheet(value: string); /** Starts a capture. Ignored while one is running, or when unsupported or disabled. */ start(): void; /** Ends the capture, keeping what was recognized. */ stop(): void; /** Ends the capture and discards it — what Escape should do. */ abort(): void; /** * Starts if idle, stops if running. * * Decided from the recognizer's own state, not the reflected `listening` attribute. The * attribute follows the platform's start event, and a capture that has begun but not yet * reported it would leave the two disagreeing — the next activation would try to start a * second capture, be refused, and the button would sit there doing nothing. */ toggle(): void; connectedCallback(): void; disconnectedCallback(): void; attributeChangedCallback(name: string, old: string | null, next: string | null): void; handlerExternalCss: () => void; /** Distance a finger must travel before releasing discards instead of keeping. */ private static readonly CANCEL_DISTANCE; private _onClick; private _onPointerDown; private _onPointerMove; private _onPointerUp; private _onPointerCancel; private _endHold; private _onKeydown; private _emit; private _ensureRecognizer; private _syncButton; } export default VoiceButton;