/
voice-search.tsx
109 lines (94 loc) · 2.88 KB
/
voice-search.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import React, { render, unmountComponentAtNode } from 'preact-compat';
import cx from 'classnames';
import {
getContainerNode,
createDocumentationMessageGenerator,
} from '../../lib/utils';
import { component } from '../../lib/suit';
import connectVoiceSearch, {
VoiceSearchRenderer,
} from '../../connectors/voice-search/connectVoiceSearch';
import VoiceSearch, {
VoiceSearchComponentCSSClasses,
} from '../../components/VoiceSearch/VoiceSearch';
import defaultTemplates from './defaultTemplates';
import { WidgetFactory, Template } from '../../types';
const withUsage = createDocumentationMessageGenerator({ name: 'voice-search' });
const suit = component('VoiceSearch');
export type VoiceSearchCSSClasses = {
root: string | string[];
button: string | string[];
status: string | string[];
};
type VoiceSearchTemplateProps = {
status: string;
errorCode: string;
isListening: boolean;
transcript: string;
isSpeechFinal: boolean;
isBrowserSupported: boolean;
};
export type VoiceSearchTemplates = {
buttonText: Template<VoiceSearchTemplateProps>;
status: Template<VoiceSearchTemplateProps>;
};
type VoiceSearchWidgetParams = {
container: string | HTMLElement;
cssClasses?: Partial<VoiceSearchCSSClasses>;
templates?: Partial<VoiceSearchTemplates>;
searchAsYouSpeak?: boolean;
};
interface VoiceSearchRendererWidgetParams extends VoiceSearchWidgetParams {
container: HTMLElement;
cssClasses: VoiceSearchComponentCSSClasses;
templates: VoiceSearchTemplates;
}
type VoiceSearch = WidgetFactory<VoiceSearchWidgetParams>;
const renderer: VoiceSearchRenderer<VoiceSearchRendererWidgetParams> = ({
isBrowserSupported,
isListening,
toggleListening,
voiceListeningState,
widgetParams,
}) => {
const { container, cssClasses, templates } = widgetParams;
render(
<VoiceSearch
cssClasses={cssClasses}
templates={templates}
isBrowserSupported={isBrowserSupported}
isListening={isListening}
toggleListening={toggleListening}
voiceListeningState={voiceListeningState}
/>,
container
);
};
const voiceSearch: VoiceSearch = (
{
container,
cssClasses: userCssClasses = {} as VoiceSearchCSSClasses,
templates,
searchAsYouSpeak = false,
} = {} as VoiceSearchWidgetParams
) => {
if (!container) {
throw new Error(withUsage('The `container` option is required.'));
}
const containerNode = getContainerNode(container);
const cssClasses = {
root: cx(suit(), userCssClasses.root),
button: cx(suit({ descendantName: 'button' }), userCssClasses.button),
status: cx(suit({ descendantName: 'status' }), userCssClasses.status),
};
const makeWidget = connectVoiceSearch(renderer, () =>
unmountComponentAtNode(containerNode)
);
return makeWidget({
container: containerNode,
cssClasses,
templates: { ...defaultTemplates, ...templates },
searchAsYouSpeak,
});
};
export default voiceSearch;