@lightningtv/solid 3.0.0-2 → 3.0.0-20
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/LICENSE +1 -1
- package/README.md +6 -0
- package/dist/src/jsx-runtime.d.ts +1 -3
- package/dist/src/primitives/Column.jsx +9 -10
- package/dist/src/primitives/Column.jsx.map +1 -1
- package/dist/src/primitives/Grid.d.ts +15 -6
- package/dist/src/primitives/Grid.jsx +35 -22
- package/dist/src/primitives/Grid.jsx.map +1 -1
- package/dist/src/primitives/Image.d.ts +8 -0
- package/dist/src/primitives/Image.jsx +24 -0
- package/dist/src/primitives/Image.jsx.map +1 -0
- package/dist/src/primitives/KeepAlive.d.ts +30 -0
- package/dist/src/primitives/KeepAlive.jsx +77 -0
- package/dist/src/primitives/KeepAlive.jsx.map +1 -0
- package/dist/src/primitives/Lazy.d.ts +8 -7
- package/dist/src/primitives/Lazy.jsx +49 -23
- package/dist/src/primitives/Lazy.jsx.map +1 -1
- package/dist/src/primitives/Marquee.d.ts +64 -0
- package/dist/src/primitives/Marquee.jsx +86 -0
- package/dist/src/primitives/Marquee.jsx.map +1 -0
- package/dist/src/primitives/Preserve.d.ts +4 -0
- package/dist/src/primitives/Preserve.jsx +11 -0
- package/dist/src/primitives/Preserve.jsx.map +1 -0
- package/dist/src/primitives/Row.jsx +9 -10
- package/dist/src/primitives/Row.jsx.map +1 -1
- package/dist/src/primitives/Suspense.d.ts +22 -0
- package/dist/src/primitives/Suspense.jsx +33 -0
- package/dist/src/primitives/Suspense.jsx.map +1 -0
- package/dist/src/primitives/Virtual.d.ts +18 -0
- package/dist/src/primitives/Virtual.jsx +434 -0
- package/dist/src/primitives/Virtual.jsx.map +1 -0
- package/dist/src/primitives/VirtualGrid.d.ts +13 -0
- package/dist/src/primitives/VirtualGrid.jsx +139 -0
- package/dist/src/primitives/VirtualGrid.jsx.map +1 -0
- package/dist/src/primitives/VirtualList.d.ts +11 -0
- package/dist/src/primitives/VirtualList.jsx +96 -0
- package/dist/src/primitives/VirtualList.jsx.map +1 -0
- package/dist/src/primitives/VirtualRow.d.ts +13 -0
- package/dist/src/primitives/VirtualRow.jsx +97 -0
- package/dist/src/primitives/VirtualRow.jsx.map +1 -0
- package/dist/src/primitives/Visible.d.ts +0 -1
- package/dist/src/primitives/Visible.jsx +1 -1
- package/dist/src/primitives/Visible.jsx.map +1 -1
- package/dist/src/primitives/announcer/announcer.d.ts +2 -0
- package/dist/src/primitives/announcer/announcer.js +7 -5
- package/dist/src/primitives/announcer/announcer.js.map +1 -1
- package/dist/src/primitives/announcer/index.d.ts +5 -1
- package/dist/src/primitives/announcer/index.js +8 -2
- package/dist/src/primitives/announcer/index.js.map +1 -1
- package/dist/src/primitives/announcer/speech.d.ts +2 -2
- package/dist/src/primitives/announcer/speech.js +157 -28
- package/dist/src/primitives/announcer/speech.js.map +1 -1
- package/dist/src/primitives/createFocusStack.d.ts +4 -4
- package/dist/src/primitives/createFocusStack.jsx +15 -6
- package/dist/src/primitives/createFocusStack.jsx.map +1 -1
- package/dist/src/primitives/createTag.d.ts +8 -0
- package/dist/src/primitives/createTag.jsx +20 -0
- package/dist/src/primitives/createTag.jsx.map +1 -0
- package/dist/src/primitives/index.d.ts +13 -3
- package/dist/src/primitives/index.js +13 -3
- package/dist/src/primitives/index.js.map +1 -1
- package/dist/src/primitives/types.d.ts +3 -0
- package/dist/src/primitives/useHold.d.ts +27 -0
- package/dist/src/primitives/useHold.js +54 -0
- package/dist/src/primitives/useHold.js.map +1 -0
- package/dist/src/primitives/useMouse.d.ts +24 -1
- package/dist/src/primitives/useMouse.js +153 -47
- package/dist/src/primitives/useMouse.js.map +1 -1
- package/dist/src/primitives/utils/chainFunctions.d.ts +30 -4
- package/dist/src/primitives/utils/chainFunctions.js +14 -3
- package/dist/src/primitives/utils/chainFunctions.js.map +1 -1
- package/dist/src/primitives/utils/createBlurredImage.d.ts +56 -0
- package/dist/src/primitives/utils/createBlurredImage.js +223 -0
- package/dist/src/primitives/utils/createBlurredImage.js.map +1 -0
- package/dist/src/primitives/utils/createSpriteMap.d.ts +2 -2
- package/dist/src/primitives/utils/createSpriteMap.js.map +1 -1
- package/dist/src/primitives/utils/handleNavigation.d.ts +85 -5
- package/dist/src/primitives/utils/handleNavigation.js +242 -69
- package/dist/src/primitives/utils/handleNavigation.js.map +1 -1
- package/dist/src/primitives/utils/withScrolling.d.ts +8 -1
- package/dist/src/primitives/utils/withScrolling.js +25 -6
- package/dist/src/primitives/utils/withScrolling.js.map +1 -1
- package/dist/src/render.d.ts +6 -5
- package/dist/src/render.js +4 -0
- package/dist/src/render.js.map +1 -1
- package/dist/src/solidOpts.d.ts +3 -2
- package/dist/src/solidOpts.js +31 -15
- package/dist/src/solidOpts.js.map +1 -1
- package/dist/src/universal.d.ts +25 -0
- package/dist/src/universal.js +232 -0
- package/dist/src/universal.js.map +1 -0
- package/dist/src/utils.d.ts +2 -0
- package/dist/src/utils.js +8 -0
- package/dist/src/utils.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/jsx-runtime.d.ts +2 -4
- package/package.json +19 -10
- package/src/primitives/Column.tsx +10 -12
- package/src/primitives/Grid.tsx +57 -33
- package/src/primitives/Image.tsx +36 -0
- package/src/primitives/KeepAlive.tsx +124 -0
- package/src/primitives/Lazy.tsx +60 -37
- package/src/primitives/Marquee.tsx +149 -0
- package/src/primitives/Preserve.tsx +18 -0
- package/src/primitives/Row.tsx +11 -12
- package/src/primitives/Suspense.tsx +39 -0
- package/src/primitives/Virtual.tsx +478 -0
- package/src/primitives/VirtualGrid.tsx +199 -0
- package/src/primitives/Visible.tsx +1 -2
- package/src/primitives/announcer/announcer.ts +16 -10
- package/src/primitives/announcer/index.ts +12 -2
- package/src/primitives/announcer/speech.ts +188 -27
- package/src/primitives/createFocusStack.tsx +18 -7
- package/src/primitives/createTag.tsx +31 -0
- package/src/primitives/index.ts +17 -3
- package/src/primitives/types.ts +10 -0
- package/src/primitives/useHold.ts +69 -0
- package/src/primitives/useMouse.ts +283 -66
- package/src/primitives/utils/chainFunctions.ts +40 -9
- package/src/primitives/utils/createBlurredImage.ts +366 -0
- package/src/primitives/utils/createSpriteMap.ts +6 -4
- package/src/primitives/utils/handleNavigation.ts +307 -84
- package/src/primitives/utils/withScrolling.ts +47 -16
- package/src/render.ts +9 -7
- package/src/solidOpts.ts +34 -19
- package/src/utils.ts +10 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as s from 'solid-js';
|
|
2
|
+
import * as lng from '@lightningtv/solid';
|
|
3
|
+
import * as lngp from '@lightningtv/solid/primitives';
|
|
4
|
+
import { List } from '@solid-primitives/list';
|
|
5
|
+
import * as utils from '../utils.js';
|
|
6
|
+
const rowOnLeft = lngp.handleNavigation('left');
|
|
7
|
+
const rowOnRight = lngp.handleNavigation('right');
|
|
8
|
+
const rowScroll = lngp.withScrolling(true);
|
|
9
|
+
const rowStyles = {
|
|
10
|
+
display: 'flex',
|
|
11
|
+
gap: 30,
|
|
12
|
+
transition: {
|
|
13
|
+
x: {
|
|
14
|
+
duration: 250,
|
|
15
|
+
easing: 'ease-out',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
function scrollToIndex(index) {
|
|
20
|
+
this.selected = index;
|
|
21
|
+
rowScroll(index, this);
|
|
22
|
+
this.setFocus();
|
|
23
|
+
}
|
|
24
|
+
export function VirtualList(props) {
|
|
25
|
+
const [cursor, setCursor] = s.createSignal(props.selected ?? 0);
|
|
26
|
+
const bufferSize = () => props.bufferSize ?? 2;
|
|
27
|
+
const items = s.createMemo(() => props.each || []);
|
|
28
|
+
const start = () => utils.clamp(cursor() - bufferSize(), 0, Math.max(0, items().length - props.displaySize - bufferSize()));
|
|
29
|
+
const end = () => Math.min(items().length, cursor() + props.displaySize + bufferSize());
|
|
30
|
+
const [slice, setSlice] = s.createSignal(items().slice(start(), end()));
|
|
31
|
+
s.createEffect(s.on([() => props.selected, items], ([selected]) => {
|
|
32
|
+
if (!viewRef || !selected)
|
|
33
|
+
return;
|
|
34
|
+
const item = items()[selected];
|
|
35
|
+
let active = viewRef.children.find(x => x.item === item);
|
|
36
|
+
const lastSelected = viewRef.selected;
|
|
37
|
+
if (active instanceof lng.ElementNode) {
|
|
38
|
+
viewRef.selected = viewRef.children.indexOf(active);
|
|
39
|
+
chainedOnSelectedChanged.call(viewRef, viewRef.selected, viewRef, active, lastSelected);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
setCursor(selected);
|
|
43
|
+
setSlice(items().slice(start(), end()));
|
|
44
|
+
queueMicrotask(() => {
|
|
45
|
+
viewRef.updateLayout();
|
|
46
|
+
active = viewRef.children.find(x => x.item === item);
|
|
47
|
+
if (active instanceof lng.ElementNode) {
|
|
48
|
+
viewRef.selected = viewRef.children.indexOf(active);
|
|
49
|
+
chainedOnSelectedChanged.call(viewRef, viewRef.selected, viewRef, active, lastSelected);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}));
|
|
54
|
+
s.createEffect(s.on(items, () => {
|
|
55
|
+
if (!viewRef)
|
|
56
|
+
return;
|
|
57
|
+
setSlice(items().slice(start(), end()));
|
|
58
|
+
}, { defer: true }));
|
|
59
|
+
const onSelectedChanged = function (_idx, elm, active, _lastIdx) {
|
|
60
|
+
let idx = _idx;
|
|
61
|
+
let lastIdx = _lastIdx;
|
|
62
|
+
if (idx === lastIdx)
|
|
63
|
+
return;
|
|
64
|
+
const prevChildX = this.x + active.x;
|
|
65
|
+
const prevStart = start();
|
|
66
|
+
// Update the displayed slice of items
|
|
67
|
+
setCursor(prevStart + idx);
|
|
68
|
+
setSlice(items().slice(start(), end()));
|
|
69
|
+
// this.selected is relative to the slice
|
|
70
|
+
// and it doesn't get corrected automatically after children change
|
|
71
|
+
const idxCorrection = prevStart - start();
|
|
72
|
+
if (lastIdx)
|
|
73
|
+
lastIdx += idxCorrection;
|
|
74
|
+
idx += idxCorrection;
|
|
75
|
+
this.selected += idxCorrection;
|
|
76
|
+
// Microtask & this.updateLayout() to make sure the child position is recalculated
|
|
77
|
+
queueMicrotask(() => {
|
|
78
|
+
this.updateLayout();
|
|
79
|
+
// Correct this.x for changes to children, bypass animation
|
|
80
|
+
this.lng.x = prevChildX - active.x;
|
|
81
|
+
// smoothly scroll to new selected element
|
|
82
|
+
rowScroll(idx, elm, active, lastIdx);
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
const chainedOnSelectedChanged = lngp.chainFunctions(props.onSelectedChanged, onSelectedChanged);
|
|
86
|
+
let viewRef;
|
|
87
|
+
return <>
|
|
88
|
+
<view {...props} scroll='always' // only supporting always scroll at the moment
|
|
89
|
+
ref={lngp.chainRefs(el => { viewRef = el; }, props.ref)} selected={props.selected || 0} cursor={cursor()} onLeft={/* @once */lngp.chainFunctions(props.onLeft, rowOnLeft)} onRight={/* @once */lngp.chainFunctions(props.onRight, rowOnRight)} forwardFocus={/* @once */lngp.navigableForwardFocus} scrollToIndex={scrollToIndex} onCreate={/* @once */props.selected ? lngp.chainFunctions(props.onCreate, rowScroll) : props.onCreate}
|
|
90
|
+
/* lngp.NavigableElement.onSelectedChanged is used by lngp.handleNavigation */
|
|
91
|
+
onSelectedChanged={chainedOnSelectedChanged} style={/* @once */lng.combineStyles(props.style, rowStyles)}>
|
|
92
|
+
<List each={slice()}>{props.children}</List>
|
|
93
|
+
</view>
|
|
94
|
+
</>;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=VirtualList.jsx.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VirtualList.jsx","sourceRoot":"","sources":["../../../src/primitives/VirtualList.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as s from 'solid-js';
|
|
2
|
+
import * as lng from '@lightningtv/solid';
|
|
3
|
+
import * as lngp from '@lightningtv/solid/primitives';
|
|
4
|
+
export type VirtualRowProps<T> = lng.NewOmit<lngp.RowProps, 'children'> & {
|
|
5
|
+
each: readonly T[] | undefined | null | false;
|
|
6
|
+
displaySize: number;
|
|
7
|
+
bufferSize?: number;
|
|
8
|
+
onEndReached?: () => void;
|
|
9
|
+
onEndReachedThreshold?: number;
|
|
10
|
+
fallback?: s.JSX.Element;
|
|
11
|
+
children: (item: s.Accessor<T>, index: s.Accessor<number>) => s.JSX.Element;
|
|
12
|
+
};
|
|
13
|
+
export declare function VirtualRow<T>(props: VirtualRowProps<T>): s.JSX.Element;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import * as s from 'solid-js';
|
|
2
|
+
import * as lng from '@lightningtv/solid';
|
|
3
|
+
import * as lngp from '@lightningtv/solid/primitives';
|
|
4
|
+
import { List } from '@solid-primitives/list';
|
|
5
|
+
import * as utils from '../utils.js';
|
|
6
|
+
const rowOnLeft = lngp.handleNavigation('left');
|
|
7
|
+
const rowOnRight = lngp.handleNavigation('right');
|
|
8
|
+
const rowScroll = lngp.withScrolling(true);
|
|
9
|
+
const rowStyles = {
|
|
10
|
+
display: 'flex',
|
|
11
|
+
gap: 30,
|
|
12
|
+
transition: {
|
|
13
|
+
x: {
|
|
14
|
+
duration: 250,
|
|
15
|
+
easing: 'ease-out',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
function scrollToIndex(index) {
|
|
20
|
+
this.selected = index;
|
|
21
|
+
rowScroll(index, this);
|
|
22
|
+
this.setFocus();
|
|
23
|
+
}
|
|
24
|
+
export function VirtualRow(props) {
|
|
25
|
+
const [cursor, setCursor] = s.createSignal(props.selected ?? 0);
|
|
26
|
+
const bufferSize = () => props.bufferSize ?? 2;
|
|
27
|
+
const items = s.createMemo(() => props.each || []);
|
|
28
|
+
const start = () => utils.clamp(cursor() - bufferSize(), 0, Math.max(0, items().length - props.displaySize - bufferSize()));
|
|
29
|
+
const end = () => Math.min(items().length, cursor() + props.displaySize + bufferSize());
|
|
30
|
+
const [slice, setSlice] = s.createSignal(items().slice(start(), end()));
|
|
31
|
+
s.createEffect(s.on([() => props.selected, items], ([selected]) => {
|
|
32
|
+
if (!viewRef || !selected)
|
|
33
|
+
return;
|
|
34
|
+
const item = items()[selected];
|
|
35
|
+
let active = viewRef.children.find(x => x.item === item);
|
|
36
|
+
const lastSelected = viewRef.selected;
|
|
37
|
+
if (active instanceof lng.ElementNode) {
|
|
38
|
+
viewRef.selected = viewRef.children.indexOf(active);
|
|
39
|
+
chainedOnSelectedChanged.call(viewRef, viewRef.selected, viewRef, active, lastSelected);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
setCursor(selected);
|
|
43
|
+
setSlice(items().slice(start(), end()));
|
|
44
|
+
queueMicrotask(() => {
|
|
45
|
+
viewRef.updateLayout();
|
|
46
|
+
active = viewRef.children.find(x => x.item === item);
|
|
47
|
+
if (active instanceof lng.ElementNode) {
|
|
48
|
+
viewRef.selected = viewRef.children.indexOf(active);
|
|
49
|
+
chainedOnSelectedChanged.call(viewRef, viewRef.selected, viewRef, active, lastSelected);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}));
|
|
54
|
+
s.createEffect(s.on(items, () => {
|
|
55
|
+
if (!viewRef)
|
|
56
|
+
return;
|
|
57
|
+
setSlice(items().slice(start(), end()));
|
|
58
|
+
}, { defer: true }));
|
|
59
|
+
const onSelectedChanged = function (_idx, elm, active, _lastIdx) {
|
|
60
|
+
let idx = _idx;
|
|
61
|
+
let lastIdx = _lastIdx;
|
|
62
|
+
if (idx === lastIdx)
|
|
63
|
+
return;
|
|
64
|
+
const prevChildX = this.x + active.x;
|
|
65
|
+
const prevStart = start();
|
|
66
|
+
// Update the displayed slice of items
|
|
67
|
+
setCursor(prevStart + idx);
|
|
68
|
+
setSlice(items().slice(start(), end()));
|
|
69
|
+
// this.selected is relative to the slice
|
|
70
|
+
// and it doesn't get corrected automatically after children change
|
|
71
|
+
const idxCorrection = prevStart - start();
|
|
72
|
+
if (lastIdx)
|
|
73
|
+
lastIdx += idxCorrection;
|
|
74
|
+
idx += idxCorrection;
|
|
75
|
+
this.selected += idxCorrection;
|
|
76
|
+
if (props.onEndReachedThreshold !== undefined && cursor() >= items().length - props.onEndReachedThreshold) {
|
|
77
|
+
props.onEndReached?.();
|
|
78
|
+
}
|
|
79
|
+
// Microtask & this.updateLayout() to make sure the child position is recalculated
|
|
80
|
+
queueMicrotask(() => {
|
|
81
|
+
this.updateLayout();
|
|
82
|
+
// Correct this.x for changes to children, bypass animation
|
|
83
|
+
this.lng.x = prevChildX - active.x;
|
|
84
|
+
// smoothly scroll to new selected element
|
|
85
|
+
rowScroll(idx, elm, active, lastIdx);
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
const chainedOnSelectedChanged = lngp.chainFunctions(props.onSelectedChanged, onSelectedChanged);
|
|
89
|
+
let viewRef;
|
|
90
|
+
return <view {...props} scroll='always' // only supporting always scroll at the moment
|
|
91
|
+
ref={lngp.chainRefs(el => { viewRef = el; }, props.ref)} selected={props.selected || 0} cursor={cursor()} onLeft={/* @once */lngp.chainFunctions(props.onLeft, rowOnLeft)} onRight={/* @once */lngp.chainFunctions(props.onRight, rowOnRight)} forwardFocus={/* @once */lngp.navigableForwardFocus} scrollToIndex={scrollToIndex} onCreate={/* @once */props.selected ? lngp.chainFunctions(props.onCreate, rowScroll) : props.onCreate}
|
|
92
|
+
/* lngp.NavigableElement.onSelectedChanged is used by lngp.handleNavigation */
|
|
93
|
+
onSelectedChanged={chainedOnSelectedChanged} style={/* @once */lng.combineStyles(props.style, rowStyles)}>
|
|
94
|
+
<List each={slice()}>{props.children}</List>
|
|
95
|
+
</view>;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=VirtualRow.jsx.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VirtualRow.jsx","sourceRoot":"","sources":["../../../src/primitives/VirtualRow.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Visible.jsx","sourceRoot":"","sources":["../../../src/primitives/Visible.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,GAAG,EACH,QAAQ,EACR,UAAU,EAGV,OAAO,EACP,SAAS,EACT,UAAU,GACX,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,UAAU,OAAO,CAAI,
|
|
1
|
+
{"version":3,"file":"Visible.jsx","sourceRoot":"","sources":["../../../src/primitives/Visible.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,GAAG,EACH,QAAQ,EACR,UAAU,EAGV,OAAO,EACP,SAAS,EACT,UAAU,GACX,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,UAAU,OAAO,CAAI,KAI1B;IACC,IAAI,KAAiC,CAAC;IACtC,IAAI,QAAkC,CAAC;IACvC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC1B,MAAM,SAAS,GAAG,UAAU,CAC1B,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,EAChB,SAAS,EACT,GAAG;QACD,CAAC,CAAC;YACE,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YAC/C,IAAI,EAAE,WAAW;SAClB;QACH,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CACxD,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAG9B,OAAO,UAAU,CAAC,GAAG,EAAE;QACrB,MAAM,CAAC,GAAG,SAAS,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,OAAO,EAAC,CAAC;YACX,QAAQ,EAAE,EAAE,CAAC;YACb,KAAK,GAAG,SAAS,CAAC;QACpB,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,QAAQ,GAAG,UAAU,CAAC,CAAC,OAAO,EAAE,EAAE;gBAChC,KAAK,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBACvC,OAAO,OAAO,CAAC;YACjB,CAAC,CAAC,CAAA;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC;QACpB,KAAK,EAAE,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE;YACrC,IAAI,SAAS,YAAY,WAAW,EAAE,CAAC;gBACrC,SAAS,CAAC,MAAM,GAAG,QAAQ,CAAC;YAC9B,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACnC,CAAC,CAA2B,CAAC;AAC/B,CAAC;AAAA,CAAC"}
|
|
@@ -37,7 +37,9 @@ function onFocusChangeCore(focusPath = []) {
|
|
|
37
37
|
}
|
|
38
38
|
prevFocusPath = focusPath.slice(0);
|
|
39
39
|
const toAnnounceText = [];
|
|
40
|
-
const toAnnounce = focusDiff
|
|
40
|
+
const toAnnounce = focusDiff
|
|
41
|
+
.reverse()
|
|
42
|
+
.reduce((acc, elm) => {
|
|
41
43
|
if (elm.announce) {
|
|
42
44
|
acc.push([getElmName(elm), 'Announce', elm.announce]);
|
|
43
45
|
toAnnounceText.push(elm.announce);
|
|
@@ -68,16 +70,17 @@ function onFocusChangeCore(focusPath = []) {
|
|
|
68
70
|
return Announcer.speak(toAnnounceText.reduce((acc, val) => acc.concat(val), []));
|
|
69
71
|
}
|
|
70
72
|
}
|
|
71
|
-
function textToSpeech(toSpeak, lang) {
|
|
73
|
+
function textToSpeech(toSpeak, aria, lang, voice) {
|
|
72
74
|
if (voiceOutDisabled) {
|
|
73
75
|
return;
|
|
74
76
|
}
|
|
75
|
-
return (currentlySpeaking = SpeechEngine(toSpeak, lang));
|
|
77
|
+
return (currentlySpeaking = SpeechEngine(toSpeak, aria, lang, voice));
|
|
76
78
|
}
|
|
77
79
|
export const Announcer = {
|
|
78
80
|
debug: false,
|
|
79
81
|
enabled: true,
|
|
80
82
|
lang: 'en-US',
|
|
83
|
+
aria: false,
|
|
81
84
|
cancel: function () {
|
|
82
85
|
currentlySpeaking && currentlySpeaking.cancel();
|
|
83
86
|
},
|
|
@@ -87,13 +90,12 @@ export const Announcer = {
|
|
|
87
90
|
},
|
|
88
91
|
speak: function (text, { append = false, notification = false } = {}) {
|
|
89
92
|
if (Announcer.onFocusChange && Announcer.enabled) {
|
|
90
|
-
Announcer.onFocusChange.flush();
|
|
91
93
|
if (append && currentlySpeaking && currentlySpeaking.active) {
|
|
92
94
|
currentlySpeaking.append(text);
|
|
93
95
|
}
|
|
94
96
|
else {
|
|
95
97
|
Announcer.cancel();
|
|
96
|
-
textToSpeech(text, Announcer.lang);
|
|
98
|
+
textToSpeech(text, Announcer.aria, Announcer.lang, Announcer.voice);
|
|
97
99
|
}
|
|
98
100
|
if (notification) {
|
|
99
101
|
voiceOutDisabled = true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"announcer.js","sourceRoot":"","sources":["../../../../src/primitives/announcer/announcer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,YAAoD,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAqBlD,IAAI,mBAAoD,CAAC;AACzD,IAAI,aAAa,GAAkB,EAAE,CAAC;AACtC,IAAI,iBAA2C,CAAC;AAChD,IAAI,gBAAgB,GAAG,KAAK,CAAC;AAC7B,MAAM,WAAW,GAAG,MAAM,CAAC;AAE3B,SAAS,iBAAiB,CACxB,QAA+B,EAC/B,IAAa;IAEb,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACzC,IAAI,WAAc,CAAC;IAEnB,MAAM,SAAS,GAAG,CAAC,QAAW,EAAE,EAAE;QAChC,WAAW,GAAG,QAAQ,CAAC;QACvB,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpB,CAAC,CAAC;IAEF,SAAS,CAAC,KAAK,GAAG,GAAG,EAAE;QACrB,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,QAAQ,CAAC,WAAW,CAAC,CAAC;IACxB,CAAC,CAAC;IAEF,SAAS,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAEhC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,UAAU,CAAC,GAAgB;IAClC,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,IAAI,CAAW,CAAC;AACxC,CAAC;AAED,SAAS,iBAAiB,CAAC,YAA2B,EAAE;IACtD,IAAI,CAAC,SAAS,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QACnD,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IAE1E,mBAAmB,EAAE,CAAC;IAEtB,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC,aAAa,EAAE,CAAC;QACvC,SAAS,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,aAAa,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnC,MAAM,cAAc,GAAiB,EAAE,CAAC;IACxC,MAAM,UAAU,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"announcer.js","sourceRoot":"","sources":["../../../../src/primitives/announcer/announcer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { createEffect, on } from 'solid-js';
|
|
2
2
|
import { Announcer } from './announcer.js';
|
|
3
3
|
import { focusPath } from '../useFocusManager.js';
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
let doOnce = false;
|
|
5
|
+
export const useAnnouncer = (options) => {
|
|
6
|
+
if (doOnce) {
|
|
7
|
+
return Announcer;
|
|
8
|
+
}
|
|
9
|
+
doOnce = true;
|
|
10
|
+
Announcer.setupTimers(options);
|
|
6
11
|
createEffect(on(focusPath, Announcer.onFocusChange, { defer: true }));
|
|
7
12
|
return Announcer;
|
|
8
13
|
};
|
|
14
|
+
export { Announcer };
|
|
9
15
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/primitives/announcer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,MAAM,CAAC,MAAM,YAAY,GAAG,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/primitives/announcer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD,IAAI,MAAM,GAAG,KAAK,CAAC;AACnB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAG5B,EAAE,EAAE;IACH,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,GAAG,IAAI,CAAC;IACd,SAAS,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC/B,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,aAAc,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAEvE,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
type CoreSpeechType = string | (() => SpeechType) | SpeechType[];
|
|
1
|
+
type CoreSpeechType = string | (() => SpeechType) | SpeechType[] | SpeechSynthesisUtterance;
|
|
2
2
|
export type SpeechType = CoreSpeechType | Promise<CoreSpeechType>;
|
|
3
3
|
export interface SeriesResult {
|
|
4
4
|
series: Promise<void>;
|
|
@@ -6,5 +6,5 @@ export interface SeriesResult {
|
|
|
6
6
|
append: (toSpeak: SpeechType) => void;
|
|
7
7
|
cancel: () => void;
|
|
8
8
|
}
|
|
9
|
-
export default function (toSpeak: SpeechType, lang?: string): SeriesResult;
|
|
9
|
+
export default function (toSpeak: SpeechType, aria: boolean, lang?: string, voice?: string): SeriesResult;
|
|
10
10
|
export {};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const ARIA_PARENT_ID = 'aria-parent';
|
|
2
|
+
let ariaLabelPhrases = [];
|
|
1
3
|
/* global SpeechSynthesisErrorEvent */
|
|
2
4
|
function flattenStrings(series = []) {
|
|
3
5
|
const flattenedSeries = [];
|
|
@@ -22,6 +24,72 @@ function delay(pause) {
|
|
|
22
24
|
setTimeout(resolve, pause);
|
|
23
25
|
});
|
|
24
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* @description This function is called at the end of the speak series
|
|
29
|
+
* @param Phrase is an object containing the text and the language
|
|
30
|
+
*/
|
|
31
|
+
function addChildrenToAriaDiv(phrase) {
|
|
32
|
+
if (phrase?.text?.trim().length === 0)
|
|
33
|
+
return;
|
|
34
|
+
ariaLabelPhrases.push(phrase);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* @description This function is triggered finally when the speak series is finished and we are to speak the aria labels
|
|
38
|
+
*/
|
|
39
|
+
function focusElementForAria() {
|
|
40
|
+
const element = createAriaElement();
|
|
41
|
+
if (!element) {
|
|
42
|
+
console.error(`ARIA div not found: ${ARIA_PARENT_ID}`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
for (const object of ariaLabelPhrases) {
|
|
46
|
+
const span = document.createElement('span');
|
|
47
|
+
// TODO: Not sure LG or Samsung support lang attribute on span or switching language
|
|
48
|
+
span.setAttribute('lang', object.lang);
|
|
49
|
+
span.setAttribute('aria-label', object.text);
|
|
50
|
+
element.appendChild(span);
|
|
51
|
+
}
|
|
52
|
+
// Cleanup
|
|
53
|
+
setTimeout(() => {
|
|
54
|
+
ariaLabelPhrases = [];
|
|
55
|
+
cleanAriaLabelParent();
|
|
56
|
+
focusCanvas();
|
|
57
|
+
}, 100);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* @description Clean the aria label parent after speaking
|
|
61
|
+
*/
|
|
62
|
+
function cleanAriaLabelParent() {
|
|
63
|
+
const parentTag = document.getElementById(ARIA_PARENT_ID);
|
|
64
|
+
if (parentTag) {
|
|
65
|
+
while (parentTag.firstChild) {
|
|
66
|
+
parentTag.removeChild(parentTag.firstChild);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* @description Focus the canvas element
|
|
72
|
+
*/
|
|
73
|
+
function focusCanvas() {
|
|
74
|
+
const canvas = document.getElementById('app')?.firstChild;
|
|
75
|
+
canvas?.focus();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* @description Create the aria element in the DOM if it doesn't exist
|
|
79
|
+
* @private For xbox, we may need to create a different element each time we wanna use aria
|
|
80
|
+
*/
|
|
81
|
+
function createAriaElement() {
|
|
82
|
+
const aria_container = document.getElementById(ARIA_PARENT_ID);
|
|
83
|
+
if (!aria_container) {
|
|
84
|
+
const element = document.createElement('div');
|
|
85
|
+
element.setAttribute('id', ARIA_PARENT_ID);
|
|
86
|
+
element.setAttribute('aria-live', 'assertive');
|
|
87
|
+
element.setAttribute('tabindex', '0');
|
|
88
|
+
document.body.appendChild(element);
|
|
89
|
+
return element;
|
|
90
|
+
}
|
|
91
|
+
return aria_container;
|
|
92
|
+
}
|
|
25
93
|
/**
|
|
26
94
|
* Speak a string
|
|
27
95
|
*
|
|
@@ -30,11 +98,20 @@ function delay(pause) {
|
|
|
30
98
|
* @param lang Language to speak in
|
|
31
99
|
* @return {Promise<void>} Promise resolved when the utterance has finished speaking, and rejected if there's an error
|
|
32
100
|
*/
|
|
33
|
-
function speak(phrase, utterances, lang = 'en-US') {
|
|
101
|
+
function speak(phrase, utterances, lang = 'en-US', voiceName) {
|
|
34
102
|
const synth = window.speechSynthesis;
|
|
35
103
|
return new Promise((resolve, reject) => {
|
|
104
|
+
let selectedVoice;
|
|
105
|
+
if (voiceName) {
|
|
106
|
+
const availableVoices = synth.getVoices();
|
|
107
|
+
selectedVoice =
|
|
108
|
+
availableVoices.find((v) => v.name === voiceName) || availableVoices[0];
|
|
109
|
+
}
|
|
36
110
|
const utterance = new SpeechSynthesisUtterance(phrase);
|
|
37
111
|
utterance.lang = lang;
|
|
112
|
+
if (selectedVoice) {
|
|
113
|
+
utterance.voice = selectedVoice;
|
|
114
|
+
}
|
|
38
115
|
utterance.onend = () => {
|
|
39
116
|
resolve();
|
|
40
117
|
};
|
|
@@ -45,15 +122,10 @@ function speak(phrase, utterances, lang = 'en-US') {
|
|
|
45
122
|
synth.speak(utterance);
|
|
46
123
|
});
|
|
47
124
|
}
|
|
48
|
-
function speakSeries(series, lang, root = true) {
|
|
125
|
+
function speakSeries(series, aria, lang, voice, root = true) {
|
|
49
126
|
const synth = window.speechSynthesis;
|
|
50
127
|
const remainingPhrases = flattenStrings(Array.isArray(series) ? series : [series]);
|
|
51
128
|
const nestedSeriesResults = [];
|
|
52
|
-
/*
|
|
53
|
-
We hold this array of SpeechSynthesisUtterances in order to prevent them from being
|
|
54
|
-
garbage collected prematurely on STB hardware which can cause the 'onend' events of
|
|
55
|
-
utterances to not fire consistently.
|
|
56
|
-
*/
|
|
57
129
|
const utterances = [];
|
|
58
130
|
let active = true;
|
|
59
131
|
const seriesChain = (async () => {
|
|
@@ -61,26 +133,68 @@ function speakSeries(series, lang, root = true) {
|
|
|
61
133
|
while (active && remainingPhrases.length) {
|
|
62
134
|
const phrase = await Promise.resolve(remainingPhrases.shift());
|
|
63
135
|
if (!active) {
|
|
64
|
-
// Exit
|
|
65
|
-
|
|
66
|
-
|
|
136
|
+
break; // Exit if canceled
|
|
137
|
+
}
|
|
138
|
+
if (typeof phrase === 'string' && phrase.includes('PAUSE-')) {
|
|
139
|
+
// Handle pauses
|
|
140
|
+
const pause = Number(phrase.split('PAUSE-')[1]) * 1000;
|
|
141
|
+
if (!isNaN(pause)) {
|
|
142
|
+
await delay(pause);
|
|
143
|
+
}
|
|
67
144
|
}
|
|
68
|
-
else if (typeof phrase === 'string'
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
145
|
+
else if (typeof phrase === 'string') {
|
|
146
|
+
if (!phrase) {
|
|
147
|
+
continue; // Skip empty strings
|
|
148
|
+
}
|
|
149
|
+
// Handle regular strings with retry logic
|
|
150
|
+
const totalRetries = 3;
|
|
151
|
+
let retriesLeft = totalRetries;
|
|
152
|
+
while (active && retriesLeft > 0) {
|
|
153
|
+
try {
|
|
154
|
+
if (aria)
|
|
155
|
+
addChildrenToAriaDiv({ text: phrase, lang });
|
|
156
|
+
else
|
|
157
|
+
await speak(phrase, utterances, lang, voice);
|
|
158
|
+
retriesLeft = 0; // Exit retry loop on success
|
|
159
|
+
}
|
|
160
|
+
catch (e) {
|
|
161
|
+
if (e instanceof SpeechSynthesisErrorEvent) {
|
|
162
|
+
if (e.error === 'network') {
|
|
163
|
+
retriesLeft--;
|
|
164
|
+
console.warn(`Speech synthesis network error. Retries left: ${retriesLeft}`);
|
|
165
|
+
await delay(500 * (totalRetries - retriesLeft));
|
|
166
|
+
}
|
|
167
|
+
else if (e.error === 'canceled' ||
|
|
168
|
+
e.error === 'interrupted') {
|
|
169
|
+
// Cancel or interrupt error (ignore)
|
|
170
|
+
retriesLeft = 0;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
throw new Error(`SpeechSynthesisErrorEvent: ${e.error}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
throw e;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
73
180
|
}
|
|
74
|
-
await delay(pause);
|
|
75
181
|
}
|
|
76
|
-
else if (
|
|
77
|
-
//
|
|
182
|
+
else if (phrase instanceof SpeechSynthesisUtterance) {
|
|
183
|
+
// Handle SpeechSynthesisUtterance objects with retry logic
|
|
78
184
|
const totalRetries = 3;
|
|
79
185
|
let retriesLeft = totalRetries;
|
|
186
|
+
const text = phrase.text;
|
|
187
|
+
const objectLang = phrase?.lang;
|
|
188
|
+
const objectVoice = phrase?.voice;
|
|
80
189
|
while (active && retriesLeft > 0) {
|
|
81
190
|
try {
|
|
82
|
-
|
|
83
|
-
|
|
191
|
+
if (text) {
|
|
192
|
+
if (aria)
|
|
193
|
+
addChildrenToAriaDiv({ text, lang: objectLang });
|
|
194
|
+
else
|
|
195
|
+
await speak(text, utterances, objectLang, objectVoice?.name);
|
|
196
|
+
retriesLeft = 0; // Exit retry loop on success
|
|
197
|
+
}
|
|
84
198
|
}
|
|
85
199
|
catch (e) {
|
|
86
200
|
if (e instanceof SpeechSynthesisErrorEvent) {
|
|
@@ -105,13 +219,14 @@ function speakSeries(series, lang, root = true) {
|
|
|
105
219
|
}
|
|
106
220
|
}
|
|
107
221
|
else if (typeof phrase === 'function') {
|
|
108
|
-
|
|
222
|
+
// Handle functions
|
|
223
|
+
const seriesResult = speakSeries(phrase(), aria, lang, voice, false);
|
|
109
224
|
nestedSeriesResults.push(seriesResult);
|
|
110
225
|
await seriesResult.series;
|
|
111
226
|
}
|
|
112
227
|
else if (Array.isArray(phrase)) {
|
|
113
|
-
//
|
|
114
|
-
const seriesResult = speakSeries(phrase, lang, false);
|
|
228
|
+
// Handle nested arrays
|
|
229
|
+
const seriesResult = speakSeries(phrase, aria, lang, voice, false);
|
|
115
230
|
nestedSeriesResults.push(seriesResult);
|
|
116
231
|
await seriesResult.series;
|
|
117
232
|
}
|
|
@@ -119,6 +234,10 @@ function speakSeries(series, lang, root = true) {
|
|
|
119
234
|
}
|
|
120
235
|
finally {
|
|
121
236
|
active = false;
|
|
237
|
+
// Call completion logic only for the original (root) series
|
|
238
|
+
if (root && aria) {
|
|
239
|
+
focusElementForAria();
|
|
240
|
+
}
|
|
122
241
|
}
|
|
123
242
|
})();
|
|
124
243
|
return {
|
|
@@ -134,19 +253,29 @@ function speakSeries(series, lang, root = true) {
|
|
|
134
253
|
return;
|
|
135
254
|
}
|
|
136
255
|
if (root) {
|
|
137
|
-
|
|
256
|
+
if (aria) {
|
|
257
|
+
const element = createAriaElement();
|
|
258
|
+
if (element) {
|
|
259
|
+
ariaLabelPhrases = [];
|
|
260
|
+
cleanAriaLabelParent();
|
|
261
|
+
element.focus();
|
|
262
|
+
focusCanvas();
|
|
263
|
+
}
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
synth.cancel(); // Cancel all ongoing speech
|
|
138
267
|
}
|
|
139
|
-
nestedSeriesResults.forEach((
|
|
140
|
-
|
|
268
|
+
nestedSeriesResults.forEach((nestedSeriesResult) => {
|
|
269
|
+
nestedSeriesResult.cancel();
|
|
141
270
|
});
|
|
142
271
|
active = false;
|
|
143
272
|
},
|
|
144
273
|
};
|
|
145
274
|
}
|
|
146
275
|
let currentSeries;
|
|
147
|
-
export default function (toSpeak, lang = 'en-US') {
|
|
276
|
+
export default function (toSpeak, aria, lang = 'en-US', voice) {
|
|
148
277
|
currentSeries && currentSeries.cancel();
|
|
149
|
-
currentSeries = speakSeries(toSpeak, lang);
|
|
278
|
+
currentSeries = speakSeries(toSpeak, aria, lang, voice);
|
|
150
279
|
return currentSeries;
|
|
151
280
|
}
|
|
152
281
|
//# sourceMappingURL=speech.js.map
|