@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.
Files changed (55) hide show
  1. package/dist/src/devtools/index.d.ts +6 -0
  2. package/dist/src/devtools/index.js +65 -0
  3. package/dist/src/devtools/index.js.map +1 -0
  4. package/dist/src/index.d.ts +1 -1
  5. package/dist/src/index.js +1 -1
  6. package/dist/src/index.js.map +1 -1
  7. package/dist/src/jsx-runtime.d.ts +2 -2
  8. package/dist/src/primitives/Column.jsx +2 -2
  9. package/dist/src/primitives/Column.jsx.map +1 -1
  10. package/dist/src/primitives/FPSCounter.jsx +60 -61
  11. package/dist/src/primitives/FPSCounter.jsx.map +1 -1
  12. package/dist/src/primitives/FadeInOut.d.ts +10 -0
  13. package/dist/src/primitives/FadeInOut.jsx +22 -0
  14. package/dist/src/primitives/FadeInOut.jsx.map +1 -0
  15. package/dist/src/primitives/Grid.jsx +3 -3
  16. package/dist/src/primitives/Grid.jsx.map +1 -1
  17. package/dist/src/primitives/Lazy.d.ts +4 -5
  18. package/dist/src/primitives/Lazy.jsx +12 -5
  19. package/dist/src/primitives/Lazy.jsx.map +1 -1
  20. package/dist/src/primitives/LazyUp.jsx +1 -0
  21. package/dist/src/primitives/LazyUp.jsx.map +1 -1
  22. package/dist/src/primitives/Row.jsx +2 -2
  23. package/dist/src/primitives/Row.jsx.map +1 -1
  24. package/dist/src/primitives/index.d.ts +1 -1
  25. package/dist/src/primitives/index.js +1 -1
  26. package/dist/src/primitives/index.js.map +1 -1
  27. package/dist/src/primitives/utils/createSpriteMap.d.ts +2 -2
  28. package/dist/src/primitives/utils/createSpriteMap.js.map +1 -1
  29. package/dist/src/primitives/utils/withScrolling.js +1 -1
  30. package/dist/src/primitives/utils/withScrolling.js.map +1 -1
  31. package/dist/src/render.d.ts +2 -2
  32. package/dist/src/render.js +8 -6
  33. package/dist/src/render.js.map +1 -1
  34. package/dist/src/solidOpts.d.ts +6 -0
  35. package/dist/src/solidOpts.js +23 -7
  36. package/dist/src/solidOpts.js.map +1 -1
  37. package/dist/tsconfig.tsbuildinfo +1 -1
  38. package/jsx-runtime.d.ts +16 -0
  39. package/package.json +26 -11
  40. package/src/devtools/index.ts +77 -0
  41. package/src/index.ts +1 -1
  42. package/src/primitives/Column.tsx +2 -2
  43. package/src/primitives/FPSCounter.tsx +61 -61
  44. package/src/primitives/FadeInOut.tsx +34 -0
  45. package/src/primitives/Grid.tsx +3 -3
  46. package/src/primitives/Lazy.tsx +21 -12
  47. package/src/primitives/Row.tsx +1 -1
  48. package/src/primitives/index.ts +1 -1
  49. package/src/primitives/utils/createSpriteMap.ts +3 -5
  50. package/src/primitives/utils/withScrolling.ts +4 -3
  51. package/src/render.ts +10 -7
  52. package/src/solidOpts.ts +36 -7
  53. package/src/jsx-runtime.ts +0 -14
  54. package/src/primitives/LazyUp.tsx +0 -71
  55. 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,4 +1,4 @@
1
- import './jsx-runtime.js';
1
+ export * from '@lightningtv/solid/jsx-runtime';
2
2
  export * from '@lightningtv/core';
3
3
  export type * from '@lightningtv/core';
4
4
  export type { KeyHandler, KeyMap } from '@lightningtv/core/focusManager';
@@ -1,5 +1,5 @@
1
1
  import { type Component } from 'solid-js';
2
- import { ElementNode, View, combineStyles, type NodeStyles } from '@lightningtv/solid';
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
- <View
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 { View, Text, type Stage, type NodeProps, RendererMain } from '@lightningtv/solid';
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
- <View {...props} style={fpsStyle}>
94
- <View y={6}>
95
- <Text style={fpsLabel}>FPS:</Text>
96
- <Text style={fpsValue} x={90}>
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
- </Text>
99
- </View>
98
+ </text>
99
+ </view>
100
100
 
101
- <View y={6} x={160}>
102
- <Text style={fpsLabel}>AVG:</Text>
103
- <Text style={fpsValue} x={100}>
101
+ <view y={6} x={160}>
102
+ <text style={fpsLabel}>AVG:</text>
103
+ <text style={fpsValue} x={100}>
104
104
  {avgFps().toString()}
105
- </Text>
106
- </View>
105
+ </text>
106
+ </view>
107
107
 
108
- <View x={0} y={26}>
109
- <Text style={fpsLabel}>MIN:</Text>
110
- <Text style={fpsValue} x={90}>
108
+ <view x={0} y={26}>
109
+ <text style={fpsLabel}>MIN:</text>
110
+ <text style={fpsValue} x={90}>
111
111
  {minFps().toString()}
112
- </Text>
113
- </View>
112
+ </text>
113
+ </view>
114
114
 
115
- <View x={160} y={26}>
116
- <Text style={fpsLabel}>MAX:</Text>
117
- <Text style={fpsValue} x={100}>
115
+ <view x={160} y={26}>
116
+ <text style={fpsLabel}>MAX:</text>
117
+ <text style={fpsValue} x={100}>
118
118
  {maxFps().toString()}
119
- </Text>
120
- </View>
119
+ </text>
120
+ </view>
121
121
 
122
- <View display="flex" flexDirection="column" y={58} gap={4}>
123
- <View height={infoFontSize}>
124
- <Text fontSize={infoFontSize} style={fpsLabel}>
122
+ <view display="flex" flexDirection="column" y={58} gap={4}>
123
+ <view height={infoFontSize}>
124
+ <text fontSize={infoFontSize} style={fpsLabel}>
125
125
  criticalThreshold:
126
- </Text>
127
- <Text fontSize={infoFontSize} style={fpsLabel} x={230}>
126
+ </text>
127
+ <text fontSize={infoFontSize} style={fpsLabel} x={230}>
128
128
  {criticalThresholdSignal()}
129
- </Text>
130
- </View>
129
+ </text>
130
+ </view>
131
131
 
132
- <View height={infoFontSize}>
133
- <Text fontSize={infoFontSize} style={fpsLabel}>
132
+ <view height={infoFontSize}>
133
+ <text fontSize={infoFontSize} style={fpsLabel}>
134
134
  targetThreshold:
135
- </Text>
136
- <Text fontSize={infoFontSize} style={fpsLabel} x={230}>
135
+ </text>
136
+ <text fontSize={infoFontSize} style={fpsLabel} x={230}>
137
137
  {targetThresholdSignal()}
138
- </Text>
139
- </View>
138
+ </text>
139
+ </view>
140
140
 
141
- <View height={infoFontSize}>
142
- <Text fontSize={infoFontSize} style={fpsLabel}>
141
+ <view height={infoFontSize}>
142
+ <text fontSize={infoFontSize} style={fpsLabel}>
143
143
  renderableMemUsed:
144
- </Text>
145
- <Text fontSize={infoFontSize} style={fpsLabel} x={230}>
144
+ </text>
145
+ <text fontSize={infoFontSize} style={fpsLabel} x={230}>
146
146
  {renderableMemUsedSignal()}
147
- </Text>
148
- </View>
147
+ </text>
148
+ </view>
149
149
 
150
- <View height={infoFontSize}>
151
- <Text fontSize={infoFontSize} style={fpsLabel}>
150
+ <view height={infoFontSize}>
151
+ <text fontSize={infoFontSize} style={fpsLabel}>
152
152
  memUsed:
153
- </Text>
154
- <Text fontSize={infoFontSize} style={fpsLabel} x={230}>
153
+ </text>
154
+ <text fontSize={infoFontSize} style={fpsLabel} x={230}>
155
155
  {memUsedSignal()}
156
- </Text>
157
- </View>
156
+ </text>
157
+ </view>
158
158
 
159
- <View height={infoFontSize}>
160
- <Text fontSize={infoFontSize} style={fpsLabel}>
159
+ <view height={infoFontSize}>
160
+ <text fontSize={infoFontSize} style={fpsLabel}>
161
161
  renderableTexturesLoaded:
162
- </Text>
163
- <Text fontSize={infoFontSize} style={fpsLabel} x={230}>
162
+ </text>
163
+ <text fontSize={infoFontSize} style={fpsLabel} x={230}>
164
164
  {renderableTexturesLoadedSignal().toString()}
165
- </Text>
166
- </View>
165
+ </text>
166
+ </view>
167
167
 
168
- <View height={infoFontSize}>
169
- <Text fontSize={infoFontSize} style={fpsLabel}>
168
+ <view height={infoFontSize}>
169
+ <text fontSize={infoFontSize} style={fpsLabel}>
170
170
  loadedTextures:
171
- </Text>
172
- <Text fontSize={infoFontSize} style={fpsLabel} x={230}>
171
+ </text>
172
+ <text fontSize={infoFontSize} style={fpsLabel} x={230}>
173
173
  {loadedTexturesSignal().toString()}
174
- </Text>
175
- </View>
176
- </View>
177
- </View>
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
+ }
@@ -1,5 +1,5 @@
1
1
  import { ValidComponent, For, createSignal, createMemo } from "solid-js";
2
- import { View, Dynamic, type NodeProps, type ElementNode, isFunction } from "@lightningtv/solid";
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
- <View
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
- </View>
98
+ </view>
99
99
  );
100
100
  };
101
101
 
@@ -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[]> = Omit<NodeProps, 'children'> & {
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
- selected?: number;
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 extends readonly any[]>(
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() > maxOffset) return;
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() > maxOffset) return;
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;
@@ -31,7 +31,7 @@ function scrollToIndex(this: ElementNode, index: number) {
31
31
 
32
32
  export const Row: Component<RowProps> = (props) => {
33
33
  return (
34
- <View
34
+ <view
35
35
  {...props}
36
36
  selected={props.selected || 0}
37
37
  onLeft={/* @once */ chainFunctions(props.onLeft, onLeft)}
@@ -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 { renderer, type TextureMap } from '@lightningtv/core';
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, InstanceType<TextureMap['SubTexture']>> {
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 = isIncrementing
76
- ? Math.min(targetPosition, componentRef[axis])
77
- : Math.max(targetPosition, componentRef[axis]);
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: RendererMain;
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
- createRenderEffect(() => {
75
- // should change whenever a keypress occurs, so we disable the task queue
76
- // until the renderer is idle again.
77
- activeElement();
78
- tasksEnabled = false;
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
- parent.rendered && node.render(true);
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
- node._queueDelete = true;
80
+
50
81
  if (node instanceof ElementNode) {
51
- // Solid replacesNodes to move them (via insert and remove),
52
- // so we need to wait for the next microtask to destroy the node
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 {
@@ -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
- }
@@ -1,8 +0,0 @@
1
- import 'solid-js';
2
- declare module 'solid-js' {
3
- namespace JSX {
4
- interface Directives {
5
- model: [() => any, (v: any) => any];
6
- }
7
- }
8
- }