@lightningtv/solid 3.0.0-0 → 3.0.0-2
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/src/devtools/index.d.ts +6 -0
- package/dist/src/devtools/index.js +65 -0
- package/dist/src/devtools/index.js.map +1 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/jsx-runtime.d.ts +2 -2
- package/dist/src/primitives/Column.jsx +2 -2
- package/dist/src/primitives/Column.jsx.map +1 -1
- package/dist/src/primitives/FPSCounter.jsx +60 -61
- package/dist/src/primitives/FPSCounter.jsx.map +1 -1
- package/dist/src/primitives/FadeInOut.d.ts +10 -0
- package/dist/src/primitives/FadeInOut.jsx +22 -0
- package/dist/src/primitives/FadeInOut.jsx.map +1 -0
- package/dist/src/primitives/Grid.jsx +3 -3
- package/dist/src/primitives/Grid.jsx.map +1 -1
- package/dist/src/primitives/Lazy.d.ts +4 -5
- package/dist/src/primitives/Lazy.jsx +12 -5
- package/dist/src/primitives/Lazy.jsx.map +1 -1
- package/dist/src/primitives/LazyUp.jsx +1 -0
- package/dist/src/primitives/LazyUp.jsx.map +1 -1
- package/dist/src/primitives/Row.jsx +2 -2
- package/dist/src/primitives/Row.jsx.map +1 -1
- package/dist/src/primitives/index.d.ts +1 -1
- package/dist/src/primitives/index.js +1 -1
- package/dist/src/primitives/index.js.map +1 -1
- 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/withScrolling.js +1 -1
- package/dist/src/primitives/utils/withScrolling.js.map +1 -1
- package/dist/src/render.d.ts +2 -2
- package/dist/src/render.js +8 -6
- package/dist/src/render.js.map +1 -1
- package/dist/src/solidOpts.d.ts +6 -0
- package/dist/src/solidOpts.js +23 -7
- package/dist/src/solidOpts.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/jsx-runtime.d.ts +16 -0
- package/package.json +26 -11
- package/src/devtools/index.ts +77 -0
- package/src/index.ts +1 -1
- package/src/primitives/Column.tsx +2 -2
- package/src/primitives/FPSCounter.tsx +61 -61
- package/src/primitives/FadeInOut.tsx +34 -0
- package/src/primitives/Grid.tsx +3 -3
- package/src/primitives/Lazy.tsx +21 -12
- package/src/primitives/Row.tsx +1 -1
- package/src/primitives/index.ts +1 -1
- package/src/primitives/utils/createSpriteMap.ts +3 -5
- package/src/primitives/utils/withScrolling.ts +4 -3
- package/src/render.ts +10 -7
- package/src/solidOpts.ts +36 -7
- package/src/jsx-runtime.ts +0 -14
- package/src/primitives/LazyUp.tsx +0 -71
- package/src/primitives/jsx-runtime.d.ts +0 -8
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as debug from '@solid-devtools/debugger/types';
|
|
2
|
+
import * as lng from '@lightningtv/core';
|
|
3
|
+
|
|
4
|
+
const EMPTY_CHILDREN: (lng.ElementNode | lng.ElementText)[] = [];
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Implementation of the solid-devtools element interface for Lightning elements
|
|
8
|
+
*/
|
|
9
|
+
export const elementInterface: debug.ElementInterface<
|
|
10
|
+
lng.ElementNode | lng.ElementText
|
|
11
|
+
> = {
|
|
12
|
+
isElement(node): node is lng.ElementNode | lng.ElementText {
|
|
13
|
+
return (
|
|
14
|
+
'_type' in node &&
|
|
15
|
+
(node._type === lng.NodeType.Element ||
|
|
16
|
+
node._type === lng.NodeType.TextNode)
|
|
17
|
+
);
|
|
18
|
+
},
|
|
19
|
+
getChildren(node) {
|
|
20
|
+
return node instanceof lng.ElementNode ? node.children : EMPTY_CHILDREN;
|
|
21
|
+
},
|
|
22
|
+
getName(node) {
|
|
23
|
+
return node._type === lng.NodeType.Element ? 'view' : 'text';
|
|
24
|
+
},
|
|
25
|
+
getParent(node) {
|
|
26
|
+
return node.parent ?? null;
|
|
27
|
+
},
|
|
28
|
+
getRect(node) {
|
|
29
|
+
let { width, height } = node;
|
|
30
|
+
let x = 0,
|
|
31
|
+
y = 0;
|
|
32
|
+
|
|
33
|
+
if (node.scaleX != null) width *= node.scaleX;
|
|
34
|
+
if (node.scaleY != null) height *= node.scaleY;
|
|
35
|
+
|
|
36
|
+
let curr = node as lng.ElementNode | undefined | null;
|
|
37
|
+
while (curr != null) {
|
|
38
|
+
x += curr.x;
|
|
39
|
+
y += curr.y;
|
|
40
|
+
|
|
41
|
+
if (curr.scaleX != null) {
|
|
42
|
+
x += (curr.width / 2) * (1 - curr.scaleX);
|
|
43
|
+
}
|
|
44
|
+
if (curr.scaleY != null) {
|
|
45
|
+
y += (curr.height / 2) * (1 - curr.scaleY);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
curr = curr.parent;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (lng.Config.rendererOptions != null) {
|
|
52
|
+
let dpr = lng.Config.rendererOptions.deviceLogicalPixelRatio;
|
|
53
|
+
if (dpr != null) {
|
|
54
|
+
x *= dpr;
|
|
55
|
+
y *= dpr;
|
|
56
|
+
width *= dpr;
|
|
57
|
+
height *= dpr;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return { x, y, width, height };
|
|
62
|
+
},
|
|
63
|
+
getElementAt(e) {
|
|
64
|
+
let target = e.target as any;
|
|
65
|
+
return target != null && target.element instanceof lng.ElementNode
|
|
66
|
+
? target.element
|
|
67
|
+
: null;
|
|
68
|
+
},
|
|
69
|
+
getLocation(node) {
|
|
70
|
+
if (typeof node[debug.LOCATION_ATTRIBUTE_NAME] === 'string') {
|
|
71
|
+
return (
|
|
72
|
+
debug.parseLocationString(node[debug.LOCATION_ATTRIBUTE_NAME]) ?? null
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
},
|
|
77
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Component } from 'solid-js';
|
|
2
|
-
import { ElementNode,
|
|
2
|
+
import { ElementNode, combineStyles, type NodeStyles } from '@lightningtv/solid';
|
|
3
3
|
import {
|
|
4
4
|
handleNavigation,
|
|
5
5
|
onGridFocus,
|
|
@@ -32,7 +32,7 @@ function scrollToIndex(this: ElementNode, index: number) {
|
|
|
32
32
|
|
|
33
33
|
export const Column: Component<ColumnProps> = (props) => {
|
|
34
34
|
return (
|
|
35
|
-
<
|
|
35
|
+
<view
|
|
36
36
|
{...props}
|
|
37
37
|
onUp={/* @once */ chainFunctions(props.onUp, onUp)}
|
|
38
38
|
onDown={/* @once */ chainFunctions(props.onDown, onDown)}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type Stage, type NodeProps, RendererMain } from '@lightningtv/solid';
|
|
2
2
|
import { createSignal } from 'solid-js';
|
|
3
3
|
|
|
4
4
|
const fpsStyle = {
|
|
@@ -90,90 +90,90 @@ export function setupFPS(root: any) {
|
|
|
90
90
|
|
|
91
91
|
export const FPSCounter = (props: NodeProps) => {
|
|
92
92
|
return (
|
|
93
|
-
<
|
|
94
|
-
<
|
|
95
|
-
<
|
|
96
|
-
<
|
|
93
|
+
<view {...props} style={fpsStyle}>
|
|
94
|
+
<view y={6}>
|
|
95
|
+
<text style={fpsLabel}>FPS:</text>
|
|
96
|
+
<text style={fpsValue} x={90}>
|
|
97
97
|
{fps().toString()}
|
|
98
|
-
</
|
|
99
|
-
</
|
|
98
|
+
</text>
|
|
99
|
+
</view>
|
|
100
100
|
|
|
101
|
-
<
|
|
102
|
-
<
|
|
103
|
-
<
|
|
101
|
+
<view y={6} x={160}>
|
|
102
|
+
<text style={fpsLabel}>AVG:</text>
|
|
103
|
+
<text style={fpsValue} x={100}>
|
|
104
104
|
{avgFps().toString()}
|
|
105
|
-
</
|
|
106
|
-
</
|
|
105
|
+
</text>
|
|
106
|
+
</view>
|
|
107
107
|
|
|
108
|
-
<
|
|
109
|
-
<
|
|
110
|
-
<
|
|
108
|
+
<view x={0} y={26}>
|
|
109
|
+
<text style={fpsLabel}>MIN:</text>
|
|
110
|
+
<text style={fpsValue} x={90}>
|
|
111
111
|
{minFps().toString()}
|
|
112
|
-
</
|
|
113
|
-
</
|
|
112
|
+
</text>
|
|
113
|
+
</view>
|
|
114
114
|
|
|
115
|
-
<
|
|
116
|
-
<
|
|
117
|
-
<
|
|
115
|
+
<view x={160} y={26}>
|
|
116
|
+
<text style={fpsLabel}>MAX:</text>
|
|
117
|
+
<text style={fpsValue} x={100}>
|
|
118
118
|
{maxFps().toString()}
|
|
119
|
-
</
|
|
120
|
-
</
|
|
119
|
+
</text>
|
|
120
|
+
</view>
|
|
121
121
|
|
|
122
|
-
<
|
|
123
|
-
<
|
|
124
|
-
<
|
|
122
|
+
<view display="flex" flexDirection="column" y={58} gap={4}>
|
|
123
|
+
<view height={infoFontSize}>
|
|
124
|
+
<text fontSize={infoFontSize} style={fpsLabel}>
|
|
125
125
|
criticalThreshold:
|
|
126
|
-
</
|
|
127
|
-
<
|
|
126
|
+
</text>
|
|
127
|
+
<text fontSize={infoFontSize} style={fpsLabel} x={230}>
|
|
128
128
|
{criticalThresholdSignal()}
|
|
129
|
-
</
|
|
130
|
-
</
|
|
129
|
+
</text>
|
|
130
|
+
</view>
|
|
131
131
|
|
|
132
|
-
<
|
|
133
|
-
<
|
|
132
|
+
<view height={infoFontSize}>
|
|
133
|
+
<text fontSize={infoFontSize} style={fpsLabel}>
|
|
134
134
|
targetThreshold:
|
|
135
|
-
</
|
|
136
|
-
<
|
|
135
|
+
</text>
|
|
136
|
+
<text fontSize={infoFontSize} style={fpsLabel} x={230}>
|
|
137
137
|
{targetThresholdSignal()}
|
|
138
|
-
</
|
|
139
|
-
</
|
|
138
|
+
</text>
|
|
139
|
+
</view>
|
|
140
140
|
|
|
141
|
-
<
|
|
142
|
-
<
|
|
141
|
+
<view height={infoFontSize}>
|
|
142
|
+
<text fontSize={infoFontSize} style={fpsLabel}>
|
|
143
143
|
renderableMemUsed:
|
|
144
|
-
</
|
|
145
|
-
<
|
|
144
|
+
</text>
|
|
145
|
+
<text fontSize={infoFontSize} style={fpsLabel} x={230}>
|
|
146
146
|
{renderableMemUsedSignal()}
|
|
147
|
-
</
|
|
148
|
-
</
|
|
147
|
+
</text>
|
|
148
|
+
</view>
|
|
149
149
|
|
|
150
|
-
<
|
|
151
|
-
<
|
|
150
|
+
<view height={infoFontSize}>
|
|
151
|
+
<text fontSize={infoFontSize} style={fpsLabel}>
|
|
152
152
|
memUsed:
|
|
153
|
-
</
|
|
154
|
-
<
|
|
153
|
+
</text>
|
|
154
|
+
<text fontSize={infoFontSize} style={fpsLabel} x={230}>
|
|
155
155
|
{memUsedSignal()}
|
|
156
|
-
</
|
|
157
|
-
</
|
|
156
|
+
</text>
|
|
157
|
+
</view>
|
|
158
158
|
|
|
159
|
-
<
|
|
160
|
-
<
|
|
159
|
+
<view height={infoFontSize}>
|
|
160
|
+
<text fontSize={infoFontSize} style={fpsLabel}>
|
|
161
161
|
renderableTexturesLoaded:
|
|
162
|
-
</
|
|
163
|
-
<
|
|
162
|
+
</text>
|
|
163
|
+
<text fontSize={infoFontSize} style={fpsLabel} x={230}>
|
|
164
164
|
{renderableTexturesLoadedSignal().toString()}
|
|
165
|
-
</
|
|
166
|
-
</
|
|
165
|
+
</text>
|
|
166
|
+
</view>
|
|
167
167
|
|
|
168
|
-
<
|
|
169
|
-
<
|
|
168
|
+
<view height={infoFontSize}>
|
|
169
|
+
<text fontSize={infoFontSize} style={fpsLabel}>
|
|
170
170
|
loadedTextures:
|
|
171
|
-
</
|
|
172
|
-
<
|
|
171
|
+
</text>
|
|
172
|
+
<text fontSize={infoFontSize} style={fpsLabel} x={230}>
|
|
173
173
|
{loadedTexturesSignal().toString()}
|
|
174
|
-
</
|
|
175
|
-
</
|
|
176
|
-
</
|
|
177
|
-
</
|
|
174
|
+
</text>
|
|
175
|
+
</view>
|
|
176
|
+
</view>
|
|
177
|
+
</view>
|
|
178
178
|
);
|
|
179
179
|
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ElementNode, NodeProps, View } from '@lightningtv/solid';
|
|
2
|
+
import { Show } from 'solid-js';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
transition?: {
|
|
6
|
+
duration?: number;
|
|
7
|
+
easing?: string;
|
|
8
|
+
};
|
|
9
|
+
when?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const DEFAULT_PROPS = {
|
|
13
|
+
duration: 250,
|
|
14
|
+
easing: 'ease-in-out',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default function FadeInOut(props: Props & NodeProps) {
|
|
18
|
+
const config = Object.assign({}, DEFAULT_PROPS, props.transition);
|
|
19
|
+
function onCreate(elm: ElementNode) {
|
|
20
|
+
elm.alpha = 0;
|
|
21
|
+
elm.animate({ alpha: 1 }, { duration: config.duration, easing: config.easing }).start();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function onDestroy(elm: ElementNode) {
|
|
25
|
+
elm.rtt = true;
|
|
26
|
+
return elm.animate({ alpha: 0 }, { duration: config.duration, easing: config.easing })
|
|
27
|
+
.start().waitUntilStopped();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<Show when={props.when} keyed>
|
|
32
|
+
<View {...props} onDestroy={onDestroy} onCreate={onCreate} />
|
|
33
|
+
</Show>);
|
|
34
|
+
}
|
package/src/primitives/Grid.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ValidComponent, For, createSignal, createMemo } from "solid-js";
|
|
2
|
-
import {
|
|
2
|
+
import { Dynamic, type NodeProps, type ElementNode, isFunction } from "@lightningtv/solid";
|
|
3
3
|
|
|
4
4
|
export const Grid = <T,>(props: {
|
|
5
5
|
item: ValidComponent;
|
|
@@ -72,7 +72,7 @@ export const Grid = <T,>(props: {
|
|
|
72
72
|
);
|
|
73
73
|
|
|
74
74
|
return (
|
|
75
|
-
<
|
|
75
|
+
<view
|
|
76
76
|
transition={{ y: true }}
|
|
77
77
|
{...props}
|
|
78
78
|
onUp={(_e, elm) => moveFocus(-columns(), elm)}
|
|
@@ -95,7 +95,7 @@ export const Grid = <T,>(props: {
|
|
|
95
95
|
/>
|
|
96
96
|
)}
|
|
97
97
|
</For>
|
|
98
|
-
</
|
|
98
|
+
</view>
|
|
99
99
|
);
|
|
100
100
|
};
|
|
101
101
|
|
package/src/primitives/Lazy.tsx
CHANGED
|
@@ -7,47 +7,46 @@ import {
|
|
|
7
7
|
type JSX,
|
|
8
8
|
type ValidComponent,
|
|
9
9
|
untrack,
|
|
10
|
+
type Accessor,
|
|
10
11
|
} from 'solid-js';
|
|
11
|
-
import { Dynamic, scheduleTask, type NodeProps } from '@lightningtv/solid';
|
|
12
|
+
import { Dynamic, type NewOmit, scheduleTask, type NodeProps } from '@lightningtv/solid';
|
|
12
13
|
import { Row, Column } from '@lightningtv/solid/primitives';
|
|
13
14
|
|
|
14
|
-
type LazyProps<T extends readonly any[]> =
|
|
15
|
+
type LazyProps<T extends readonly any[]> = NewOmit<NodeProps, 'children'> & {
|
|
15
16
|
each: T | undefined | null | false;
|
|
16
17
|
fallback?: JSX.Element;
|
|
17
18
|
upCount: number;
|
|
18
19
|
delay?: number;
|
|
19
20
|
sync?: boolean;
|
|
20
21
|
eagerLoad?: boolean;
|
|
21
|
-
|
|
22
|
-
children: (item: T[number], index: number) => JSX.Element;
|
|
22
|
+
children: (item: Accessor<T[number]>, index: number) => JSX.Element;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
function createLazy<T
|
|
25
|
+
function createLazy<T>(
|
|
26
26
|
component: ValidComponent,
|
|
27
|
-
props: LazyProps<T>,
|
|
27
|
+
props: LazyProps<readonly T[]>,
|
|
28
28
|
keyHandler: (updateOffset: () => void) => Record<string, () => void>
|
|
29
29
|
) {
|
|
30
30
|
// Need at least one item so it can be focused
|
|
31
31
|
const [offset, setOffset] = createSignal(1);
|
|
32
32
|
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
|
33
33
|
|
|
34
|
-
createEffect(() => setOffset(props.selected || 1));
|
|
34
|
+
createEffect(() => setOffset((props.selected || 0) + 1));
|
|
35
35
|
|
|
36
36
|
if (props.sync) {
|
|
37
37
|
setOffset(props.upCount);
|
|
38
38
|
} else {
|
|
39
39
|
createEffect(() => {
|
|
40
40
|
if (props.each) {
|
|
41
|
-
let count = untrack(offset);
|
|
42
|
-
|
|
43
41
|
const loadItems = () => {
|
|
42
|
+
let count = untrack(offset);
|
|
44
43
|
if (count < props.upCount) {
|
|
45
44
|
setOffset(count + 1);
|
|
46
45
|
timeoutId = setTimeout(loadItems, 16); // ~60fps
|
|
47
46
|
count++;
|
|
48
47
|
} else if (props.eagerLoad) {
|
|
49
48
|
const maxOffset = props.each ? props.each.length : 0;
|
|
50
|
-
if (offset()
|
|
49
|
+
if (offset() >= maxOffset) return;
|
|
51
50
|
setOffset((prev) => Math.min(prev + 1, maxOffset));
|
|
52
51
|
scheduleTask(loadItems);
|
|
53
52
|
}
|
|
@@ -61,9 +60,19 @@ function createLazy<T extends readonly any[]>(
|
|
|
61
60
|
|
|
62
61
|
const updateOffset = () => {
|
|
63
62
|
const maxOffset = props.each ? props.each.length : 0;
|
|
64
|
-
if (offset()
|
|
63
|
+
if (offset() >= maxOffset) return;
|
|
64
|
+
|
|
65
|
+
if (!props.delay) {
|
|
66
|
+
setOffset((prev) => Math.min(prev + 1, maxOffset));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (timeoutId) {
|
|
71
|
+
clearTimeout(timeoutId);
|
|
72
|
+
//Moving faster than the delay so need to go sync
|
|
73
|
+
setOffset((prev) => Math.min(prev + 1, maxOffset));
|
|
74
|
+
}
|
|
65
75
|
|
|
66
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
67
76
|
timeoutId = setTimeout(() => {
|
|
68
77
|
setOffset((prev) => Math.min(prev + 1, maxOffset));
|
|
69
78
|
timeoutId = null;
|
package/src/primitives/Row.tsx
CHANGED
package/src/primitives/index.ts
CHANGED
|
@@ -3,7 +3,6 @@ export * from './announcer/index.js';
|
|
|
3
3
|
export * from './createInfiniteItems.js';
|
|
4
4
|
export * from './useMouse.js';
|
|
5
5
|
export * from './portal.jsx';
|
|
6
|
-
export * from './LazyUp.jsx';
|
|
7
6
|
export * from './Lazy.jsx';
|
|
8
7
|
export * from './Visible.jsx';
|
|
9
8
|
export * from './router.js';
|
|
@@ -11,6 +10,7 @@ export * from './Column.jsx';
|
|
|
11
10
|
export * from './Row.jsx';
|
|
12
11
|
export * from './Grid.jsx';
|
|
13
12
|
export * from './FPSCounter.jsx';
|
|
13
|
+
export * from './FadeInOut.jsx';
|
|
14
14
|
export * from './createFocusStack.jsx';
|
|
15
15
|
export { withScrolling } from './utils/withScrolling.js';
|
|
16
16
|
export { chainFunctions } from './utils/chainFunctions.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type IRendererTexture, renderer } from '@lightningtv/core';
|
|
2
2
|
|
|
3
3
|
export interface SpriteDef {
|
|
4
4
|
name: string | number;
|
|
@@ -11,14 +11,12 @@ export interface SpriteDef {
|
|
|
11
11
|
export function createSpriteMap(
|
|
12
12
|
src: string,
|
|
13
13
|
subTextures: SpriteDef[],
|
|
14
|
-
): Record<string,
|
|
14
|
+
): Record<string, IRendererTexture> {
|
|
15
15
|
const spriteMapTexture = renderer.createTexture('ImageTexture', {
|
|
16
16
|
src,
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
return subTextures.reduce<
|
|
20
|
-
Record<string, InstanceType<TextureMap['SubTexture']>>
|
|
21
|
-
>((acc, t) => {
|
|
19
|
+
return subTextures.reduce<Record<string, IRendererTexture>>((acc, t) => {
|
|
22
20
|
const { x, y, width, height } = t;
|
|
23
21
|
acc[t.name] = renderer.createTexture('SubTexture', {
|
|
24
22
|
texture: spriteMapTexture,
|
|
@@ -72,9 +72,10 @@ export function withScrolling(isRow: boolean) {
|
|
|
72
72
|
|
|
73
73
|
// Allows manual position control
|
|
74
74
|
const targetPosition = componentRef._targetPosition ?? componentRef[axis];
|
|
75
|
-
const rootPosition =
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
const rootPosition =
|
|
76
|
+
isIncrementing || scroll === 'auto'
|
|
77
|
+
? Math.min(targetPosition, componentRef[axis])
|
|
78
|
+
: Math.max(targetPosition, componentRef[axis]);
|
|
78
79
|
componentRef.offset = componentRef.offset ?? rootPosition;
|
|
79
80
|
const offset = componentRef.offset;
|
|
80
81
|
selectedElement =
|
package/src/render.ts
CHANGED
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
type NodeProps,
|
|
5
5
|
type TextProps,
|
|
6
6
|
startLightningRenderer,
|
|
7
|
-
type RendererMain,
|
|
8
7
|
type RendererMainSettings,
|
|
8
|
+
type IRendererMain,
|
|
9
9
|
} from '@lightningtv/core';
|
|
10
10
|
import nodeOpts from './solidOpts.js';
|
|
11
11
|
import {
|
|
@@ -15,13 +15,14 @@ import {
|
|
|
15
15
|
untrack,
|
|
16
16
|
type JSXElement,
|
|
17
17
|
type ValidComponent,
|
|
18
|
+
createRoot,
|
|
18
19
|
} from 'solid-js';
|
|
19
20
|
import type { SolidNode } from './types.js';
|
|
20
21
|
import { activeElement, setActiveElement } from './activeElement.js';
|
|
21
22
|
|
|
22
23
|
const solidRenderer = solidCreateRenderer<SolidNode>(nodeOpts);
|
|
23
24
|
|
|
24
|
-
let renderer:
|
|
25
|
+
let renderer: IRendererMain;
|
|
25
26
|
export const rootNode = nodeOpts.createElement('App');
|
|
26
27
|
|
|
27
28
|
const render = function (code: () => JSXElement) {
|
|
@@ -71,11 +72,13 @@ type Task = () => void;
|
|
|
71
72
|
const taskQueue: Task[] = [];
|
|
72
73
|
let tasksEnabled = false;
|
|
73
74
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
createRoot(() => {
|
|
76
|
+
createRenderEffect(() => {
|
|
77
|
+
// should change whenever a keypress occurs, so we disable the task queue
|
|
78
|
+
// until the renderer is idle again.
|
|
79
|
+
activeElement();
|
|
80
|
+
tasksEnabled = false;
|
|
81
|
+
});
|
|
79
82
|
});
|
|
80
83
|
|
|
81
84
|
export function setTasksEnabled(enabled: boolean): void {
|
package/src/solidOpts.ts
CHANGED
|
@@ -9,6 +9,35 @@ import {
|
|
|
9
9
|
} from '@lightningtv/core';
|
|
10
10
|
import type { SolidNode, SolidRendererOptions } from './types.js';
|
|
11
11
|
|
|
12
|
+
declare module '@lightningtv/core' {
|
|
13
|
+
interface ElementNode {
|
|
14
|
+
_queueInsert?: true;
|
|
15
|
+
_queueRemove?: true;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let elementQueue: ElementNode[] = [];
|
|
20
|
+
|
|
21
|
+
function flushQueue(): void {
|
|
22
|
+
for (let el of elementQueue) {
|
|
23
|
+
if (el._queueRemove && !el._queueInsert) {
|
|
24
|
+
el.destroy();
|
|
25
|
+
}
|
|
26
|
+
el._queueInsert = el._queueRemove = undefined;
|
|
27
|
+
}
|
|
28
|
+
elementQueue.length = 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function addToQueue(node: ElementNode): void {
|
|
32
|
+
if (node._queueInsert && node._queueRemove) {
|
|
33
|
+
return; // Already in the queue
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (elementQueue.push(node) === 1) {
|
|
37
|
+
queueMicrotask(flushQueue);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
12
41
|
export default {
|
|
13
42
|
createElement(name: string): ElementNode {
|
|
14
43
|
return new ElementNode(name);
|
|
@@ -31,10 +60,11 @@ export default {
|
|
|
31
60
|
log('INSERT: ', parent, node, anchor);
|
|
32
61
|
|
|
33
62
|
parent.insertChild(node, anchor);
|
|
34
|
-
node._queueDelete = false;
|
|
35
63
|
|
|
36
64
|
if (node instanceof ElementNode) {
|
|
37
|
-
|
|
65
|
+
node._queueInsert = true;
|
|
66
|
+
node.parent!.rendered && node.render(true);
|
|
67
|
+
addToQueue(node);
|
|
38
68
|
} else if (isElementText(parent)) {
|
|
39
69
|
// TextNodes can be placed outside of <text> nodes when <Show> is used as placeholder
|
|
40
70
|
parent.text = parent.getText();
|
|
@@ -45,13 +75,12 @@ export default {
|
|
|
45
75
|
},
|
|
46
76
|
removeNode(parent: ElementNode, node: SolidNode): void {
|
|
47
77
|
log('REMOVE: ', parent, node);
|
|
78
|
+
|
|
48
79
|
parent.removeChild(node);
|
|
49
|
-
|
|
80
|
+
|
|
50
81
|
if (node instanceof ElementNode) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// in the event it gets a new parent.
|
|
54
|
-
queueMicrotask(() => node.destroy());
|
|
82
|
+
node._queueRemove = true;
|
|
83
|
+
addToQueue(node);
|
|
55
84
|
}
|
|
56
85
|
},
|
|
57
86
|
getParentNode(node: SolidNode): ElementNode | ElementText | undefined {
|
package/src/jsx-runtime.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-namespace */
|
|
2
|
-
import type { NodeProps, TextProps } from '@lightningtv/core';
|
|
3
|
-
|
|
4
|
-
declare module 'solid-js' {
|
|
5
|
-
namespace JSX {
|
|
6
|
-
interface IntrinsicElements {
|
|
7
|
-
node: NodeProps;
|
|
8
|
-
view: NodeProps;
|
|
9
|
-
text: TextProps;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface IntrinsicAttributes extends Omit<NodeProps, 'children'> {}
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Index,
|
|
3
|
-
createEffect,
|
|
4
|
-
createMemo,
|
|
5
|
-
createSignal,
|
|
6
|
-
splitProps,
|
|
7
|
-
Show,
|
|
8
|
-
type JSX,
|
|
9
|
-
type ValidComponent,
|
|
10
|
-
} from 'solid-js';
|
|
11
|
-
import { Dynamic, type ElementNode } from '@lightningtv/solid';
|
|
12
|
-
|
|
13
|
-
export function LazyUp<T extends readonly any[], U extends JSX.Element>(
|
|
14
|
-
props: T &
|
|
15
|
-
ElementNode & {
|
|
16
|
-
each: T | undefined | null | false;
|
|
17
|
-
fallback?: JSX.Element;
|
|
18
|
-
container?: JSX.Element;
|
|
19
|
-
component?: ValidComponent;
|
|
20
|
-
direction?: 'row' | 'column';
|
|
21
|
-
upCount: number;
|
|
22
|
-
children: (item: T[number], index: number) => U;
|
|
23
|
-
},
|
|
24
|
-
) {
|
|
25
|
-
const [p, others] = splitProps(props, [
|
|
26
|
-
'component',
|
|
27
|
-
'each',
|
|
28
|
-
'fallback',
|
|
29
|
-
'children',
|
|
30
|
-
]);
|
|
31
|
-
|
|
32
|
-
const [offset, setOffset] = createSignal(0);
|
|
33
|
-
|
|
34
|
-
createEffect(() => {
|
|
35
|
-
setOffset(props.selected || 0);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
const items = createMemo(() => {
|
|
39
|
-
if (p.each) {
|
|
40
|
-
return p.each.slice(0, props.upCount + offset());
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
console.log('LazyUp is deprecated. Please use LazyRow or LazyColumn instead.');
|
|
45
|
-
|
|
46
|
-
const isRow = createMemo(() => {
|
|
47
|
-
return (
|
|
48
|
-
others.direction !== undefined && others.direction === 'row' ||
|
|
49
|
-
others.style?.flexDirection === 'row' ||
|
|
50
|
-
others.flexDirection === 'row'
|
|
51
|
-
);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
const keyHandlers = createMemo(() => {
|
|
55
|
-
const updateOffset = () => {
|
|
56
|
-
setOffset(
|
|
57
|
-
(prev) => p.each && Math.min(prev + 1, p.each.length - props.upCount),
|
|
58
|
-
);
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
return isRow() ? { onRight: updateOffset } : { onDown: updateOffset };
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
return (
|
|
65
|
-
<Show when={items()}>
|
|
66
|
-
<Dynamic component={p.component} {...others} {...keyHandlers()}>
|
|
67
|
-
<Index each={items()} fallback={p.fallback} children={p.children} />
|
|
68
|
-
</Dynamic>
|
|
69
|
-
</Show>
|
|
70
|
-
);
|
|
71
|
-
}
|