@lightningtv/solid 3.0.0-9 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +6 -0
- package/dist/jsx-runtime.d.ts +14 -0
- package/dist/src/activeElement.d.ts +1 -1
- package/dist/src/core/animation.d.ts +35 -0
- package/dist/src/core/animation.js +119 -0
- package/dist/src/core/animation.js.map +1 -0
- package/dist/src/core/config.d.ts +49 -0
- package/dist/src/core/config.js +33 -0
- package/dist/src/core/config.js.map +1 -0
- package/dist/src/core/domRenderer.d.ts +115 -0
- package/dist/src/core/domRenderer.js +1152 -0
- package/dist/src/core/domRenderer.js.map +1 -0
- package/dist/src/core/elementNode.d.ts +463 -0
- package/dist/src/core/elementNode.js +833 -0
- package/dist/src/core/elementNode.js.map +1 -0
- package/dist/src/core/flex.d.ts +2 -0
- package/dist/src/core/flex.js +243 -0
- package/dist/src/core/flex.js.map +1 -0
- package/dist/src/core/focusKeyTypes.d.ts +42 -0
- package/dist/src/core/focusKeyTypes.js +2 -0
- package/dist/src/core/focusKeyTypes.js.map +1 -0
- package/dist/src/core/focusManager.d.ts +13 -0
- package/dist/src/core/focusManager.js +276 -0
- package/dist/src/core/focusManager.js.map +1 -0
- package/dist/src/core/index.d.ts +12 -0
- package/dist/src/core/index.js +12 -0
- package/dist/src/core/index.js.map +1 -0
- package/dist/src/core/intrinsicTypes.d.ts +90 -0
- package/dist/src/core/intrinsicTypes.js +2 -0
- package/dist/src/core/intrinsicTypes.js.map +1 -0
- package/dist/src/core/lightningInit.d.ts +89 -0
- package/dist/src/core/lightningInit.js +26 -0
- package/dist/src/core/lightningInit.js.map +1 -0
- package/dist/src/core/nodeTypes.d.ts +6 -0
- package/dist/src/core/nodeTypes.js +6 -0
- package/dist/src/core/nodeTypes.js.map +1 -0
- package/dist/src/core/shaders.d.ts +51 -0
- package/dist/src/core/shaders.js +446 -0
- package/dist/src/core/shaders.js.map +1 -0
- package/dist/src/core/states.d.ts +12 -0
- package/dist/src/core/states.js +84 -0
- package/dist/src/core/states.js.map +1 -0
- package/dist/src/core/utils.d.ts +39 -0
- package/dist/src/core/utils.js +164 -0
- package/dist/src/core/utils.js.map +1 -0
- package/dist/src/devtools/index.d.ts +1 -1
- package/dist/src/devtools/index.js +1 -1
- package/dist/src/devtools/index.js.map +1 -1
- package/dist/src/index.d.ts +3 -3
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/primitives/Column.jsx +9 -10
- package/dist/src/primitives/Column.jsx.map +1 -1
- package/dist/src/primitives/FPSCounter.jsx +15 -2
- package/dist/src/primitives/FPSCounter.jsx.map +1 -1
- package/dist/src/primitives/Image.d.ts +8 -0
- package/dist/src/primitives/Image.jsx +24 -0
- package/dist/src/primitives/Image.jsx.map +1 -0
- package/dist/src/primitives/KeepAlive.d.ts +30 -0
- package/dist/src/primitives/KeepAlive.jsx +77 -0
- package/dist/src/primitives/KeepAlive.jsx.map +1 -0
- package/dist/src/primitives/Lazy.d.ts +8 -7
- package/dist/src/primitives/Lazy.jsx +52 -20
- package/dist/src/primitives/Lazy.jsx.map +1 -1
- package/dist/src/primitives/Preserve.d.ts +4 -0
- package/dist/src/primitives/Preserve.jsx +11 -0
- package/dist/src/primitives/Preserve.jsx.map +1 -0
- package/dist/src/primitives/Row.jsx +9 -10
- package/dist/src/primitives/Row.jsx.map +1 -1
- package/dist/src/primitives/Suspense.d.ts +22 -0
- package/dist/src/primitives/Suspense.jsx +33 -0
- package/dist/src/primitives/Suspense.jsx.map +1 -0
- package/dist/src/primitives/Virtual.d.ts +18 -0
- package/dist/src/primitives/Virtual.jsx +443 -0
- package/dist/src/primitives/Virtual.jsx.map +1 -0
- package/dist/src/primitives/VirtualGrid.d.ts +13 -0
- package/dist/src/primitives/VirtualGrid.jsx +160 -0
- package/dist/src/primitives/VirtualGrid.jsx.map +1 -0
- package/dist/src/primitives/Visible.d.ts +0 -1
- package/dist/src/primitives/Visible.jsx +1 -1
- package/dist/src/primitives/Visible.jsx.map +1 -1
- package/dist/src/primitives/announcer/announcer.d.ts +1 -0
- package/dist/src/primitives/announcer/announcer.js +4 -3
- package/dist/src/primitives/announcer/announcer.js.map +1 -1
- package/dist/src/primitives/announcer/speech.d.ts +1 -1
- package/dist/src/primitives/announcer/speech.js +98 -8
- package/dist/src/primitives/announcer/speech.js.map +1 -1
- package/dist/src/primitives/createFocusStack.d.ts +4 -4
- package/dist/src/primitives/createFocusStack.jsx +15 -6
- package/dist/src/primitives/createFocusStack.jsx.map +1 -1
- package/dist/src/primitives/createTag.d.ts +8 -0
- package/dist/src/primitives/createTag.jsx +20 -0
- package/dist/src/primitives/createTag.jsx.map +1 -0
- package/dist/src/primitives/index.d.ts +12 -4
- package/dist/src/primitives/index.js +11 -3
- package/dist/src/primitives/index.js.map +1 -1
- package/dist/src/primitives/types.d.ts +3 -2
- package/dist/src/primitives/useFocusManager.d.ts +2 -2
- package/dist/src/primitives/useFocusManager.js +2 -2
- package/dist/src/primitives/useFocusManager.js.map +1 -1
- package/dist/src/primitives/useMouse.d.ts +18 -2
- package/dist/src/primitives/useMouse.js +171 -47
- package/dist/src/primitives/useMouse.js.map +1 -1
- package/dist/src/primitives/utils/createBlurredImage.d.ts +56 -0
- package/dist/src/primitives/utils/createBlurredImage.js +223 -0
- package/dist/src/primitives/utils/createBlurredImage.js.map +1 -0
- package/dist/src/primitives/utils/createSpriteMap.d.ts +2 -2
- package/dist/src/primitives/utils/createSpriteMap.js +3 -3
- package/dist/src/primitives/utils/createSpriteMap.js.map +1 -1
- package/dist/src/primitives/utils/handleNavigation.d.ts +79 -5
- package/dist/src/primitives/utils/handleNavigation.js +241 -69
- package/dist/src/primitives/utils/handleNavigation.js.map +1 -1
- package/dist/src/primitives/utils/withScrolling.d.ts +12 -2
- package/dist/src/primitives/utils/withScrolling.js +59 -7
- package/dist/src/primitives/utils/withScrolling.js.map +1 -1
- package/dist/src/render.d.ts +5 -4
- package/dist/src/render.js +5 -1
- package/dist/src/render.js.map +1 -1
- package/dist/src/shaders/Rounded.d.ts +7 -0
- package/dist/src/shaders/Rounded.js +88 -0
- package/dist/src/shaders/Rounded.js.map +1 -0
- package/dist/src/shaders/RoundedWithBorder.d.ts +3 -0
- package/dist/src/shaders/RoundedWithBorder.js +217 -0
- package/dist/src/shaders/RoundedWithBorder.js.map +1 -0
- package/dist/src/shaders/index.d.ts +4 -0
- package/dist/src/shaders/index.js +5 -0
- package/dist/src/shaders/index.js.map +1 -0
- package/dist/src/shaders/templates/RoundedTemplate.d.ts +12 -0
- package/dist/src/shaders/templates/RoundedTemplate.js +48 -0
- package/dist/src/shaders/templates/RoundedTemplate.js.map +1 -0
- package/dist/src/shaders/templates/RoundedWithBorderTemplate.d.ts +20 -0
- package/dist/src/shaders/templates/RoundedWithBorderTemplate.js +93 -0
- package/dist/src/shaders/templates/RoundedWithBorderTemplate.js.map +1 -0
- package/dist/src/shaders/utils.d.ts +3 -0
- package/dist/src/shaders/utils.js +31 -0
- package/dist/src/shaders/utils.js.map +1 -0
- package/dist/src/solidOpts.d.ts +1 -7
- package/dist/src/solidOpts.js +9 -1
- package/dist/src/solidOpts.js.map +1 -1
- package/dist/src/types.d.ts +1 -13
- package/dist/src/utils.d.ts +3 -1
- package/dist/src/utils.js +9 -1
- package/dist/src/utils.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/jsx-runtime.d.ts +1 -1
- package/package.json +28 -16
- package/src/activeElement.ts +1 -1
- package/src/core/animation.ts +185 -0
- package/src/core/config.ts +89 -0
- package/src/core/domRenderer.ts +1300 -0
- package/src/core/elementNode.ts +1458 -0
- package/src/core/flex.ts +284 -0
- package/src/core/focusKeyTypes.ts +90 -0
- package/src/core/focusManager.ts +381 -0
- package/src/core/index.ts +13 -0
- package/src/core/intrinsicTypes.ts +199 -0
- package/src/core/lightningInit.ts +147 -0
- package/src/core/nodeTypes.ts +6 -0
- package/src/core/shaders.ts +567 -0
- package/src/core/states.ts +91 -0
- package/src/core/utils.ts +222 -0
- package/src/devtools/index.ts +1 -1
- package/src/index.ts +3 -3
- package/src/primitives/Column.tsx +10 -12
- package/src/primitives/FPSCounter.tsx +16 -2
- package/src/primitives/Image.tsx +36 -0
- package/src/primitives/KeepAlive.tsx +124 -0
- package/src/primitives/Lazy.tsx +66 -37
- package/src/primitives/Preserve.tsx +18 -0
- package/src/primitives/Row.tsx +13 -14
- package/src/primitives/Suspense.tsx +39 -0
- package/src/primitives/Virtual.tsx +486 -0
- package/src/primitives/VirtualGrid.tsx +220 -0
- package/src/primitives/Visible.tsx +1 -2
- package/src/primitives/announcer/announcer.ts +10 -3
- package/src/primitives/announcer/speech.ts +113 -6
- package/src/primitives/createFocusStack.tsx +18 -7
- package/src/primitives/createTag.tsx +33 -0
- package/src/primitives/index.ts +12 -4
- package/src/primitives/types.ts +3 -2
- package/src/primitives/useFocusManager.ts +3 -3
- package/src/primitives/useMouse.ts +306 -67
- package/src/primitives/utils/createBlurredImage.ts +366 -0
- package/src/primitives/utils/createSpriteMap.ts +8 -6
- package/src/primitives/utils/handleNavigation.ts +300 -84
- package/src/primitives/utils/withScrolling.ts +76 -18
- package/src/render.ts +7 -3
- package/src/shaders/Rounded.ts +100 -0
- package/src/shaders/RoundedWithBorder.ts +245 -0
- package/src/shaders/index.ts +4 -0
- package/src/shaders/templates/RoundedTemplate.ts +57 -0
- package/src/shaders/templates/RoundedWithBorderTemplate.ts +110 -0
- package/src/shaders/utils.ts +44 -0
- package/src/solidOpts.ts +9 -7
- package/src/types.ts +1 -15
- package/src/utils.ts +11 -1
- package/dist/src/client.d.ts +0 -1
- package/dist/src/client.js +0 -2
- package/dist/src/client.js.map +0 -1
- package/dist/src/core.d.ts +0 -1
- package/dist/src/core.js +0 -3
- package/dist/src/core.js.map +0 -1
- package/dist/src/jsx-runtime.d.ts +0 -10
- package/dist/src/jsx-runtime.js +0 -2
- package/dist/src/jsx-runtime.js.map +0 -1
- package/dist/src/primitives/Infinite.d.ts +0 -15
- package/dist/src/primitives/Infinite.jsx +0 -59
- package/dist/src/primitives/Infinite.jsx.map +0 -1
- package/dist/src/primitives/LazyUp.d.ts +0 -11
- package/dist/src/primitives/LazyUp.jsx +0 -38
- package/dist/src/primitives/LazyUp.jsx.map +0 -1
- package/dist/src/primitives/sprite.d.ts +0 -9
- package/dist/src/primitives/sprite.js +0 -18
- package/dist/src/primitives/sprite.js.map +0 -1
- package/dist/src/primitives/utils/createFocusStack.d.ts +0 -24
- package/dist/src/primitives/utils/createFocusStack.js +0 -59
- package/dist/src/primitives/utils/createFocusStack.js.map +0 -1
- package/dist/src/primitives/utils/scrollToIndex.d.ts +0 -2
- package/dist/src/primitives/utils/scrollToIndex.js +0 -33
- package/dist/src/primitives/utils/scrollToIndex.js.map +0 -1
- package/dist/src/renderClient.d.ts +0 -21
- package/dist/src/renderClient.js +0 -64
- package/dist/src/renderClient.js.map +0 -1
|
@@ -0,0 +1,1458 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IRendererNode,
|
|
3
|
+
IRendererNodeProps,
|
|
4
|
+
IRendererShader,
|
|
5
|
+
IRendererShaderProps,
|
|
6
|
+
IRendererTextNode,
|
|
7
|
+
IRendererTextNodeProps,
|
|
8
|
+
renderer,
|
|
9
|
+
} from './lightningInit.js';
|
|
10
|
+
import {
|
|
11
|
+
type BorderRadius,
|
|
12
|
+
type BorderStyle,
|
|
13
|
+
type StyleEffects,
|
|
14
|
+
type AnimationSettings,
|
|
15
|
+
type ElementText,
|
|
16
|
+
type Styles,
|
|
17
|
+
type AnimationEvents,
|
|
18
|
+
type AnimationEventHandler,
|
|
19
|
+
AddColorString,
|
|
20
|
+
TextProps,
|
|
21
|
+
TextNode,
|
|
22
|
+
type OnEvent,
|
|
23
|
+
NewOmit,
|
|
24
|
+
} from './intrinsicTypes.js';
|
|
25
|
+
import States, { type NodeStates } from './states.js';
|
|
26
|
+
import calculateFlex from './flex.js';
|
|
27
|
+
import {
|
|
28
|
+
log,
|
|
29
|
+
isArray,
|
|
30
|
+
isFunc,
|
|
31
|
+
keyExists,
|
|
32
|
+
isINode,
|
|
33
|
+
isElementNode,
|
|
34
|
+
isElementText,
|
|
35
|
+
logRenderTree,
|
|
36
|
+
isFunction,
|
|
37
|
+
spliceItem,
|
|
38
|
+
} from './utils.js';
|
|
39
|
+
import { Config, DOM_RENDERING, isDev, SHADERS_ENABLED } from './config.js';
|
|
40
|
+
import type {
|
|
41
|
+
RendererMain,
|
|
42
|
+
INode,
|
|
43
|
+
INodeAnimateProps,
|
|
44
|
+
IAnimationController,
|
|
45
|
+
LinearGradientProps,
|
|
46
|
+
RadialGradientProps,
|
|
47
|
+
ShadowProps,
|
|
48
|
+
CoreShaderNode,
|
|
49
|
+
} from '@lightningjs/renderer';
|
|
50
|
+
import { assertTruthy } from '@lightningjs/renderer/utils';
|
|
51
|
+
import { NodeType } from './nodeTypes.js';
|
|
52
|
+
import {
|
|
53
|
+
ForwardFocusHandler,
|
|
54
|
+
setActiveElement,
|
|
55
|
+
FocusNode,
|
|
56
|
+
} from './focusManager.js';
|
|
57
|
+
import simpleAnimation, { SimpleAnimationSettings } from './animation.js';
|
|
58
|
+
|
|
59
|
+
let layoutRunQueued = false;
|
|
60
|
+
const layoutQueue = new Set<ElementNode>();
|
|
61
|
+
|
|
62
|
+
function addToLayoutQueue(node: ElementNode) {
|
|
63
|
+
layoutQueue.add(node);
|
|
64
|
+
if (!layoutRunQueued) {
|
|
65
|
+
layoutRunQueued = true;
|
|
66
|
+
queueMicrotask(runLayout);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function runLayout() {
|
|
71
|
+
layoutRunQueued = false;
|
|
72
|
+
const queue = [...layoutQueue];
|
|
73
|
+
layoutQueue.clear();
|
|
74
|
+
for (let i = queue.length - 1; i >= 0; i--) {
|
|
75
|
+
const node = queue[i] as ElementNode;
|
|
76
|
+
node.updateLayout();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const parseAndAssignShaderProps = (
|
|
81
|
+
prefix: string,
|
|
82
|
+
obj: Record<string, any>,
|
|
83
|
+
props: Record<string, any> = {},
|
|
84
|
+
) => {
|
|
85
|
+
if (!obj) return;
|
|
86
|
+
props[prefix] = obj;
|
|
87
|
+
Object.entries(obj).forEach(([key, value]) => {
|
|
88
|
+
let transformedKey = key === 'width' ? 'w' : key;
|
|
89
|
+
props[`${prefix}-${transformedKey}`] = value;
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
function convertToShader(_node: ElementNode, v: StyleEffects): IRendererShader {
|
|
94
|
+
let type = 'rounded';
|
|
95
|
+
if (v.border) type += 'WithBorder';
|
|
96
|
+
if (v.shadow) type += 'WithShadow';
|
|
97
|
+
return renderer.createShader(type, v as IRendererShaderProps);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function getPropertyAlias(name: string) {
|
|
101
|
+
if (name === 'w') return 'width';
|
|
102
|
+
if (name === 'h') return 'height';
|
|
103
|
+
return name;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const LightningRendererNumberProps = [
|
|
107
|
+
'alpha',
|
|
108
|
+
'color',
|
|
109
|
+
'colorTop',
|
|
110
|
+
'colorRight',
|
|
111
|
+
'colorLeft',
|
|
112
|
+
'colorBottom',
|
|
113
|
+
'colorTl',
|
|
114
|
+
'colorTr',
|
|
115
|
+
'colorBl',
|
|
116
|
+
'colorBr',
|
|
117
|
+
'h',
|
|
118
|
+
'fontSize',
|
|
119
|
+
'lineHeight',
|
|
120
|
+
'mount',
|
|
121
|
+
'mountX',
|
|
122
|
+
'mountY',
|
|
123
|
+
'pivot',
|
|
124
|
+
'pivotX',
|
|
125
|
+
'pivotY',
|
|
126
|
+
'rotation',
|
|
127
|
+
'scale',
|
|
128
|
+
'scaleX',
|
|
129
|
+
'scaleY',
|
|
130
|
+
'w',
|
|
131
|
+
'worldX',
|
|
132
|
+
'worldY',
|
|
133
|
+
'x',
|
|
134
|
+
'y',
|
|
135
|
+
'zIndex',
|
|
136
|
+
'zIndexLocked',
|
|
137
|
+
];
|
|
138
|
+
|
|
139
|
+
const LightningRendererNonAnimatingProps = [
|
|
140
|
+
'absX',
|
|
141
|
+
'absY',
|
|
142
|
+
'autosize',
|
|
143
|
+
'clipping',
|
|
144
|
+
'contain',
|
|
145
|
+
'data',
|
|
146
|
+
'destroyed',
|
|
147
|
+
'fontFamily',
|
|
148
|
+
'fontStretch',
|
|
149
|
+
'fontStyle',
|
|
150
|
+
'imageType',
|
|
151
|
+
'letterSpacing',
|
|
152
|
+
'maxHeight',
|
|
153
|
+
'maxLines',
|
|
154
|
+
'maxWidth',
|
|
155
|
+
'offsetY',
|
|
156
|
+
'overflowSuffix',
|
|
157
|
+
'preventCleanup',
|
|
158
|
+
'rtt',
|
|
159
|
+
'scrollable',
|
|
160
|
+
'scrollY',
|
|
161
|
+
'srcHeight',
|
|
162
|
+
'srcWidth',
|
|
163
|
+
'srcX',
|
|
164
|
+
'srcY',
|
|
165
|
+
'strictBounds',
|
|
166
|
+
'text',
|
|
167
|
+
'textAlign',
|
|
168
|
+
'textBaseline',
|
|
169
|
+
'textOverflow',
|
|
170
|
+
'texture',
|
|
171
|
+
'textureOptions',
|
|
172
|
+
'verticalAlign',
|
|
173
|
+
'wordWrap',
|
|
174
|
+
];
|
|
175
|
+
|
|
176
|
+
declare global {
|
|
177
|
+
interface HTMLElement {
|
|
178
|
+
/** Assigned for development, to quickly get ElementNode from selected HTMLElement */
|
|
179
|
+
element?: ElementNode;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export type RendererNode = AddColorString<
|
|
184
|
+
Partial<
|
|
185
|
+
NewOmit<
|
|
186
|
+
INode,
|
|
187
|
+
'parent' | 'shader' | 'src' | 'children' | 'id' | 'removeChild'
|
|
188
|
+
>
|
|
189
|
+
>
|
|
190
|
+
>;
|
|
191
|
+
export interface ElementNode extends RendererNode, FocusNode {
|
|
192
|
+
[key: string]: unknown;
|
|
193
|
+
|
|
194
|
+
// Properties
|
|
195
|
+
/** @internal for managing series of insertions and deletions */
|
|
196
|
+
_queueDelete?: number;
|
|
197
|
+
preserve?: boolean;
|
|
198
|
+
_animationQueue?:
|
|
199
|
+
| Array<{
|
|
200
|
+
props: Partial<INodeAnimateProps<CoreShaderNode>>;
|
|
201
|
+
animationSettings?: AnimationSettings;
|
|
202
|
+
}>
|
|
203
|
+
| undefined;
|
|
204
|
+
_animationQueueSettings?: AnimationSettings;
|
|
205
|
+
_animationRunning?: boolean;
|
|
206
|
+
_animationSettings?: AnimationSettings;
|
|
207
|
+
_autofocus?: boolean;
|
|
208
|
+
_containsFlexGrow?: boolean | null;
|
|
209
|
+
_hasRenderedChildren?: boolean;
|
|
210
|
+
_effects?: StyleEffects;
|
|
211
|
+
_id: string | undefined;
|
|
212
|
+
_parent: ElementNode | undefined;
|
|
213
|
+
_rendererProps?: any;
|
|
214
|
+
_states?: States;
|
|
215
|
+
_style?: Styles;
|
|
216
|
+
_lastAnyKeyPressTime?: number;
|
|
217
|
+
_type: 'element' | 'textNode';
|
|
218
|
+
_undoStyles?: string[];
|
|
219
|
+
autosize?: boolean;
|
|
220
|
+
/**
|
|
221
|
+
* The distance from the bottom edge of the parent element.
|
|
222
|
+
* When `bottom` is set, `mountY` is automatically set to 1.
|
|
223
|
+
*
|
|
224
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout
|
|
225
|
+
*/
|
|
226
|
+
bottom?: number;
|
|
227
|
+
/**
|
|
228
|
+
* An array of child `ElementNode` or `ElementText` nodes.
|
|
229
|
+
*/
|
|
230
|
+
children: Array<ElementNode | ElementText>;
|
|
231
|
+
/**
|
|
232
|
+
* Enable debug logging for this specific node.
|
|
233
|
+
*/
|
|
234
|
+
debug?: boolean;
|
|
235
|
+
/**
|
|
236
|
+
* Specifies how much a flex item should grow relative to the rest of the flex items.
|
|
237
|
+
*
|
|
238
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout?id=flex-grow
|
|
239
|
+
*/
|
|
240
|
+
flexGrow?: number;
|
|
241
|
+
/**
|
|
242
|
+
* Specifies whether flex items are forced onto one line or can wrap onto multiple lines.
|
|
243
|
+
*
|
|
244
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout?id=flex
|
|
245
|
+
*/
|
|
246
|
+
flexWrap?: 'nowrap' | 'wrap';
|
|
247
|
+
/**
|
|
248
|
+
* Determines if an element is a flex item. If set to `false`, the element will be ignored by the flexbox layout.
|
|
249
|
+
* @default false
|
|
250
|
+
*/
|
|
251
|
+
flexItem?: boolean;
|
|
252
|
+
/**
|
|
253
|
+
* Specifies the order of a flex item relative to the rest of the flex items.
|
|
254
|
+
*
|
|
255
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout?id=flex
|
|
256
|
+
*/
|
|
257
|
+
flexOrder?: number;
|
|
258
|
+
/**
|
|
259
|
+
* Forwards focus to a child element. It can be a numeric index of the child or a handler function.
|
|
260
|
+
*
|
|
261
|
+
* @see https://lightning-tv.github.io/solid/#/essentials/focus?id=forwardfocus
|
|
262
|
+
*/
|
|
263
|
+
forwardFocus?: number | ForwardFocusHandler;
|
|
264
|
+
/**
|
|
265
|
+
* If `true`, the states of this node will be propagated to its children.
|
|
266
|
+
*
|
|
267
|
+
* @see https://lightning-tv.github.io/solid/#/essentials/states?id=forwardstates
|
|
268
|
+
*/
|
|
269
|
+
forwardStates?: boolean;
|
|
270
|
+
/**
|
|
271
|
+
* The underlying Lightning Renderer node object. This is where the properties are ultimately set for rendering.
|
|
272
|
+
*/
|
|
273
|
+
lng:
|
|
274
|
+
| Partial<ElementNode>
|
|
275
|
+
| IRendererNode
|
|
276
|
+
| (IRendererTextNode & { shader?: any });
|
|
277
|
+
/**
|
|
278
|
+
* A reference to the `ElementNode` instance. Can be an object or a callback function.
|
|
279
|
+
*/
|
|
280
|
+
ref?: ElementNode | ((node: ElementNode) => void) | undefined;
|
|
281
|
+
/**
|
|
282
|
+
* A boolean indicating whether the node has been rendered.
|
|
283
|
+
*/
|
|
284
|
+
rendered: boolean;
|
|
285
|
+
/**
|
|
286
|
+
* The main renderer instance.
|
|
287
|
+
*/
|
|
288
|
+
renderer?: RendererMain;
|
|
289
|
+
/**
|
|
290
|
+
* The distance from the right edge of the parent element.
|
|
291
|
+
* When `right` is set, `mountX` is automatically set to 1.
|
|
292
|
+
*
|
|
293
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout?id=layout-and-positioning-elements
|
|
294
|
+
*/
|
|
295
|
+
right?: number;
|
|
296
|
+
/**
|
|
297
|
+
* The index of the currently selected child element, used for focus management for Column and Row components.
|
|
298
|
+
*/
|
|
299
|
+
selected?: number;
|
|
300
|
+
/**
|
|
301
|
+
* The width of the element before flexbox layout is applied. Used internally for layout calculations.
|
|
302
|
+
*/
|
|
303
|
+
preFlexwidth?: number;
|
|
304
|
+
/**
|
|
305
|
+
* The height of the element before flexbox layout is applied. Used internally for layout calculations.
|
|
306
|
+
*/
|
|
307
|
+
preFlexheight?: number;
|
|
308
|
+
/**
|
|
309
|
+
* The text content of a text node.
|
|
310
|
+
*/
|
|
311
|
+
text?: string;
|
|
312
|
+
/**
|
|
313
|
+
* Aligns flex items along the cross axis of the current line of the flex container.
|
|
314
|
+
*
|
|
315
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout?id=flex-properties
|
|
316
|
+
*/
|
|
317
|
+
alignItems?: 'flexStart' | 'flexEnd' | 'center';
|
|
318
|
+
/**
|
|
319
|
+
* Aligns a flex item along the cross axis, overriding the `alignItems` value of the flex container.
|
|
320
|
+
*
|
|
321
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout?id=flex-properties
|
|
322
|
+
*/
|
|
323
|
+
alignSelf?: 'flexStart' | 'flexEnd' | 'center';
|
|
324
|
+
/**
|
|
325
|
+
* The border style for all sides of the element. Takes an object with width and color properties.
|
|
326
|
+
*
|
|
327
|
+
* @see https://lightning-tv.github.io/solid/#/essentials/effects?id=border-and-borderradius
|
|
328
|
+
*/
|
|
329
|
+
border?: BorderStyle;
|
|
330
|
+
/**
|
|
331
|
+
* The border style for the bottom side of the element.
|
|
332
|
+
*
|
|
333
|
+
* @see https://lightning-tv.github.io/solid/#/essentials/effects?id=border-and-borderradius
|
|
334
|
+
*/
|
|
335
|
+
borderBottom?: BorderStyle;
|
|
336
|
+
/**
|
|
337
|
+
* The border style for the left side of the element.
|
|
338
|
+
*
|
|
339
|
+
* @see https://lightning-tv.github.io/solid/#/essentials/effects?id=border-and-borderradius
|
|
340
|
+
*/
|
|
341
|
+
borderLeft?: BorderStyle;
|
|
342
|
+
/**
|
|
343
|
+
* The radius of the element's corners.
|
|
344
|
+
*
|
|
345
|
+
* @see https://lightning-tv.github.io/solid/#/essentials/effects?id=border-and-borderradius
|
|
346
|
+
*/
|
|
347
|
+
borderRadius?: BorderRadius;
|
|
348
|
+
/**
|
|
349
|
+
* The border style for the right side of the element.
|
|
350
|
+
*
|
|
351
|
+
* @see https://lightning-tv.github.io/solid/#/essentials/effects?id=border-and-borderradius
|
|
352
|
+
*/
|
|
353
|
+
borderRight?: BorderStyle;
|
|
354
|
+
/**
|
|
355
|
+
* The border style for the top side of the element.
|
|
356
|
+
*
|
|
357
|
+
* @see https://lightning-tv.github.io/solid/#/essentials/effects?id=border-and-borderradius
|
|
358
|
+
*/
|
|
359
|
+
borderTop?: BorderStyle;
|
|
360
|
+
/**
|
|
361
|
+
* A shorthand to set both `centerX` and `centerY` to true.
|
|
362
|
+
*
|
|
363
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout?id=layout-and-positioning-elements
|
|
364
|
+
*/
|
|
365
|
+
center?: boolean;
|
|
366
|
+
/**
|
|
367
|
+
* If `true`, centers the element horizontally within its parent.
|
|
368
|
+
*
|
|
369
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout?id=layout-and-positioning-elements
|
|
370
|
+
*/
|
|
371
|
+
centerX?: boolean;
|
|
372
|
+
/**
|
|
373
|
+
* If `true`, centers the element vertically within its parent.
|
|
374
|
+
*
|
|
375
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout?id=layout-and-positioning-elements
|
|
376
|
+
*/
|
|
377
|
+
centerY?: boolean;
|
|
378
|
+
/**
|
|
379
|
+
* Specifies the direction of the flex items.
|
|
380
|
+
*
|
|
381
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout?id=flex
|
|
382
|
+
*/
|
|
383
|
+
direction?: 'ltr' | 'rtl';
|
|
384
|
+
/**
|
|
385
|
+
* Specifies the display behavior of an element. 'flex' enables flexbox layout.
|
|
386
|
+
*
|
|
387
|
+
* @default 'block'
|
|
388
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout?id=flex
|
|
389
|
+
*/
|
|
390
|
+
display?: 'flex' | 'block';
|
|
391
|
+
/**
|
|
392
|
+
* Defines how the flex container's size is determined. 'contain' allows it to grow with its content, 'fixed' keeps it at its specified size.
|
|
393
|
+
*
|
|
394
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout?id=flex
|
|
395
|
+
*/
|
|
396
|
+
flexBoundary?: 'contain' | 'fixed';
|
|
397
|
+
/**
|
|
398
|
+
* Defines how the flex container's cross-axis size is determined. 'fixed' keeps it at its specified size. Default is 'contain'.
|
|
399
|
+
*
|
|
400
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout?id=flex
|
|
401
|
+
*/
|
|
402
|
+
flexCrossBoundary?: 'fixed'; // default is contain
|
|
403
|
+
/**
|
|
404
|
+
* Specifies the direction of the main axis for flex items.
|
|
405
|
+
*
|
|
406
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout?id=flex
|
|
407
|
+
*/
|
|
408
|
+
flexDirection?: 'row' | 'column';
|
|
409
|
+
/**
|
|
410
|
+
* The gap between flex items.
|
|
411
|
+
*
|
|
412
|
+
* @see @see https://lightning-tv.github.io/solid/#/flow/layout?id=flex
|
|
413
|
+
*/
|
|
414
|
+
gap?: number;
|
|
415
|
+
/**
|
|
416
|
+
* The gap between flex rows.
|
|
417
|
+
*
|
|
418
|
+
* @see @see https://lightning-tv.github.io/solid/#/flow/layout?id=flex
|
|
419
|
+
*/
|
|
420
|
+
rowGap?: number;
|
|
421
|
+
/**
|
|
422
|
+
* The gap between flex columns.
|
|
423
|
+
*
|
|
424
|
+
* @see @see https://lightning-tv.github.io/solid/#/flow/layout?id=flex
|
|
425
|
+
*/
|
|
426
|
+
columnGap?: number;
|
|
427
|
+
/**
|
|
428
|
+
* Defines the alignment of flex items along the main axis.
|
|
429
|
+
*
|
|
430
|
+
* @see @see https://lightning-tv.github.io/solid/#/flow/layout?id=flex
|
|
431
|
+
*/
|
|
432
|
+
justifyContent?:
|
|
433
|
+
| 'flexStart'
|
|
434
|
+
| 'flexEnd'
|
|
435
|
+
| 'center'
|
|
436
|
+
| 'spaceBetween'
|
|
437
|
+
| 'spaceAround'
|
|
438
|
+
| 'spaceEvenly';
|
|
439
|
+
/**
|
|
440
|
+
* Applies a linear gradient effect to the element.
|
|
441
|
+
*
|
|
442
|
+
* @see https://lightning-tv.github.io/solid/#/essentials/effects
|
|
443
|
+
*/
|
|
444
|
+
linearGradient?: LinearGradientProps;
|
|
445
|
+
/**
|
|
446
|
+
* Applies a radial gradient effect to the element.
|
|
447
|
+
*
|
|
448
|
+
* @see https://lightning-tv.github.io/solid/#/essentials/effects
|
|
449
|
+
*/
|
|
450
|
+
radialGradient?: RadialGradientProps;
|
|
451
|
+
/**
|
|
452
|
+
* The margin on the bottom side of the element for a flexItem.
|
|
453
|
+
*
|
|
454
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout
|
|
455
|
+
*/
|
|
456
|
+
marginBottom?: number;
|
|
457
|
+
/**
|
|
458
|
+
* The margin on the left side of the element for a flexItem.
|
|
459
|
+
*
|
|
460
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout
|
|
461
|
+
*/
|
|
462
|
+
marginLeft?: number;
|
|
463
|
+
/**
|
|
464
|
+
* The margin on the right side of the element for a flexItem.
|
|
465
|
+
*
|
|
466
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout
|
|
467
|
+
*/
|
|
468
|
+
marginRight?: number;
|
|
469
|
+
/**
|
|
470
|
+
* The margin on the top side of the element for a flexItem.
|
|
471
|
+
*
|
|
472
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout
|
|
473
|
+
*/
|
|
474
|
+
marginTop?: number;
|
|
475
|
+
/**
|
|
476
|
+
* The padding on all sides of the flex element.
|
|
477
|
+
*
|
|
478
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout
|
|
479
|
+
*/
|
|
480
|
+
padding?: number;
|
|
481
|
+
/**
|
|
482
|
+
* The x-coordinate of the element's position.
|
|
483
|
+
*
|
|
484
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout
|
|
485
|
+
*/
|
|
486
|
+
x: number;
|
|
487
|
+
/**
|
|
488
|
+
* The y-coordinate of the element's position.
|
|
489
|
+
*
|
|
490
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout
|
|
491
|
+
*/
|
|
492
|
+
y: number;
|
|
493
|
+
/**
|
|
494
|
+
* Throttles key press events by the specified number of milliseconds.
|
|
495
|
+
*
|
|
496
|
+
* @see https://lightning-tv.github.io/solid/#/primitives/useFocusManager?id=input-throttling-available-core-212
|
|
497
|
+
*/
|
|
498
|
+
throttleInput?: number;
|
|
499
|
+
/**
|
|
500
|
+
* The width of the element.
|
|
501
|
+
*
|
|
502
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout
|
|
503
|
+
*/
|
|
504
|
+
w: number;
|
|
505
|
+
/**
|
|
506
|
+
* The height of the element.
|
|
507
|
+
*
|
|
508
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout
|
|
509
|
+
*/
|
|
510
|
+
h: number;
|
|
511
|
+
/**
|
|
512
|
+
* The z-index of the element, which affects its stacking order.
|
|
513
|
+
*
|
|
514
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout
|
|
515
|
+
*/
|
|
516
|
+
zIndex?: number;
|
|
517
|
+
/**
|
|
518
|
+
* Defines transitions for animatable properties.
|
|
519
|
+
*
|
|
520
|
+
* @see https://lightning-tv.github.io/solid/#/essentials/transitions?id=transitions-animations
|
|
521
|
+
*/
|
|
522
|
+
transition?:
|
|
523
|
+
| Record<string, AnimationSettings | undefined | true | false>
|
|
524
|
+
| true
|
|
525
|
+
| false;
|
|
526
|
+
/**
|
|
527
|
+
* Optional handlers for animation events.
|
|
528
|
+
*
|
|
529
|
+
* Available animation events:
|
|
530
|
+
* - 'animating': Fired when the animation is in progress.
|
|
531
|
+
* - 'tick': Fired at each tick or frame update of the animation.
|
|
532
|
+
* - 'stopped': Fired when the animation stops.
|
|
533
|
+
*
|
|
534
|
+
* Each event handler is optional and maps to a corresponding event.
|
|
535
|
+
*
|
|
536
|
+
* @type {Partial<Record<AnimationEvents, AnimationEventHandler>>}
|
|
537
|
+
*
|
|
538
|
+
* @property {AnimationEventHandler} [animating] - Handler for the 'animating' event.
|
|
539
|
+
* @property {AnimationEventHandler} [tick] - Handler for the 'tick' event.
|
|
540
|
+
* @property {AnimationEventHandler} [stopped] - Handler for the 'stopped' event.
|
|
541
|
+
*
|
|
542
|
+
* @see https://lightning-tv.github.io/solid/#/essentials/transitions?id=animation-callbacks
|
|
543
|
+
*/
|
|
544
|
+
onAnimation?: Partial<Record<AnimationEvents, AnimationEventHandler>>;
|
|
545
|
+
/** Optional handler for when the element is created and rendered.
|
|
546
|
+
*
|
|
547
|
+
* @see https://lightning-tv.github.io/solid/#/flow/ondestroy
|
|
548
|
+
*/
|
|
549
|
+
onCreate?: (this: ElementNode, el: ElementNode) => void;
|
|
550
|
+
/**
|
|
551
|
+
* Optional handler for when the element is destroyed.
|
|
552
|
+
* It can return a promise to wait for the cleanup to finish before the element is destroyed.
|
|
553
|
+
*
|
|
554
|
+
* @see https://lightning-tv.github.io/solid/#/flow/ondestroy
|
|
555
|
+
*/
|
|
556
|
+
onDestroy?: (this: ElementNode, el: ElementNode) => Promise<any> | void;
|
|
557
|
+
/**
|
|
558
|
+
* Optional handlers for when the element is rendered—after creation and when switching parents.
|
|
559
|
+
*
|
|
560
|
+
* @see https://lightning-tv.github.io/solid/#/primitives/KeepAlive
|
|
561
|
+
*/
|
|
562
|
+
onRender?: (this: ElementNode, el: ElementNode) => void;
|
|
563
|
+
/**
|
|
564
|
+
* Optional handlers for when the element is removed from a parent element.
|
|
565
|
+
*
|
|
566
|
+
* @see https://lightning-tv.github.io/solid/#/primitives/KeepAlive
|
|
567
|
+
*/
|
|
568
|
+
onRemove?: (this: ElementNode, el: ElementNode) => void;
|
|
569
|
+
/**
|
|
570
|
+
* Listen to Events coming from the renderer
|
|
571
|
+
* @param NodeEvents
|
|
572
|
+
*
|
|
573
|
+
* Available events:
|
|
574
|
+
* - 'loaded'
|
|
575
|
+
* - 'failed'
|
|
576
|
+
* - 'freed'
|
|
577
|
+
* - 'inBounds'
|
|
578
|
+
* - 'outOfBounds'
|
|
579
|
+
* - 'inViewport'
|
|
580
|
+
* - 'outOfViewport'
|
|
581
|
+
*
|
|
582
|
+
* @typedef {'loaded' | 'failed' | 'freed' | 'inBounds' | 'outOfBounds' | 'inViewport' | 'outOfViewport'} NodeEvents
|
|
583
|
+
*
|
|
584
|
+
* @param {Partial<Record<NodeEvents, EventHandler>>} events - An object where the keys are event names from NodeEvents and the values are the respective event handlers.
|
|
585
|
+
* @returns {void}
|
|
586
|
+
*
|
|
587
|
+
* @see https://lightning-tv.github.io/solid/#/essentials/events
|
|
588
|
+
*/
|
|
589
|
+
onEvent?: OnEvent;
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Callback run after flex layout is calculated on flex elements
|
|
593
|
+
*
|
|
594
|
+
* @see https://lightning-tv.github.io/solid/#/flow/layout
|
|
595
|
+
*/
|
|
596
|
+
onLayout?: (this: ElementNode, target: ElementNode) => void;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
export class ElementNode extends Object {
|
|
600
|
+
constructor(name: string) {
|
|
601
|
+
super();
|
|
602
|
+
this._type = name === 'text' ? NodeType.TextNode : NodeType.Element;
|
|
603
|
+
this.rendered = false;
|
|
604
|
+
this.lng = {};
|
|
605
|
+
this.children = [];
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
get effects(): StyleEffects | undefined {
|
|
609
|
+
return this.lng.shader;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
set effects(v: StyleEffects) {
|
|
613
|
+
if (!SHADERS_ENABLED) return;
|
|
614
|
+
let target = this.lng.shader || {};
|
|
615
|
+
if (this.lng.shader?.program) {
|
|
616
|
+
target = this.lng.shader.props;
|
|
617
|
+
}
|
|
618
|
+
if (v.rounded) target.radius = v.rounded.radius;
|
|
619
|
+
if (v.borderRadius) target.radius = v.borderRadius;
|
|
620
|
+
if (v.border) parseAndAssignShaderProps('border', v.border, target);
|
|
621
|
+
if (v.shadow) parseAndAssignShaderProps('shadow', v.shadow, target);
|
|
622
|
+
|
|
623
|
+
if (this.rendered) {
|
|
624
|
+
if (!this.lng.shader) {
|
|
625
|
+
this.lng.shader = convertToShader(this, target);
|
|
626
|
+
} else if (DOM_RENDERING) {
|
|
627
|
+
this.lng.shader = this.lng.shader; // lng.shader is a setter, force style update
|
|
628
|
+
}
|
|
629
|
+
} else {
|
|
630
|
+
this.lng.shader = target;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
set id(id: string) {
|
|
635
|
+
this._id = id;
|
|
636
|
+
if (Config.rendererOptions?.inspector) {
|
|
637
|
+
this.data = { ...this.data, testId: id };
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
get id(): string | undefined {
|
|
642
|
+
return this._id;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
get parent() {
|
|
646
|
+
return this._parent;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
set parent(p) {
|
|
650
|
+
this._parent = p;
|
|
651
|
+
if (this.rendered && p?.rendered) {
|
|
652
|
+
this.lng.parent = (p.lng as IRendererNode) ?? null;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
get height() {
|
|
657
|
+
return this.h;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
set height(h) {
|
|
661
|
+
this.h = h;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
get width() {
|
|
665
|
+
return this.w;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
set width(w) {
|
|
669
|
+
this.w = w;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
set fontWeight(v) {
|
|
673
|
+
this._fontWeight = v;
|
|
674
|
+
const family = this.fontFamily || Config.fontSettings?.fontFamily;
|
|
675
|
+
const weight =
|
|
676
|
+
(Config.fontWeightAlias &&
|
|
677
|
+
(Config.fontWeightAlias[v as string] as number | string)) ??
|
|
678
|
+
v;
|
|
679
|
+
this.fontFamily = `${family}${weight}`;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
get fontWeight() {
|
|
683
|
+
return this._fontWeight;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
insertChild(
|
|
687
|
+
node: ElementNode | ElementText | TextNode,
|
|
688
|
+
beforeNode?: ElementNode | ElementText | TextNode | null,
|
|
689
|
+
) {
|
|
690
|
+
// always remove nodes if they have a parent - for back swap of node
|
|
691
|
+
// this will then put the node at the end of the array when re-added
|
|
692
|
+
if (node.parent) {
|
|
693
|
+
node.parent.removeChild(node);
|
|
694
|
+
|
|
695
|
+
// We're inserting a node thats been rendered into a node that hasn't been
|
|
696
|
+
if (!this.rendered) {
|
|
697
|
+
this._hasRenderedChildren = true;
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
node.parent = this;
|
|
702
|
+
|
|
703
|
+
if (beforeNode) {
|
|
704
|
+
// SolidJS can move nodes around in the children array.
|
|
705
|
+
// We need to insert following DOM insertBefore which moves elements.
|
|
706
|
+
spliceItem(this.children, node as ElementNode, 1);
|
|
707
|
+
if (spliceItem(this.children, beforeNode as ElementNode, 0, node) > -1) {
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
this.children.push(node as ElementNode);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
removeChild(node: ElementNode | ElementText | TextNode) {
|
|
716
|
+
if (spliceItem(this.children, node, 1) > -1) {
|
|
717
|
+
node.onRemove?.call(node, node);
|
|
718
|
+
if (this.requiresLayout()) {
|
|
719
|
+
addToLayoutQueue(this);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
get selectedNode(): ElementNode | undefined {
|
|
725
|
+
const selectedIndex = this.selected || 0;
|
|
726
|
+
|
|
727
|
+
for (let i = selectedIndex; i < this.children.length; i++) {
|
|
728
|
+
const element = this.children[i];
|
|
729
|
+
if (isElementNode(element)) {
|
|
730
|
+
this.selected = i;
|
|
731
|
+
return element;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
return undefined;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
set shader(
|
|
739
|
+
shaderProps: IRendererShader | [kind: string, props: IRendererShaderProps],
|
|
740
|
+
) {
|
|
741
|
+
this.lng.shader = isArray(shaderProps)
|
|
742
|
+
? renderer.createShader(...shaderProps)
|
|
743
|
+
: shaderProps;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
_sendToLightningAnimatable(name: string, value: number) {
|
|
747
|
+
if (
|
|
748
|
+
this.transition &&
|
|
749
|
+
this.rendered &&
|
|
750
|
+
Config.animationsEnabled &&
|
|
751
|
+
(this.transition === true ||
|
|
752
|
+
this.transition[name] ||
|
|
753
|
+
this.transition[getPropertyAlias(name)])
|
|
754
|
+
) {
|
|
755
|
+
const animationSettings =
|
|
756
|
+
this.transition === true || this.transition[name] === true
|
|
757
|
+
? undefined
|
|
758
|
+
: (this.transition[name] as undefined | AnimationSettings);
|
|
759
|
+
|
|
760
|
+
if (Config.simpleAnimationsEnabled) {
|
|
761
|
+
simpleAnimation.add(
|
|
762
|
+
this,
|
|
763
|
+
name,
|
|
764
|
+
value,
|
|
765
|
+
animationSettings ||
|
|
766
|
+
(this.animationSettings as SimpleAnimationSettings),
|
|
767
|
+
);
|
|
768
|
+
simpleAnimation.register(renderer.stage);
|
|
769
|
+
return;
|
|
770
|
+
} else {
|
|
771
|
+
const animationController = this.animate(
|
|
772
|
+
{ [name]: value },
|
|
773
|
+
animationSettings,
|
|
774
|
+
);
|
|
775
|
+
|
|
776
|
+
if (this.onAnimation) {
|
|
777
|
+
const animationEvents = Object.keys(
|
|
778
|
+
this.onAnimation,
|
|
779
|
+
) as AnimationEvents[];
|
|
780
|
+
for (const event of animationEvents) {
|
|
781
|
+
const handler = this.onAnimation[event];
|
|
782
|
+
animationController.on(
|
|
783
|
+
event,
|
|
784
|
+
(controller: IAnimationController, props?: any) => {
|
|
785
|
+
handler!.call(this, controller, name, value, props);
|
|
786
|
+
},
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
return animationController.start();
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
(this.lng[name as keyof IRendererNode] as number | string) = value;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
animate(
|
|
799
|
+
props: Partial<INodeAnimateProps<CoreShaderNode>>,
|
|
800
|
+
animationSettings?: AnimationSettings,
|
|
801
|
+
): IAnimationController {
|
|
802
|
+
isDev &&
|
|
803
|
+
assertTruthy(this.rendered, 'Node must be rendered before animating');
|
|
804
|
+
return (this.lng as IRendererNode).animate(
|
|
805
|
+
props,
|
|
806
|
+
animationSettings || this.animationSettings || {},
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
chain(
|
|
811
|
+
props: Partial<INodeAnimateProps<CoreShaderNode>>,
|
|
812
|
+
animationSettings?: AnimationSettings,
|
|
813
|
+
) {
|
|
814
|
+
if (this._animationRunning) {
|
|
815
|
+
this._animationQueue = [];
|
|
816
|
+
this._animationRunning = false;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
if (animationSettings) {
|
|
820
|
+
this._animationQueueSettings = animationSettings;
|
|
821
|
+
} else if (!this._animationQueueSettings) {
|
|
822
|
+
this._animationQueueSettings =
|
|
823
|
+
animationSettings || this.animationSettings;
|
|
824
|
+
}
|
|
825
|
+
animationSettings = animationSettings || this._animationQueueSettings;
|
|
826
|
+
this._animationQueue = this._animationQueue || [];
|
|
827
|
+
this._animationQueue.push({ props, animationSettings });
|
|
828
|
+
return this;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
async start() {
|
|
832
|
+
let animation = this._animationQueue!.shift();
|
|
833
|
+
while (animation) {
|
|
834
|
+
this._animationRunning = true;
|
|
835
|
+
await this.animate(animation.props, animation.animationSettings)
|
|
836
|
+
.start()
|
|
837
|
+
.waitUntilStopped();
|
|
838
|
+
animation = this._animationQueue!.shift();
|
|
839
|
+
}
|
|
840
|
+
this._animationRunning = false;
|
|
841
|
+
this._animationQueueSettings = undefined;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
emit(event: string, ...args: any[]): boolean {
|
|
845
|
+
let current = this as ElementNode;
|
|
846
|
+
const capitalizedEvent = `on${event.charAt(0).toUpperCase()}${event.slice(1)}`;
|
|
847
|
+
|
|
848
|
+
while (current) {
|
|
849
|
+
const handler = current[capitalizedEvent];
|
|
850
|
+
if (isFunction(handler)) {
|
|
851
|
+
if (handler.call(current, this, ...args) === true) {
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
current = current.parent!;
|
|
856
|
+
}
|
|
857
|
+
return false;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
setFocus(): void {
|
|
861
|
+
if (this.rendered) {
|
|
862
|
+
// can be 0
|
|
863
|
+
if (this.forwardFocus !== undefined) {
|
|
864
|
+
if (isFunc(this.forwardFocus)) {
|
|
865
|
+
if (this.forwardFocus.call(this, this) !== false) {
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
} else {
|
|
869
|
+
const focusedIndex =
|
|
870
|
+
typeof this.forwardFocus === 'number' ? this.forwardFocus : null;
|
|
871
|
+
const nodes = this.children;
|
|
872
|
+
if (focusedIndex !== null && focusedIndex < nodes.length) {
|
|
873
|
+
const child = nodes[focusedIndex];
|
|
874
|
+
isElementNode(child) && child.setFocus();
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
// Delay setting focus so children can render (useful for Row + Column)
|
|
880
|
+
queueMicrotask(() => setActiveElement(this));
|
|
881
|
+
} else {
|
|
882
|
+
this._autofocus = true;
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
_layoutOnLoad() {
|
|
887
|
+
(this.lng as IRendererNode).on('loaded', () => {
|
|
888
|
+
this.parent!.updateLayout();
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
getText(this: ElementText) {
|
|
893
|
+
let result = '';
|
|
894
|
+
for (let i = 0; i < this.children.length; i++) {
|
|
895
|
+
result += this.children[i]!.text;
|
|
896
|
+
}
|
|
897
|
+
return result;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
destroy() {
|
|
901
|
+
if (this.onDestroy) {
|
|
902
|
+
const destroyPromise: unknown = this.onDestroy(this);
|
|
903
|
+
|
|
904
|
+
// If onDestroy returns a promise, wait for it to resolve before destroying
|
|
905
|
+
// Useful with animations waitUntilStopped method which returns promise
|
|
906
|
+
if (destroyPromise instanceof Promise) {
|
|
907
|
+
destroyPromise.then(() => this._destroy());
|
|
908
|
+
} else {
|
|
909
|
+
this._destroy();
|
|
910
|
+
}
|
|
911
|
+
} else {
|
|
912
|
+
this._destroy();
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
_destroy() {
|
|
917
|
+
if (isINode(this.lng)) {
|
|
918
|
+
this.lng.destroy();
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
set style(style: Styles | undefined) {
|
|
923
|
+
if (isDev && this._style) {
|
|
924
|
+
// Avoid processing style changes again
|
|
925
|
+
console.warn(
|
|
926
|
+
'Style already set: https://lightning-tv.github.io/solid/#/essentials/styling?id=style-patterns-to-avoid',
|
|
927
|
+
);
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
if (Config.lockStyles && this._style) {
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
if (!style) {
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
this._style = style;
|
|
939
|
+
|
|
940
|
+
// Keys set in JSX are more important
|
|
941
|
+
for (const key in this._style) {
|
|
942
|
+
// be careful of 0 values
|
|
943
|
+
if (this[key as keyof Styles] === undefined) {
|
|
944
|
+
this[key as keyof Styles] = this._style[key as keyof Styles];
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
get style(): Styles {
|
|
950
|
+
return this._style!;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
get hasChildren() {
|
|
954
|
+
return this.children.length > 0;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
set src(src) {
|
|
958
|
+
if (typeof src === 'string') {
|
|
959
|
+
this.lng.src = src;
|
|
960
|
+
if (!this.color && this.rendered) {
|
|
961
|
+
this.color = 0xffffffff;
|
|
962
|
+
}
|
|
963
|
+
} else {
|
|
964
|
+
this.color = 0x00000000;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
get src(): string | null | undefined {
|
|
969
|
+
return this.lng.src;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
getChildById(id: string) {
|
|
973
|
+
return this.children.find((c) => c.id === id);
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
searchChildrenById(id: string): ElementNode | undefined {
|
|
977
|
+
// traverse all the childrens children
|
|
978
|
+
for (let i = 0; i < this.children.length; i++) {
|
|
979
|
+
const child = this.children[i];
|
|
980
|
+
if (isElementNode(child)) {
|
|
981
|
+
if (child.id === id) {
|
|
982
|
+
return child;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
const found = child.searchChildrenById(id);
|
|
986
|
+
if (found) {
|
|
987
|
+
return found;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
set states(states: NodeStates) {
|
|
994
|
+
this._states = this._states
|
|
995
|
+
? this._states.merge(states)
|
|
996
|
+
: new States(this._stateChanged.bind(this), states);
|
|
997
|
+
if (this.rendered) {
|
|
998
|
+
this._stateChanged();
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
get states(): States {
|
|
1003
|
+
this._states = this._states || new States(this._stateChanged.bind(this));
|
|
1004
|
+
return this._states;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
get animationSettings(): AnimationSettings | undefined {
|
|
1008
|
+
return this._animationSettings || Config.animationSettings;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
set animationSettings(animationSettings: AnimationSettings | undefined) {
|
|
1012
|
+
this._animationSettings = animationSettings;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
set hidden(val: boolean) {
|
|
1016
|
+
this.alpha = val ? 0 : 1;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
get hidden() {
|
|
1020
|
+
return this.alpha === 0;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
/**
|
|
1024
|
+
* Sets the autofocus state of the element.
|
|
1025
|
+
* When set to a truthy value, the element will automatically gain focus.
|
|
1026
|
+
* You can also set it to a signal to recalculate
|
|
1027
|
+
*
|
|
1028
|
+
* @param val - A value to determine if the element should autofocus.
|
|
1029
|
+
* A truthy value enables autofocus, otherwise disables it.
|
|
1030
|
+
*/
|
|
1031
|
+
set autofocus(val: any) {
|
|
1032
|
+
this._autofocus = val;
|
|
1033
|
+
// Delay setting focus so children can render (useful for Row + Column)
|
|
1034
|
+
// which now uses forwardFocus
|
|
1035
|
+
val && queueMicrotask(() => this.setFocus());
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
get autofocus() {
|
|
1039
|
+
return this._autofocus;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
requiresLayout() {
|
|
1043
|
+
return this.display === 'flex' || this.onLayout;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
set updateLayoutOn(v: any) {
|
|
1047
|
+
this.updateLayout();
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
get updateLayoutOn() {
|
|
1051
|
+
return null;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
updateLayout() {
|
|
1055
|
+
if (this.hasChildren) {
|
|
1056
|
+
isDev && log('Layout: ', this);
|
|
1057
|
+
|
|
1058
|
+
if (this.display === 'flex' && this.flexGrow && this.width === 0) {
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
const flexChanged = this.display === 'flex' && calculateFlex(this);
|
|
1063
|
+
layoutQueue.delete(this);
|
|
1064
|
+
const onLayoutChanged =
|
|
1065
|
+
isFunc(this.onLayout) && this.onLayout.call(this, this);
|
|
1066
|
+
|
|
1067
|
+
if ((flexChanged || onLayoutChanged) && this.parent) {
|
|
1068
|
+
addToLayoutQueue(this.parent);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
if (this._containsFlexGrow === true) {
|
|
1072
|
+
// Need to reprocess children
|
|
1073
|
+
this.children.forEach((c) => {
|
|
1074
|
+
if (c.display === 'flex' && isElementNode(c)) {
|
|
1075
|
+
// calculating directly to prevent infinite loops recalculating parents
|
|
1076
|
+
calculateFlex(c);
|
|
1077
|
+
isFunc(c.onLayout) && c.onLayout.call(c, c);
|
|
1078
|
+
addToLayoutQueue(this);
|
|
1079
|
+
}
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
_stateChanged() {
|
|
1086
|
+
isDev && log('State Changed: ', this, this.states);
|
|
1087
|
+
|
|
1088
|
+
if (this.forwardStates) {
|
|
1089
|
+
// apply states to children first
|
|
1090
|
+
const states = this.states.slice() as States;
|
|
1091
|
+
this.children.forEach((c) => {
|
|
1092
|
+
c.states = states;
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
const states = this.states;
|
|
1097
|
+
|
|
1098
|
+
if (this._undoStyles || keyExists(this, states)) {
|
|
1099
|
+
let stylesToUndo: { [key: string]: any } | undefined;
|
|
1100
|
+
if (this._undoStyles && this._undoStyles.length) {
|
|
1101
|
+
stylesToUndo = {};
|
|
1102
|
+
this._undoStyles.forEach((styleKey) => {
|
|
1103
|
+
if (isDev) {
|
|
1104
|
+
if (this.style[styleKey] === undefined) {
|
|
1105
|
+
console.warn('fallback style key not found: ', styleKey);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
stylesToUndo![styleKey] = this.style[styleKey];
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
const numStates = states.length;
|
|
1113
|
+
if (numStates === 0) {
|
|
1114
|
+
Object.assign(this, stylesToUndo);
|
|
1115
|
+
this._undoStyles = [];
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
let newStyles: Styles;
|
|
1120
|
+
if (numStates === 1) {
|
|
1121
|
+
newStyles = this[states[0] as keyof Styles] as Styles;
|
|
1122
|
+
newStyles = stylesToUndo
|
|
1123
|
+
? { ...stylesToUndo, ...newStyles }
|
|
1124
|
+
: newStyles;
|
|
1125
|
+
} else {
|
|
1126
|
+
newStyles = states.reduce((acc, state) => {
|
|
1127
|
+
const styles = this[state];
|
|
1128
|
+
return styles ? { ...acc, ...styles } : acc;
|
|
1129
|
+
}, stylesToUndo || {});
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
if (newStyles) {
|
|
1133
|
+
this._undoStyles = Object.keys(newStyles);
|
|
1134
|
+
// Apply transition first
|
|
1135
|
+
if (newStyles.transition !== undefined) {
|
|
1136
|
+
this.transition = newStyles.transition as Styles['transition'];
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
// Apply the styles
|
|
1140
|
+
Object.assign(this, newStyles);
|
|
1141
|
+
} else {
|
|
1142
|
+
this._undoStyles = [];
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
render(topNode?: boolean) {
|
|
1148
|
+
// Elements are inserted from the inside out, then rendered from the outside in.
|
|
1149
|
+
// Render starts when an element is inserted with a parent that is already renderered.
|
|
1150
|
+
const node = this;
|
|
1151
|
+
const parent = this.parent;
|
|
1152
|
+
|
|
1153
|
+
if (!parent) {
|
|
1154
|
+
console.warn('Parent not set - no node created for: ', this);
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
if (!parent.rendered) {
|
|
1159
|
+
console.warn('Parent not rendered yet: ', this);
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
if (parent.requiresLayout()) {
|
|
1164
|
+
layoutQueue.add(parent);
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
if (this.rendered) {
|
|
1168
|
+
// This happens if Array of items is reordered to reuse elements.
|
|
1169
|
+
// We return after layout is queued so the change can trigger layout updates.
|
|
1170
|
+
this.onRender?.(this);
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
if (this._states) {
|
|
1175
|
+
this._stateChanged();
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
const props = node.lng;
|
|
1179
|
+
const parentWidth = parent.w || 0;
|
|
1180
|
+
const parentHeight = parent.h || 0;
|
|
1181
|
+
|
|
1182
|
+
props.x = props.x || 0;
|
|
1183
|
+
props.y = props.y || 0;
|
|
1184
|
+
props.parent = parent.lng as IRendererNode;
|
|
1185
|
+
|
|
1186
|
+
if (this.right || this.right === 0) {
|
|
1187
|
+
props.x = parentWidth - this.right;
|
|
1188
|
+
props.mountX = 1;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
if (this.bottom || this.bottom === 0) {
|
|
1192
|
+
props.y = parentHeight - this.bottom;
|
|
1193
|
+
props.mountY = 1;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
if (this.center) {
|
|
1197
|
+
this.centerX = this.centerY = true;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
if (this.centerX) {
|
|
1201
|
+
props.x += parentWidth / 2;
|
|
1202
|
+
props.mountX = 0.5;
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
if (this.centerY) {
|
|
1206
|
+
props.y += parentHeight / 2;
|
|
1207
|
+
props.mountY = 0.5;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
if (isElementText(node)) {
|
|
1211
|
+
const textProps = props as TextProps;
|
|
1212
|
+
if (Config.fontSettings) {
|
|
1213
|
+
for (const key in Config.fontSettings) {
|
|
1214
|
+
if (textProps[key] === undefined) {
|
|
1215
|
+
textProps[key] = Config.fontSettings[key];
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
textProps.text = textProps.text || node.getText();
|
|
1220
|
+
|
|
1221
|
+
if (textProps.textAlign && !textProps.contain) {
|
|
1222
|
+
console.warn('Text align requires contain: ', node.getText());
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
// contain is either width or both
|
|
1226
|
+
if (textProps.contain) {
|
|
1227
|
+
if (textProps.contain === 'both') {
|
|
1228
|
+
textProps.maxWidth = textProps.maxWidth ?? textProps.w;
|
|
1229
|
+
textProps.maxHeight = textProps.maxHeight ?? textProps.h;
|
|
1230
|
+
} else if (textProps.contain === 'width') {
|
|
1231
|
+
textProps.maxWidth = textProps.maxWidth ?? textProps.w;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
if (!textProps.h && !textProps.maxHeight) {
|
|
1235
|
+
textProps.maxLines = textProps.maxLines ?? 99;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
if (!textProps.maxWidth) {
|
|
1239
|
+
textProps.maxWidth =
|
|
1240
|
+
parentWidth - textProps.x! - (textProps.marginRight || 0);
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
if (textProps.contain === 'both' && !textProps.maxHeight) {
|
|
1244
|
+
textProps.maxHeight =
|
|
1245
|
+
parentHeight - textProps.y! - (textProps.marginBottom || 0);
|
|
1246
|
+
} else if (textProps.maxLines === 1) {
|
|
1247
|
+
textProps.maxHeight = (textProps.maxHeight ||
|
|
1248
|
+
textProps.lineHeight ||
|
|
1249
|
+
textProps.fontSize) as number;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
textProps.w = textProps.h = undefined;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
// Can you put effects on Text nodes? Need to confirm...
|
|
1256
|
+
if (SHADERS_ENABLED && props.shader && !props.shader.program) {
|
|
1257
|
+
props.shader = convertToShader(node, props.shader);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
isDev && log('Rendering: ', this, props);
|
|
1261
|
+
node.lng = renderer.createTextNode(
|
|
1262
|
+
props as unknown as IRendererTextNodeProps,
|
|
1263
|
+
);
|
|
1264
|
+
if (parent.requiresLayout()) {
|
|
1265
|
+
if (!textProps.maxWidth || !textProps.maxHeight) {
|
|
1266
|
+
node._layoutOnLoad();
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
} else {
|
|
1270
|
+
// If its not an image or texture apply some defaults
|
|
1271
|
+
if (!props.texture) {
|
|
1272
|
+
// Set width and height to parent less offset
|
|
1273
|
+
if (isNaN(props.w as number)) {
|
|
1274
|
+
props.w = node.flexGrow ? 0 : parentWidth - props.x;
|
|
1275
|
+
node._calcWidth = true;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
if (isNaN(props.h as number)) {
|
|
1279
|
+
props.h = parentHeight - props.y;
|
|
1280
|
+
node._calcHeight = true;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
if (props.rtt && !props.color) {
|
|
1284
|
+
props.color = 0xffffffff;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
if (!props.color && !props.src) {
|
|
1288
|
+
// Default color to transparent - If you later set a src, you'll need
|
|
1289
|
+
// to set color '#ffffffff'
|
|
1290
|
+
props.color = 0x00000000;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
if (SHADERS_ENABLED && props.shader && !props.shader.program) {
|
|
1295
|
+
props.shader = convertToShader(node, props.shader);
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
isDev && log('Rendering: ', this, props);
|
|
1299
|
+
node.lng = renderer.createNode(props as IRendererNodeProps);
|
|
1300
|
+
|
|
1301
|
+
if (node._hasRenderedChildren) {
|
|
1302
|
+
node._hasRenderedChildren = false;
|
|
1303
|
+
|
|
1304
|
+
for (const child of node.children) {
|
|
1305
|
+
if (isElementNode(child) && isINode(child.lng)) {
|
|
1306
|
+
child.lng.parent = node.lng as any;
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
node.rendered = true;
|
|
1313
|
+
if (isDev) {
|
|
1314
|
+
// Store props so we can recreate raw renderer code
|
|
1315
|
+
node._rendererProps = props;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
if (node.autosize && parent.requiresLayout()) {
|
|
1319
|
+
node._layoutOnLoad();
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
this.onCreate?.(this);
|
|
1323
|
+
this.onRender?.(this);
|
|
1324
|
+
|
|
1325
|
+
if (node.onEvent) {
|
|
1326
|
+
for (const [name, handler] of Object.entries(node.onEvent)) {
|
|
1327
|
+
node.lng.on(name, (_inode, data) => handler.call(node, node, data));
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
// L3 Inspector adds div to the lng object
|
|
1332
|
+
if (node.lng?.div) {
|
|
1333
|
+
node.lng.div.element = node;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
if (node._type === NodeType.Element) {
|
|
1337
|
+
// only element nodes will have children that need rendering
|
|
1338
|
+
const numChildren = node.children.length;
|
|
1339
|
+
for (let i = 0; i < numChildren; i++) {
|
|
1340
|
+
const c = node.children[i];
|
|
1341
|
+
isDev && assertTruthy(c, 'Child is undefined');
|
|
1342
|
+
// Text elements sneak in from Solid creating tracked nodes
|
|
1343
|
+
if (isElementNode(c)) {
|
|
1344
|
+
c.render();
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
if (topNode && !layoutRunQueued) {
|
|
1349
|
+
//Do one pass of layout, then another with Text loads
|
|
1350
|
+
layoutRunQueued = true;
|
|
1351
|
+
// We use queue because <For> loop will add children one at a time, causing lots of layout
|
|
1352
|
+
queueMicrotask(runLayout);
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
node._autofocus && node.setFocus();
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
for (const key of LightningRendererNumberProps) {
|
|
1360
|
+
Object.defineProperty(ElementNode.prototype, key, {
|
|
1361
|
+
get(): number {
|
|
1362
|
+
return this.lng[key];
|
|
1363
|
+
},
|
|
1364
|
+
set(this: ElementNode, v: number) {
|
|
1365
|
+
this._sendToLightningAnimatable(key, v);
|
|
1366
|
+
},
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
for (const key of LightningRendererNonAnimatingProps) {
|
|
1371
|
+
Object.defineProperty(ElementNode.prototype, key, {
|
|
1372
|
+
get(): unknown {
|
|
1373
|
+
return this.lng[key];
|
|
1374
|
+
},
|
|
1375
|
+
set(v: unknown) {
|
|
1376
|
+
this.lng[key] = v;
|
|
1377
|
+
},
|
|
1378
|
+
});
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
function createRawShaderAccessor<T>(key: keyof StyleEffects) {
|
|
1382
|
+
return {
|
|
1383
|
+
set(this: ElementNode, value: T) {
|
|
1384
|
+
this.shader = [key, value as unknown as IRendererShaderProps];
|
|
1385
|
+
},
|
|
1386
|
+
|
|
1387
|
+
get(this: ElementNode) {
|
|
1388
|
+
return this.shader;
|
|
1389
|
+
},
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
function shaderAccessor<T extends Record<string, any> | number>(
|
|
1394
|
+
key: 'border' | 'shadow' | 'rounded',
|
|
1395
|
+
) {
|
|
1396
|
+
return {
|
|
1397
|
+
set(this: ElementNode, value: T) {
|
|
1398
|
+
let target = this.lng.shader || {};
|
|
1399
|
+
|
|
1400
|
+
let animationSettings: AnimationSettings | undefined;
|
|
1401
|
+
if (this.lng.shader?.program) {
|
|
1402
|
+
target = this.lng.shader.props;
|
|
1403
|
+
const transitionKey = key === 'rounded' ? 'borderRadius' : key;
|
|
1404
|
+
if (
|
|
1405
|
+
this.transition &&
|
|
1406
|
+
(this.transition === true || this.transition[transitionKey])
|
|
1407
|
+
) {
|
|
1408
|
+
target = {};
|
|
1409
|
+
animationSettings =
|
|
1410
|
+
this.transition === true || this.transition[transitionKey] === true
|
|
1411
|
+
? undefined
|
|
1412
|
+
: (this.transition[transitionKey] as
|
|
1413
|
+
| undefined
|
|
1414
|
+
| AnimationSettings);
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
if (key === 'rounded' || typeof value === 'number') {
|
|
1419
|
+
target.radius = value;
|
|
1420
|
+
} else {
|
|
1421
|
+
parseAndAssignShaderProps(key, value, target);
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
if (this.rendered) {
|
|
1425
|
+
if (!this.lng.shader) {
|
|
1426
|
+
this.lng.shader = convertToShader(this, target);
|
|
1427
|
+
}
|
|
1428
|
+
} else {
|
|
1429
|
+
this.lng.shader = target;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
if (animationSettings) {
|
|
1433
|
+
this.animate({ shaderProps: target }, animationSettings).start();
|
|
1434
|
+
}
|
|
1435
|
+
},
|
|
1436
|
+
get(this: ElementNode) {
|
|
1437
|
+
return this.effects?.[key];
|
|
1438
|
+
},
|
|
1439
|
+
};
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
if (isDev) {
|
|
1443
|
+
ElementNode.prototype.lngTree = function () {
|
|
1444
|
+
return logRenderTree(this);
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
Object.defineProperties(ElementNode.prototype, {
|
|
1449
|
+
border: shaderAccessor<BorderStyle>('border'),
|
|
1450
|
+
shadow: shaderAccessor<ShadowProps>('shadow'),
|
|
1451
|
+
rounded: shaderAccessor<BorderRadius>('rounded'),
|
|
1452
|
+
// Alias for rounded
|
|
1453
|
+
borderRadius: shaderAccessor<BorderRadius>('rounded'),
|
|
1454
|
+
linearGradient:
|
|
1455
|
+
createRawShaderAccessor<LinearGradientProps>('linearGradient'),
|
|
1456
|
+
radialGradient:
|
|
1457
|
+
createRawShaderAccessor<RadialGradientProps>('radialGradient'),
|
|
1458
|
+
});
|