@lightningtv/solid 3.0.0-20 → 3.0.0-22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/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 +47 -0
- package/dist/src/core/config.js +23 -0
- package/dist/src/core/config.js.map +1 -0
- package/dist/src/core/dom-renderer/domRenderer.d.ts +137 -0
- package/dist/src/core/dom-renderer/domRenderer.js +1545 -0
- package/dist/src/core/dom-renderer/domRenderer.js.map +1 -0
- package/dist/src/core/dom-renderer/domRendererTypes.d.ts +117 -0
- package/dist/src/core/dom-renderer/domRendererTypes.js +2 -0
- package/dist/src/core/dom-renderer/domRendererTypes.js.map +1 -0
- package/dist/src/core/dom-renderer/domRendererUtils.d.ts +16 -0
- package/dist/src/core/dom-renderer/domRendererUtils.js +132 -0
- package/dist/src/core/dom-renderer/domRendererUtils.js.map +1 -0
- package/dist/src/core/domRenderer.d.ts +117 -0
- package/dist/src/core/domRenderer.js +1160 -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 +830 -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/timings.d.ts +36 -0
- package/dist/src/core/timings.js +199 -0
- package/dist/src/core/timings.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/FPSCounter.jsx +14 -1
- package/dist/src/primitives/FPSCounter.jsx.map +1 -1
- package/dist/src/primitives/Lazy.d.ts +1 -1
- package/dist/src/primitives/Lazy.jsx +5 -2
- package/dist/src/primitives/Lazy.jsx.map +1 -1
- package/dist/src/primitives/Row.jsx.map +1 -1
- package/dist/src/primitives/Virtual.jsx +2 -2
- package/dist/src/primitives/Virtual.jsx.map +1 -1
- package/dist/src/primitives/VirtualGrid.jsx +26 -5
- package/dist/src/primitives/VirtualGrid.jsx.map +1 -1
- package/dist/src/primitives/index.d.ts +1 -1
- package/dist/src/primitives/types.d.ts +2 -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 +2 -9
- package/dist/src/primitives/useMouse.js +30 -12
- package/dist/src/primitives/useMouse.js.map +1 -1
- package/dist/src/primitives/utils/createSpriteMap.d.ts +1 -1
- 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 +2 -8
- package/dist/src/primitives/utils/handleNavigation.js +5 -5
- package/dist/src/primitives/utils/handleNavigation.js.map +1 -1
- package/dist/src/primitives/utils/withScrolling.d.ts +8 -3
- package/dist/src/primitives/utils/withScrolling.js +43 -3
- package/dist/src/primitives/utils/withScrolling.js.map +1 -1
- package/dist/src/render.d.ts +5 -5
- package/dist/src/render.js +1 -1
- package/dist/src/render.js.map +1 -1
- package/dist/src/solidOpts.d.ts +1 -8
- package/dist/src/solidOpts.js +1 -1
- package/dist/src/solidOpts.js.map +1 -1
- package/dist/src/types.d.ts +1 -13
- package/dist/src/utils.d.ts +1 -1
- package/dist/src/utils.js +1 -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 +8 -12
- package/src/activeElement.ts +1 -1
- package/src/core/animation.ts +185 -0
- package/src/core/config.ts +77 -0
- package/src/core/domRenderer.ts +1308 -0
- package/src/core/elementNode.ts +1449 -0
- package/src/core/flex.ts +284 -0
- package/src/core/focusKeyTypes.ts +87 -0
- package/src/core/focusManager.ts +369 -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/FPSCounter.tsx +15 -1
- package/src/primitives/Lazy.tsx +8 -2
- package/src/primitives/Row.tsx +3 -3
- package/src/primitives/Virtual.tsx +2 -2
- package/src/primitives/VirtualGrid.tsx +26 -5
- package/src/primitives/index.ts +1 -1
- package/src/primitives/types.ts +2 -2
- package/src/primitives/useFocusManager.ts +3 -3
- package/src/primitives/useMouse.ts +48 -26
- package/src/primitives/utils/createSpriteMap.ts +3 -3
- package/src/primitives/utils/handleNavigation.ts +6 -13
- package/src/primitives/utils/withScrolling.ts +47 -5
- package/src/render.ts +1 -1
- package/src/solidOpts.ts +1 -9
- package/src/types.ts +1 -15
- package/src/utils.ts +1 -1
|
@@ -0,0 +1,1545 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|
|
3
|
+
Experimental DOM renderer
|
|
4
|
+
|
|
5
|
+
*/
|
|
6
|
+
import * as lng from '@lightningjs/renderer';
|
|
7
|
+
import { EventEmitter } from '@lightningjs/renderer/utils';
|
|
8
|
+
import { Config } from '../config.js';
|
|
9
|
+
import { colorToRgba, buildGradientStops, computeLegacyObjectFit, applySubTextureScaling, getNodeLineHeight, } from './domRendererUtils.js';
|
|
10
|
+
// Feature detection for legacy brousers
|
|
11
|
+
const _styleRef = typeof document !== 'undefined' ? document.documentElement?.style || {} : {};
|
|
12
|
+
const supportsObjectFit = 'objectFit' in _styleRef;
|
|
13
|
+
const supportsObjectPosition = 'objectPosition' in _styleRef;
|
|
14
|
+
const supportsMixBlendMode = 'mixBlendMode' in _styleRef;
|
|
15
|
+
const supportsStandardMask = 'maskImage' in _styleRef;
|
|
16
|
+
const supportsWebkitMask = 'webkitMaskImage' in _styleRef;
|
|
17
|
+
const supportsCssMask = supportsStandardMask || supportsWebkitMask;
|
|
18
|
+
function applyEasing(easing, progress) {
|
|
19
|
+
switch (easing) {
|
|
20
|
+
case 'linear':
|
|
21
|
+
default:
|
|
22
|
+
return progress;
|
|
23
|
+
case 'ease-in':
|
|
24
|
+
return progress * progress;
|
|
25
|
+
case 'ease-out':
|
|
26
|
+
return progress * (2 - progress);
|
|
27
|
+
case 'ease-in-out':
|
|
28
|
+
return progress < 0.5
|
|
29
|
+
? 2 * progress * progress
|
|
30
|
+
: -1 + (4 - 2 * progress) * progress;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function interpolate(start, end, t) {
|
|
34
|
+
return start + (end - start) * t;
|
|
35
|
+
}
|
|
36
|
+
function interpolateColor(start, end, t) {
|
|
37
|
+
return ((interpolate((start >> 24) & 0xff, (end >> 24) & 0xff, t) << 24) |
|
|
38
|
+
(interpolate((start >> 16) & 0xff, (end >> 16) & 0xff, t) << 16) |
|
|
39
|
+
(interpolate((start >> 8) & 0xff, (end >> 8) & 0xff, t) << 8) |
|
|
40
|
+
interpolate(start & 0xff, end & 0xff, t));
|
|
41
|
+
}
|
|
42
|
+
function interpolateProp(name, start, end, t) {
|
|
43
|
+
return name.startsWith('color')
|
|
44
|
+
? interpolateColor(start, end, t)
|
|
45
|
+
: interpolate(start, end, t);
|
|
46
|
+
}
|
|
47
|
+
/*
|
|
48
|
+
Animations
|
|
49
|
+
*/
|
|
50
|
+
let animationTasks = [];
|
|
51
|
+
let animationFrameRequested = false;
|
|
52
|
+
function requestAnimationUpdate() {
|
|
53
|
+
if (!animationFrameRequested && animationTasks.length > 0) {
|
|
54
|
+
animationFrameRequested = true;
|
|
55
|
+
requestAnimationFrame(updateAnimations);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function updateAnimations(time) {
|
|
59
|
+
animationFrameRequested = false;
|
|
60
|
+
/*
|
|
61
|
+
tasks are iterated in insertion order
|
|
62
|
+
so that the later task will override the earlier ones
|
|
63
|
+
*/
|
|
64
|
+
for (let i = 0; i < animationTasks.length; i++) {
|
|
65
|
+
let task = animationTasks[i];
|
|
66
|
+
if (task.pausedTime != null)
|
|
67
|
+
continue;
|
|
68
|
+
let elapsed = time - task.timeStart;
|
|
69
|
+
// Still in delay period
|
|
70
|
+
if (elapsed < task.settings.delay) {
|
|
71
|
+
requestAnimationUpdate();
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
let activeTime = elapsed - task.settings.delay;
|
|
75
|
+
if (activeTime >= task.settings.duration) {
|
|
76
|
+
// Start next iteration
|
|
77
|
+
if (task.settings.loop || task.iteration < task.settings.repeat - 1) {
|
|
78
|
+
task.iteration++;
|
|
79
|
+
task.timeStart = time - task.settings.delay;
|
|
80
|
+
if (task.settings.repeatDelay > 0) {
|
|
81
|
+
task.timeStart += task.settings.repeatDelay;
|
|
82
|
+
}
|
|
83
|
+
requestAnimationUpdate();
|
|
84
|
+
}
|
|
85
|
+
// Animation complete
|
|
86
|
+
else {
|
|
87
|
+
Object.assign(task.node.props, task.propsEnd);
|
|
88
|
+
updateNodeStyles(task.node);
|
|
89
|
+
task.stop();
|
|
90
|
+
i--;
|
|
91
|
+
}
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
/*
|
|
95
|
+
Update props and styles
|
|
96
|
+
*/
|
|
97
|
+
let t = activeTime / task.settings.duration;
|
|
98
|
+
t = applyEasing(task.settings.easing, t);
|
|
99
|
+
for (let prop in task.propsEnd) {
|
|
100
|
+
let start = task.propsStart[prop];
|
|
101
|
+
let end = task.propsEnd[prop];
|
|
102
|
+
task.node.props[prop] = interpolateProp(prop, start, end, t);
|
|
103
|
+
}
|
|
104
|
+
updateNodeStyles(task.node);
|
|
105
|
+
}
|
|
106
|
+
requestAnimationUpdate();
|
|
107
|
+
}
|
|
108
|
+
class AnimationController {
|
|
109
|
+
node;
|
|
110
|
+
state = 'paused';
|
|
111
|
+
stopPromise = null;
|
|
112
|
+
stopResolve = null;
|
|
113
|
+
propsStart = {};
|
|
114
|
+
propsEnd = {};
|
|
115
|
+
timeStart = performance.now();
|
|
116
|
+
timeEnd;
|
|
117
|
+
settings;
|
|
118
|
+
iteration = 0;
|
|
119
|
+
pausedTime = null;
|
|
120
|
+
constructor(node, props, rawSettings) {
|
|
121
|
+
this.node = node;
|
|
122
|
+
this.settings = {
|
|
123
|
+
duration: rawSettings.duration ?? 300,
|
|
124
|
+
delay: rawSettings.delay ?? 0,
|
|
125
|
+
easing: rawSettings.easing ?? 'linear',
|
|
126
|
+
loop: rawSettings.loop ?? false,
|
|
127
|
+
repeat: rawSettings.repeat ?? 1,
|
|
128
|
+
repeatDelay: rawSettings.repeatDelay ?? 0,
|
|
129
|
+
stopMethod: false,
|
|
130
|
+
};
|
|
131
|
+
this.timeEnd =
|
|
132
|
+
this.timeStart + this.settings.delay + this.settings.duration;
|
|
133
|
+
for (let [prop, value] of Object.entries(props)) {
|
|
134
|
+
if (value != null && typeof value === 'number') {
|
|
135
|
+
this.propsStart[prop] = node.props[prop];
|
|
136
|
+
this.propsEnd[prop] = value;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
animationTasks.push(this);
|
|
140
|
+
}
|
|
141
|
+
start() {
|
|
142
|
+
if (this.pausedTime != null) {
|
|
143
|
+
this.timeStart += performance.now() - this.pausedTime;
|
|
144
|
+
this.pausedTime = null;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
this.timeStart = performance.now();
|
|
148
|
+
}
|
|
149
|
+
this.state = 'running';
|
|
150
|
+
requestAnimationUpdate();
|
|
151
|
+
return this;
|
|
152
|
+
}
|
|
153
|
+
pause() {
|
|
154
|
+
this.pausedTime = performance.now();
|
|
155
|
+
this.state = 'paused';
|
|
156
|
+
return this;
|
|
157
|
+
}
|
|
158
|
+
stop() {
|
|
159
|
+
let index = animationTasks.indexOf(this);
|
|
160
|
+
if (index !== -1) {
|
|
161
|
+
animationTasks.splice(index, 1);
|
|
162
|
+
}
|
|
163
|
+
this.state = 'stopped';
|
|
164
|
+
if (this.stopResolve) {
|
|
165
|
+
this.stopResolve();
|
|
166
|
+
this.stopResolve = null;
|
|
167
|
+
this.stopPromise = null;
|
|
168
|
+
}
|
|
169
|
+
return this;
|
|
170
|
+
}
|
|
171
|
+
restore() {
|
|
172
|
+
return this;
|
|
173
|
+
}
|
|
174
|
+
waitUntilStopped() {
|
|
175
|
+
this.stopPromise ??= new Promise((resolve) => {
|
|
176
|
+
this.stopResolve = resolve;
|
|
177
|
+
});
|
|
178
|
+
return this.stopPromise;
|
|
179
|
+
}
|
|
180
|
+
on() {
|
|
181
|
+
return this;
|
|
182
|
+
}
|
|
183
|
+
once() {
|
|
184
|
+
return this;
|
|
185
|
+
}
|
|
186
|
+
off() {
|
|
187
|
+
return this;
|
|
188
|
+
}
|
|
189
|
+
emit() {
|
|
190
|
+
return this;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function animate(props, settings) {
|
|
194
|
+
return new AnimationController(this, props, settings);
|
|
195
|
+
}
|
|
196
|
+
/*
|
|
197
|
+
Node Properties
|
|
198
|
+
*/
|
|
199
|
+
let elMap = new WeakMap();
|
|
200
|
+
function updateNodeParent(node) {
|
|
201
|
+
if (node.parent != null) {
|
|
202
|
+
elMap.get(node.parent).appendChild(node.div);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// getNodeLineHeight moved to domRendererUtils.ts
|
|
206
|
+
// measureText fallback
|
|
207
|
+
function measureText(props) {
|
|
208
|
+
const canvas = document.createElement('canvas');
|
|
209
|
+
const context = canvas.getContext('2d');
|
|
210
|
+
if (!context)
|
|
211
|
+
return {
|
|
212
|
+
width: 0,
|
|
213
|
+
height: 0,
|
|
214
|
+
fontBoundingBoxAscent: 0,
|
|
215
|
+
actualBoundingBoxAscent: 0,
|
|
216
|
+
};
|
|
217
|
+
context.font = `${props.fontStyle || ''} ${props.fontWeight || ''} ${props.fontSize || 16}px ${props.fontFamily || 'serif'}`;
|
|
218
|
+
return context.measureText(props.text || '');
|
|
219
|
+
}
|
|
220
|
+
function updateNodeStyles(node) {
|
|
221
|
+
let { props } = node;
|
|
222
|
+
let style = `position: absolute; z-index: ${props.zIndex};`;
|
|
223
|
+
if (props.alpha !== 1)
|
|
224
|
+
style += `opacity: ${props.alpha};`;
|
|
225
|
+
if (props.clipping) {
|
|
226
|
+
style += `overflow: hidden;`;
|
|
227
|
+
}
|
|
228
|
+
// Transform
|
|
229
|
+
{
|
|
230
|
+
let transform = '';
|
|
231
|
+
let { x, y } = props;
|
|
232
|
+
if (props.mountX != null) {
|
|
233
|
+
x -= (props.width ?? 0) * props.mountX;
|
|
234
|
+
}
|
|
235
|
+
if (props.mountY != null) {
|
|
236
|
+
y -= (props.height ?? 0) * props.mountY;
|
|
237
|
+
}
|
|
238
|
+
if (x !== 0)
|
|
239
|
+
transform += `translateX(${x}px)`;
|
|
240
|
+
if (y !== 0)
|
|
241
|
+
transform += `translateY(${y}px)`;
|
|
242
|
+
if (props.rotation !== 0)
|
|
243
|
+
transform += `rotate(${props.rotation}rad)`;
|
|
244
|
+
if (props.scale !== 1 && props.scale != null) {
|
|
245
|
+
transform += `scale(${props.scale})`;
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
if (props.scaleX !== 1)
|
|
249
|
+
transform += `scaleX(${props.scaleX})`;
|
|
250
|
+
if (props.scaleY !== 1)
|
|
251
|
+
transform += `scaleY(${props.scaleY})`;
|
|
252
|
+
}
|
|
253
|
+
if (transform.length > 0) {
|
|
254
|
+
style += `transform: ${transform};`;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// <Text>
|
|
258
|
+
if (node instanceof DOMText) {
|
|
259
|
+
const textProps = node.props;
|
|
260
|
+
if (textProps.color != null && textProps.color !== 0) {
|
|
261
|
+
style += `color: ${colorToRgba(textProps.color)};`;
|
|
262
|
+
}
|
|
263
|
+
if (textProps.fontFamily) {
|
|
264
|
+
style += `font-family: ${textProps.fontFamily};`;
|
|
265
|
+
}
|
|
266
|
+
if (textProps.fontSize) {
|
|
267
|
+
style += `font-size: ${textProps.fontSize}px;`;
|
|
268
|
+
}
|
|
269
|
+
if (textProps.fontStyle) {
|
|
270
|
+
style += `font-style: ${textProps.fontStyle};`;
|
|
271
|
+
}
|
|
272
|
+
if (textProps.fontWeight) {
|
|
273
|
+
style += `font-weight: ${textProps.fontWeight};`;
|
|
274
|
+
}
|
|
275
|
+
if (textProps.fontStretch) {
|
|
276
|
+
style += `font-stretch: ${textProps.fontStretch};`;
|
|
277
|
+
}
|
|
278
|
+
if (textProps.lineHeight ||
|
|
279
|
+
(textProps.fontSize && typeof textProps.fontSize === 'number')) {
|
|
280
|
+
style += `line-height: ${textProps.lineHeight
|
|
281
|
+
? textProps.lineHeight + 'px'
|
|
282
|
+
: textProps.fontSize + 'px'};`;
|
|
283
|
+
}
|
|
284
|
+
if (textProps.letterSpacing) {
|
|
285
|
+
style += `letter-spacing: ${textProps.letterSpacing}px;`;
|
|
286
|
+
}
|
|
287
|
+
if (textProps.textAlign) {
|
|
288
|
+
style += `text-align: ${textProps.textAlign};`;
|
|
289
|
+
}
|
|
290
|
+
if (textProps.maxLines && textProps.maxLines > 0) {
|
|
291
|
+
if (textProps.contain === 'width' || textProps.contain === 'both') {
|
|
292
|
+
style += `display: -webkit-box; -webkit-line-clamp: ${textProps.maxLines}; -webkit-box-orient: vertical; overflow: hidden;`;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// Canvas fallback for baseline (simplified)
|
|
296
|
+
const metrics = measureText(textProps);
|
|
297
|
+
const offsetY = (metrics.fontBoundingBoxAscent || textProps.fontSize || 16) -
|
|
298
|
+
(metrics.actualBoundingBoxAscent || 0);
|
|
299
|
+
// This is approximate and might need adjustment based on specific needs
|
|
300
|
+
let maxLines = textProps.maxLines || Infinity;
|
|
301
|
+
switch (textProps.contain) {
|
|
302
|
+
case 'width':
|
|
303
|
+
style += `width: ${textProps.width}px; overflow: hidden;`;
|
|
304
|
+
break;
|
|
305
|
+
case 'both': {
|
|
306
|
+
let lineHeight = getNodeLineHeight(textProps);
|
|
307
|
+
maxLines = Math.min(maxLines, Math.floor((textProps.height || 0) / lineHeight));
|
|
308
|
+
maxLines = Math.max(1, maxLines);
|
|
309
|
+
let height = maxLines * lineHeight;
|
|
310
|
+
style += `width: ${textProps.width}px; height: ${height}px; overflow: hidden;`;
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
case 'none':
|
|
314
|
+
style += `width: max-content;`;
|
|
315
|
+
style += `width: -webkit-max-content;`;
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
if (maxLines !== Infinity) {
|
|
319
|
+
// https://stackoverflow.com/a/13924997
|
|
320
|
+
style += `display: -webkit-box;
|
|
321
|
+
overflow: hidden;
|
|
322
|
+
-webkit-line-clamp: ${maxLines};
|
|
323
|
+
line-clamp: ${maxLines};
|
|
324
|
+
-webkit-box-orient: vertical;`;
|
|
325
|
+
}
|
|
326
|
+
// if (node.overflowSuffix) style += `overflow-suffix: ${node.overflowSuffix};`
|
|
327
|
+
// if (node.verticalAlign) style += `vertical-align: ${node.verticalAlign};`
|
|
328
|
+
scheduleUpdateDOMTextMeasurement(node);
|
|
329
|
+
}
|
|
330
|
+
// <Node>
|
|
331
|
+
else {
|
|
332
|
+
if (props.width !== 0)
|
|
333
|
+
style += `width: ${props.width}px;`;
|
|
334
|
+
if (props.height !== 0)
|
|
335
|
+
style += `height: ${props.height}px;`;
|
|
336
|
+
let vGradient = props.colorBottom !== props.colorTop
|
|
337
|
+
? `linear-gradient(to bottom, ${colorToRgba(props.colorTop)}, ${colorToRgba(props.colorBottom)})`
|
|
338
|
+
: null;
|
|
339
|
+
let hGradient = props.colorLeft !== props.colorRight
|
|
340
|
+
? `linear-gradient(to right, ${colorToRgba(props.colorLeft)}, ${colorToRgba(props.colorRight)})`
|
|
341
|
+
: null;
|
|
342
|
+
let gradient = vGradient && hGradient
|
|
343
|
+
? `${vGradient}, ${hGradient}`
|
|
344
|
+
: vGradient || hGradient;
|
|
345
|
+
let srcImg = null;
|
|
346
|
+
let srcPos = null;
|
|
347
|
+
let rawImgSrc = null;
|
|
348
|
+
if (props.texture != null &&
|
|
349
|
+
props.texture.type === lng.TextureType.subTexture) {
|
|
350
|
+
const texture = props.texture;
|
|
351
|
+
srcPos = texture.props;
|
|
352
|
+
rawImgSrc = texture.props.texture.props.src;
|
|
353
|
+
}
|
|
354
|
+
else if (props.src) {
|
|
355
|
+
rawImgSrc = props.src;
|
|
356
|
+
}
|
|
357
|
+
if (rawImgSrc) {
|
|
358
|
+
srcImg = `url(${rawImgSrc})`;
|
|
359
|
+
}
|
|
360
|
+
let bgStyle = '';
|
|
361
|
+
let borderStyle = '';
|
|
362
|
+
let radiusStyle = '';
|
|
363
|
+
let maskStyle = '';
|
|
364
|
+
let needsBackgroundLayer = false;
|
|
365
|
+
let imgStyle = '';
|
|
366
|
+
if (rawImgSrc) {
|
|
367
|
+
needsBackgroundLayer = true;
|
|
368
|
+
const hasTint = props.color !== 0xffffffff && props.color !== 0x00000000;
|
|
369
|
+
if (hasTint) {
|
|
370
|
+
bgStyle += `background-color: ${colorToRgba(props.color)};`;
|
|
371
|
+
if (srcImg) {
|
|
372
|
+
maskStyle += `mask-image: ${srcImg};`;
|
|
373
|
+
if (srcPos !== null) {
|
|
374
|
+
maskStyle += `mask-position: -${srcPos.x}px -${srcPos.y}px;`;
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
maskStyle += `mask-size: 100% 100%;`;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
else if (gradient) {
|
|
382
|
+
// use gradient as a mask when no tint is applied
|
|
383
|
+
maskStyle += `mask-image: ${gradient};`;
|
|
384
|
+
}
|
|
385
|
+
const imgStyleParts = [
|
|
386
|
+
'position: absolute',
|
|
387
|
+
'top: 0',
|
|
388
|
+
'left: 0',
|
|
389
|
+
'right: 0',
|
|
390
|
+
'bottom: 0',
|
|
391
|
+
'display: block',
|
|
392
|
+
'pointer-events: none',
|
|
393
|
+
];
|
|
394
|
+
if (props.textureOptions.resizeMode?.type) {
|
|
395
|
+
const resizeMode = props.textureOptions.resizeMode;
|
|
396
|
+
imgStyleParts.push('width: 100%');
|
|
397
|
+
imgStyleParts.push('height: 100%');
|
|
398
|
+
imgStyleParts.push(`object-fit: ${resizeMode.type}`);
|
|
399
|
+
// Handle clipX and clipY for object-position
|
|
400
|
+
const clipX = resizeMode.clipX ?? 0.5;
|
|
401
|
+
const clipY = resizeMode.clipY ?? 0.5;
|
|
402
|
+
imgStyleParts.push(`object-position: ${clipX * 100}% ${clipY * 100}%`);
|
|
403
|
+
}
|
|
404
|
+
else if (srcPos !== null) {
|
|
405
|
+
imgStyleParts.push('width: auto');
|
|
406
|
+
imgStyleParts.push('height: auto');
|
|
407
|
+
imgStyleParts.push('object-fit: none');
|
|
408
|
+
imgStyleParts.push(`object-position: -${srcPos.x}px -${srcPos.y}px`);
|
|
409
|
+
}
|
|
410
|
+
else if (props.width && !props.height) {
|
|
411
|
+
imgStyleParts.push('width: 100%');
|
|
412
|
+
imgStyleParts.push('height: auto');
|
|
413
|
+
}
|
|
414
|
+
else if (props.height && !props.width) {
|
|
415
|
+
imgStyleParts.push('width: auto');
|
|
416
|
+
imgStyleParts.push('height: 100%');
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
imgStyleParts.push('width: 100%');
|
|
420
|
+
imgStyleParts.push('height: 100%');
|
|
421
|
+
imgStyleParts.push('object-fit: fill');
|
|
422
|
+
}
|
|
423
|
+
if (hasTint) {
|
|
424
|
+
if (supportsMixBlendMode) {
|
|
425
|
+
imgStyleParts.push('mix-blend-mode: multiply');
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
imgStyleParts.push('opacity: 0.9');
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
imgStyle = imgStyleParts.join('; ') + ';';
|
|
432
|
+
}
|
|
433
|
+
else if (gradient) {
|
|
434
|
+
bgStyle += `background-image: ${gradient};`;
|
|
435
|
+
bgStyle += `background-repeat: no-repeat;`;
|
|
436
|
+
bgStyle += `background-size: 100% 100%;`;
|
|
437
|
+
}
|
|
438
|
+
else if (props.color !== 0) {
|
|
439
|
+
bgStyle += `background-color: ${colorToRgba(props.color)};`;
|
|
440
|
+
}
|
|
441
|
+
if (props.shader != null) {
|
|
442
|
+
let effects = props.shader.props?.effects;
|
|
443
|
+
if (Array.isArray(effects)) {
|
|
444
|
+
for (let effect of effects) {
|
|
445
|
+
switch (effect.type) {
|
|
446
|
+
case 'radius': {
|
|
447
|
+
let radius = effect.props?.radius;
|
|
448
|
+
if (typeof radius === 'number' && radius > 0) {
|
|
449
|
+
radiusStyle += `border-radius: ${radius}px;`;
|
|
450
|
+
}
|
|
451
|
+
else if (Array.isArray(radius) && radius.length === 4) {
|
|
452
|
+
radiusStyle += `border-radius: ${radius[0]}px ${radius[1]}px ${radius[2]}px ${radius[3]}px;`;
|
|
453
|
+
}
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
case 'border':
|
|
457
|
+
case 'borderTop':
|
|
458
|
+
case 'borderBottom':
|
|
459
|
+
case 'borderLeft':
|
|
460
|
+
case 'borderRight': {
|
|
461
|
+
let borderWidth = effect.props?.width;
|
|
462
|
+
let borderColor = effect.props?.color;
|
|
463
|
+
if (typeof borderWidth === 'number' &&
|
|
464
|
+
borderWidth !== 0 &&
|
|
465
|
+
typeof borderColor === 'number' &&
|
|
466
|
+
borderColor !== 0) {
|
|
467
|
+
const rgbaColor = colorToRgba(borderColor);
|
|
468
|
+
if (effect.type === 'border') {
|
|
469
|
+
// Avoid affecting layout sizing while applying uniform borders
|
|
470
|
+
borderStyle += `box-shadow: inset 0px 0px 0px ${borderWidth}px ${rgbaColor};`;
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
const side = effect.type.slice('border'.length).toLowerCase();
|
|
474
|
+
borderStyle += `border-${side}: ${borderWidth}px solid ${rgbaColor};`;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
case 'radialGradient': {
|
|
480
|
+
const rg = effect.props;
|
|
481
|
+
const colors = Array.isArray(rg?.colors) ? rg.colors : [];
|
|
482
|
+
const stops = Array.isArray(rg?.stops) ? rg.stops : undefined;
|
|
483
|
+
const pivot = Array.isArray(rg?.pivot) ? rg.pivot : [0.5, 0.5];
|
|
484
|
+
const width = typeof rg?.width === 'number' ? rg.width : props.width || 0;
|
|
485
|
+
const height = typeof rg?.height === 'number' ? rg.height : width;
|
|
486
|
+
if (colors.length > 0) {
|
|
487
|
+
const gradientStops = buildGradientStops(colors, stops);
|
|
488
|
+
if (gradientStops) {
|
|
489
|
+
if (colors.length === 1) {
|
|
490
|
+
// Single color -> solid fill
|
|
491
|
+
if (srcImg || gradient) {
|
|
492
|
+
maskStyle += `mask-image: linear-gradient(${gradientStops});`;
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
bgStyle += `background-color: ${colorToRgba(colors[0])};`;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
const isEllipse = width > 0 && height > 0 && width !== height;
|
|
500
|
+
const pivotX = (pivot[0] ?? 0.5) * 100;
|
|
501
|
+
const pivotY = (pivot[1] ?? 0.5) * 100;
|
|
502
|
+
let sizePart = '';
|
|
503
|
+
if (width > 0 && height > 0) {
|
|
504
|
+
if (!isEllipse && width === height) {
|
|
505
|
+
sizePart = `${Math.round(width)}px`;
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
sizePart = `${Math.round(width)}px ${Math.round(height)}px`;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
else {
|
|
512
|
+
sizePart = 'closest-side';
|
|
513
|
+
}
|
|
514
|
+
const radialGradient = `radial-gradient(${isEllipse ? 'ellipse' : 'circle'} ${sizePart} at ${pivotX.toFixed(2)}% ${pivotY.toFixed(2)}%, ${gradientStops})`;
|
|
515
|
+
if (srcImg || gradient) {
|
|
516
|
+
maskStyle += `mask-image: ${radialGradient};`;
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
519
|
+
bgStyle += `background-image: ${radialGradient};`;
|
|
520
|
+
bgStyle += `background-repeat: no-repeat;`;
|
|
521
|
+
bgStyle += `background-size: 100% 100%;`;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
break;
|
|
527
|
+
}
|
|
528
|
+
case 'linearGradient': {
|
|
529
|
+
const lg = effect.props;
|
|
530
|
+
const colors = Array.isArray(lg?.colors) ? lg.colors : [];
|
|
531
|
+
const stops = Array.isArray(lg?.stops) ? lg.stops : undefined;
|
|
532
|
+
const angleRad = typeof lg?.angle === 'number' ? lg.angle : 0; // radians
|
|
533
|
+
if (colors.length > 0) {
|
|
534
|
+
const gradientStops = buildGradientStops(colors, stops);
|
|
535
|
+
if (gradientStops) {
|
|
536
|
+
if (colors.length === 1) {
|
|
537
|
+
if (srcImg || gradient) {
|
|
538
|
+
maskStyle += `mask-image: linear-gradient(${gradientStops});`;
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
bgStyle += `background-color: ${colorToRgba(colors[0])};`;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
const angleDeg = 180 * (angleRad / Math.PI - 1);
|
|
546
|
+
const linearGradient = `linear-gradient(${angleDeg.toFixed(2)}deg, ${gradientStops})`;
|
|
547
|
+
if (srcImg || gradient) {
|
|
548
|
+
maskStyle += `mask-image: ${linearGradient};`;
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
bgStyle += `background-image: ${linearGradient};`;
|
|
552
|
+
bgStyle += `background-repeat: no-repeat;`;
|
|
553
|
+
bgStyle += `background-size: 100% 100%;`;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
break;
|
|
559
|
+
}
|
|
560
|
+
default:
|
|
561
|
+
console.warn(`Unknown shader effect type: ${effect.type}`);
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (maskStyle !== '') {
|
|
568
|
+
if (!supportsStandardMask && supportsWebkitMask) {
|
|
569
|
+
maskStyle = maskStyle.replace(/mask-/g, '-webkit-mask-');
|
|
570
|
+
}
|
|
571
|
+
else if (!supportsCssMask) {
|
|
572
|
+
maskStyle = '';
|
|
573
|
+
}
|
|
574
|
+
if (maskStyle !== '') {
|
|
575
|
+
needsBackgroundLayer = true;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
style += radiusStyle;
|
|
579
|
+
if (needsBackgroundLayer) {
|
|
580
|
+
if (node.divBg == null) {
|
|
581
|
+
node.divBg = document.createElement('div');
|
|
582
|
+
node.div.insertBefore(node.divBg, node.div.firstChild);
|
|
583
|
+
}
|
|
584
|
+
else if (node.divBg.parentElement !== node.div) {
|
|
585
|
+
node.div.insertBefore(node.divBg, node.div.firstChild);
|
|
586
|
+
}
|
|
587
|
+
let bgLayerStyle = 'position: absolute; top:0; left:0; right:0; bottom:0; z-index: -1; pointer-events: none; overflow: hidden;';
|
|
588
|
+
if (bgStyle) {
|
|
589
|
+
bgLayerStyle += bgStyle;
|
|
590
|
+
}
|
|
591
|
+
if (maskStyle) {
|
|
592
|
+
bgLayerStyle += maskStyle;
|
|
593
|
+
}
|
|
594
|
+
node.divBg.setAttribute('style', bgLayerStyle + radiusStyle);
|
|
595
|
+
if (rawImgSrc) {
|
|
596
|
+
if (!node.imgEl) {
|
|
597
|
+
node.imgEl = document.createElement('img');
|
|
598
|
+
node.imgEl.alt = '';
|
|
599
|
+
node.imgEl.setAttribute('aria-hidden', 'true');
|
|
600
|
+
node.imgEl.setAttribute('loading', 'lazy');
|
|
601
|
+
node.imgEl.addEventListener('load', () => {
|
|
602
|
+
const payload = {
|
|
603
|
+
type: 'texture',
|
|
604
|
+
dimensions: {
|
|
605
|
+
width: node.imgEl.naturalWidth,
|
|
606
|
+
height: node.imgEl.naturalHeight,
|
|
607
|
+
},
|
|
608
|
+
};
|
|
609
|
+
applySubTextureScaling(node, node.imgEl, srcPos);
|
|
610
|
+
const resizeMode = node.props.textureOptions?.resizeMode;
|
|
611
|
+
const clipX = resizeMode?.clipX ?? 0.5;
|
|
612
|
+
const clipY = resizeMode?.clipY ?? 0.5;
|
|
613
|
+
computeLegacyObjectFit(node, node.imgEl, resizeMode, clipX, clipY, srcPos, supportsObjectFit, supportsObjectPosition);
|
|
614
|
+
node.emit('loaded', payload);
|
|
615
|
+
});
|
|
616
|
+
node.imgEl.addEventListener('error', () => {
|
|
617
|
+
if (node.imgEl) {
|
|
618
|
+
node.imgEl.src = '';
|
|
619
|
+
node.imgEl.style.display = 'none';
|
|
620
|
+
}
|
|
621
|
+
const payload = {
|
|
622
|
+
type: 'texture',
|
|
623
|
+
error: new Error(`Failed to load image: ${rawImgSrc}`),
|
|
624
|
+
};
|
|
625
|
+
node.emit('failed', payload);
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
if (node.imgEl.dataset.rawSrc !== rawImgSrc) {
|
|
629
|
+
node.imgEl.src = rawImgSrc;
|
|
630
|
+
node.imgEl.dataset.rawSrc = rawImgSrc;
|
|
631
|
+
}
|
|
632
|
+
if (node.imgEl.parentElement !== node.divBg) {
|
|
633
|
+
node.divBg.appendChild(node.imgEl);
|
|
634
|
+
}
|
|
635
|
+
node.imgEl.setAttribute('style', imgStyle);
|
|
636
|
+
if (srcPos && node.imgEl.complete) {
|
|
637
|
+
applySubTextureScaling(node, node.imgEl, srcPos);
|
|
638
|
+
}
|
|
639
|
+
if (!srcPos && (!supportsObjectFit || !supportsObjectPosition)) {
|
|
640
|
+
const resizeMode = node.props.textureOptions?.resizeMode;
|
|
641
|
+
const clipX = resizeMode?.clipX ?? 0.5;
|
|
642
|
+
const clipY = resizeMode?.clipY ?? 0.5;
|
|
643
|
+
computeLegacyObjectFit(node, node.imgEl, resizeMode, clipX, clipY, srcPos, supportsObjectFit, supportsObjectPosition);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
else if (node.imgEl) {
|
|
647
|
+
node.imgEl.remove();
|
|
648
|
+
node.imgEl = undefined;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
else {
|
|
652
|
+
if (node.imgEl) {
|
|
653
|
+
node.imgEl.remove();
|
|
654
|
+
node.imgEl = undefined;
|
|
655
|
+
}
|
|
656
|
+
if (node.divBg) {
|
|
657
|
+
node.divBg.remove();
|
|
658
|
+
node.divBg = undefined;
|
|
659
|
+
}
|
|
660
|
+
style += bgStyle;
|
|
661
|
+
}
|
|
662
|
+
const needsSeparateBorderLayer = needsBackgroundLayer && maskStyle !== '';
|
|
663
|
+
if (needsSeparateBorderLayer) {
|
|
664
|
+
if (node.divBorder == null) {
|
|
665
|
+
node.divBorder = document.createElement('div');
|
|
666
|
+
node.div.appendChild(node.divBorder);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
else if (node.divBorder) {
|
|
670
|
+
node.divBorder.remove();
|
|
671
|
+
node.divBorder = undefined;
|
|
672
|
+
}
|
|
673
|
+
if (node.divBorder == null) {
|
|
674
|
+
style += borderStyle;
|
|
675
|
+
}
|
|
676
|
+
else {
|
|
677
|
+
let borderLayerStyle = 'position: absolute; top:0; left:0; right:0; bottom:0; z-index: -1; pointer-events: none;';
|
|
678
|
+
borderLayerStyle += borderStyle;
|
|
679
|
+
node.divBorder.setAttribute('style', borderLayerStyle + radiusStyle);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
node.div.setAttribute('style', style);
|
|
683
|
+
}
|
|
684
|
+
const fontFamiliesToLoad = new Set();
|
|
685
|
+
const textNodesToMeasure = new Set();
|
|
686
|
+
function getElSize(node) {
|
|
687
|
+
const rawRect = node.div.getBoundingClientRect();
|
|
688
|
+
const dpr = Config.rendererOptions?.deviceLogicalPixelRatio ?? 1;
|
|
689
|
+
let width = rawRect.width / dpr;
|
|
690
|
+
let height = rawRect.height / dpr;
|
|
691
|
+
for (;;) {
|
|
692
|
+
if (node.props.scale != null && node.props.scale !== 1) {
|
|
693
|
+
width /= node.props.scale;
|
|
694
|
+
height /= node.props.scale;
|
|
695
|
+
}
|
|
696
|
+
else {
|
|
697
|
+
width /= node.props.scaleX;
|
|
698
|
+
height /= node.props.scaleY;
|
|
699
|
+
}
|
|
700
|
+
if (node.parent instanceof DOMNode) {
|
|
701
|
+
node = node.parent;
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
704
|
+
break;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
return { width, height };
|
|
708
|
+
}
|
|
709
|
+
/*
|
|
710
|
+
Text nodes with contain 'width' or 'none'
|
|
711
|
+
need to have their height or width calculated.
|
|
712
|
+
And then cause the flex layout to be recalculated.
|
|
713
|
+
*/
|
|
714
|
+
function updateDOMTextSize(node) {
|
|
715
|
+
let size;
|
|
716
|
+
switch (node.contain) {
|
|
717
|
+
case 'width':
|
|
718
|
+
size = getElSize(node);
|
|
719
|
+
if (node.props.height !== size.height) {
|
|
720
|
+
node.props.height = size.height;
|
|
721
|
+
updateNodeStyles(node);
|
|
722
|
+
}
|
|
723
|
+
break;
|
|
724
|
+
case 'none':
|
|
725
|
+
size = getElSize(node);
|
|
726
|
+
if (node.props.height !== size.height ||
|
|
727
|
+
node.props.width !== size.width) {
|
|
728
|
+
node.props.width = size.width;
|
|
729
|
+
node.props.height = size.height;
|
|
730
|
+
updateNodeStyles(node);
|
|
731
|
+
}
|
|
732
|
+
break;
|
|
733
|
+
}
|
|
734
|
+
const payload = {
|
|
735
|
+
type: 'text',
|
|
736
|
+
dimensions: {
|
|
737
|
+
width: node.props.width,
|
|
738
|
+
height: node.props.height,
|
|
739
|
+
},
|
|
740
|
+
};
|
|
741
|
+
node.emit('loaded', payload);
|
|
742
|
+
}
|
|
743
|
+
function updateDOMTextMeasurements() {
|
|
744
|
+
textNodesToMeasure.forEach(updateDOMTextSize);
|
|
745
|
+
textNodesToMeasure.clear();
|
|
746
|
+
}
|
|
747
|
+
function scheduleUpdateDOMTextMeasurement(node) {
|
|
748
|
+
/*
|
|
749
|
+
Make sure the font is loaded before measuring
|
|
750
|
+
*/
|
|
751
|
+
if (node.fontFamily && !fontFamiliesToLoad.has(node.fontFamily)) {
|
|
752
|
+
fontFamiliesToLoad.add(node.fontFamily);
|
|
753
|
+
document.fonts.load(`16px ${node.fontFamily}`);
|
|
754
|
+
}
|
|
755
|
+
if (textNodesToMeasure.size === 0) {
|
|
756
|
+
const fonts = document.fonts;
|
|
757
|
+
if (document.fonts.status === 'loaded') {
|
|
758
|
+
setTimeout(updateDOMTextMeasurements);
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
761
|
+
if (fonts && fonts.ready && typeof fonts.ready.then === 'function') {
|
|
762
|
+
fonts.ready.then(updateDOMTextMeasurements);
|
|
763
|
+
}
|
|
764
|
+
else {
|
|
765
|
+
setTimeout(updateDOMTextMeasurements);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
textNodesToMeasure.add(node);
|
|
770
|
+
}
|
|
771
|
+
function updateNodeData(node) {
|
|
772
|
+
for (let key in node.data) {
|
|
773
|
+
let keyValue = node.data[key];
|
|
774
|
+
if (keyValue === undefined) {
|
|
775
|
+
node.div.removeAttribute('data-' + key);
|
|
776
|
+
}
|
|
777
|
+
else {
|
|
778
|
+
node.div.setAttribute('data-' + key, String(keyValue));
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
function resolveNodeDefaults(props) {
|
|
783
|
+
const color = props.color ?? 0x00000000;
|
|
784
|
+
return {
|
|
785
|
+
x: props.x ?? 0,
|
|
786
|
+
y: props.y ?? 0,
|
|
787
|
+
width: props.width ?? 0,
|
|
788
|
+
height: props.height ?? 0,
|
|
789
|
+
alpha: props.alpha ?? 1,
|
|
790
|
+
autosize: props.autosize ?? false,
|
|
791
|
+
boundsMargin: props.boundsMargin ?? null,
|
|
792
|
+
clipping: props.clipping ?? false,
|
|
793
|
+
color,
|
|
794
|
+
colorTop: props.colorTop ?? color,
|
|
795
|
+
colorBottom: props.colorBottom ?? color,
|
|
796
|
+
colorLeft: props.colorLeft ?? color,
|
|
797
|
+
colorRight: props.colorRight ?? color,
|
|
798
|
+
colorBl: props.colorBl ?? props.colorBottom ?? props.colorLeft ?? color,
|
|
799
|
+
colorBr: props.colorBr ?? props.colorBottom ?? props.colorRight ?? color,
|
|
800
|
+
colorTl: props.colorTl ?? props.colorTop ?? props.colorLeft ?? color,
|
|
801
|
+
colorTr: props.colorTr ?? props.colorTop ?? props.colorRight ?? color,
|
|
802
|
+
zIndex: Math.ceil(props.zIndex ?? 0),
|
|
803
|
+
zIndexLocked: props.zIndexLocked ?? 0,
|
|
804
|
+
parent: props.parent ?? null,
|
|
805
|
+
texture: props.texture ?? null,
|
|
806
|
+
textureOptions: props.textureOptions ?? {},
|
|
807
|
+
shader: props.shader ?? defaultShader,
|
|
808
|
+
// Since setting the `src` will trigger a texture load, we need to set it after
|
|
809
|
+
// we set the texture. Otherwise, problems happen.
|
|
810
|
+
src: props.src ?? null,
|
|
811
|
+
srcHeight: props.srcHeight,
|
|
812
|
+
srcWidth: props.srcWidth,
|
|
813
|
+
srcX: props.srcX,
|
|
814
|
+
srcY: props.srcY,
|
|
815
|
+
scale: props.scale ?? null,
|
|
816
|
+
scaleX: props.scaleX ?? props.scale ?? 1,
|
|
817
|
+
scaleY: props.scaleY ?? props.scale ?? 1,
|
|
818
|
+
mount: props.mount ?? 0,
|
|
819
|
+
mountX: props.mountX ?? props.mount ?? 0,
|
|
820
|
+
mountY: props.mountY ?? props.mount ?? 0,
|
|
821
|
+
pivot: props.pivot ?? 0.5,
|
|
822
|
+
pivotX: props.pivotX ?? props.pivot ?? 0.5,
|
|
823
|
+
pivotY: props.pivotY ?? props.pivot ?? 0.5,
|
|
824
|
+
rotation: props.rotation ?? 0,
|
|
825
|
+
rtt: props.rtt ?? false,
|
|
826
|
+
data: {},
|
|
827
|
+
imageType: props.imageType,
|
|
828
|
+
strictBounds: props.strictBounds ?? false,
|
|
829
|
+
preventCleanup: props.preventCleanup ?? false,
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
function resolveTextNodeDefaults(props) {
|
|
833
|
+
return {
|
|
834
|
+
...resolveNodeDefaults(props),
|
|
835
|
+
text: props.text ?? '',
|
|
836
|
+
textRendererOverride: props.textRendererOverride ?? null,
|
|
837
|
+
fontSize: props.fontSize ?? 16,
|
|
838
|
+
fontFamily: props.fontFamily ?? 'sans-serif',
|
|
839
|
+
fontStyle: props.fontStyle ?? 'normal',
|
|
840
|
+
fontWeight: props.fontWeight ?? 'normal',
|
|
841
|
+
fontStretch: props.fontStretch ?? 'normal',
|
|
842
|
+
textAlign: props.textAlign ?? 'left',
|
|
843
|
+
contain: props.contain ?? 'none',
|
|
844
|
+
scrollable: props.scrollable ?? false,
|
|
845
|
+
scrollY: props.scrollY ?? 0,
|
|
846
|
+
offsetY: props.offsetY ?? 0,
|
|
847
|
+
letterSpacing: props.letterSpacing ?? 0,
|
|
848
|
+
lineHeight: props.lineHeight, // `undefined` is a valid value
|
|
849
|
+
maxLines: props.maxLines ?? 0,
|
|
850
|
+
textBaseline: props.textBaseline ?? 'alphabetic',
|
|
851
|
+
verticalAlign: props.verticalAlign ?? 'middle',
|
|
852
|
+
overflowSuffix: props.overflowSuffix ?? '...',
|
|
853
|
+
debug: props.debug ?? {},
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
const defaultShader = {
|
|
857
|
+
shaderType: '',
|
|
858
|
+
props: undefined,
|
|
859
|
+
};
|
|
860
|
+
let lastNodeId = 0;
|
|
861
|
+
export class DOMNode extends EventEmitter {
|
|
862
|
+
stage;
|
|
863
|
+
props;
|
|
864
|
+
div = document.createElement('div');
|
|
865
|
+
divBg;
|
|
866
|
+
divBorder;
|
|
867
|
+
imgEl;
|
|
868
|
+
id = ++lastNodeId;
|
|
869
|
+
renderState = 0 /* Init */;
|
|
870
|
+
preventCleanup = true;
|
|
871
|
+
constructor(stage, props) {
|
|
872
|
+
super();
|
|
873
|
+
this.stage = stage;
|
|
874
|
+
this.props = props;
|
|
875
|
+
// @ts-ignore
|
|
876
|
+
this.div._node = this;
|
|
877
|
+
this.div.setAttribute('data-id', String(this.id));
|
|
878
|
+
elMap.set(this, this.div);
|
|
879
|
+
updateNodeParent(this);
|
|
880
|
+
updateNodeStyles(this);
|
|
881
|
+
updateNodeData(this);
|
|
882
|
+
}
|
|
883
|
+
destroy() {
|
|
884
|
+
elMap.delete(this);
|
|
885
|
+
this.div.parentNode.removeChild(this.div);
|
|
886
|
+
}
|
|
887
|
+
get parent() {
|
|
888
|
+
return this.props.parent;
|
|
889
|
+
}
|
|
890
|
+
set parent(value) {
|
|
891
|
+
this.props.parent = value;
|
|
892
|
+
updateNodeParent(this);
|
|
893
|
+
}
|
|
894
|
+
animate = animate;
|
|
895
|
+
get w() {
|
|
896
|
+
return this.props.width || 0;
|
|
897
|
+
}
|
|
898
|
+
set w(v) {
|
|
899
|
+
this.props.width = v;
|
|
900
|
+
updateNodeStyles(this);
|
|
901
|
+
}
|
|
902
|
+
get h() {
|
|
903
|
+
return this.props.height || 0;
|
|
904
|
+
}
|
|
905
|
+
set h(v) {
|
|
906
|
+
this.props.height = v;
|
|
907
|
+
updateNodeStyles(this);
|
|
908
|
+
}
|
|
909
|
+
get x() {
|
|
910
|
+
return this.props.x;
|
|
911
|
+
}
|
|
912
|
+
set x(v) {
|
|
913
|
+
this.props.x = v;
|
|
914
|
+
updateNodeStyles(this);
|
|
915
|
+
}
|
|
916
|
+
get y() {
|
|
917
|
+
return this.props.y;
|
|
918
|
+
}
|
|
919
|
+
set y(v) {
|
|
920
|
+
this.props.y = v;
|
|
921
|
+
updateNodeStyles(this);
|
|
922
|
+
}
|
|
923
|
+
get width() {
|
|
924
|
+
return this.props.width;
|
|
925
|
+
}
|
|
926
|
+
set width(v) {
|
|
927
|
+
this.props.width = v;
|
|
928
|
+
updateNodeStyles(this);
|
|
929
|
+
}
|
|
930
|
+
get height() {
|
|
931
|
+
return this.props.height;
|
|
932
|
+
}
|
|
933
|
+
set height(v) {
|
|
934
|
+
this.props.height = v;
|
|
935
|
+
updateNodeStyles(this);
|
|
936
|
+
}
|
|
937
|
+
get alpha() {
|
|
938
|
+
return this.props.alpha;
|
|
939
|
+
}
|
|
940
|
+
set alpha(v) {
|
|
941
|
+
this.props.alpha = v;
|
|
942
|
+
updateNodeStyles(this);
|
|
943
|
+
}
|
|
944
|
+
get autosize() {
|
|
945
|
+
return this.props.autosize;
|
|
946
|
+
}
|
|
947
|
+
set autosize(v) {
|
|
948
|
+
this.props.autosize = v;
|
|
949
|
+
updateNodeStyles(this);
|
|
950
|
+
}
|
|
951
|
+
get clipping() {
|
|
952
|
+
return this.props.clipping;
|
|
953
|
+
}
|
|
954
|
+
set clipping(v) {
|
|
955
|
+
this.props.clipping = v;
|
|
956
|
+
updateNodeStyles(this);
|
|
957
|
+
}
|
|
958
|
+
get color() {
|
|
959
|
+
return this.props.color;
|
|
960
|
+
}
|
|
961
|
+
set color(v) {
|
|
962
|
+
this.props.color = v;
|
|
963
|
+
updateNodeStyles(this);
|
|
964
|
+
}
|
|
965
|
+
get colorTop() {
|
|
966
|
+
return this.props.colorTop;
|
|
967
|
+
}
|
|
968
|
+
set colorTop(v) {
|
|
969
|
+
this.props.colorTop = v;
|
|
970
|
+
updateNodeStyles(this);
|
|
971
|
+
}
|
|
972
|
+
get colorBottom() {
|
|
973
|
+
return this.props.colorBottom;
|
|
974
|
+
}
|
|
975
|
+
set colorBottom(v) {
|
|
976
|
+
this.props.colorBottom = v;
|
|
977
|
+
updateNodeStyles(this);
|
|
978
|
+
}
|
|
979
|
+
get colorLeft() {
|
|
980
|
+
return this.props.colorLeft;
|
|
981
|
+
}
|
|
982
|
+
set colorLeft(v) {
|
|
983
|
+
this.props.colorLeft = v;
|
|
984
|
+
updateNodeStyles(this);
|
|
985
|
+
}
|
|
986
|
+
get colorRight() {
|
|
987
|
+
return this.props.colorRight;
|
|
988
|
+
}
|
|
989
|
+
set colorRight(v) {
|
|
990
|
+
this.props.colorRight = v;
|
|
991
|
+
updateNodeStyles(this);
|
|
992
|
+
}
|
|
993
|
+
get colorTl() {
|
|
994
|
+
return this.props.colorTl;
|
|
995
|
+
}
|
|
996
|
+
set colorTl(v) {
|
|
997
|
+
this.props.colorTl = v;
|
|
998
|
+
updateNodeStyles(this);
|
|
999
|
+
}
|
|
1000
|
+
get colorTr() {
|
|
1001
|
+
return this.props.colorTr;
|
|
1002
|
+
}
|
|
1003
|
+
set colorTr(v) {
|
|
1004
|
+
this.props.colorTr = v;
|
|
1005
|
+
updateNodeStyles(this);
|
|
1006
|
+
}
|
|
1007
|
+
get colorBr() {
|
|
1008
|
+
return this.props.colorBr;
|
|
1009
|
+
}
|
|
1010
|
+
set colorBr(v) {
|
|
1011
|
+
this.props.colorBr = v;
|
|
1012
|
+
updateNodeStyles(this);
|
|
1013
|
+
}
|
|
1014
|
+
get colorBl() {
|
|
1015
|
+
return this.props.colorBl;
|
|
1016
|
+
}
|
|
1017
|
+
set colorBl(v) {
|
|
1018
|
+
this.props.colorBl = v;
|
|
1019
|
+
updateNodeStyles(this);
|
|
1020
|
+
}
|
|
1021
|
+
get zIndex() {
|
|
1022
|
+
return this.props.zIndex;
|
|
1023
|
+
}
|
|
1024
|
+
set zIndex(v) {
|
|
1025
|
+
this.props.zIndex = Math.ceil(v);
|
|
1026
|
+
updateNodeStyles(this);
|
|
1027
|
+
}
|
|
1028
|
+
get texture() {
|
|
1029
|
+
return this.props.texture;
|
|
1030
|
+
}
|
|
1031
|
+
set texture(v) {
|
|
1032
|
+
this.props.texture = v;
|
|
1033
|
+
updateNodeStyles(this);
|
|
1034
|
+
}
|
|
1035
|
+
get textureOptions() {
|
|
1036
|
+
return this.props.textureOptions;
|
|
1037
|
+
}
|
|
1038
|
+
set textureOptions(v) {
|
|
1039
|
+
this.props.textureOptions = v;
|
|
1040
|
+
updateNodeStyles(this);
|
|
1041
|
+
}
|
|
1042
|
+
get src() {
|
|
1043
|
+
return this.props.src;
|
|
1044
|
+
}
|
|
1045
|
+
set src(v) {
|
|
1046
|
+
this.props.src = v;
|
|
1047
|
+
updateNodeStyles(this);
|
|
1048
|
+
}
|
|
1049
|
+
get zIndexLocked() {
|
|
1050
|
+
return this.props.zIndexLocked;
|
|
1051
|
+
}
|
|
1052
|
+
set zIndexLocked(v) {
|
|
1053
|
+
this.props.zIndexLocked = v;
|
|
1054
|
+
updateNodeStyles(this);
|
|
1055
|
+
}
|
|
1056
|
+
get scale() {
|
|
1057
|
+
return this.props.scale ?? 1;
|
|
1058
|
+
}
|
|
1059
|
+
set scale(v) {
|
|
1060
|
+
this.props.scale = v;
|
|
1061
|
+
updateNodeStyles(this);
|
|
1062
|
+
}
|
|
1063
|
+
get scaleX() {
|
|
1064
|
+
return this.props.scaleX;
|
|
1065
|
+
}
|
|
1066
|
+
set scaleX(v) {
|
|
1067
|
+
this.props.scaleX = v;
|
|
1068
|
+
updateNodeStyles(this);
|
|
1069
|
+
}
|
|
1070
|
+
get scaleY() {
|
|
1071
|
+
return this.props.scaleY;
|
|
1072
|
+
}
|
|
1073
|
+
set scaleY(v) {
|
|
1074
|
+
this.props.scaleY = v;
|
|
1075
|
+
updateNodeStyles(this);
|
|
1076
|
+
}
|
|
1077
|
+
get mount() {
|
|
1078
|
+
return this.props.mount;
|
|
1079
|
+
}
|
|
1080
|
+
set mount(v) {
|
|
1081
|
+
this.props.mount = v;
|
|
1082
|
+
updateNodeStyles(this);
|
|
1083
|
+
}
|
|
1084
|
+
get mountX() {
|
|
1085
|
+
return this.props.mountX;
|
|
1086
|
+
}
|
|
1087
|
+
set mountX(v) {
|
|
1088
|
+
this.props.mountX = v;
|
|
1089
|
+
updateNodeStyles(this);
|
|
1090
|
+
}
|
|
1091
|
+
get mountY() {
|
|
1092
|
+
return this.props.mountY;
|
|
1093
|
+
}
|
|
1094
|
+
set mountY(v) {
|
|
1095
|
+
this.props.mountY = v;
|
|
1096
|
+
updateNodeStyles(this);
|
|
1097
|
+
}
|
|
1098
|
+
get pivot() {
|
|
1099
|
+
return this.props.pivot;
|
|
1100
|
+
}
|
|
1101
|
+
set pivot(v) {
|
|
1102
|
+
this.props.pivot = v;
|
|
1103
|
+
updateNodeStyles(this);
|
|
1104
|
+
}
|
|
1105
|
+
get pivotX() {
|
|
1106
|
+
return this.props.pivotX;
|
|
1107
|
+
}
|
|
1108
|
+
set pivotX(v) {
|
|
1109
|
+
this.props.pivotX = v;
|
|
1110
|
+
updateNodeStyles(this);
|
|
1111
|
+
}
|
|
1112
|
+
get pivotY() {
|
|
1113
|
+
return this.props.pivotY;
|
|
1114
|
+
}
|
|
1115
|
+
set pivotY(v) {
|
|
1116
|
+
this.props.pivotY = v;
|
|
1117
|
+
updateNodeStyles(this);
|
|
1118
|
+
}
|
|
1119
|
+
get rotation() {
|
|
1120
|
+
return this.props.rotation;
|
|
1121
|
+
}
|
|
1122
|
+
set rotation(v) {
|
|
1123
|
+
this.props.rotation = v;
|
|
1124
|
+
updateNodeStyles(this);
|
|
1125
|
+
}
|
|
1126
|
+
get rtt() {
|
|
1127
|
+
return this.props.rtt;
|
|
1128
|
+
}
|
|
1129
|
+
set rtt(v) {
|
|
1130
|
+
this.props.rtt = v;
|
|
1131
|
+
updateNodeStyles(this);
|
|
1132
|
+
}
|
|
1133
|
+
get shader() {
|
|
1134
|
+
return this.props.shader;
|
|
1135
|
+
}
|
|
1136
|
+
set shader(v) {
|
|
1137
|
+
this.props.shader = v;
|
|
1138
|
+
updateNodeStyles(this);
|
|
1139
|
+
}
|
|
1140
|
+
get strictBounds() {
|
|
1141
|
+
return this.props.strictBounds;
|
|
1142
|
+
}
|
|
1143
|
+
set strictBounds(v) {
|
|
1144
|
+
this.props.strictBounds = v;
|
|
1145
|
+
updateNodeStyles(this);
|
|
1146
|
+
}
|
|
1147
|
+
get data() {
|
|
1148
|
+
return this.props.data;
|
|
1149
|
+
}
|
|
1150
|
+
set data(v) {
|
|
1151
|
+
this.props.data = v;
|
|
1152
|
+
updateNodeData(this);
|
|
1153
|
+
}
|
|
1154
|
+
get imageType() {
|
|
1155
|
+
return this.props.imageType;
|
|
1156
|
+
}
|
|
1157
|
+
set imageType(v) {
|
|
1158
|
+
this.props.imageType = v;
|
|
1159
|
+
}
|
|
1160
|
+
get srcWidth() {
|
|
1161
|
+
return this.props.srcWidth;
|
|
1162
|
+
}
|
|
1163
|
+
set srcWidth(v) {
|
|
1164
|
+
this.props.srcWidth = v;
|
|
1165
|
+
}
|
|
1166
|
+
get srcHeight() {
|
|
1167
|
+
return this.props.srcHeight;
|
|
1168
|
+
}
|
|
1169
|
+
set srcHeight(v) {
|
|
1170
|
+
this.props.srcHeight = v;
|
|
1171
|
+
}
|
|
1172
|
+
get srcX() {
|
|
1173
|
+
return this.props.srcX;
|
|
1174
|
+
}
|
|
1175
|
+
set srcX(v) {
|
|
1176
|
+
this.props.srcX = v;
|
|
1177
|
+
}
|
|
1178
|
+
get srcY() {
|
|
1179
|
+
return this.props.srcY;
|
|
1180
|
+
}
|
|
1181
|
+
set srcY(v) {
|
|
1182
|
+
this.props.srcY = v;
|
|
1183
|
+
}
|
|
1184
|
+
get boundsMargin() {
|
|
1185
|
+
return this.props.boundsMargin;
|
|
1186
|
+
}
|
|
1187
|
+
set boundsMargin(value) {
|
|
1188
|
+
this.props.boundsMargin = value;
|
|
1189
|
+
}
|
|
1190
|
+
get absX() {
|
|
1191
|
+
return this.x + -this.width * this.mountX + (this.parent?.absX ?? 0);
|
|
1192
|
+
}
|
|
1193
|
+
get absY() {
|
|
1194
|
+
return this.y + -this.height * this.mountY + (this.parent?.absY ?? 0);
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
class DOMText extends DOMNode {
|
|
1198
|
+
// Unused props
|
|
1199
|
+
maxWidth;
|
|
1200
|
+
maxHeight;
|
|
1201
|
+
forceLoad;
|
|
1202
|
+
wordBreak;
|
|
1203
|
+
constructor(stage, props) {
|
|
1204
|
+
super(stage, props);
|
|
1205
|
+
this.div.innerText = props.text;
|
|
1206
|
+
}
|
|
1207
|
+
get text() {
|
|
1208
|
+
return this.props.text;
|
|
1209
|
+
}
|
|
1210
|
+
set text(v) {
|
|
1211
|
+
this.props.text = v;
|
|
1212
|
+
this.div.innerText = v;
|
|
1213
|
+
scheduleUpdateDOMTextMeasurement(this);
|
|
1214
|
+
}
|
|
1215
|
+
get fontFamily() {
|
|
1216
|
+
return this.props.fontFamily;
|
|
1217
|
+
}
|
|
1218
|
+
set fontFamily(v) {
|
|
1219
|
+
this.props.fontFamily = v;
|
|
1220
|
+
updateNodeStyles(this);
|
|
1221
|
+
}
|
|
1222
|
+
get fontSize() {
|
|
1223
|
+
return this.props.fontSize;
|
|
1224
|
+
}
|
|
1225
|
+
set fontSize(v) {
|
|
1226
|
+
this.props.fontSize = v;
|
|
1227
|
+
updateNodeStyles(this);
|
|
1228
|
+
}
|
|
1229
|
+
get fontStyle() {
|
|
1230
|
+
return this.props.fontStyle;
|
|
1231
|
+
}
|
|
1232
|
+
set fontStyle(v) {
|
|
1233
|
+
this.props.fontStyle = v;
|
|
1234
|
+
updateNodeStyles(this);
|
|
1235
|
+
}
|
|
1236
|
+
get fontWeight() {
|
|
1237
|
+
return this.props.fontWeight;
|
|
1238
|
+
}
|
|
1239
|
+
set fontWeight(v) {
|
|
1240
|
+
this.props.fontWeight = v;
|
|
1241
|
+
updateNodeStyles(this);
|
|
1242
|
+
}
|
|
1243
|
+
get fontStretch() {
|
|
1244
|
+
return this.props.fontStretch;
|
|
1245
|
+
}
|
|
1246
|
+
set fontStretch(v) {
|
|
1247
|
+
this.props.fontStretch = v;
|
|
1248
|
+
updateNodeStyles(this);
|
|
1249
|
+
}
|
|
1250
|
+
get lineHeight() {
|
|
1251
|
+
return this.props.lineHeight;
|
|
1252
|
+
}
|
|
1253
|
+
set lineHeight(v) {
|
|
1254
|
+
this.props.lineHeight = v;
|
|
1255
|
+
updateNodeStyles(this);
|
|
1256
|
+
}
|
|
1257
|
+
get letterSpacing() {
|
|
1258
|
+
return this.props.letterSpacing;
|
|
1259
|
+
}
|
|
1260
|
+
set letterSpacing(v) {
|
|
1261
|
+
this.props.letterSpacing = v;
|
|
1262
|
+
updateNodeStyles(this);
|
|
1263
|
+
}
|
|
1264
|
+
get textAlign() {
|
|
1265
|
+
return this.props.textAlign;
|
|
1266
|
+
}
|
|
1267
|
+
set textAlign(v) {
|
|
1268
|
+
this.props.textAlign = v;
|
|
1269
|
+
updateNodeStyles(this);
|
|
1270
|
+
}
|
|
1271
|
+
get overflowSuffix() {
|
|
1272
|
+
return this.props.overflowSuffix;
|
|
1273
|
+
}
|
|
1274
|
+
set overflowSuffix(v) {
|
|
1275
|
+
this.props.overflowSuffix = v;
|
|
1276
|
+
updateNodeStyles(this);
|
|
1277
|
+
}
|
|
1278
|
+
get maxLines() {
|
|
1279
|
+
return this.props.maxLines;
|
|
1280
|
+
}
|
|
1281
|
+
set maxLines(v) {
|
|
1282
|
+
this.props.maxLines = v;
|
|
1283
|
+
updateNodeStyles(this);
|
|
1284
|
+
}
|
|
1285
|
+
get contain() {
|
|
1286
|
+
return this.props.contain;
|
|
1287
|
+
}
|
|
1288
|
+
set contain(v) {
|
|
1289
|
+
this.props.contain = v;
|
|
1290
|
+
updateNodeStyles(this);
|
|
1291
|
+
}
|
|
1292
|
+
get verticalAlign() {
|
|
1293
|
+
return this.props.verticalAlign;
|
|
1294
|
+
}
|
|
1295
|
+
set verticalAlign(v) {
|
|
1296
|
+
this.props.verticalAlign = v;
|
|
1297
|
+
updateNodeStyles(this);
|
|
1298
|
+
}
|
|
1299
|
+
get textBaseline() {
|
|
1300
|
+
return this.props.textBaseline;
|
|
1301
|
+
}
|
|
1302
|
+
set textBaseline(v) {
|
|
1303
|
+
this.props.textBaseline = v;
|
|
1304
|
+
updateNodeStyles(this);
|
|
1305
|
+
}
|
|
1306
|
+
get textRendererOverride() {
|
|
1307
|
+
return this.props.textRendererOverride;
|
|
1308
|
+
}
|
|
1309
|
+
set textRendererOverride(v) {
|
|
1310
|
+
this.props.textRendererOverride = v;
|
|
1311
|
+
updateNodeStyles(this);
|
|
1312
|
+
}
|
|
1313
|
+
get scrollable() {
|
|
1314
|
+
return this.props.scrollable;
|
|
1315
|
+
}
|
|
1316
|
+
set scrollable(v) {
|
|
1317
|
+
this.props.scrollable = v;
|
|
1318
|
+
updateNodeStyles(this);
|
|
1319
|
+
}
|
|
1320
|
+
get scrollY() {
|
|
1321
|
+
return this.props.scrollY;
|
|
1322
|
+
}
|
|
1323
|
+
set scrollY(v) {
|
|
1324
|
+
this.props.scrollY = v;
|
|
1325
|
+
updateNodeStyles(this);
|
|
1326
|
+
}
|
|
1327
|
+
get offsetY() {
|
|
1328
|
+
return this.props.offsetY;
|
|
1329
|
+
}
|
|
1330
|
+
set offsetY(v) {
|
|
1331
|
+
this.props.offsetY = v;
|
|
1332
|
+
updateNodeStyles(this);
|
|
1333
|
+
}
|
|
1334
|
+
get debug() {
|
|
1335
|
+
return this.props.debug;
|
|
1336
|
+
}
|
|
1337
|
+
set debug(v) {
|
|
1338
|
+
this.props.debug = v;
|
|
1339
|
+
updateNodeStyles(this);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
function updateRootPosition() {
|
|
1343
|
+
let { canvas, settings } = this;
|
|
1344
|
+
let rect = canvas.getBoundingClientRect();
|
|
1345
|
+
let top = document.documentElement.scrollTop + rect.top;
|
|
1346
|
+
let left = document.documentElement.scrollLeft + rect.left;
|
|
1347
|
+
let dpr = settings.deviceLogicalPixelRatio ?? 1;
|
|
1348
|
+
let height = Math.ceil(settings.appHeight ?? 1080 / dpr);
|
|
1349
|
+
let width = Math.ceil(settings.appWidth ?? 1920 / dpr);
|
|
1350
|
+
this.root.div.style.left = `${left}px`;
|
|
1351
|
+
this.root.div.style.top = `${top}px`;
|
|
1352
|
+
this.root.div.style.width = `${width}px`;
|
|
1353
|
+
this.root.div.style.height = `${height}px`;
|
|
1354
|
+
this.root.div.style.position = 'absolute';
|
|
1355
|
+
this.root.div.style.transformOrigin = '0 0 0';
|
|
1356
|
+
this.root.div.style.transform = `scale(${dpr}, ${dpr})`;
|
|
1357
|
+
this.root.div.style.overflow = 'hidden';
|
|
1358
|
+
}
|
|
1359
|
+
export class DOMRendererMain {
|
|
1360
|
+
settings;
|
|
1361
|
+
root;
|
|
1362
|
+
canvas;
|
|
1363
|
+
stage;
|
|
1364
|
+
eventListeners = new Map();
|
|
1365
|
+
constructor(settings, rawTarget) {
|
|
1366
|
+
this.settings = settings;
|
|
1367
|
+
let target;
|
|
1368
|
+
if (typeof rawTarget === 'string') {
|
|
1369
|
+
let result = document.getElementById(rawTarget);
|
|
1370
|
+
if (result instanceof HTMLElement) {
|
|
1371
|
+
target = result;
|
|
1372
|
+
}
|
|
1373
|
+
else {
|
|
1374
|
+
throw new Error(`Target #${rawTarget} not found`);
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
else {
|
|
1378
|
+
target = rawTarget;
|
|
1379
|
+
}
|
|
1380
|
+
let canvas = document.body.appendChild(document.createElement('canvas'));
|
|
1381
|
+
canvas.style.position = 'absolute';
|
|
1382
|
+
canvas.style.top = '0';
|
|
1383
|
+
canvas.style.left = '0';
|
|
1384
|
+
canvas.style.width = '100vw';
|
|
1385
|
+
canvas.style.height = '100vh';
|
|
1386
|
+
this.canvas = canvas;
|
|
1387
|
+
this.stage = {
|
|
1388
|
+
root: null,
|
|
1389
|
+
renderer: {
|
|
1390
|
+
mode: 'canvas',
|
|
1391
|
+
},
|
|
1392
|
+
fontManager: {
|
|
1393
|
+
addFontFace: () => { },
|
|
1394
|
+
},
|
|
1395
|
+
shManager: {
|
|
1396
|
+
registerShaderType() { },
|
|
1397
|
+
},
|
|
1398
|
+
animationManager: {
|
|
1399
|
+
registerAnimation(anim) {
|
|
1400
|
+
console.log('registerAnimation', anim);
|
|
1401
|
+
},
|
|
1402
|
+
unregisterAnimation(anim) {
|
|
1403
|
+
console.log('unregisterAnimation', anim);
|
|
1404
|
+
},
|
|
1405
|
+
},
|
|
1406
|
+
};
|
|
1407
|
+
this.root = new DOMNode(this.stage, resolveNodeDefaults({
|
|
1408
|
+
width: settings.appWidth ?? 1920,
|
|
1409
|
+
height: settings.appHeight ?? 1080,
|
|
1410
|
+
shader: defaultShader,
|
|
1411
|
+
zIndex: 1,
|
|
1412
|
+
}));
|
|
1413
|
+
this.stage.root = this.root;
|
|
1414
|
+
target.appendChild(this.root.div);
|
|
1415
|
+
if (Config.fontSettings.fontFamily) {
|
|
1416
|
+
this.root.div.style.fontFamily = Config.fontSettings.fontFamily;
|
|
1417
|
+
}
|
|
1418
|
+
if (Config.fontSettings.fontSize) {
|
|
1419
|
+
this.root.div.style.fontSize = Config.fontSettings.fontSize + 'px';
|
|
1420
|
+
}
|
|
1421
|
+
if (Config.fontSettings.lineHeight) {
|
|
1422
|
+
this.root.div.style.lineHeight = Config.fontSettings.lineHeight + 'px';
|
|
1423
|
+
}
|
|
1424
|
+
else {
|
|
1425
|
+
this.root.div.style.lineHeight = '1.2';
|
|
1426
|
+
}
|
|
1427
|
+
if (Config.fontSettings.fontWeight) {
|
|
1428
|
+
if (typeof Config.fontSettings.fontWeight === 'number') {
|
|
1429
|
+
this.root.div.style.fontWeight = Config.fontSettings.fontWeight + 'px';
|
|
1430
|
+
}
|
|
1431
|
+
else {
|
|
1432
|
+
this.root.div.style.fontWeight = Config.fontSettings.fontWeight;
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
updateRootPosition.call(this);
|
|
1436
|
+
new MutationObserver(updateRootPosition.bind(this)).observe(this.canvas, {
|
|
1437
|
+
attributes: true,
|
|
1438
|
+
});
|
|
1439
|
+
new ResizeObserver(updateRootPosition.bind(this)).observe(this.canvas);
|
|
1440
|
+
window.addEventListener('resize', updateRootPosition.bind(this));
|
|
1441
|
+
}
|
|
1442
|
+
removeAllListeners() {
|
|
1443
|
+
if (this.eventListeners.size === 0)
|
|
1444
|
+
return;
|
|
1445
|
+
this.eventListeners.forEach((listeners) => listeners.clear());
|
|
1446
|
+
this.eventListeners.clear();
|
|
1447
|
+
}
|
|
1448
|
+
once(event, listener) {
|
|
1449
|
+
const wrappedListener = (target, data) => {
|
|
1450
|
+
this.off(event, wrappedListener);
|
|
1451
|
+
listener(target, data);
|
|
1452
|
+
};
|
|
1453
|
+
this.on(event, wrappedListener);
|
|
1454
|
+
}
|
|
1455
|
+
on(name, callback) {
|
|
1456
|
+
let listeners = this.eventListeners.get(name);
|
|
1457
|
+
if (!listeners) {
|
|
1458
|
+
listeners = new Set();
|
|
1459
|
+
this.eventListeners.set(name, listeners);
|
|
1460
|
+
}
|
|
1461
|
+
listeners.add(callback);
|
|
1462
|
+
}
|
|
1463
|
+
off(event, listener) {
|
|
1464
|
+
const listeners = this.eventListeners.get(event);
|
|
1465
|
+
if (listeners) {
|
|
1466
|
+
listeners.delete(listener);
|
|
1467
|
+
if (listeners.size === 0) {
|
|
1468
|
+
this.eventListeners.delete(event);
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
emit(event, targetOrData, maybeData) {
|
|
1473
|
+
const listeners = this.eventListeners.get(event);
|
|
1474
|
+
if (!listeners || listeners.size === 0) {
|
|
1475
|
+
return;
|
|
1476
|
+
}
|
|
1477
|
+
const hasExplicitTarget = arguments.length === 3;
|
|
1478
|
+
const target = hasExplicitTarget ? targetOrData : this.root;
|
|
1479
|
+
const data = hasExplicitTarget ? maybeData : targetOrData;
|
|
1480
|
+
for (const listener of Array.from(listeners)) {
|
|
1481
|
+
try {
|
|
1482
|
+
listener(target, data);
|
|
1483
|
+
}
|
|
1484
|
+
catch (error) {
|
|
1485
|
+
console.error(`Error in listener for event "${event}"`, error);
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
createNode(props) {
|
|
1490
|
+
return new DOMNode(this.stage, resolveNodeDefaults(props));
|
|
1491
|
+
}
|
|
1492
|
+
createTextNode(props) {
|
|
1493
|
+
return new DOMText(this.stage, resolveTextNodeDefaults(props));
|
|
1494
|
+
}
|
|
1495
|
+
createShader(shaderType, props) {
|
|
1496
|
+
return {
|
|
1497
|
+
shaderType,
|
|
1498
|
+
props,
|
|
1499
|
+
program: {},
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
createTexture(textureType, props) {
|
|
1503
|
+
let type = lng.TextureType.generic;
|
|
1504
|
+
switch (textureType) {
|
|
1505
|
+
case 'SubTexture':
|
|
1506
|
+
type = lng.TextureType.subTexture;
|
|
1507
|
+
break;
|
|
1508
|
+
case 'ImageTexture':
|
|
1509
|
+
type = lng.TextureType.image;
|
|
1510
|
+
break;
|
|
1511
|
+
case 'ColorTexture':
|
|
1512
|
+
type = lng.TextureType.color;
|
|
1513
|
+
break;
|
|
1514
|
+
case 'NoiseTexture':
|
|
1515
|
+
type = lng.TextureType.noise;
|
|
1516
|
+
break;
|
|
1517
|
+
case 'RenderTexture':
|
|
1518
|
+
type = lng.TextureType.renderToTexture;
|
|
1519
|
+
break;
|
|
1520
|
+
}
|
|
1521
|
+
return { type, props };
|
|
1522
|
+
}
|
|
1523
|
+
createEffect(type, props, name) {
|
|
1524
|
+
return { type, props, name: name };
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
export function loadFontToDom(font) {
|
|
1528
|
+
const fontFaceDescriptors = font.descriptors
|
|
1529
|
+
? {
|
|
1530
|
+
...font.descriptors,
|
|
1531
|
+
weight: typeof font.descriptors.weight === 'number'
|
|
1532
|
+
? String(font.descriptors.weight)
|
|
1533
|
+
: font.descriptors.weight,
|
|
1534
|
+
}
|
|
1535
|
+
: undefined;
|
|
1536
|
+
const fontFace = new FontFace(font.fontFamily, `url(${font.fontUrl})`, fontFaceDescriptors);
|
|
1537
|
+
if (typeof document !== 'undefined' && 'fonts' in document) {
|
|
1538
|
+
const fontSet = document.fonts;
|
|
1539
|
+
fontSet.add?.(fontFace);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
export function isDomRenderer(r) {
|
|
1543
|
+
return r instanceof DOMRendererMain;
|
|
1544
|
+
}
|
|
1545
|
+
//# sourceMappingURL=domRenderer.js.map
|