@lightningtv/solid 3.1.18 → 3.2.1

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.
@@ -3,7 +3,7 @@ import { createSignal } from 'solid-js';
3
3
 
4
4
  const fpsStyle = {
5
5
  color: 0x000000ff,
6
- height: 192,
6
+ height: 216,
7
7
  width: 330,
8
8
  x: 1900,
9
9
  y: 6,
@@ -34,6 +34,12 @@ const [renderableMemUsedSignal, setRenderableMemUsedSignal] = createSignal('');
34
34
  const [memUsedSignal, setMemUsedSignal] = createSignal('');
35
35
  const [renderableTexturesLoadedSignal, setRenderableTexturesLoadedSignal] = createSignal(0);
36
36
  const [loadedTexturesSignal, setLoadedTexturesSignal] = createSignal(0);
37
+ const [renderOps, setRenderOps] = createSignal(0);
38
+
39
+ interface RenderUpdatePayload {
40
+ quads: number;
41
+ renderOps: number;
42
+ }
37
43
 
38
44
  let count = 0;
39
45
  let totalFps = 0;
@@ -88,8 +94,9 @@ export function setupFPS(root: any) {
88
94
  }
89
95
  });
90
96
 
91
- root.renderer.on('quadsUpdate', (target: RendererMain, quadsData: any) => {
97
+ root.renderer.on('renderUpdate', (target: RendererMain, quadsData: RenderUpdatePayload) => {
92
98
  setQuads(quadsData.quads);
99
+ setRenderOps(quadsData.renderOps);
93
100
  });
94
101
  }
95
102
 
@@ -163,30 +170,39 @@ export const FPSCounter = (props: NodeProps) => {
163
170
 
164
171
  <view height={infoFontSize}>
165
172
  <text fontSize={infoFontSize} style={fpsLabel}>
166
- renderableTexturesLoaded:
173
+ Textures In Memory:
167
174
  </text>
168
175
  <text fontSize={infoFontSize} style={fpsLabel} x={230}>
169
- {renderableTexturesLoadedSignal().toString()}
176
+ {loadedTexturesSignal().toString()}
170
177
  </text>
171
178
  </view>
172
179
 
173
180
  <view height={infoFontSize}>
174
181
  <text fontSize={infoFontSize} style={fpsLabel}>
175
- loadedTextures:
182
+ Textures On Screen:
176
183
  </text>
177
184
  <text fontSize={infoFontSize} style={fpsLabel} x={230}>
178
- {loadedTexturesSignal().toString()}
185
+ {renderableTexturesLoadedSignal().toString()}
179
186
  </text>
180
187
  </view>
181
188
 
182
189
  <view height={infoFontSize}>
183
190
  <text fontSize={infoFontSize} style={fpsLabel}>
184
- quads:
191
+ Quads:
185
192
  </text>
186
193
  <text fontSize={infoFontSize} style={fpsLabel} x={230}>
187
194
  {quads().toString()}
188
195
  </text>
189
196
  </view>
197
+
198
+ <view height={infoFontSize}>
199
+ <text fontSize={infoFontSize} style={fpsLabel}>
200
+ Draws:
201
+ </text>
202
+ <text fontSize={infoFontSize} style={fpsLabel} x={230}>
203
+ {renderOps().toString()}
204
+ </text>
205
+ </view>
190
206
  </view>
191
207
  </view>
192
208
  );
@@ -8,6 +8,8 @@ export interface KeepAliveElement {
8
8
  owner: s.Owner | null;
9
9
  children: s.JSX.Element;
10
10
  routeSignal?: s.Signal<unknown>;
11
+ isAlive?: s.Accessor<boolean>;
12
+ setIsAlive?: (v: boolean) => void;
11
13
  dispose: () => void;
12
14
  }
13
15
 
@@ -18,11 +20,10 @@ const _storeKeepAlive = (
18
20
  map: Map<string, KeepAliveElement>,
19
21
  element: KeepAliveElement,
20
22
  ): KeepAliveElement | undefined => {
21
- if (map.has(element.id)) {
22
- console.warn(
23
- `[KeepAlive] Element with id "${element.id}" already in cache.`,
24
- );
25
- return element;
23
+ const existing = map.get(element.id);
24
+ if (existing) {
25
+ Object.assign(existing, element);
26
+ return existing;
26
27
  }
27
28
  map.set(element.id, element);
28
29
  return element;
@@ -70,27 +71,34 @@ interface KeepAliveProps {
70
71
  transition?: ElementNode['transition'];
71
72
  }
72
73
 
73
- function wrapChildren(props: s.ParentProps<KeepAliveProps>) {
74
- const onRemove =
74
+ function wrapChildren(
75
+ props: s.ParentProps<KeepAliveProps>,
76
+ setIsAlive?: (v: boolean) => void,
77
+ ) {
78
+ const onRemove = chainFunctions(
75
79
  props.onRemove ||
76
- ((elm: ElementNode) => {
77
- elm.alpha = 0;
78
- });
79
- const onRender =
80
+ ((elm: ElementNode) => {
81
+ elm.alpha = 0;
82
+ }),
83
+ () => setIsAlive?.(false),
84
+ );
85
+ const onRender = chainFunctions(
80
86
  props.onRender ||
81
- ((elm: ElementNode) => {
82
- elm.alpha = 1;
83
- });
87
+ ((elm: ElementNode) => {
88
+ elm.alpha = 1;
89
+ }),
90
+ () => setIsAlive?.(true),
91
+ );
84
92
  const transition = props.transition || { alpha: true };
85
93
 
86
94
  return (
87
95
  <view
96
+ {...props}
88
97
  preserve
89
98
  onRemove={onRemove}
90
99
  onRender={onRender}
91
100
  forwardFocus={0}
92
101
  transition={transition}
93
- {...props}
94
102
  />
95
103
  );
96
104
  }
@@ -108,25 +116,31 @@ const createKeepAliveComponent = (
108
116
  (existing.children as unknown as ElementNode)?.destroyed)
109
117
  ) {
110
118
  (existing.children as unknown as ElementNode).destroy();
111
- existing.dispose();
119
+ existing.dispose?.();
112
120
  map.delete(props.id);
113
121
  existing = undefined;
114
122
  }
115
123
 
116
- if (!existing) {
124
+ if (!existing || !existing.dispose) {
117
125
  return s.createRoot((dispose) => {
118
- const children = wrapChildren(props);
126
+ const [isAlive, setIsAlive] =
127
+ existing?.isAlive && existing?.setIsAlive
128
+ ? [existing.isAlive, existing.setIsAlive]
129
+ : s.createSignal(true);
130
+ const children = wrapChildren(props, setIsAlive);
119
131
  storeFn({
120
132
  id: props.id,
121
133
  owner: s.getOwner(),
122
134
  children,
123
135
  dispose,
136
+ isAlive,
137
+ setIsAlive,
124
138
  });
125
139
  return children;
126
140
  });
127
141
  } else if (existing && !existing.children) {
128
142
  existing.children = s.runWithOwner(existing.owner, () =>
129
- wrapChildren(props),
143
+ wrapChildren(props, existing!.setIsAlive),
130
144
  );
131
145
  }
132
146
  return existing.children;
@@ -146,16 +160,32 @@ export const KeepAliveRoute = <S extends string>(
146
160
  props: RouteProps<S> & {
147
161
  id?: string;
148
162
  path: string;
149
- component: s.Component<RouteProps<S>>;
163
+ component: (
164
+ props: RouteProps<S> & { isAlive: s.Accessor<boolean> },
165
+ ) => s.JSX.Element;
150
166
  shouldDispose?: (key: string) => boolean;
151
167
  onRemove?: ElementNode['onRemove'];
152
168
  onRender?: ElementNode['onRender'];
153
169
  transition?: ElementNode['transition'];
170
+ preload?: (
171
+ args: RoutePreloadFuncArgs & { isAlive: s.Accessor<boolean> },
172
+ ) => void;
154
173
  },
155
174
  ) => {
156
175
  const key = props.id || props.path;
157
176
  let savedFocusedElement: ElementNode | undefined;
158
177
 
178
+ let existing = keepAliveRouteElements.get(key);
179
+ if (!existing) {
180
+ const [isAlive, setIsAlive] = s.createSignal(true);
181
+ keepAliveRouteElements.set(key, {
182
+ id: key,
183
+ isAlive,
184
+ setIsAlive,
185
+ } as any);
186
+ existing = keepAliveRouteElements.get(key);
187
+ }
188
+
159
189
  const onRemove = chainFunctions(props.onRemove, (elm: ElementNode) => {
160
190
  savedFocusedElement = activeElement() as ElementNode;
161
191
  elm.alpha = 0;
@@ -186,27 +216,40 @@ export const KeepAliveRoute = <S extends string>(
186
216
 
187
217
  if (
188
218
  existing &&
219
+ existing.children &&
189
220
  (props.shouldDispose?.(key) ||
190
221
  (existing.children as unknown as ElementNode)?.destroyed)
191
222
  ) {
192
223
  (existing.children as unknown as ElementNode).destroy();
193
- existing.dispose();
224
+ existing.dispose?.();
194
225
  keepAliveRouteElements.delete(key);
195
226
  existing = undefined;
196
227
  }
197
228
 
198
- if (!existing) {
229
+ if (!existing || !existing.dispose) {
199
230
  return s.createRoot((dispose) => {
231
+ const [isAlive, setIsAlive] =
232
+ existing?.isAlive && existing?.setIsAlive
233
+ ? [existing.isAlive, existing.setIsAlive]
234
+ : s.createSignal(true);
200
235
  storeKeepAliveRoute({
201
236
  id: key,
202
237
  owner: s.getOwner(),
203
238
  dispose,
204
239
  children: null,
240
+ isAlive,
241
+ setIsAlive,
205
242
  });
206
- return props.preload!(preloadProps);
243
+ return props.preload!({ ...preloadProps, isAlive });
207
244
  });
208
245
  } else if (existing.children) {
209
246
  (existing.children as unknown as ElementNode)?.setFocus();
247
+ return props.preload!({ ...preloadProps, isAlive: existing.isAlive! });
248
+ } else {
249
+ return props.preload!({
250
+ ...preloadProps,
251
+ isAlive: existing.isAlive!,
252
+ });
210
253
  }
211
254
  }
212
255
  : undefined;
@@ -215,16 +258,19 @@ export const KeepAliveRoute = <S extends string>(
215
258
  <Route
216
259
  {...props}
217
260
  preload={preload}
218
- component={(childProps) => (
219
- <KeepAliveRouteInternal
220
- id={key}
221
- onRemove={onRemove}
222
- onRender={onRender}
223
- transition={props.transition}
224
- >
225
- {props.component(childProps)}
226
- </KeepAliveRouteInternal>
227
- )}
261
+ component={(childProps) => {
262
+ const existing = keepAliveRouteElements.get(key)!;
263
+ return (
264
+ <KeepAliveRouteInternal
265
+ id={key}
266
+ onRemove={onRemove}
267
+ onRender={onRender}
268
+ transition={props.transition}
269
+ >
270
+ {props.component({ ...childProps, isAlive: existing.isAlive! })}
271
+ </KeepAliveRouteInternal>
272
+ );
273
+ }}
228
274
  />
229
275
  );
230
276
  };
@@ -1,35 +0,0 @@
1
- import { type ElementNode, LightningRendererNumberProps } from './elementNode.js';
2
- import { TimingFunction } from '@lightningjs/renderer';
3
- import { IRendererStage } from './dom-renderer/domRendererTypes.js';
4
- /**
5
- * Simplified Animation Settings
6
- */
7
- export interface SimpleAnimationSettings {
8
- duration?: number;
9
- delay?: number;
10
- easing?: string | TimingFunction;
11
- }
12
- /**
13
- * Properties of a Node used by the SimpleAnimation
14
- * (Excludes shaderProps)
15
- */
16
- export type SimpleAnimationProps = (typeof LightningRendererNumberProps)[number];
17
- export declare class SimpleAnimation {
18
- private nodeConfigs;
19
- private isRegistered;
20
- private stage;
21
- register(stage: IRendererStage): void;
22
- /**
23
- * Adds a node and its animation properties to this animation instance.
24
- * The animation's start values for the specified properties are captured
25
- * from the node's current state when this method is called.
26
- *
27
- * @param node - The CoreNode to animate.
28
- * @param props - The properties to animate and their target values. Only number properties are supported.
29
- * @param settings - Animation settings for this specific node animation.
30
- */
31
- add(node: ElementNode, key: SimpleAnimationProps, value: number, settings: SimpleAnimationSettings): void;
32
- update(dt: number): void;
33
- }
34
- export declare const simpleAnimation: SimpleAnimation;
35
- export default simpleAnimation;
@@ -1,119 +0,0 @@
1
- import { getTimingFunction, mergeColorProgress, } from '@lightningjs/renderer/utils';
2
- import { isFunc } from './utils.js';
3
- export class SimpleAnimation {
4
- nodeConfigs = [];
5
- isRegistered = false;
6
- stage;
7
- register(stage) {
8
- if (this.isRegistered) {
9
- return;
10
- }
11
- this.isRegistered = true;
12
- this.stage = stage;
13
- stage.animationManager.registerAnimation(this);
14
- }
15
- /**
16
- * Adds a node and its animation properties to this animation instance.
17
- * The animation's start values for the specified properties are captured
18
- * from the node's current state when this method is called.
19
- *
20
- * @param node - The CoreNode to animate.
21
- * @param props - The properties to animate and their target values. Only number properties are supported.
22
- * @param settings - Animation settings for this specific node animation.
23
- */
24
- add(node, key, value, settings) {
25
- const existingConfig = this.nodeConfigs.find((config) => config.node === node && config.propName === key);
26
- const duration = settings.duration ?? 0;
27
- const delay = settings.delay ?? 0;
28
- const easing = settings.easing || 'linear';
29
- const timingFunction = isFunc(easing) ? easing : getTimingFunction(easing);
30
- const targetValue = value;
31
- const startValue = node[key];
32
- if (existingConfig) {
33
- existingConfig.duration = duration;
34
- existingConfig.delay = delay;
35
- existingConfig.easing = easing;
36
- existingConfig.timingFunction = timingFunction;
37
- existingConfig.targetValue = targetValue;
38
- existingConfig.startValue = startValue;
39
- existingConfig.progress = 0;
40
- existingConfig.delayFor = delay;
41
- }
42
- else {
43
- this.nodeConfigs.push({
44
- node,
45
- duration,
46
- delay,
47
- easing,
48
- progress: 0,
49
- delayFor: delay,
50
- timingFunction,
51
- propName: key,
52
- startValue,
53
- targetValue,
54
- });
55
- }
56
- }
57
- update(dt) {
58
- // Iterate backward to safely remove finished animations
59
- for (let i = this.nodeConfigs.length - 1; i >= 0; i--) {
60
- const nodeConfig = this.nodeConfigs[i];
61
- const { node, duration, timingFunction, propName, startValue, targetValue, } = nodeConfig;
62
- let remainingDt = dt;
63
- // 1. Handle Delay
64
- if (nodeConfig.delayFor > 0) {
65
- nodeConfig.delayFor -= remainingDt;
66
- if (nodeConfig.delayFor >= 0) {
67
- // Still in delay phase for this node, skip applying values this frame
68
- continue;
69
- }
70
- else {
71
- // Delay finished this frame, use the remaining time for animation
72
- remainingDt = -nodeConfig.delayFor;
73
- nodeConfig.delayFor = 0;
74
- }
75
- }
76
- // 2. Update Progress (directly on nodeConfig.progress)
77
- if (duration > 0) {
78
- nodeConfig.progress += remainingDt / duration;
79
- // Clamp progress between 0 and 1
80
- nodeConfig.progress = Math.max(0, Math.min(1, nodeConfig.progress));
81
- }
82
- else if (duration === 0 && nodeConfig.delayFor <= 0) {
83
- // Duration is 0 and delay is finished or was 0. Animation completes instantly.
84
- nodeConfig.progress = 1;
85
- }
86
- // 3. Calculate Eased Progress
87
- const easedProgress = timingFunction(nodeConfig.progress) || nodeConfig.progress;
88
- // 4. Apply Animated Values to the Node
89
- let interpolatedValue;
90
- if (nodeConfig.progress === 1) {
91
- interpolatedValue = targetValue;
92
- }
93
- else {
94
- if (propName.includes('color')) {
95
- // Handle color interpolation
96
- interpolatedValue = mergeColorProgress(startValue, targetValue, easedProgress);
97
- }
98
- else {
99
- // Handle linear interpolation for other number properties
100
- interpolatedValue =
101
- startValue + (targetValue - startValue) * easedProgress;
102
- }
103
- }
104
- // @typescript-eslint/no-explicit-any
105
- node.lng[propName] = interpolatedValue; // Cast to any because the properties on CoreNode might have broader types.
106
- // 5. Remove Node if Progress is 1
107
- if (nodeConfig.progress === 1) {
108
- this.nodeConfigs.splice(i, 1);
109
- }
110
- if (this.nodeConfigs.length === 0) {
111
- this.stage?.animationManager.unregisterAnimation(this);
112
- this.isRegistered = false;
113
- }
114
- }
115
- }
116
- }
117
- export const simpleAnimation = new SimpleAnimation();
118
- export default simpleAnimation;
119
- //# sourceMappingURL=animation.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"animation.js","sourceRoot":"","sources":["../../../src/core/animation.ts"],"names":[],"mappings":"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"}
@@ -1,188 +0,0 @@
1
- import {
2
- getTimingFunction,
3
- mergeColorProgress,
4
- } from '@lightningjs/renderer/utils';
5
- import {
6
- type ElementNode,
7
- LightningRendererNumberProps,
8
- } from './elementNode.js';
9
- import { TimingFunction } from '@lightningjs/renderer';
10
- import { isFunc } from './utils.js';
11
- import { IRendererStage } from './dom-renderer/domRendererTypes.js';
12
- import { CoreAnimation } from './intrinsicTypes.js';
13
-
14
- /**
15
- * Simplified Animation Settings
16
- */
17
- export interface SimpleAnimationSettings {
18
- duration?: number;
19
- delay?: number;
20
- easing?: string | TimingFunction;
21
- }
22
-
23
- /**
24
- * Properties of a Node used by the SimpleAnimation
25
- * (Excludes shaderProps)
26
- */
27
- export type SimpleAnimationProps =
28
- (typeof LightningRendererNumberProps)[number];
29
-
30
- /**
31
- * Configuration for a single node within a SimpleAnimation
32
- */
33
- interface SimpleAnimationNodeConfig {
34
- node: ElementNode;
35
- duration: number;
36
- delay: number;
37
- easing: string | TimingFunction;
38
- progress: number;
39
- delayFor: number;
40
- timingFunction: (t: number) => number | undefined;
41
- propName: SimpleAnimationProps;
42
- startValue: number;
43
- targetValue: number;
44
- }
45
-
46
- export class SimpleAnimation {
47
- private nodeConfigs: SimpleAnimationNodeConfig[] = [];
48
- private isRegistered = false;
49
- private stage: IRendererStage | undefined;
50
-
51
- register(stage: IRendererStage) {
52
- if (this.isRegistered) {
53
- return;
54
- }
55
- this.isRegistered = true;
56
- this.stage = stage;
57
- stage.animationManager.registerAnimation(this as unknown as CoreAnimation);
58
- }
59
-
60
- /**
61
- * Adds a node and its animation properties to this animation instance.
62
- * The animation's start values for the specified properties are captured
63
- * from the node's current state when this method is called.
64
- *
65
- * @param node - The CoreNode to animate.
66
- * @param props - The properties to animate and their target values. Only number properties are supported.
67
- * @param settings - Animation settings for this specific node animation.
68
- */
69
- add(
70
- node: ElementNode,
71
- key: SimpleAnimationProps,
72
- value: number,
73
- settings: SimpleAnimationSettings,
74
- ): void {
75
- const existingConfig = this.nodeConfigs.find(
76
- (config) => config.node === node && config.propName === key,
77
- );
78
-
79
- const duration = settings.duration ?? 0;
80
- const delay = settings.delay ?? 0;
81
- const easing = settings.easing || 'linear';
82
- const timingFunction = isFunc(easing) ? easing : getTimingFunction(easing);
83
- const targetValue = value;
84
- const startValue = node[key] as number;
85
-
86
- if (existingConfig) {
87
- existingConfig.duration = duration;
88
- existingConfig.delay = delay;
89
- existingConfig.easing = easing;
90
- existingConfig.timingFunction = timingFunction;
91
- existingConfig.targetValue = targetValue;
92
- existingConfig.startValue = startValue;
93
- existingConfig.progress = 0;
94
- existingConfig.delayFor = delay;
95
- } else {
96
- this.nodeConfigs.push({
97
- node,
98
- duration,
99
- delay,
100
- easing,
101
- progress: 0,
102
- delayFor: delay,
103
- timingFunction,
104
- propName: key,
105
- startValue,
106
- targetValue,
107
- });
108
- }
109
- }
110
-
111
- update(dt: number) {
112
- // Iterate backward to safely remove finished animations
113
- for (let i = this.nodeConfigs.length - 1; i >= 0; i--) {
114
- const nodeConfig = this.nodeConfigs[i] as SimpleAnimationNodeConfig;
115
- const {
116
- node,
117
- duration,
118
- timingFunction,
119
- propName,
120
- startValue,
121
- targetValue,
122
- } = nodeConfig;
123
- let remainingDt = dt;
124
-
125
- // 1. Handle Delay
126
- if (nodeConfig.delayFor > 0) {
127
- nodeConfig.delayFor -= remainingDt;
128
- if (nodeConfig.delayFor >= 0) {
129
- // Still in delay phase for this node, skip applying values this frame
130
- continue;
131
- } else {
132
- // Delay finished this frame, use the remaining time for animation
133
- remainingDt = -nodeConfig.delayFor;
134
- nodeConfig.delayFor = 0;
135
- }
136
- }
137
-
138
- // 2. Update Progress (directly on nodeConfig.progress)
139
- if (duration > 0) {
140
- nodeConfig.progress += remainingDt / duration;
141
- // Clamp progress between 0 and 1
142
- nodeConfig.progress = Math.max(0, Math.min(1, nodeConfig.progress));
143
- } else if (duration === 0 && nodeConfig.delayFor <= 0) {
144
- // Duration is 0 and delay is finished or was 0. Animation completes instantly.
145
- nodeConfig.progress = 1;
146
- }
147
-
148
- // 3. Calculate Eased Progress
149
- const easedProgress =
150
- timingFunction(nodeConfig.progress) || nodeConfig.progress;
151
-
152
- // 4. Apply Animated Values to the Node
153
- let interpolatedValue: number;
154
- if (nodeConfig.progress === 1) {
155
- interpolatedValue = targetValue;
156
- } else {
157
- if (propName.includes('color')) {
158
- // Handle color interpolation
159
- interpolatedValue = mergeColorProgress(
160
- startValue,
161
- targetValue,
162
- easedProgress,
163
- );
164
- } else {
165
- // Handle linear interpolation for other number properties
166
- interpolatedValue =
167
- startValue + (targetValue - startValue) * easedProgress;
168
- }
169
- }
170
- // @typescript-eslint/no-explicit-any
171
- (node.lng as any)[propName] = interpolatedValue; // Cast to any because the properties on CoreNode might have broader types.
172
-
173
- // 5. Remove Node if Progress is 1
174
- if (nodeConfig.progress === 1) {
175
- this.nodeConfigs.splice(i, 1);
176
- }
177
- if (this.nodeConfigs.length === 0) {
178
- this.stage?.animationManager.unregisterAnimation(
179
- this as unknown as CoreAnimation,
180
- );
181
- this.isRegistered = false;
182
- }
183
- }
184
- }
185
- }
186
-
187
- export const simpleAnimation = new SimpleAnimation();
188
- export default simpleAnimation;