@lightningtv/solid 0.0.9 → 0.0.11
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/{source → src}/Text.jsx +1 -0
- package/dist/src/Text.jsx.map +1 -0
- package/dist/{source → src}/View.jsx +1 -0
- package/dist/src/View.jsx.map +1 -0
- package/dist/{types → src}/activeElement.d.ts +1 -1
- package/dist/{source → src}/activeElement.js +1 -0
- package/dist/src/activeElement.js.map +1 -0
- package/dist/{types → src}/index.d.ts +3 -4
- package/dist/{source → src}/index.js +4 -4
- package/dist/src/index.js.map +1 -0
- package/dist/src/jsx-runtime.js +2 -0
- package/dist/src/jsx-runtime.js.map +1 -0
- package/dist/{source → src}/primitives/announcer/announcer.js +1 -0
- package/dist/src/primitives/announcer/announcer.js.map +1 -0
- package/dist/{source → src}/primitives/announcer/index.js +1 -0
- package/dist/src/primitives/announcer/index.js.map +1 -0
- package/dist/{source → src}/primitives/announcer/speech.js +1 -0
- package/dist/src/primitives/announcer/speech.js.map +1 -0
- package/dist/{source → src}/primitives/createInfiniteItems.js +1 -0
- package/dist/src/primitives/createInfiniteItems.js.map +1 -0
- package/dist/{types → src}/primitives/createSpriteMap.d.ts +1 -0
- package/dist/{source → src}/primitives/createSpriteMap.js +1 -0
- package/dist/src/primitives/createSpriteMap.js.map +1 -0
- package/dist/{source → src}/primitives/index.js +1 -0
- package/dist/src/primitives/index.js.map +1 -0
- package/dist/{source → src}/primitives/portal.jsx +1 -0
- package/dist/src/primitives/portal.jsx.map +1 -0
- package/dist/{source → src}/primitives/useFocusManager.js +1 -0
- package/dist/src/primitives/useFocusManager.js.map +1 -0
- package/dist/{source → src}/primitives/useMouse.js +26 -12
- package/dist/src/primitives/useMouse.js.map +1 -0
- package/dist/{source → src}/primitives/withPadding.js +1 -0
- package/dist/src/primitives/withPadding.js.map +1 -0
- package/dist/src/render.d.ts +22 -0
- package/dist/{source → src}/render.js +1 -0
- package/dist/src/render.js.map +1 -0
- package/dist/{source → src}/solidOpts.js +1 -0
- package/dist/src/solidOpts.js.map +1 -0
- package/dist/{source → src}/utils.js +1 -0
- package/dist/src/utils.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +12 -8
- package/src/index.ts +6 -7
- package/src/primitives/useMouse.ts +32 -14
- package/dist/esm/index.js +0 -1013
- package/dist/esm/index.js.map +0 -1
- package/dist/source/jsx-runtime.js +0 -1
- package/dist/types/render.d.ts +0 -22
- /package/dist/{types → src}/Text.d.ts +0 -0
- /package/dist/{types → src}/View.d.ts +0 -0
- /package/dist/{types → src}/jsx-runtime.d.ts +0 -0
- /package/dist/{types → src}/primitives/announcer/announcer.d.ts +0 -0
- /package/dist/{types → src}/primitives/announcer/index.d.ts +0 -0
- /package/dist/{types → src}/primitives/announcer/speech.d.ts +0 -0
- /package/dist/{types → src}/primitives/createInfiniteItems.d.ts +0 -0
- /package/dist/{types → src}/primitives/index.d.ts +0 -0
- /package/dist/{types → src}/primitives/portal.d.ts +0 -0
- /package/dist/{types → src}/primitives/useFocusManager.d.ts +0 -0
- /package/dist/{types → src}/primitives/useMouse.d.ts +0 -0
- /package/dist/{types → src}/primitives/withPadding.d.ts +0 -0
- /package/dist/{types → src}/solidOpts.d.ts +0 -0
- /package/dist/{types → src}/utils.d.ts +0 -0
package/dist/esm/index.js
DELETED
|
@@ -1,1013 +0,0 @@
|
|
|
1
|
-
import { createSignal, mergeProps as mergeProps$1, createRoot, createRenderEffect, createMemo, createComponent as createComponent$1, untrack, splitProps, createEffect, on, createResource, createComputed, batch } from 'solid-js';
|
|
2
|
-
export { ErrorBoundary, For, Index, Match, Show, Suspense, SuspenseList, Switch } from 'solid-js';
|
|
3
|
-
import { Config, isInteger, ElementNode, NodeType, log, startLightningRenderer } from '@lightningtv/core';
|
|
4
|
-
export * from '@lightningtv/core';
|
|
5
|
-
import { createElement as createElement$1, spread as spread$1, isArray, activeElement as activeElement$1, isFunc, renderer as renderer$1, setActiveElement as setActiveElement$1, rootNode as rootNode$1, Config as Config$1, ElementNode as ElementNode$1, createComponent as createComponent$2, View as View$1 } from '@lightningtv/solid';
|
|
6
|
-
import { useKeyDownEvent } from '@solid-primitives/keyboard';
|
|
7
|
-
import { debounce, throttle, createScheduled } from '@solid-primitives/scheduled';
|
|
8
|
-
import { makeEventListener } from '@solid-primitives/event-listener';
|
|
9
|
-
import { useMousePosition } from '@solid-primitives/mouse';
|
|
10
|
-
|
|
11
|
-
const [activeElement, setActiveElement] = createSignal(undefined);
|
|
12
|
-
Config.setActiveElement = setActiveElement;
|
|
13
|
-
|
|
14
|
-
const View = props => (() => {
|
|
15
|
-
var _el$ = createElement$1("node");
|
|
16
|
-
spread$1(_el$, props, false);
|
|
17
|
-
return _el$;
|
|
18
|
-
})();
|
|
19
|
-
|
|
20
|
-
const Text = props => (() => {
|
|
21
|
-
var _el$ = createElement$1("text");
|
|
22
|
-
spread$1(_el$, props, false);
|
|
23
|
-
return _el$;
|
|
24
|
-
})();
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Converts a color string to a color number value.
|
|
28
|
-
*/
|
|
29
|
-
function hexColor(color = '') {
|
|
30
|
-
if (isInteger(color)) {
|
|
31
|
-
return color;
|
|
32
|
-
}
|
|
33
|
-
if (typeof color === 'string') {
|
|
34
|
-
// Renderer expects RGBA values
|
|
35
|
-
if (color.startsWith('#')) {
|
|
36
|
-
return Number(color.replace('#', '0x') + (color.length === 7 ? 'ff' : ''));
|
|
37
|
-
}
|
|
38
|
-
if (color.startsWith('0x')) {
|
|
39
|
-
return Number(color);
|
|
40
|
-
}
|
|
41
|
-
return Number('0x' + (color.length === 6 ? color + 'ff' : color));
|
|
42
|
-
}
|
|
43
|
-
return 0x00000000;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Converts degrees to radians
|
|
48
|
-
*/
|
|
49
|
-
function deg2rad(deg) {
|
|
50
|
-
return deg * Math.PI / 180;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function createRenderer$1({
|
|
54
|
-
createElement,
|
|
55
|
-
createTextNode,
|
|
56
|
-
isTextNode,
|
|
57
|
-
replaceText,
|
|
58
|
-
insertNode,
|
|
59
|
-
removeNode,
|
|
60
|
-
setProperty,
|
|
61
|
-
getParentNode,
|
|
62
|
-
getFirstChild,
|
|
63
|
-
getNextSibling
|
|
64
|
-
}) {
|
|
65
|
-
function insert(parent, accessor, marker, initial) {
|
|
66
|
-
if (marker !== undefined && !initial) initial = [];
|
|
67
|
-
if (typeof accessor !== "function") return insertExpression(parent, accessor, initial, marker);
|
|
68
|
-
createRenderEffect(current => insertExpression(parent, accessor(), current, marker), initial);
|
|
69
|
-
}
|
|
70
|
-
function insertExpression(parent, value, current, marker, unwrapArray) {
|
|
71
|
-
while (typeof current === "function") current = current();
|
|
72
|
-
if (value === current) return current;
|
|
73
|
-
const t = typeof value,
|
|
74
|
-
multi = marker !== undefined;
|
|
75
|
-
if (t === "string" || t === "number") {
|
|
76
|
-
if (t === "number") value = value.toString();
|
|
77
|
-
if (multi) {
|
|
78
|
-
let node = current[0];
|
|
79
|
-
if (node && isTextNode(node)) {
|
|
80
|
-
replaceText(node, value);
|
|
81
|
-
} else node = createTextNode(value);
|
|
82
|
-
current = cleanChildren(parent, current, marker, node);
|
|
83
|
-
} else {
|
|
84
|
-
if (current !== "" && typeof current === "string") {
|
|
85
|
-
replaceText(getFirstChild(parent), current = value);
|
|
86
|
-
} else {
|
|
87
|
-
cleanChildren(parent, current, marker, createTextNode(value));
|
|
88
|
-
current = value;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
} else if (value == null || t === "boolean") {
|
|
92
|
-
current = cleanChildren(parent, current, marker);
|
|
93
|
-
} else if (t === "function") {
|
|
94
|
-
createRenderEffect(() => {
|
|
95
|
-
let v = value();
|
|
96
|
-
while (typeof v === "function") v = v();
|
|
97
|
-
current = insertExpression(parent, v, current, marker);
|
|
98
|
-
});
|
|
99
|
-
return () => current;
|
|
100
|
-
} else if (Array.isArray(value)) {
|
|
101
|
-
const array = [];
|
|
102
|
-
if (normalizeIncomingArray(array, value, unwrapArray)) {
|
|
103
|
-
createRenderEffect(() => current = insertExpression(parent, array, current, marker, true));
|
|
104
|
-
return () => current;
|
|
105
|
-
}
|
|
106
|
-
if (array.length === 0) {
|
|
107
|
-
const replacement = cleanChildren(parent, current, marker);
|
|
108
|
-
if (multi) return current = replacement;
|
|
109
|
-
} else {
|
|
110
|
-
if (Array.isArray(current)) {
|
|
111
|
-
if (current.length === 0) {
|
|
112
|
-
appendNodes(parent, array, marker);
|
|
113
|
-
} else reconcileArrays(parent, current, array);
|
|
114
|
-
} else if (current == null || current === "") {
|
|
115
|
-
appendNodes(parent, array);
|
|
116
|
-
} else {
|
|
117
|
-
reconcileArrays(parent, multi && current || [getFirstChild(parent)], array);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
current = array;
|
|
121
|
-
} else {
|
|
122
|
-
if (Array.isArray(current)) {
|
|
123
|
-
if (multi) return current = cleanChildren(parent, current, marker, value);
|
|
124
|
-
cleanChildren(parent, current, null, value);
|
|
125
|
-
} else if (current == null || current === "" || !getFirstChild(parent)) {
|
|
126
|
-
insertNode(parent, value);
|
|
127
|
-
} else replaceNode(parent, value, getFirstChild(parent));
|
|
128
|
-
current = value;
|
|
129
|
-
}
|
|
130
|
-
return current;
|
|
131
|
-
}
|
|
132
|
-
function normalizeIncomingArray(normalized, array, unwrap) {
|
|
133
|
-
let dynamic = false;
|
|
134
|
-
for (let i = 0, len = array.length; i < len; i++) {
|
|
135
|
-
let item = array[i],
|
|
136
|
-
t;
|
|
137
|
-
if (item == null || item === true || item === false) ;else if (Array.isArray(item)) {
|
|
138
|
-
dynamic = normalizeIncomingArray(normalized, item) || dynamic;
|
|
139
|
-
} else if ((t = typeof item) === "string" || t === "number") {
|
|
140
|
-
normalized.push(createTextNode(item));
|
|
141
|
-
} else if (t === "function") {
|
|
142
|
-
if (unwrap) {
|
|
143
|
-
while (typeof item === "function") item = item();
|
|
144
|
-
dynamic = normalizeIncomingArray(normalized, Array.isArray(item) ? item : [item]) || dynamic;
|
|
145
|
-
} else {
|
|
146
|
-
normalized.push(item);
|
|
147
|
-
dynamic = true;
|
|
148
|
-
}
|
|
149
|
-
} else normalized.push(item);
|
|
150
|
-
}
|
|
151
|
-
return dynamic;
|
|
152
|
-
}
|
|
153
|
-
function reconcileArrays(parentNode, a, b) {
|
|
154
|
-
let bLength = b.length,
|
|
155
|
-
aEnd = a.length,
|
|
156
|
-
bEnd = bLength,
|
|
157
|
-
aStart = 0,
|
|
158
|
-
bStart = 0,
|
|
159
|
-
after = getNextSibling(a[aEnd - 1]),
|
|
160
|
-
map = null;
|
|
161
|
-
while (aStart < aEnd || bStart < bEnd) {
|
|
162
|
-
if (a[aStart] === b[bStart]) {
|
|
163
|
-
aStart++;
|
|
164
|
-
bStart++;
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
while (a[aEnd - 1] === b[bEnd - 1]) {
|
|
168
|
-
aEnd--;
|
|
169
|
-
bEnd--;
|
|
170
|
-
}
|
|
171
|
-
if (aEnd === aStart) {
|
|
172
|
-
const node = bEnd < bLength ? bStart ? getNextSibling(b[bStart - 1]) : b[bEnd - bStart] : after;
|
|
173
|
-
while (bStart < bEnd) insertNode(parentNode, b[bStart++], node);
|
|
174
|
-
} else if (bEnd === bStart) {
|
|
175
|
-
while (aStart < aEnd) {
|
|
176
|
-
if (!map || !map.has(a[aStart])) removeNode(parentNode, a[aStart]);
|
|
177
|
-
aStart++;
|
|
178
|
-
}
|
|
179
|
-
} else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) {
|
|
180
|
-
const node = getNextSibling(a[--aEnd]);
|
|
181
|
-
insertNode(parentNode, b[bStart++], getNextSibling(a[aStart++]));
|
|
182
|
-
insertNode(parentNode, b[--bEnd], node);
|
|
183
|
-
a[aEnd] = b[bEnd];
|
|
184
|
-
} else {
|
|
185
|
-
if (!map) {
|
|
186
|
-
map = new Map();
|
|
187
|
-
let i = bStart;
|
|
188
|
-
while (i < bEnd) map.set(b[i], i++);
|
|
189
|
-
}
|
|
190
|
-
const index = map.get(a[aStart]);
|
|
191
|
-
if (index != null) {
|
|
192
|
-
if (bStart < index && index < bEnd) {
|
|
193
|
-
let i = aStart,
|
|
194
|
-
sequence = 1,
|
|
195
|
-
t;
|
|
196
|
-
while (++i < aEnd && i < bEnd) {
|
|
197
|
-
if ((t = map.get(a[i])) == null || t !== index + sequence) break;
|
|
198
|
-
sequence++;
|
|
199
|
-
}
|
|
200
|
-
if (sequence > index - bStart) {
|
|
201
|
-
const node = a[aStart];
|
|
202
|
-
while (bStart < index) insertNode(parentNode, b[bStart++], node);
|
|
203
|
-
} else replaceNode(parentNode, b[bStart++], a[aStart++]);
|
|
204
|
-
} else aStart++;
|
|
205
|
-
} else removeNode(parentNode, a[aStart++]);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
function cleanChildren(parent, current, marker, replacement) {
|
|
210
|
-
if (marker === undefined) {
|
|
211
|
-
let removed;
|
|
212
|
-
while (removed = getFirstChild(parent)) removeNode(parent, removed);
|
|
213
|
-
replacement && insertNode(parent, replacement);
|
|
214
|
-
return "";
|
|
215
|
-
}
|
|
216
|
-
const node = replacement || createTextNode("");
|
|
217
|
-
if (current.length) {
|
|
218
|
-
let inserted = false;
|
|
219
|
-
for (let i = current.length - 1; i >= 0; i--) {
|
|
220
|
-
const el = current[i];
|
|
221
|
-
if (node !== el) {
|
|
222
|
-
const isParent = getParentNode(el) === parent;
|
|
223
|
-
if (!inserted && !i) isParent ? replaceNode(parent, node, el) : insertNode(parent, node, marker);else isParent && removeNode(parent, el);
|
|
224
|
-
} else inserted = true;
|
|
225
|
-
}
|
|
226
|
-
} else insertNode(parent, node, marker);
|
|
227
|
-
return [node];
|
|
228
|
-
}
|
|
229
|
-
function appendNodes(parent, array, marker) {
|
|
230
|
-
for (let i = 0, len = array.length; i < len; i++) insertNode(parent, array[i], marker);
|
|
231
|
-
}
|
|
232
|
-
function replaceNode(parent, newNode, oldNode) {
|
|
233
|
-
insertNode(parent, newNode, oldNode);
|
|
234
|
-
removeNode(parent, oldNode);
|
|
235
|
-
}
|
|
236
|
-
function spreadExpression(node, props, prevProps = {}, skipChildren) {
|
|
237
|
-
props || (props = {});
|
|
238
|
-
if (!skipChildren) {
|
|
239
|
-
createRenderEffect(() => prevProps.children = insertExpression(node, props.children, prevProps.children));
|
|
240
|
-
}
|
|
241
|
-
createRenderEffect(() => props.ref && props.ref(node));
|
|
242
|
-
createRenderEffect(() => {
|
|
243
|
-
for (const prop in props) {
|
|
244
|
-
if (prop === "children" || prop === "ref") continue;
|
|
245
|
-
const value = props[prop];
|
|
246
|
-
if (value === prevProps[prop]) continue;
|
|
247
|
-
setProperty(node, prop, value, prevProps[prop]);
|
|
248
|
-
prevProps[prop] = value;
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
return prevProps;
|
|
252
|
-
}
|
|
253
|
-
return {
|
|
254
|
-
render(code, element) {
|
|
255
|
-
let disposer;
|
|
256
|
-
createRoot(dispose => {
|
|
257
|
-
disposer = dispose;
|
|
258
|
-
insert(element, code());
|
|
259
|
-
});
|
|
260
|
-
return disposer;
|
|
261
|
-
},
|
|
262
|
-
insert,
|
|
263
|
-
spread(node, accessor, skipChildren) {
|
|
264
|
-
if (typeof accessor === "function") {
|
|
265
|
-
createRenderEffect(current => spreadExpression(node, accessor(), current, skipChildren));
|
|
266
|
-
} else spreadExpression(node, accessor, undefined, skipChildren);
|
|
267
|
-
},
|
|
268
|
-
createElement,
|
|
269
|
-
createTextNode,
|
|
270
|
-
insertNode,
|
|
271
|
-
setProp(node, name, value, prev) {
|
|
272
|
-
setProperty(node, name, value, prev);
|
|
273
|
-
return value;
|
|
274
|
-
},
|
|
275
|
-
mergeProps: mergeProps$1,
|
|
276
|
-
effect: createRenderEffect,
|
|
277
|
-
memo: createMemo,
|
|
278
|
-
createComponent: createComponent$1,
|
|
279
|
-
use(fn, element, arg) {
|
|
280
|
-
return untrack(() => fn(element, arg));
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
function createRenderer(options) {
|
|
285
|
-
const renderer = createRenderer$1(options);
|
|
286
|
-
renderer.mergeProps = mergeProps$1;
|
|
287
|
-
return renderer;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/*
|
|
291
|
-
* If not stated otherwise in this file or this component's LICENSE file the
|
|
292
|
-
* following copyright and licenses apply:
|
|
293
|
-
*
|
|
294
|
-
* Copyright 2023 Comcast Cable Communications Management, LLC.
|
|
295
|
-
*
|
|
296
|
-
* Licensed under the Apache License, Version 2.0 (the License);
|
|
297
|
-
* you may not use this file except in compliance with the License.
|
|
298
|
-
* You may obtain a copy of the License at
|
|
299
|
-
*
|
|
300
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
301
|
-
*
|
|
302
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
303
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
304
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
305
|
-
* See the License for the specific language governing permissions and
|
|
306
|
-
* limitations under the License.
|
|
307
|
-
*/
|
|
308
|
-
/**
|
|
309
|
-
* Asserts a condition is truthy, otherwise throws an error
|
|
310
|
-
*
|
|
311
|
-
* @remarks
|
|
312
|
-
* Useful at the top of functions to ensure certain conditions, arguments and
|
|
313
|
-
* properties are set/met before continuing. When using this function,
|
|
314
|
-
* TypeScript will narrow away falsy types from the condition.
|
|
315
|
-
*
|
|
316
|
-
* @param condition
|
|
317
|
-
* @param message
|
|
318
|
-
* @returns
|
|
319
|
-
*/
|
|
320
|
-
function assertTruthy(condition, message) {
|
|
321
|
-
if (isProductionEnvironment()) return;
|
|
322
|
-
if (!condition) {
|
|
323
|
-
throw new Error('Assertion failed');
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* Checks import.meta if env is production
|
|
328
|
-
*
|
|
329
|
-
* @returns
|
|
330
|
-
*/
|
|
331
|
-
function isProductionEnvironment() {
|
|
332
|
-
return import.meta.env && import.meta.env.PROD;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
var nodeOpts = {
|
|
336
|
-
createElement(name) {
|
|
337
|
-
return new ElementNode(name);
|
|
338
|
-
},
|
|
339
|
-
createTextNode(text) {
|
|
340
|
-
// A text node is just a string - not the <text> node
|
|
341
|
-
return {
|
|
342
|
-
type: NodeType.Text,
|
|
343
|
-
text,
|
|
344
|
-
parent: undefined
|
|
345
|
-
};
|
|
346
|
-
},
|
|
347
|
-
replaceText(node, value) {
|
|
348
|
-
log('Replace Text: ', node, value);
|
|
349
|
-
node.text = value;
|
|
350
|
-
const parent = node.parent;
|
|
351
|
-
assertTruthy(parent);
|
|
352
|
-
parent.text = parent.getText();
|
|
353
|
-
},
|
|
354
|
-
setProperty(node, name, value = true) {
|
|
355
|
-
node[name] = value;
|
|
356
|
-
},
|
|
357
|
-
insertNode(parent, node, anchor) {
|
|
358
|
-
log('INSERT: ', parent, node, anchor);
|
|
359
|
-
parent.children.insert(node, anchor);
|
|
360
|
-
node._queueDelete = false;
|
|
361
|
-
if (node instanceof ElementNode) {
|
|
362
|
-
parent.rendered && node.render();
|
|
363
|
-
} else if (parent.isTextNode()) {
|
|
364
|
-
// TextNodes can be placed outside of <text> nodes when <Show> is used as placeholder
|
|
365
|
-
parent.text = parent.getText();
|
|
366
|
-
}
|
|
367
|
-
},
|
|
368
|
-
isTextNode(node) {
|
|
369
|
-
return node.isTextNode();
|
|
370
|
-
},
|
|
371
|
-
removeNode(parent, node) {
|
|
372
|
-
log('REMOVE: ', parent, node);
|
|
373
|
-
parent.children.remove(node);
|
|
374
|
-
node._queueDelete = true;
|
|
375
|
-
if (node instanceof ElementNode) {
|
|
376
|
-
// Solid replacesNodes to move them (via insert and remove),
|
|
377
|
-
// so we need to wait for the next microtask to destroy the node
|
|
378
|
-
// in the event it gets a new parent.
|
|
379
|
-
queueMicrotask(() => node.destroy());
|
|
380
|
-
}
|
|
381
|
-
},
|
|
382
|
-
getParentNode(node) {
|
|
383
|
-
return node.parent;
|
|
384
|
-
},
|
|
385
|
-
getFirstChild(node) {
|
|
386
|
-
return node.children[0];
|
|
387
|
-
},
|
|
388
|
-
getNextSibling(node) {
|
|
389
|
-
const children = node.parent.children || [];
|
|
390
|
-
const index = children.indexOf(node) + 1;
|
|
391
|
-
if (index < children.length) {
|
|
392
|
-
return children[index];
|
|
393
|
-
}
|
|
394
|
-
return undefined;
|
|
395
|
-
}
|
|
396
|
-
};
|
|
397
|
-
|
|
398
|
-
/* eslint-disable @typescript-eslint/unbound-method */
|
|
399
|
-
const solidRenderer = createRenderer(nodeOpts);
|
|
400
|
-
let renderer;
|
|
401
|
-
const rootNode = nodeOpts.createElement('App');
|
|
402
|
-
async function startLightning(options, rootId) {
|
|
403
|
-
renderer = startLightningRenderer(options || Config.rendererOptions, rootId || 'app');
|
|
404
|
-
return await renderer.init();
|
|
405
|
-
}
|
|
406
|
-
const render = async function (code, node) {
|
|
407
|
-
await startLightning(undefined, node);
|
|
408
|
-
rootNode.lng = renderer.root;
|
|
409
|
-
rootNode.rendered = true;
|
|
410
|
-
// @ts-expect-error - code is jsx element and not SolidElement yet
|
|
411
|
-
const dispose = solidRenderer.render(code, rootNode);
|
|
412
|
-
return {
|
|
413
|
-
dispose,
|
|
414
|
-
rootNode,
|
|
415
|
-
renderer
|
|
416
|
-
};
|
|
417
|
-
};
|
|
418
|
-
|
|
419
|
-
// used for playground - must be sync so user must await startLightning
|
|
420
|
-
const renderSync = function (code) {
|
|
421
|
-
rootNode.lng = renderer.root;
|
|
422
|
-
// @ts-expect-error - code is jsx element and not SolidElement yet
|
|
423
|
-
return solidRenderer.render(code, rootNode);
|
|
424
|
-
};
|
|
425
|
-
const {
|
|
426
|
-
effect,
|
|
427
|
-
memo,
|
|
428
|
-
createComponent,
|
|
429
|
-
createElement,
|
|
430
|
-
createTextNode,
|
|
431
|
-
insertNode,
|
|
432
|
-
insert,
|
|
433
|
-
spread,
|
|
434
|
-
setProp,
|
|
435
|
-
mergeProps,
|
|
436
|
-
use
|
|
437
|
-
} = solidRenderer;
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* renders an arbitrary custom or native component and passes the other props
|
|
441
|
-
* ```typescript
|
|
442
|
-
* <Dynamic component={multiline() ? 'textarea' : 'input'} value={value()} />
|
|
443
|
-
* ```
|
|
444
|
-
* @description https://www.solidjs.com/docs/latest/api#dynamic
|
|
445
|
-
*/
|
|
446
|
-
function Dynamic(props) {
|
|
447
|
-
const [p, others] = splitProps(props, ['component']);
|
|
448
|
-
const cached = createMemo(() => p.component);
|
|
449
|
-
return createMemo(() => {
|
|
450
|
-
const component = cached();
|
|
451
|
-
switch (typeof component) {
|
|
452
|
-
case 'function':
|
|
453
|
-
return untrack(() => component(others));
|
|
454
|
-
case 'string':
|
|
455
|
-
{
|
|
456
|
-
const el = createElement(component);
|
|
457
|
-
spread(el, others);
|
|
458
|
-
return el;
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* Generates a map of event handlers for each key in the KeyMap
|
|
466
|
-
*/
|
|
467
|
-
|
|
468
|
-
const keyMapEntries = {
|
|
469
|
-
ArrowLeft: 'Left',
|
|
470
|
-
ArrowRight: 'Right',
|
|
471
|
-
ArrowUp: 'Up',
|
|
472
|
-
ArrowDown: 'Down',
|
|
473
|
-
Enter: 'Enter',
|
|
474
|
-
l: 'Last',
|
|
475
|
-
' ': 'Space',
|
|
476
|
-
Backspace: 'Back',
|
|
477
|
-
Escape: 'Escape'
|
|
478
|
-
};
|
|
479
|
-
const [focusPath, setFocusPath] = createSignal([]);
|
|
480
|
-
const useFocusManager = userKeyMap => {
|
|
481
|
-
const keypressEvent = useKeyDownEvent();
|
|
482
|
-
if (userKeyMap) {
|
|
483
|
-
// Flatten the userKeyMap to a hash
|
|
484
|
-
for (const [key, value] of Object.entries(userKeyMap)) {
|
|
485
|
-
if (isArray(value)) {
|
|
486
|
-
value.forEach(v => {
|
|
487
|
-
keyMapEntries[v] = key;
|
|
488
|
-
});
|
|
489
|
-
} else {
|
|
490
|
-
keyMapEntries[value] = key;
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
createEffect(on(activeElement$1, (currentFocusedElm, prevFocusedElm, prevFocusPath = []) => {
|
|
495
|
-
let current = currentFocusedElm;
|
|
496
|
-
const fp = [];
|
|
497
|
-
while (current) {
|
|
498
|
-
if (!current.states.has('focus')) {
|
|
499
|
-
current.states.add('focus');
|
|
500
|
-
isFunc(current.onFocus) && current.onFocus.call(current, currentFocusedElm, prevFocusedElm);
|
|
501
|
-
}
|
|
502
|
-
fp.push(current);
|
|
503
|
-
current = current.parent;
|
|
504
|
-
}
|
|
505
|
-
prevFocusPath.forEach(elm => {
|
|
506
|
-
if (!fp.includes(elm)) {
|
|
507
|
-
elm.states.remove('focus');
|
|
508
|
-
isFunc(elm.onBlur) && elm.onBlur.call(elm, currentFocusedElm, prevFocusedElm);
|
|
509
|
-
}
|
|
510
|
-
});
|
|
511
|
-
setFocusPath(fp);
|
|
512
|
-
return fp;
|
|
513
|
-
}, {
|
|
514
|
-
defer: true
|
|
515
|
-
}));
|
|
516
|
-
createEffect(() => {
|
|
517
|
-
const e = keypressEvent();
|
|
518
|
-
if (e) {
|
|
519
|
-
// Search keyMap for the value of the pressed key or keyCode if value undefined
|
|
520
|
-
const mappedKeyEvent = keyMapEntries[e.key] || keyMapEntries[e.keyCode];
|
|
521
|
-
untrack(() => {
|
|
522
|
-
const fp = focusPath();
|
|
523
|
-
let finalFocusElm = undefined;
|
|
524
|
-
for (const elm of fp) {
|
|
525
|
-
finalFocusElm = finalFocusElm || elm;
|
|
526
|
-
if (mappedKeyEvent) {
|
|
527
|
-
const onKeyHandler = elm[`on${mappedKeyEvent}`];
|
|
528
|
-
if (isFunc(onKeyHandler)) {
|
|
529
|
-
if (onKeyHandler.call(elm, e, elm, finalFocusElm) === true) {
|
|
530
|
-
break;
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
} else {
|
|
534
|
-
console.log(`Unhandled key event: ${e.key || e.keyCode}`);
|
|
535
|
-
}
|
|
536
|
-
if (isFunc(elm.onKeyPress)) {
|
|
537
|
-
if (elm.onKeyPress.call(elm, e, mappedKeyEvent, elm, finalFocusElm) === true) {
|
|
538
|
-
break;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
return false;
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
});
|
|
546
|
-
return focusPath;
|
|
547
|
-
};
|
|
548
|
-
|
|
549
|
-
// To use with TS import withPadding and then put withPadding; on the next line to prevent tree shaking
|
|
550
|
-
function withPadding(el, padding) {
|
|
551
|
-
const pad = padding();
|
|
552
|
-
let top, left, right, bottom;
|
|
553
|
-
if (Array.isArray(pad)) {
|
|
554
|
-
// top right bottom left
|
|
555
|
-
if (pad.length === 2) {
|
|
556
|
-
top = bottom = pad[0];
|
|
557
|
-
left = right = pad[1];
|
|
558
|
-
} else if (pad.length === 3) {
|
|
559
|
-
top = pad[0];
|
|
560
|
-
left = right = pad[1];
|
|
561
|
-
bottom = pad[2];
|
|
562
|
-
} else {
|
|
563
|
-
[top, right, bottom, left] = pad;
|
|
564
|
-
}
|
|
565
|
-
} else {
|
|
566
|
-
top = right = bottom = left = pad;
|
|
567
|
-
}
|
|
568
|
-
el.onBeforeLayout = (node, size) => {
|
|
569
|
-
if (size) {
|
|
570
|
-
el.width = el.children.reduce((acc, child) => {
|
|
571
|
-
const c = child;
|
|
572
|
-
return acc + (c.width || 0);
|
|
573
|
-
}, 0) + left + right;
|
|
574
|
-
const firstChild = el.children[0];
|
|
575
|
-
if (firstChild) {
|
|
576
|
-
// set padding or marginLeft for flex
|
|
577
|
-
firstChild.x = left;
|
|
578
|
-
firstChild.marginLeft = left;
|
|
579
|
-
}
|
|
580
|
-
let maxHeight = 0;
|
|
581
|
-
el.children.forEach(child => {
|
|
582
|
-
const c = child;
|
|
583
|
-
c.y = top;
|
|
584
|
-
c.marginTop = top;
|
|
585
|
-
maxHeight = Math.max(maxHeight, c.height || 0);
|
|
586
|
-
});
|
|
587
|
-
el.height = maxHeight + top + bottom;
|
|
588
|
-
// let flex know we need to re-layout
|
|
589
|
-
return true;
|
|
590
|
-
}
|
|
591
|
-
};
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
/* global SpeechSynthesisErrorEvent */
|
|
595
|
-
function flattenStrings(series = []) {
|
|
596
|
-
const flattenedSeries = [];
|
|
597
|
-
let i;
|
|
598
|
-
for (i = 0; i < series.length; i++) {
|
|
599
|
-
const s = series[i];
|
|
600
|
-
if (typeof s === 'string' && !s.includes('PAUSE-')) {
|
|
601
|
-
flattenedSeries.push(series[i]);
|
|
602
|
-
} else {
|
|
603
|
-
break;
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
// add a "word boundary" to ensure the Announcer doesn't automatically try to
|
|
607
|
-
// interpret strings that look like dates but are not actually dates
|
|
608
|
-
// for example, if "Rising Sun" and "1993" are meant to be two separate lines,
|
|
609
|
-
// when read together, "Sun 1993" is interpretted as "Sunday 1993"
|
|
610
|
-
return [flattenedSeries.join(',\b ')].concat(series.slice(i));
|
|
611
|
-
}
|
|
612
|
-
function delay(pause) {
|
|
613
|
-
return new Promise(resolve => {
|
|
614
|
-
setTimeout(resolve, pause);
|
|
615
|
-
});
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
/**
|
|
619
|
-
* Speak a string
|
|
620
|
-
*
|
|
621
|
-
* @param phrase Phrase to speak
|
|
622
|
-
* @param utterances An array which the new SpeechSynthesisUtterance instance representing this utterance will be appended
|
|
623
|
-
* @param lang Language to speak in
|
|
624
|
-
* @return {Promise<void>} Promise resolved when the utterance has finished speaking, and rejected if there's an error
|
|
625
|
-
*/
|
|
626
|
-
function speak(phrase, utterances, lang = 'en-US') {
|
|
627
|
-
const synth = window.speechSynthesis;
|
|
628
|
-
return new Promise((resolve, reject) => {
|
|
629
|
-
const utterance = new SpeechSynthesisUtterance(phrase);
|
|
630
|
-
utterance.lang = lang;
|
|
631
|
-
utterance.onend = () => {
|
|
632
|
-
resolve();
|
|
633
|
-
};
|
|
634
|
-
utterance.onerror = e => {
|
|
635
|
-
reject(e);
|
|
636
|
-
};
|
|
637
|
-
utterances.push(utterance);
|
|
638
|
-
synth.speak(utterance);
|
|
639
|
-
});
|
|
640
|
-
}
|
|
641
|
-
function speakSeries(series, lang, root = true) {
|
|
642
|
-
const synth = window.speechSynthesis;
|
|
643
|
-
const remainingPhrases = flattenStrings(Array.isArray(series) ? series : [series]);
|
|
644
|
-
const nestedSeriesResults = [];
|
|
645
|
-
/*
|
|
646
|
-
We hold this array of SpeechSynthesisUtterances in order to prevent them from being
|
|
647
|
-
garbage collected prematurely on STB hardware which can cause the 'onend' events of
|
|
648
|
-
utterances to not fire consistently.
|
|
649
|
-
*/
|
|
650
|
-
const utterances = [];
|
|
651
|
-
let active = true;
|
|
652
|
-
const seriesChain = (async () => {
|
|
653
|
-
try {
|
|
654
|
-
while (active && remainingPhrases.length) {
|
|
655
|
-
const phrase = await Promise.resolve(remainingPhrases.shift());
|
|
656
|
-
if (!active) {
|
|
657
|
-
// Exit
|
|
658
|
-
// Need to check this after the await in case it was cancelled in between
|
|
659
|
-
break;
|
|
660
|
-
} else if (typeof phrase === 'string' && phrase.includes('PAUSE-')) {
|
|
661
|
-
// Pause it
|
|
662
|
-
let pause = Number(phrase.split('PAUSE-')[1]) * 1000;
|
|
663
|
-
if (isNaN(pause)) {
|
|
664
|
-
pause = 0;
|
|
665
|
-
}
|
|
666
|
-
await delay(pause);
|
|
667
|
-
} else if (typeof phrase === 'string' && phrase.length) {
|
|
668
|
-
// Speak it
|
|
669
|
-
const totalRetries = 3;
|
|
670
|
-
let retriesLeft = totalRetries;
|
|
671
|
-
while (active && retriesLeft > 0) {
|
|
672
|
-
try {
|
|
673
|
-
await speak(phrase, utterances, lang);
|
|
674
|
-
retriesLeft = 0;
|
|
675
|
-
} catch (e) {
|
|
676
|
-
// eslint-disable-next-line no-undef
|
|
677
|
-
if (e instanceof SpeechSynthesisErrorEvent) {
|
|
678
|
-
if (e.error === 'network') {
|
|
679
|
-
retriesLeft--;
|
|
680
|
-
console.warn(`Speech synthesis network error. Retries left: ${retriesLeft}`);
|
|
681
|
-
await delay(500 * (totalRetries - retriesLeft));
|
|
682
|
-
} else if (e.error === 'canceled' || e.error === 'interrupted') {
|
|
683
|
-
// Cancel or interrupt error (ignore)
|
|
684
|
-
retriesLeft = 0;
|
|
685
|
-
} else {
|
|
686
|
-
throw new Error(`SpeechSynthesisErrorEvent: ${e.error}`);
|
|
687
|
-
}
|
|
688
|
-
} else {
|
|
689
|
-
throw e;
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
} else if (typeof phrase === 'function') {
|
|
694
|
-
const seriesResult = speakSeries(phrase(), lang, false);
|
|
695
|
-
nestedSeriesResults.push(seriesResult);
|
|
696
|
-
await seriesResult.series;
|
|
697
|
-
} else if (Array.isArray(phrase)) {
|
|
698
|
-
// Speak it (recursively)
|
|
699
|
-
const seriesResult = speakSeries(phrase, lang, false);
|
|
700
|
-
nestedSeriesResults.push(seriesResult);
|
|
701
|
-
await seriesResult.series;
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
} finally {
|
|
705
|
-
active = false;
|
|
706
|
-
}
|
|
707
|
-
})();
|
|
708
|
-
return {
|
|
709
|
-
series: seriesChain,
|
|
710
|
-
get active() {
|
|
711
|
-
return active;
|
|
712
|
-
},
|
|
713
|
-
append: toSpeak => {
|
|
714
|
-
remainingPhrases.push(toSpeak);
|
|
715
|
-
},
|
|
716
|
-
cancel: () => {
|
|
717
|
-
if (!active) {
|
|
718
|
-
return;
|
|
719
|
-
}
|
|
720
|
-
if (root) {
|
|
721
|
-
synth.cancel();
|
|
722
|
-
}
|
|
723
|
-
nestedSeriesResults.forEach(nestedSeriesResults => {
|
|
724
|
-
nestedSeriesResults.cancel();
|
|
725
|
-
});
|
|
726
|
-
active = false;
|
|
727
|
-
}
|
|
728
|
-
};
|
|
729
|
-
}
|
|
730
|
-
let currentSeries;
|
|
731
|
-
function SpeechEngine (toSpeak, lang = 'en-US') {
|
|
732
|
-
currentSeries && currentSeries.cancel();
|
|
733
|
-
currentSeries = speakSeries(toSpeak, lang);
|
|
734
|
-
return currentSeries;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
let resetFocusPathTimer;
|
|
738
|
-
let prevFocusPath = [];
|
|
739
|
-
let currentlySpeaking;
|
|
740
|
-
let voiceOutDisabled = false;
|
|
741
|
-
const fiveMinutes = 300000;
|
|
742
|
-
function debounceWithFlush(callback, time) {
|
|
743
|
-
const trigger = debounce(callback, time);
|
|
744
|
-
let scopedValue;
|
|
745
|
-
const debounced = newValue => {
|
|
746
|
-
scopedValue = newValue;
|
|
747
|
-
trigger(newValue);
|
|
748
|
-
};
|
|
749
|
-
debounced.flush = () => {
|
|
750
|
-
trigger.clear();
|
|
751
|
-
callback(scopedValue);
|
|
752
|
-
};
|
|
753
|
-
debounced.clear = trigger.clear;
|
|
754
|
-
return debounced;
|
|
755
|
-
}
|
|
756
|
-
function getElmName(elm) {
|
|
757
|
-
return elm.id || elm.name;
|
|
758
|
-
}
|
|
759
|
-
function onFocusChangeCore(focusPath = []) {
|
|
760
|
-
if (!Announcer.onFocusChange || !Announcer.enabled) {
|
|
761
|
-
return;
|
|
762
|
-
}
|
|
763
|
-
const loaded = focusPath.every(elm => !elm.loading);
|
|
764
|
-
const focusDiff = focusPath.filter(elm => !prevFocusPath.includes(elm));
|
|
765
|
-
resetFocusPathTimer();
|
|
766
|
-
if (!loaded && Announcer.onFocusChange) {
|
|
767
|
-
Announcer.onFocusChange([]);
|
|
768
|
-
return;
|
|
769
|
-
}
|
|
770
|
-
prevFocusPath = focusPath.slice(0);
|
|
771
|
-
const toAnnounceText = [];
|
|
772
|
-
const toAnnounce = focusDiff.reduce((acc, elm) => {
|
|
773
|
-
if (elm.announce) {
|
|
774
|
-
acc.push([getElmName(elm), 'Announce', elm.announce]);
|
|
775
|
-
toAnnounceText.push(elm.announce);
|
|
776
|
-
} else if (elm.title) {
|
|
777
|
-
acc.push([getElmName(elm), 'Title', elm.title]);
|
|
778
|
-
toAnnounceText.push(elm.title);
|
|
779
|
-
} else {
|
|
780
|
-
acc.push([getElmName(elm), 'No Announce', '']);
|
|
781
|
-
}
|
|
782
|
-
return acc;
|
|
783
|
-
}, []);
|
|
784
|
-
focusDiff.reverse().reduce((acc, elm) => {
|
|
785
|
-
if (elm.announceContext) {
|
|
786
|
-
acc.push([getElmName(elm), 'Context', elm.announceContext]);
|
|
787
|
-
toAnnounceText.push(elm.announceContext);
|
|
788
|
-
} else {
|
|
789
|
-
acc.push([getElmName(elm), 'No Context', '']);
|
|
790
|
-
}
|
|
791
|
-
return acc;
|
|
792
|
-
}, toAnnounce);
|
|
793
|
-
if (Announcer.debug) {
|
|
794
|
-
console.table(toAnnounce);
|
|
795
|
-
}
|
|
796
|
-
if (toAnnounceText.length) {
|
|
797
|
-
return Announcer.speak(toAnnounceText.reduce((acc, val) => acc.concat(val), []));
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
function textToSpeech(toSpeak) {
|
|
801
|
-
if (voiceOutDisabled) {
|
|
802
|
-
return;
|
|
803
|
-
}
|
|
804
|
-
return currentlySpeaking = SpeechEngine(toSpeak);
|
|
805
|
-
}
|
|
806
|
-
const Announcer = {
|
|
807
|
-
debug: false,
|
|
808
|
-
enabled: true,
|
|
809
|
-
cancel: function () {
|
|
810
|
-
currentlySpeaking && currentlySpeaking.cancel();
|
|
811
|
-
},
|
|
812
|
-
clearPrevFocus: function (depth = 0) {
|
|
813
|
-
prevFocusPath = prevFocusPath.slice(0, depth);
|
|
814
|
-
resetFocusPathTimer();
|
|
815
|
-
},
|
|
816
|
-
speak: function (text, {
|
|
817
|
-
append = false,
|
|
818
|
-
notification = false
|
|
819
|
-
} = {}) {
|
|
820
|
-
if (Announcer.onFocusChange && Announcer.enabled) {
|
|
821
|
-
Announcer.onFocusChange.flush();
|
|
822
|
-
if (append && currentlySpeaking && currentlySpeaking.active) {
|
|
823
|
-
currentlySpeaking.append(text);
|
|
824
|
-
} else {
|
|
825
|
-
Announcer.cancel();
|
|
826
|
-
textToSpeech(text);
|
|
827
|
-
}
|
|
828
|
-
if (notification) {
|
|
829
|
-
voiceOutDisabled = true;
|
|
830
|
-
currentlySpeaking?.series.finally(() => {
|
|
831
|
-
voiceOutDisabled = false;
|
|
832
|
-
Announcer.refresh();
|
|
833
|
-
}).catch(console.error);
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
return currentlySpeaking;
|
|
837
|
-
},
|
|
838
|
-
refresh: function (depth = 0) {
|
|
839
|
-
Announcer.clearPrevFocus(depth);
|
|
840
|
-
Announcer.onFocusChange && Announcer.onFocusChange(untrack(() => focusPath()));
|
|
841
|
-
},
|
|
842
|
-
setupTimers: function ({
|
|
843
|
-
focusDebounce = 400,
|
|
844
|
-
focusChangeTimeout = fiveMinutes
|
|
845
|
-
} = {}) {
|
|
846
|
-
Announcer.onFocusChange = debounceWithFlush(onFocusChangeCore, focusDebounce);
|
|
847
|
-
resetFocusPathTimer = debounceWithFlush(() => {
|
|
848
|
-
// Reset focus path for full announce
|
|
849
|
-
prevFocusPath = [];
|
|
850
|
-
}, focusChangeTimeout);
|
|
851
|
-
}
|
|
852
|
-
};
|
|
853
|
-
|
|
854
|
-
const useAnnouncer = () => {
|
|
855
|
-
Announcer.setupTimers();
|
|
856
|
-
createEffect(on(focusPath, Announcer.onFocusChange, {
|
|
857
|
-
defer: true
|
|
858
|
-
}));
|
|
859
|
-
return Announcer;
|
|
860
|
-
};
|
|
861
|
-
|
|
862
|
-
// Adopted from https://github.com/solidjs-community/solid-primitives/blob/main/packages/pagination/src/index.ts
|
|
863
|
-
// As we don't have intersection observer in Lightning, we can't use the original implementation
|
|
864
|
-
|
|
865
|
-
/**
|
|
866
|
-
* Provides an easy way to implement infinite items.
|
|
867
|
-
*
|
|
868
|
-
* ```ts
|
|
869
|
-
* const [items, loader, { item, setItem, setItems, end, setEnd }] = createInfiniteScroll(fetcher);
|
|
870
|
-
* ```
|
|
871
|
-
* @param fetcher `(item: number) => Promise<T[]>`
|
|
872
|
-
* @return `items()` is an accessor contains array of contents
|
|
873
|
-
* @property `items.loading` is a boolean indicator for the loading state
|
|
874
|
-
* @property `items.error` contains any error encountered
|
|
875
|
-
* @method `page` is an accessor that contains page number
|
|
876
|
-
* @method `setPage` allows to manually change the page number
|
|
877
|
-
* @method `setItems` allows to manually change the contents of the item
|
|
878
|
-
* @method `end` is a boolean indicator for end of the item
|
|
879
|
-
* @method `setEnd` allows to manually change the end
|
|
880
|
-
*/
|
|
881
|
-
function createInfiniteItems(fetcher) {
|
|
882
|
-
const [items, setItems] = createSignal([]);
|
|
883
|
-
const [page, setPage] = createSignal(0);
|
|
884
|
-
const [end, setEnd] = createSignal(false);
|
|
885
|
-
const [contents] = createResource(page, fetcher);
|
|
886
|
-
createComputed(() => {
|
|
887
|
-
const content = contents();
|
|
888
|
-
if (!content) return;
|
|
889
|
-
batch(() => {
|
|
890
|
-
if (content.length === 0) setEnd(true);
|
|
891
|
-
setItems(p => [...p, ...content]);
|
|
892
|
-
});
|
|
893
|
-
});
|
|
894
|
-
return [items, {
|
|
895
|
-
page,
|
|
896
|
-
setPage,
|
|
897
|
-
setItems,
|
|
898
|
-
end,
|
|
899
|
-
setEnd
|
|
900
|
-
}];
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
function createSpriteMap(src, subTextures) {
|
|
904
|
-
const spriteMapTexture = renderer$1.createTexture('ImageTexture', {
|
|
905
|
-
src
|
|
906
|
-
});
|
|
907
|
-
return subTextures.reduce((acc, t) => {
|
|
908
|
-
const {
|
|
909
|
-
x,
|
|
910
|
-
y,
|
|
911
|
-
width,
|
|
912
|
-
height
|
|
913
|
-
} = t;
|
|
914
|
-
acc[t.name] = renderer$1.createTexture('SubTexture', {
|
|
915
|
-
texture: spriteMapTexture,
|
|
916
|
-
x,
|
|
917
|
-
y,
|
|
918
|
-
width,
|
|
919
|
-
height
|
|
920
|
-
});
|
|
921
|
-
return acc;
|
|
922
|
-
}, {});
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
function createKeyboardEvent(key, keyCode) {
|
|
926
|
-
return new KeyboardEvent('keydown', {
|
|
927
|
-
key,
|
|
928
|
-
keyCode,
|
|
929
|
-
which: keyCode,
|
|
930
|
-
ctrlKey: false,
|
|
931
|
-
altKey: false,
|
|
932
|
-
shiftKey: false,
|
|
933
|
-
metaKey: false,
|
|
934
|
-
bubbles: true
|
|
935
|
-
});
|
|
936
|
-
}
|
|
937
|
-
const handleScroll = throttle(e => {
|
|
938
|
-
const deltaY = e.deltaY;
|
|
939
|
-
if (deltaY < 0) {
|
|
940
|
-
document.dispatchEvent(createKeyboardEvent('ArrowUp', 38));
|
|
941
|
-
} else if (deltaY > 0) {
|
|
942
|
-
document.dispatchEvent(createKeyboardEvent('ArrowDown', 40));
|
|
943
|
-
}
|
|
944
|
-
}, 250);
|
|
945
|
-
const handleClick = e => {
|
|
946
|
-
const active = activeElement$1();
|
|
947
|
-
const precision = Config$1.rendererOptions?.deviceLogicalPixelRatio || 1;
|
|
948
|
-
if (active && testCollision(e.clientX, e.clientY, active.lng.coreNode.absX * precision, active.lng.coreNode.absY * precision, active.width * precision, active.height * precision)) {
|
|
949
|
-
document.dispatchEvent(createKeyboardEvent('Enter', 13));
|
|
950
|
-
}
|
|
951
|
-
};
|
|
952
|
-
function testCollision(px, py, cx, cy, cw = 0, ch = 0) {
|
|
953
|
-
return px >= cx && px <= cx + cw && py >= cy && py <= cy + ch;
|
|
954
|
-
}
|
|
955
|
-
function getChildrenByPosition(node, x, y) {
|
|
956
|
-
let result = [node];
|
|
957
|
-
const precision = Config$1.rendererOptions?.deviceLogicalPixelRatio || 1;
|
|
958
|
-
for (let i = 0; i < node.children.length; i++) {
|
|
959
|
-
const child = node.children[i];
|
|
960
|
-
if (child instanceof ElementNode$1) {
|
|
961
|
-
if (child.alpha !== 0 && testCollision(x, y, child.lng.coreNode.absX * precision, child.lng.coreNode.absY * precision, child.width * precision, child.height * precision)) {
|
|
962
|
-
// continue searching tree
|
|
963
|
-
result = [...result, ...getChildrenByPosition(child, x, y)];
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
return result;
|
|
968
|
-
}
|
|
969
|
-
function useMouse(myApp = rootNode$1) {
|
|
970
|
-
const pos = useMousePosition();
|
|
971
|
-
const scheduled = createScheduled(fn => throttle(fn, 100));
|
|
972
|
-
makeEventListener(window, 'wheel', handleScroll);
|
|
973
|
-
makeEventListener(window, 'click', handleClick);
|
|
974
|
-
createEffect(() => {
|
|
975
|
-
if (scheduled()) {
|
|
976
|
-
const result = getChildrenByPosition(myApp, pos.x, pos.y).filter(el => (el.focus || el.onFocus || el.onEnter) && !el.skipFocus).sort((a, b) => (a.zIndex || 0) - (b.zIndex || 0));
|
|
977
|
-
if (result.length) {
|
|
978
|
-
let activeElm = result[result.length - 1];
|
|
979
|
-
while (activeElm) {
|
|
980
|
-
const elmParent = activeElm.parent;
|
|
981
|
-
if (elmParent?.forwardStates) {
|
|
982
|
-
activeElm = activeElm.parent;
|
|
983
|
-
} else {
|
|
984
|
-
break;
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
const activeElmParent = activeElm?.parent;
|
|
988
|
-
if (activeElm && activeElmParent?.selected !== undefined) {
|
|
989
|
-
activeElmParent.selected = activeElmParent.children.indexOf(activeElm);
|
|
990
|
-
}
|
|
991
|
-
setActiveElement$1(activeElm);
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
});
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
function Portal(props) {
|
|
998
|
-
function getMount(mount) {
|
|
999
|
-
if (!mount) return rootNode$1;
|
|
1000
|
-
return rootNode$1.searchChildrenById(mount) || rootNode$1;
|
|
1001
|
-
}
|
|
1002
|
-
return createComponent$2(View$1, {
|
|
1003
|
-
get parent() {
|
|
1004
|
-
return getMount(props.mount);
|
|
1005
|
-
},
|
|
1006
|
-
get children() {
|
|
1007
|
-
return props.children;
|
|
1008
|
-
}
|
|
1009
|
-
});
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
export { Dynamic, Portal, Text, View, activeElement, createComponent, createElement, createInfiniteItems, createSpriteMap, createTextNode, deg2rad, effect, focusPath, hexColor, insert, insertNode, memo, mergeProps, render, renderSync, rootNode, setActiveElement, setProp, spread, startLightning, use, useAnnouncer, useFocusManager, useMouse, withPadding };
|
|
1013
|
-
//# sourceMappingURL=index.js.map
|