@playcanvas/web-components 0.8.1 → 0.9.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/dist/app.d.ts +10 -2
- package/dist/asset.d.ts +18 -3
- package/dist/async-element.d.ts +51 -4
- package/dist/components/button-component.d.ts +10 -4
- package/dist/components/camera-component.d.ts +9 -4
- package/dist/components/collision-component.d.ts +9 -4
- package/dist/components/component.d.ts +7 -1
- package/dist/components/element-component.d.ts +17 -12
- package/dist/components/gsplat-component.d.ts +6 -1
- package/dist/components/layoutchild-component.d.ts +6 -1
- package/dist/components/layoutgroup-component.d.ts +21 -15
- package/dist/components/light-component.d.ts +12 -6
- package/dist/components/listener-component.d.ts +6 -1
- package/dist/components/particlesystem-component.d.ts +6 -1
- package/dist/components/render-component.d.ts +13 -4
- package/dist/components/rigidbody-component.d.ts +9 -4
- package/dist/components/screen-component.d.ts +6 -1
- package/dist/components/script-component.d.ts +116 -16
- package/dist/components/script.d.ts +72 -8
- package/dist/components/scrollbar-component.d.ts +10 -4
- package/dist/components/scrollview-component.d.ts +17 -10
- package/dist/components/sound-component.d.ts +6 -1
- package/dist/components/sound-slot.d.ts +8 -3
- package/dist/entity.d.ts +26 -2
- package/dist/index.d.ts +3 -2
- package/dist/material.d.ts +10 -0
- package/dist/model.d.ts +5 -0
- package/dist/module.d.ts +5 -0
- package/dist/pwc.cjs +1574 -853
- package/dist/pwc.cjs.map +1 -1
- package/dist/pwc.js +1574 -853
- package/dist/pwc.js.map +1 -1
- package/dist/pwc.min.js +1 -1
- package/dist/pwc.min.js.map +1 -1
- package/dist/pwc.mjs +1575 -855
- package/dist/pwc.mjs.map +1 -1
- package/dist/scene.d.ts +14 -5
- package/dist/sky.d.ts +6 -0
- package/dist/utils.d.ts +81 -23
- package/package.json +23 -13
- package/src/app.ts +38 -12
- package/src/asset.ts +61 -8
- package/src/async-element.ts +86 -5
- package/src/components/button-component.ts +26 -19
- package/src/components/camera-component.ts +29 -23
- package/src/components/collision-component.ts +19 -13
- package/src/components/component.ts +32 -13
- package/src/components/element-component.ts +58 -52
- package/src/components/gsplat-component.ts +14 -7
- package/src/components/layoutchild-component.ts +16 -9
- package/src/components/layoutgroup-component.ts +38 -31
- package/src/components/light-component.ts +33 -31
- package/src/components/listener-component.ts +8 -2
- package/src/components/particlesystem-component.ts +8 -2
- package/src/components/render-component.ts +19 -8
- package/src/components/rigidbody-component.ts +21 -15
- package/src/components/screen-component.ts +15 -9
- package/src/components/script-component.ts +512 -125
- package/src/components/script.ts +116 -16
- package/src/components/scrollbar-component.ts +19 -12
- package/src/components/scrollview-component.ts +37 -29
- package/src/components/sound-component.ts +16 -9
- package/src/components/sound-slot.ts +23 -14
- package/src/entity.ts +61 -71
- package/src/index.ts +5 -2
- package/src/material.ts +34 -1
- package/src/model.ts +6 -0
- package/src/module.ts +6 -0
- package/src/scene.ts +25 -12
- package/src/sky.ts +34 -16
- package/src/utils.ts +180 -40
package/dist/pwc.js
CHANGED
|
@@ -24,21 +24,51 @@
|
|
|
24
24
|
return (_a = this.parentElement) === null || _a === void 0 ? void 0 : _a.closest('pc-entity');
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
* Called when the element is fully initialized and ready.
|
|
28
|
-
*
|
|
27
|
+
* Called when the element is fully initialized and ready. Subclasses should call this when
|
|
28
|
+
* they're ready. Resolves the ready promise and dispatches a bubbling, composed `ready`
|
|
29
|
+
* event.
|
|
29
30
|
*/
|
|
30
31
|
_onReady() {
|
|
31
32
|
this._readyResolve();
|
|
32
|
-
this.dispatchEvent(new CustomEvent('ready'));
|
|
33
|
+
this.dispatchEvent(new CustomEvent('ready', { bubbles: true, composed: true }));
|
|
33
34
|
}
|
|
34
35
|
/**
|
|
35
|
-
* Returns a promise that resolves with this element when it's ready.
|
|
36
|
+
* Returns a promise that resolves with this element when it's ready. This is the low-level
|
|
37
|
+
* primitive underlying {@link whenReady}, which is the recommended way to wait for elements.
|
|
36
38
|
* @returns A promise that resolves with this element when it's ready.
|
|
37
39
|
*/
|
|
38
40
|
ready() {
|
|
39
41
|
return this._readyPromise.then(() => this);
|
|
40
42
|
}
|
|
41
43
|
}
|
|
44
|
+
async function whenReady(target) {
|
|
45
|
+
let element;
|
|
46
|
+
if (typeof target === 'string') {
|
|
47
|
+
if (document.readyState === 'loading') {
|
|
48
|
+
await new Promise((resolve) => {
|
|
49
|
+
document.addEventListener('DOMContentLoaded', resolve, { once: true });
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
element = document.querySelector(target);
|
|
54
|
+
}
|
|
55
|
+
catch (_a) {
|
|
56
|
+
throw new Error(`whenReady: '${target}' is not a valid CSS selector`);
|
|
57
|
+
}
|
|
58
|
+
if (!element) {
|
|
59
|
+
throw new Error(`whenReady: no element found matching '${target}'`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
element = target;
|
|
64
|
+
}
|
|
65
|
+
if (!(element instanceof AsyncElement)) {
|
|
66
|
+
const description = element instanceof Element ? `<${element.tagName.toLowerCase()}>` : String(target);
|
|
67
|
+
throw new Error(`whenReady: ${description} does not initialize asynchronously`);
|
|
68
|
+
}
|
|
69
|
+
await element.ready();
|
|
70
|
+
return element;
|
|
71
|
+
}
|
|
42
72
|
|
|
43
73
|
/**
|
|
44
74
|
* The ModuleElement interface provides properties and methods for manipulating
|
|
@@ -74,6 +104,393 @@
|
|
|
74
104
|
}
|
|
75
105
|
customElements.define('pc-module', ModuleElement);
|
|
76
106
|
|
|
107
|
+
const CSS_COLORS = {
|
|
108
|
+
aliceblue: '#f0f8ff',
|
|
109
|
+
antiquewhite: '#faebd7',
|
|
110
|
+
aqua: '#00ffff',
|
|
111
|
+
aquamarine: '#7fffd4',
|
|
112
|
+
azure: '#f0ffff',
|
|
113
|
+
beige: '#f5f5dc',
|
|
114
|
+
bisque: '#ffe4c4',
|
|
115
|
+
black: '#000000',
|
|
116
|
+
blanchedalmond: '#ffebcd',
|
|
117
|
+
blue: '#0000ff',
|
|
118
|
+
blueviolet: '#8a2be2',
|
|
119
|
+
brown: '#a52a2a',
|
|
120
|
+
burlywood: '#deb887',
|
|
121
|
+
cadetblue: '#5f9ea0',
|
|
122
|
+
chartreuse: '#7fff00',
|
|
123
|
+
chocolate: '#d2691e',
|
|
124
|
+
coral: '#ff7f50',
|
|
125
|
+
cornflowerblue: '#6495ed',
|
|
126
|
+
cornsilk: '#fff8dc',
|
|
127
|
+
crimson: '#dc143c',
|
|
128
|
+
cyan: '#00ffff',
|
|
129
|
+
darkblue: '#00008b',
|
|
130
|
+
darkcyan: '#008b8b',
|
|
131
|
+
darkgoldenrod: '#b8860b',
|
|
132
|
+
darkgray: '#a9a9a9',
|
|
133
|
+
darkgreen: '#006400',
|
|
134
|
+
darkgrey: '#a9a9a9',
|
|
135
|
+
darkkhaki: '#bdb76b',
|
|
136
|
+
darkmagenta: '#8b008b',
|
|
137
|
+
darkolivegreen: '#556b2f',
|
|
138
|
+
darkorange: '#ff8c00',
|
|
139
|
+
darkorchid: '#9932cc',
|
|
140
|
+
darkred: '#8b0000',
|
|
141
|
+
darksalmon: '#e9967a',
|
|
142
|
+
darkseagreen: '#8fbc8f',
|
|
143
|
+
darkslateblue: '#483d8b',
|
|
144
|
+
darkslategray: '#2f4f4f',
|
|
145
|
+
darkslategrey: '#2f4f4f',
|
|
146
|
+
darkturquoise: '#00ced1',
|
|
147
|
+
darkviolet: '#9400d3',
|
|
148
|
+
deeppink: '#ff1493',
|
|
149
|
+
deepskyblue: '#00bfff',
|
|
150
|
+
dimgray: '#696969',
|
|
151
|
+
dimgrey: '#696969',
|
|
152
|
+
dodgerblue: '#1e90ff',
|
|
153
|
+
firebrick: '#b22222',
|
|
154
|
+
floralwhite: '#fffaf0',
|
|
155
|
+
forestgreen: '#228b22',
|
|
156
|
+
fuchsia: '#ff00ff',
|
|
157
|
+
gainsboro: '#dcdcdc',
|
|
158
|
+
ghostwhite: '#f8f8ff',
|
|
159
|
+
gold: '#ffd700',
|
|
160
|
+
goldenrod: '#daa520',
|
|
161
|
+
gray: '#808080',
|
|
162
|
+
green: '#008000',
|
|
163
|
+
greenyellow: '#adff2f',
|
|
164
|
+
grey: '#808080',
|
|
165
|
+
honeydew: '#f0fff0',
|
|
166
|
+
hotpink: '#ff69b4',
|
|
167
|
+
indianred: '#cd5c5c',
|
|
168
|
+
indigo: '#4b0082',
|
|
169
|
+
ivory: '#fffff0',
|
|
170
|
+
khaki: '#f0e68c',
|
|
171
|
+
lavender: '#e6e6fa',
|
|
172
|
+
lavenderblush: '#fff0f5',
|
|
173
|
+
lawngreen: '#7cfc00',
|
|
174
|
+
lemonchiffon: '#fffacd',
|
|
175
|
+
lightblue: '#add8e6',
|
|
176
|
+
lightcoral: '#f08080',
|
|
177
|
+
lightcyan: '#e0ffff',
|
|
178
|
+
lightgoldenrodyellow: '#fafad2',
|
|
179
|
+
lightgray: '#d3d3d3',
|
|
180
|
+
lightgreen: '#90ee90',
|
|
181
|
+
lightgrey: '#d3d3d3',
|
|
182
|
+
lightpink: '#ffb6c1',
|
|
183
|
+
lightsalmon: '#ffa07a',
|
|
184
|
+
lightseagreen: '#20b2aa',
|
|
185
|
+
lightskyblue: '#87cefa',
|
|
186
|
+
lightslategray: '#778899',
|
|
187
|
+
lightslategrey: '#778899',
|
|
188
|
+
lightsteelblue: '#b0c4de',
|
|
189
|
+
lightyellow: '#ffffe0',
|
|
190
|
+
lime: '#00ff00',
|
|
191
|
+
limegreen: '#32cd32',
|
|
192
|
+
linen: '#faf0e6',
|
|
193
|
+
magenta: '#ff00ff',
|
|
194
|
+
maroon: '#800000',
|
|
195
|
+
mediumaquamarine: '#66cdaa',
|
|
196
|
+
mediumblue: '#0000cd',
|
|
197
|
+
mediumorchid: '#ba55d3',
|
|
198
|
+
mediumpurple: '#9370db',
|
|
199
|
+
mediumseagreen: '#3cb371',
|
|
200
|
+
mediumslateblue: '#7b68ee',
|
|
201
|
+
mediumspringgreen: '#00fa9a',
|
|
202
|
+
mediumturquoise: '#48d1cc',
|
|
203
|
+
mediumvioletred: '#c71585',
|
|
204
|
+
midnightblue: '#191970',
|
|
205
|
+
mintcream: '#f5fffa',
|
|
206
|
+
mistyrose: '#ffe4e1',
|
|
207
|
+
moccasin: '#ffe4b5',
|
|
208
|
+
navajowhite: '#ffdead',
|
|
209
|
+
navy: '#000080',
|
|
210
|
+
oldlace: '#fdf5e6',
|
|
211
|
+
olive: '#808000',
|
|
212
|
+
olivedrab: '#6b8e23',
|
|
213
|
+
orange: '#ffa500',
|
|
214
|
+
orangered: '#ff4500',
|
|
215
|
+
orchid: '#da70d6',
|
|
216
|
+
palegoldenrod: '#eee8aa',
|
|
217
|
+
palegreen: '#98fb98',
|
|
218
|
+
paleturquoise: '#afeeee',
|
|
219
|
+
palevioletred: '#db7093',
|
|
220
|
+
papayawhip: '#ffefd5',
|
|
221
|
+
peachpuff: '#ffdab9',
|
|
222
|
+
peru: '#cd853f',
|
|
223
|
+
pink: '#ffc0cb',
|
|
224
|
+
plum: '#dda0dd',
|
|
225
|
+
powderblue: '#b0e0e6',
|
|
226
|
+
purple: '#800080',
|
|
227
|
+
rebeccapurple: '#663399',
|
|
228
|
+
red: '#ff0000',
|
|
229
|
+
rosybrown: '#bc8f8f',
|
|
230
|
+
royalblue: '#4169e1',
|
|
231
|
+
saddlebrown: '#8b4513',
|
|
232
|
+
salmon: '#fa8072',
|
|
233
|
+
sandybrown: '#f4a460',
|
|
234
|
+
seagreen: '#2e8b57',
|
|
235
|
+
seashell: '#fff5ee',
|
|
236
|
+
sienna: '#a0522d',
|
|
237
|
+
silver: '#c0c0c0',
|
|
238
|
+
skyblue: '#87ceeb',
|
|
239
|
+
slateblue: '#6a5acd',
|
|
240
|
+
slategray: '#708090',
|
|
241
|
+
slategrey: '#708090',
|
|
242
|
+
snow: '#fffafa',
|
|
243
|
+
springgreen: '#00ff7f',
|
|
244
|
+
steelblue: '#4682b4',
|
|
245
|
+
tan: '#d2b48c',
|
|
246
|
+
teal: '#008080',
|
|
247
|
+
thistle: '#d8bfd8',
|
|
248
|
+
tomato: '#ff6347',
|
|
249
|
+
turquoise: '#40e0d0',
|
|
250
|
+
violet: '#ee82ee',
|
|
251
|
+
wheat: '#f5deb3',
|
|
252
|
+
white: '#ffffff',
|
|
253
|
+
whitesmoke: '#f5f5f5',
|
|
254
|
+
yellow: '#ffff00',
|
|
255
|
+
yellowgreen: '#9acd32'
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Parse a boolean attribute value. The same rules apply to every boolean attribute:
|
|
260
|
+
*
|
|
261
|
+
* - Attribute absent (or removed): the supplied default is used.
|
|
262
|
+
* - Attribute set to the string 'false': `false`.
|
|
263
|
+
* - Attribute present with any other value, including the empty string of a bare boolean
|
|
264
|
+
* attribute (e.g. `<pc-light cast-shadows>`): `true`.
|
|
265
|
+
*
|
|
266
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
267
|
+
* @param defaultValue - The value to use when the attribute is absent or removed.
|
|
268
|
+
* @returns The parsed boolean.
|
|
269
|
+
*/
|
|
270
|
+
const parseBool = (value, defaultValue) => {
|
|
271
|
+
return value === null ? defaultValue : value !== 'false';
|
|
272
|
+
};
|
|
273
|
+
/**
|
|
274
|
+
* Splits an attribute value into exactly `count` numeric components. Returns `null` when the
|
|
275
|
+
* value does not consist of exactly `count` whitespace-separated finite numbers.
|
|
276
|
+
*
|
|
277
|
+
* @param value - The value to split.
|
|
278
|
+
* @param count - The required number of components.
|
|
279
|
+
* @returns The parsed components, or `null`.
|
|
280
|
+
* @ignore
|
|
281
|
+
*/
|
|
282
|
+
const parseComponents = (value, count) => {
|
|
283
|
+
const components = value.trim().split(/\s+/).map(Number);
|
|
284
|
+
if (components.length !== count || components.some(component => !Number.isFinite(component))) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
return components;
|
|
288
|
+
};
|
|
289
|
+
/**
|
|
290
|
+
* Clones a math-type default so parsed results never alias the caller's default instance. This
|
|
291
|
+
* is what makes it safe to pass the engine's shared frozen constants (e.g. `Vec3.ZERO`,
|
|
292
|
+
* `Color.WHITE`) as defaults.
|
|
293
|
+
*
|
|
294
|
+
* @param value - The default value to clone (`null` is passed through).
|
|
295
|
+
* @returns The cloned value.
|
|
296
|
+
*/
|
|
297
|
+
const cloneDefault = (value) => {
|
|
298
|
+
return (value === null ? null : value.clone());
|
|
299
|
+
};
|
|
300
|
+
/**
|
|
301
|
+
* Parse a color attribute value. The expected format is a CSS color name (e.g. 'rebeccapurple'),
|
|
302
|
+
* a hex color (e.g. '#ff0000' or '#f00'), or 3 or 4 space-separated numbers in the range 0 to 1
|
|
303
|
+
* (e.g. '1 0.5 0.5' or '1 0.5 0.5 0.5'). Returns `defaultValue` (cloned, when it is a color)
|
|
304
|
+
* when the attribute is absent (`null`), or when the value is malformed — the latter also logs
|
|
305
|
+
* a warning.
|
|
306
|
+
*
|
|
307
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
308
|
+
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
309
|
+
* @param attribute - The attribute name, used in the warning message.
|
|
310
|
+
* @returns The parsed Color object.
|
|
311
|
+
*/
|
|
312
|
+
const parseColor = (value, defaultValue, attribute) => {
|
|
313
|
+
var _a;
|
|
314
|
+
if (value === null) {
|
|
315
|
+
return cloneDefault(defaultValue);
|
|
316
|
+
}
|
|
317
|
+
// A CSS color name (e.g. 'rebeccapurple')
|
|
318
|
+
const hexColor = CSS_COLORS[value.toLowerCase()];
|
|
319
|
+
if (hexColor) {
|
|
320
|
+
return new playcanvas.Color().fromString(hexColor);
|
|
321
|
+
}
|
|
322
|
+
// A hex color (e.g. '#ff0000'), expanding short forms (e.g. '#f00') for Color.fromString
|
|
323
|
+
if (/^#(?:[0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(value)) {
|
|
324
|
+
let hex = value.slice(1);
|
|
325
|
+
if (hex.length === 3 || hex.length === 4) {
|
|
326
|
+
hex = hex.split('').map(char => char + char).join('');
|
|
327
|
+
}
|
|
328
|
+
return new playcanvas.Color().fromString(`#${hex}`);
|
|
329
|
+
}
|
|
330
|
+
// 3 or 4 space-separated components (e.g. '1 0.5 0.5')
|
|
331
|
+
const components = (_a = parseComponents(value, 4)) !== null && _a !== void 0 ? _a : parseComponents(value, 3);
|
|
332
|
+
if (components) {
|
|
333
|
+
return new playcanvas.Color(components);
|
|
334
|
+
}
|
|
335
|
+
console.warn(`Invalid value '${value}' for attribute '${attribute}'. Expected a CSS color name, a hex color or 3 or 4 space-separated numbers. Using '${defaultValue}'.`);
|
|
336
|
+
return cloneDefault(defaultValue);
|
|
337
|
+
};
|
|
338
|
+
/**
|
|
339
|
+
* Parse an Euler-angles attribute value into a quaternion. The expected format is 3
|
|
340
|
+
* space-separated angles in degrees (e.g. '0 90 0'). Returns `defaultValue` (cloned, when it is
|
|
341
|
+
* a quaternion) when the attribute is absent (`null`), or when the value is malformed — the
|
|
342
|
+
* latter also logs a warning.
|
|
343
|
+
*
|
|
344
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
345
|
+
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
346
|
+
* @param attribute - The attribute name, used in the warning message.
|
|
347
|
+
* @returns The parsed Quat object.
|
|
348
|
+
*/
|
|
349
|
+
const parseQuat = (value, defaultValue, attribute) => {
|
|
350
|
+
if (value === null) {
|
|
351
|
+
return cloneDefault(defaultValue);
|
|
352
|
+
}
|
|
353
|
+
const components = parseComponents(value, 3);
|
|
354
|
+
if (!components) {
|
|
355
|
+
console.warn(`Invalid value '${value}' for attribute '${attribute}'. Expected 3 space-separated numbers. Using '${defaultValue}'.`);
|
|
356
|
+
return cloneDefault(defaultValue);
|
|
357
|
+
}
|
|
358
|
+
return new playcanvas.Quat().setFromEulerAngles(components[0], components[1], components[2]);
|
|
359
|
+
};
|
|
360
|
+
/**
|
|
361
|
+
* Parse a Vec2 attribute value. The expected format is 2 space-separated numbers (e.g. '1 2').
|
|
362
|
+
* Returns `defaultValue` (cloned, when it is a vector) when the attribute is absent (`null`),
|
|
363
|
+
* or when the value is malformed — the latter also logs a warning.
|
|
364
|
+
*
|
|
365
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
366
|
+
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
367
|
+
* @param attribute - The attribute name, used in the warning message.
|
|
368
|
+
* @returns The parsed Vec2 object.
|
|
369
|
+
*/
|
|
370
|
+
const parseVec2 = (value, defaultValue, attribute) => {
|
|
371
|
+
if (value === null) {
|
|
372
|
+
return cloneDefault(defaultValue);
|
|
373
|
+
}
|
|
374
|
+
const components = parseComponents(value, 2);
|
|
375
|
+
if (!components) {
|
|
376
|
+
console.warn(`Invalid value '${value}' for attribute '${attribute}'. Expected 2 space-separated numbers. Using '${defaultValue}'.`);
|
|
377
|
+
return cloneDefault(defaultValue);
|
|
378
|
+
}
|
|
379
|
+
return new playcanvas.Vec2(components);
|
|
380
|
+
};
|
|
381
|
+
/**
|
|
382
|
+
* Parse a Vec3 attribute value. The expected format is 3 space-separated numbers (e.g. '1 2 3').
|
|
383
|
+
* Returns `defaultValue` (cloned, when it is a vector) when the attribute is absent (`null`),
|
|
384
|
+
* or when the value is malformed — the latter also logs a warning.
|
|
385
|
+
*
|
|
386
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
387
|
+
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
388
|
+
* @param attribute - The attribute name, used in the warning message.
|
|
389
|
+
* @returns The parsed Vec3 object.
|
|
390
|
+
*/
|
|
391
|
+
const parseVec3 = (value, defaultValue, attribute) => {
|
|
392
|
+
if (value === null) {
|
|
393
|
+
return cloneDefault(defaultValue);
|
|
394
|
+
}
|
|
395
|
+
const components = parseComponents(value, 3);
|
|
396
|
+
if (!components) {
|
|
397
|
+
console.warn(`Invalid value '${value}' for attribute '${attribute}'. Expected 3 space-separated numbers. Using '${defaultValue}'.`);
|
|
398
|
+
return cloneDefault(defaultValue);
|
|
399
|
+
}
|
|
400
|
+
return new playcanvas.Vec3(components);
|
|
401
|
+
};
|
|
402
|
+
/**
|
|
403
|
+
* Parse a Vec4 attribute value. The expected format is 4 space-separated numbers
|
|
404
|
+
* (e.g. '1 2 3 4'). Returns `defaultValue` (cloned, when it is a vector) when the attribute is
|
|
405
|
+
* absent (`null`), or when the value is malformed — the latter also logs a warning.
|
|
406
|
+
*
|
|
407
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
408
|
+
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
409
|
+
* @param attribute - The attribute name, used in the warning message.
|
|
410
|
+
* @returns The parsed Vec4 object.
|
|
411
|
+
*/
|
|
412
|
+
const parseVec4 = (value, defaultValue, attribute) => {
|
|
413
|
+
if (value === null) {
|
|
414
|
+
return cloneDefault(defaultValue);
|
|
415
|
+
}
|
|
416
|
+
const components = parseComponents(value, 4);
|
|
417
|
+
if (!components) {
|
|
418
|
+
console.warn(`Invalid value '${value}' for attribute '${attribute}'. Expected 4 space-separated numbers. Using '${defaultValue}'.`);
|
|
419
|
+
return cloneDefault(defaultValue);
|
|
420
|
+
}
|
|
421
|
+
return new playcanvas.Vec4(components);
|
|
422
|
+
};
|
|
423
|
+
/**
|
|
424
|
+
* Resolves an enum attribute value against its set of valid names. Returns the value when it is
|
|
425
|
+
* one of the valid names. Returns `defaultValue` when the attribute is absent (`null`), or when
|
|
426
|
+
* the value is invalid — the latter also logs a warning listing the valid names.
|
|
427
|
+
*
|
|
428
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
429
|
+
* @param valid - The valid names: an array, or a map whose keys are the valid names.
|
|
430
|
+
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
431
|
+
* @param attribute - The attribute name, used in the warning message.
|
|
432
|
+
* @returns The resolved enum name.
|
|
433
|
+
*/
|
|
434
|
+
const parseEnum = (value, valid, defaultValue, attribute) => {
|
|
435
|
+
if (value === null) {
|
|
436
|
+
return defaultValue;
|
|
437
|
+
}
|
|
438
|
+
const names = Array.isArray(valid) ? valid : [...valid.keys()];
|
|
439
|
+
if (names.includes(value)) {
|
|
440
|
+
return value;
|
|
441
|
+
}
|
|
442
|
+
console.warn(`Invalid value '${value}' for attribute '${attribute}'. Valid values: ${names.join(', ')}. Using '${defaultValue}'.`);
|
|
443
|
+
return defaultValue;
|
|
444
|
+
};
|
|
445
|
+
/**
|
|
446
|
+
* Parses a number attribute value. Returns the parsed number when the value is a finite number.
|
|
447
|
+
* Returns `defaultValue` when the attribute is absent (`null`), or when the value is not a
|
|
448
|
+
* finite number — the latter also logs a warning.
|
|
449
|
+
*
|
|
450
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
451
|
+
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
452
|
+
* @param attribute - The attribute name, used in the warning message.
|
|
453
|
+
* @returns The parsed number.
|
|
454
|
+
*/
|
|
455
|
+
const parseNumber = (value, defaultValue, attribute) => {
|
|
456
|
+
if (value === null) {
|
|
457
|
+
return defaultValue;
|
|
458
|
+
}
|
|
459
|
+
const number = value.trim() === '' ? NaN : Number(value);
|
|
460
|
+
if (!Number.isFinite(number)) {
|
|
461
|
+
console.warn(`Invalid value '${value}' for attribute '${attribute}'. Expected a finite number. Using '${defaultValue}'.`);
|
|
462
|
+
return defaultValue;
|
|
463
|
+
}
|
|
464
|
+
return number;
|
|
465
|
+
};
|
|
466
|
+
/**
|
|
467
|
+
* Resolves a reference string to the {@link Entity} backing a `<pc-entity>` element. The reference
|
|
468
|
+
* can be a CSS selector (e.g. `#my-id`, `pc-entity[name="Foo"]`), a bare element id, or a bare
|
|
469
|
+
* entity name. Returns `null` if no matching element (or backing entity) is found.
|
|
470
|
+
*
|
|
471
|
+
* @param ref - The reference string to resolve.
|
|
472
|
+
* @returns The resolved entity, or `null`.
|
|
473
|
+
*/
|
|
474
|
+
const getEntity = (ref) => {
|
|
475
|
+
var _a, _b;
|
|
476
|
+
if (!ref) {
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
let element = null;
|
|
480
|
+
// Try the reference as a CSS selector. An invalid selector (e.g. a bare name containing
|
|
481
|
+
// spaces) throws, in which case we fall back to id/name lookups below.
|
|
482
|
+
try {
|
|
483
|
+
element = document.querySelector(ref);
|
|
484
|
+
}
|
|
485
|
+
catch (_c) {
|
|
486
|
+
element = null;
|
|
487
|
+
}
|
|
488
|
+
if (!element) {
|
|
489
|
+
element = (_a = document.getElementById(ref)) !== null && _a !== void 0 ? _a : document.querySelector(`pc-entity[name="${ref}"]`);
|
|
490
|
+
}
|
|
491
|
+
return (_b = element === null || element === void 0 ? void 0 : element.entity) !== null && _b !== void 0 ? _b : null;
|
|
492
|
+
};
|
|
493
|
+
|
|
77
494
|
/**
|
|
78
495
|
* The AppElement interface provides properties and methods for manipulating
|
|
79
496
|
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-app/ | `<pc-app>`} elements.
|
|
@@ -81,6 +498,14 @@
|
|
|
81
498
|
* {@link HTMLElement} interface.
|
|
82
499
|
*/
|
|
83
500
|
class AppElement extends AsyncElement {
|
|
501
|
+
/**
|
|
502
|
+
* The PlayCanvas application instance. Available once the element is ready — await
|
|
503
|
+
* {@link whenReady} or the element's `ready()` promise before accessing it.
|
|
504
|
+
* @returns The application instance.
|
|
505
|
+
*/
|
|
506
|
+
get app() {
|
|
507
|
+
return this._app;
|
|
508
|
+
}
|
|
84
509
|
/**
|
|
85
510
|
* Creates a new AppElement instance.
|
|
86
511
|
*
|
|
@@ -113,10 +538,7 @@
|
|
|
113
538
|
pointerdown: null,
|
|
114
539
|
pointerup: null
|
|
115
540
|
};
|
|
116
|
-
|
|
117
|
-
* The PlayCanvas application instance.
|
|
118
|
-
*/
|
|
119
|
-
this.app = null;
|
|
541
|
+
this._app = null;
|
|
120
542
|
// Bind methods to maintain 'this' context
|
|
121
543
|
this._onWindowResize = this._onWindowResize.bind(this);
|
|
122
544
|
}
|
|
@@ -208,7 +630,7 @@
|
|
|
208
630
|
createOptions.lightmapper = playcanvas.Lightmapper;
|
|
209
631
|
createOptions.batchManager = playcanvas.BatchManager;
|
|
210
632
|
createOptions.xr = playcanvas.XrManager;
|
|
211
|
-
this.
|
|
633
|
+
this._app = new playcanvas.AppBase(this._canvas);
|
|
212
634
|
this.app.init(createOptions);
|
|
213
635
|
this.app.setCanvasFillMode(playcanvas.FILLMODE_FILL_WINDOW);
|
|
214
636
|
this.app.setCanvasResolution(playcanvas.RESOLUTION_AUTO);
|
|
@@ -251,7 +673,7 @@
|
|
|
251
673
|
// Clean up the application
|
|
252
674
|
if (this.app) {
|
|
253
675
|
this.app.destroy();
|
|
254
|
-
this.
|
|
676
|
+
this._app = null;
|
|
255
677
|
}
|
|
256
678
|
// Remove event listeners
|
|
257
679
|
window.removeEventListener('resize', this._onWindowResize);
|
|
@@ -277,6 +699,13 @@
|
|
|
277
699
|
['pointermove', 'pointerdown', 'pointerup', 'pointerenter', 'pointerleave'].forEach((type) => {
|
|
278
700
|
this.addEventListener(`${type}:connect`, () => this._onPointerListenerAdded(type));
|
|
279
701
|
this.addEventListener(`${type}:disconnect`, () => this._onPointerListenerRemoved(type));
|
|
702
|
+
// Attach canvas handlers for listeners registered before this point (e.g. handlers
|
|
703
|
+
// created from onpointer* attributes when their elements were first upgraded)
|
|
704
|
+
const anyListeners = Array.from(this.querySelectorAll('pc-entity'))
|
|
705
|
+
.some(entity => entity.hasListeners(type));
|
|
706
|
+
if (anyListeners) {
|
|
707
|
+
this._onPointerListenerAdded(type);
|
|
708
|
+
}
|
|
280
709
|
});
|
|
281
710
|
}
|
|
282
711
|
_pickerDestroy() {
|
|
@@ -293,6 +722,13 @@
|
|
|
293
722
|
pointerdown: null,
|
|
294
723
|
pointerup: null
|
|
295
724
|
};
|
|
725
|
+
this._hasPointerListeners = {
|
|
726
|
+
pointerenter: false,
|
|
727
|
+
pointerleave: false,
|
|
728
|
+
pointerdown: false,
|
|
729
|
+
pointerup: false,
|
|
730
|
+
pointermove: false
|
|
731
|
+
};
|
|
296
732
|
}
|
|
297
733
|
// New helper to convert CSS coordinates to canvas (picker) coordinates
|
|
298
734
|
_getPickerCoordinates(event) {
|
|
@@ -477,324 +913,65 @@
|
|
|
477
913
|
get hierarchyReady() {
|
|
478
914
|
return this._hierarchyReady;
|
|
479
915
|
}
|
|
480
|
-
/**
|
|
481
|
-
* Sets the high resolution flag. When true, the application will render at the device's
|
|
482
|
-
* physical resolution. When false, the application will render at CSS resolution.
|
|
483
|
-
* @param value - The high resolution flag.
|
|
484
|
-
*/
|
|
485
|
-
set highResolution(value) {
|
|
486
|
-
this._highResolution = value;
|
|
487
|
-
if (this.app) {
|
|
488
|
-
this.app.graphicsDevice.maxPixelRatio = value ? window.devicePixelRatio : 1;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
/**
|
|
492
|
-
* Gets the high resolution flag.
|
|
493
|
-
* @returns The high resolution flag.
|
|
494
|
-
*/
|
|
495
|
-
get highResolution() {
|
|
496
|
-
return this._highResolution;
|
|
497
|
-
}
|
|
498
|
-
/**
|
|
499
|
-
* Sets the stencil flag.
|
|
500
|
-
* @param value - The stencil flag.
|
|
501
|
-
*/
|
|
502
|
-
set stencil(value) {
|
|
503
|
-
this._stencil = value;
|
|
504
|
-
}
|
|
505
|
-
/**
|
|
506
|
-
* Gets the stencil flag.
|
|
507
|
-
* @returns The stencil flag.
|
|
508
|
-
*/
|
|
509
|
-
get stencil() {
|
|
510
|
-
return this._stencil;
|
|
511
|
-
}
|
|
512
|
-
static get observedAttributes() {
|
|
513
|
-
return ['alpha', 'antialias', 'backend', 'depth', 'stencil', 'high-resolution'];
|
|
514
|
-
}
|
|
515
|
-
attributeChangedCallback(name, _oldValue, newValue) {
|
|
516
|
-
switch (name) {
|
|
517
|
-
case 'alpha':
|
|
518
|
-
this.alpha = newValue !== 'false';
|
|
519
|
-
break;
|
|
520
|
-
case 'antialias':
|
|
521
|
-
this.antialias = newValue !== 'false';
|
|
522
|
-
break;
|
|
523
|
-
case 'backend':
|
|
524
|
-
if (newValue === 'webgpu' || newValue === 'webgl2' || newValue === 'null') {
|
|
525
|
-
this.backend = newValue;
|
|
526
|
-
}
|
|
527
|
-
break;
|
|
528
|
-
case 'depth':
|
|
529
|
-
this.depth = newValue !== 'false';
|
|
530
|
-
break;
|
|
531
|
-
case 'high-resolution':
|
|
532
|
-
this.highResolution = newValue !== 'false';
|
|
533
|
-
break;
|
|
534
|
-
case 'stencil':
|
|
535
|
-
this.stencil = newValue !== 'false';
|
|
536
|
-
break;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
customElements.define('pc-app', AppElement);
|
|
541
|
-
|
|
542
|
-
const CSS_COLORS = {
|
|
543
|
-
aliceblue: '#f0f8ff',
|
|
544
|
-
antiquewhite: '#faebd7',
|
|
545
|
-
aqua: '#00ffff',
|
|
546
|
-
aquamarine: '#7fffd4',
|
|
547
|
-
azure: '#f0ffff',
|
|
548
|
-
beige: '#f5f5dc',
|
|
549
|
-
bisque: '#ffe4c4',
|
|
550
|
-
black: '#000000',
|
|
551
|
-
blanchedalmond: '#ffebcd',
|
|
552
|
-
blue: '#0000ff',
|
|
553
|
-
blueviolet: '#8a2be2',
|
|
554
|
-
brown: '#a52a2a',
|
|
555
|
-
burlywood: '#deb887',
|
|
556
|
-
cadetblue: '#5f9ea0',
|
|
557
|
-
chartreuse: '#7fff00',
|
|
558
|
-
chocolate: '#d2691e',
|
|
559
|
-
coral: '#ff7f50',
|
|
560
|
-
cornflowerblue: '#6495ed',
|
|
561
|
-
cornsilk: '#fff8dc',
|
|
562
|
-
crimson: '#dc143c',
|
|
563
|
-
cyan: '#00ffff',
|
|
564
|
-
darkblue: '#00008b',
|
|
565
|
-
darkcyan: '#008b8b',
|
|
566
|
-
darkgoldenrod: '#b8860b',
|
|
567
|
-
darkgray: '#a9a9a9',
|
|
568
|
-
darkgreen: '#006400',
|
|
569
|
-
darkgrey: '#a9a9a9',
|
|
570
|
-
darkkhaki: '#bdb76b',
|
|
571
|
-
darkmagenta: '#8b008b',
|
|
572
|
-
darkolivegreen: '#556b2f',
|
|
573
|
-
darkorange: '#ff8c00',
|
|
574
|
-
darkorchid: '#9932cc',
|
|
575
|
-
darkred: '#8b0000',
|
|
576
|
-
darksalmon: '#e9967a',
|
|
577
|
-
darkseagreen: '#8fbc8f',
|
|
578
|
-
darkslateblue: '#483d8b',
|
|
579
|
-
darkslategray: '#2f4f4f',
|
|
580
|
-
darkslategrey: '#2f4f4f',
|
|
581
|
-
darkturquoise: '#00ced1',
|
|
582
|
-
darkviolet: '#9400d3',
|
|
583
|
-
deeppink: '#ff1493',
|
|
584
|
-
deepskyblue: '#00bfff',
|
|
585
|
-
dimgray: '#696969',
|
|
586
|
-
dimgrey: '#696969',
|
|
587
|
-
dodgerblue: '#1e90ff',
|
|
588
|
-
firebrick: '#b22222',
|
|
589
|
-
floralwhite: '#fffaf0',
|
|
590
|
-
forestgreen: '#228b22',
|
|
591
|
-
fuchsia: '#ff00ff',
|
|
592
|
-
gainsboro: '#dcdcdc',
|
|
593
|
-
ghostwhite: '#f8f8ff',
|
|
594
|
-
gold: '#ffd700',
|
|
595
|
-
goldenrod: '#daa520',
|
|
596
|
-
gray: '#808080',
|
|
597
|
-
green: '#008000',
|
|
598
|
-
greenyellow: '#adff2f',
|
|
599
|
-
grey: '#808080',
|
|
600
|
-
honeydew: '#f0fff0',
|
|
601
|
-
hotpink: '#ff69b4',
|
|
602
|
-
indianred: '#cd5c5c',
|
|
603
|
-
indigo: '#4b0082',
|
|
604
|
-
ivory: '#fffff0',
|
|
605
|
-
khaki: '#f0e68c',
|
|
606
|
-
lavender: '#e6e6fa',
|
|
607
|
-
lavenderblush: '#fff0f5',
|
|
608
|
-
lawngreen: '#7cfc00',
|
|
609
|
-
lemonchiffon: '#fffacd',
|
|
610
|
-
lightblue: '#add8e6',
|
|
611
|
-
lightcoral: '#f08080',
|
|
612
|
-
lightcyan: '#e0ffff',
|
|
613
|
-
lightgoldenrodyellow: '#fafad2',
|
|
614
|
-
lightgray: '#d3d3d3',
|
|
615
|
-
lightgreen: '#90ee90',
|
|
616
|
-
lightgrey: '#d3d3d3',
|
|
617
|
-
lightpink: '#ffb6c1',
|
|
618
|
-
lightsalmon: '#ffa07a',
|
|
619
|
-
lightseagreen: '#20b2aa',
|
|
620
|
-
lightskyblue: '#87cefa',
|
|
621
|
-
lightslategray: '#778899',
|
|
622
|
-
lightslategrey: '#778899',
|
|
623
|
-
lightsteelblue: '#b0c4de',
|
|
624
|
-
lightyellow: '#ffffe0',
|
|
625
|
-
lime: '#00ff00',
|
|
626
|
-
limegreen: '#32cd32',
|
|
627
|
-
linen: '#faf0e6',
|
|
628
|
-
magenta: '#ff00ff',
|
|
629
|
-
maroon: '#800000',
|
|
630
|
-
mediumaquamarine: '#66cdaa',
|
|
631
|
-
mediumblue: '#0000cd',
|
|
632
|
-
mediumorchid: '#ba55d3',
|
|
633
|
-
mediumpurple: '#9370db',
|
|
634
|
-
mediumseagreen: '#3cb371',
|
|
635
|
-
mediumslateblue: '#7b68ee',
|
|
636
|
-
mediumspringgreen: '#00fa9a',
|
|
637
|
-
mediumturquoise: '#48d1cc',
|
|
638
|
-
mediumvioletred: '#c71585',
|
|
639
|
-
midnightblue: '#191970',
|
|
640
|
-
mintcream: '#f5fffa',
|
|
641
|
-
mistyrose: '#ffe4e1',
|
|
642
|
-
moccasin: '#ffe4b5',
|
|
643
|
-
navajowhite: '#ffdead',
|
|
644
|
-
navy: '#000080',
|
|
645
|
-
oldlace: '#fdf5e6',
|
|
646
|
-
olive: '#808000',
|
|
647
|
-
olivedrab: '#6b8e23',
|
|
648
|
-
orange: '#ffa500',
|
|
649
|
-
orangered: '#ff4500',
|
|
650
|
-
orchid: '#da70d6',
|
|
651
|
-
palegoldenrod: '#eee8aa',
|
|
652
|
-
palegreen: '#98fb98',
|
|
653
|
-
paleturquoise: '#afeeee',
|
|
654
|
-
palevioletred: '#db7093',
|
|
655
|
-
papayawhip: '#ffefd5',
|
|
656
|
-
peachpuff: '#ffdab9',
|
|
657
|
-
peru: '#cd853f',
|
|
658
|
-
pink: '#ffc0cb',
|
|
659
|
-
plum: '#dda0dd',
|
|
660
|
-
powderblue: '#b0e0e6',
|
|
661
|
-
purple: '#800080',
|
|
662
|
-
rebeccapurple: '#663399',
|
|
663
|
-
red: '#ff0000',
|
|
664
|
-
rosybrown: '#bc8f8f',
|
|
665
|
-
royalblue: '#4169e1',
|
|
666
|
-
saddlebrown: '#8b4513',
|
|
667
|
-
salmon: '#fa8072',
|
|
668
|
-
sandybrown: '#f4a460',
|
|
669
|
-
seagreen: '#2e8b57',
|
|
670
|
-
seashell: '#fff5ee',
|
|
671
|
-
sienna: '#a0522d',
|
|
672
|
-
silver: '#c0c0c0',
|
|
673
|
-
skyblue: '#87ceeb',
|
|
674
|
-
slateblue: '#6a5acd',
|
|
675
|
-
slategray: '#708090',
|
|
676
|
-
slategrey: '#708090',
|
|
677
|
-
snow: '#fffafa',
|
|
678
|
-
springgreen: '#00ff7f',
|
|
679
|
-
steelblue: '#4682b4',
|
|
680
|
-
tan: '#d2b48c',
|
|
681
|
-
teal: '#008080',
|
|
682
|
-
thistle: '#d8bfd8',
|
|
683
|
-
tomato: '#ff6347',
|
|
684
|
-
turquoise: '#40e0d0',
|
|
685
|
-
violet: '#ee82ee',
|
|
686
|
-
wheat: '#f5deb3',
|
|
687
|
-
white: '#ffffff',
|
|
688
|
-
whitesmoke: '#f5f5f5',
|
|
689
|
-
yellow: '#ffff00',
|
|
690
|
-
yellowgreen: '#9acd32'
|
|
691
|
-
};
|
|
692
|
-
|
|
693
|
-
/**
|
|
694
|
-
* Parse a color string into a Color object. String can be in the format of '#rgb', '#rgba',
|
|
695
|
-
* '#rrggbb', '#rrggbbaa', or a string of 3 or 4 comma-delimited numbers.
|
|
696
|
-
*
|
|
697
|
-
* @param value - The color string to parse.
|
|
698
|
-
* @returns The parsed Color object.
|
|
699
|
-
*/
|
|
700
|
-
const parseColor = (value) => {
|
|
701
|
-
// Check if it's a CSS color name first
|
|
702
|
-
const hexColor = CSS_COLORS[value.toLowerCase()];
|
|
703
|
-
if (hexColor) {
|
|
704
|
-
return new playcanvas.Color().fromString(hexColor);
|
|
705
|
-
}
|
|
706
|
-
if (value.startsWith('#')) {
|
|
707
|
-
return new playcanvas.Color().fromString(value);
|
|
708
|
-
}
|
|
709
|
-
const components = value.split(' ').map(Number);
|
|
710
|
-
return new playcanvas.Color(components);
|
|
711
|
-
};
|
|
712
|
-
/**
|
|
713
|
-
* Parse an Euler angles string into a Quat object. String can be in the format of 'x,y,z'.
|
|
714
|
-
*
|
|
715
|
-
* @param value - The Euler angles string to parse.
|
|
716
|
-
* @returns The parsed Quat object.
|
|
717
|
-
*/
|
|
718
|
-
const parseQuat = (value) => {
|
|
719
|
-
const [x, y, z] = value.split(' ').map(Number);
|
|
720
|
-
const q = new playcanvas.Quat();
|
|
721
|
-
q.setFromEulerAngles(x, y, z);
|
|
722
|
-
return q;
|
|
723
|
-
};
|
|
724
|
-
/**
|
|
725
|
-
* Parse a Vec2 string into a Vec2 object. String can be in the format of 'x,y'.
|
|
726
|
-
*
|
|
727
|
-
* @param value - The Vec2 string to parse.
|
|
728
|
-
* @returns The parsed Vec2 object.
|
|
729
|
-
*/
|
|
730
|
-
const parseVec2 = (value) => {
|
|
731
|
-
const components = value.split(' ').map(Number);
|
|
732
|
-
return new playcanvas.Vec2(components);
|
|
733
|
-
};
|
|
734
|
-
/**
|
|
735
|
-
* Parse a Vec3 string into a Vec3 object. String can be in the format of 'x,y,z'.
|
|
736
|
-
*
|
|
737
|
-
* @param value - The Vec3 string to parse.
|
|
738
|
-
* @returns The parsed Vec3 object.
|
|
739
|
-
*/
|
|
740
|
-
const parseVec3 = (value) => {
|
|
741
|
-
const components = value.split(' ').map(Number);
|
|
742
|
-
return new playcanvas.Vec3(components);
|
|
743
|
-
};
|
|
744
|
-
/**
|
|
745
|
-
* Parse a Vec4 string into a Vec4 object. String can be in the format of 'x,y,z,w'.
|
|
746
|
-
*
|
|
747
|
-
* @param value - The Vec4 string to parse.
|
|
748
|
-
* @returns The parsed Vec4 object.
|
|
749
|
-
*/
|
|
750
|
-
const parseVec4 = (value) => {
|
|
751
|
-
const components = value.split(' ').map(Number);
|
|
752
|
-
return new playcanvas.Vec4(components);
|
|
753
|
-
};
|
|
754
|
-
/**
|
|
755
|
-
* Resolves an enum value supplied as either a named string (looked up in `map`) or a numeric
|
|
756
|
-
* string. Falls back to `defaultValue` when the value is neither a known name nor a finite number.
|
|
757
|
-
*
|
|
758
|
-
* @param value - The attribute value to parse.
|
|
759
|
-
* @param map - A map of named values to their numeric enum equivalents.
|
|
760
|
-
* @param defaultValue - The value to return when parsing fails.
|
|
761
|
-
* @returns The resolved numeric enum value.
|
|
762
|
-
*/
|
|
763
|
-
const parseEnum = (value, map, defaultValue) => {
|
|
764
|
-
const named = map.get(value);
|
|
765
|
-
if (named !== undefined) {
|
|
766
|
-
return named;
|
|
767
|
-
}
|
|
768
|
-
const numeric = Number(value);
|
|
769
|
-
return Number.isFinite(numeric) ? numeric : defaultValue;
|
|
770
|
-
};
|
|
771
|
-
/**
|
|
772
|
-
* Resolves a reference string to the {@link Entity} backing a `<pc-entity>` element. The reference
|
|
773
|
-
* can be a CSS selector (e.g. `#my-id`, `pc-entity[name="Foo"]`), a bare element id, or a bare
|
|
774
|
-
* entity name. Returns `null` if no matching element (or backing entity) is found.
|
|
775
|
-
*
|
|
776
|
-
* @param ref - The reference string to resolve.
|
|
777
|
-
* @returns The resolved entity, or `null`.
|
|
778
|
-
*/
|
|
779
|
-
const getEntity = (ref) => {
|
|
780
|
-
var _a, _b;
|
|
781
|
-
if (!ref) {
|
|
782
|
-
return null;
|
|
916
|
+
/**
|
|
917
|
+
* Sets the high resolution flag. When true, the application will render at the device's
|
|
918
|
+
* physical resolution. When false, the application will render at CSS resolution.
|
|
919
|
+
* @param value - The high resolution flag.
|
|
920
|
+
*/
|
|
921
|
+
set highResolution(value) {
|
|
922
|
+
this._highResolution = value;
|
|
923
|
+
if (this.app) {
|
|
924
|
+
this.app.graphicsDevice.maxPixelRatio = value ? window.devicePixelRatio : 1;
|
|
925
|
+
}
|
|
783
926
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
927
|
+
/**
|
|
928
|
+
* Gets the high resolution flag.
|
|
929
|
+
* @returns The high resolution flag.
|
|
930
|
+
*/
|
|
931
|
+
get highResolution() {
|
|
932
|
+
return this._highResolution;
|
|
789
933
|
}
|
|
790
|
-
|
|
791
|
-
|
|
934
|
+
/**
|
|
935
|
+
* Sets the stencil flag.
|
|
936
|
+
* @param value - The stencil flag.
|
|
937
|
+
*/
|
|
938
|
+
set stencil(value) {
|
|
939
|
+
this._stencil = value;
|
|
792
940
|
}
|
|
793
|
-
|
|
794
|
-
|
|
941
|
+
/**
|
|
942
|
+
* Gets the stencil flag.
|
|
943
|
+
* @returns The stencil flag.
|
|
944
|
+
*/
|
|
945
|
+
get stencil() {
|
|
946
|
+
return this._stencil;
|
|
795
947
|
}
|
|
796
|
-
|
|
797
|
-
|
|
948
|
+
static get observedAttributes() {
|
|
949
|
+
return ['alpha', 'antialias', 'backend', 'depth', 'stencil', 'high-resolution'];
|
|
950
|
+
}
|
|
951
|
+
attributeChangedCallback(name, _oldValue, newValue) {
|
|
952
|
+
switch (name) {
|
|
953
|
+
case 'alpha':
|
|
954
|
+
this.alpha = parseBool(newValue, true);
|
|
955
|
+
break;
|
|
956
|
+
case 'antialias':
|
|
957
|
+
this.antialias = parseBool(newValue, true);
|
|
958
|
+
break;
|
|
959
|
+
case 'backend':
|
|
960
|
+
this.backend = parseEnum(newValue, ['webgpu', 'webgl2', 'null'], 'webgl2', name);
|
|
961
|
+
break;
|
|
962
|
+
case 'depth':
|
|
963
|
+
this.depth = parseBool(newValue, true);
|
|
964
|
+
break;
|
|
965
|
+
case 'high-resolution':
|
|
966
|
+
this.highResolution = parseBool(newValue, true);
|
|
967
|
+
break;
|
|
968
|
+
case 'stencil':
|
|
969
|
+
this.stencil = parseBool(newValue, true);
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
customElements.define('pc-app', AppElement);
|
|
798
975
|
|
|
799
976
|
/**
|
|
800
977
|
* The EntityElement interface provides properties and methods for manipulating
|
|
@@ -834,67 +1011,41 @@
|
|
|
834
1011
|
*/
|
|
835
1012
|
this._listeners = {};
|
|
836
1013
|
/**
|
|
837
|
-
*
|
|
1014
|
+
* The event types for which an inline `onpointer*` attribute is currently present.
|
|
838
1015
|
*/
|
|
839
|
-
this.
|
|
1016
|
+
this._inlineHandlerTypes = new Set();
|
|
840
1017
|
/**
|
|
841
|
-
*
|
|
1018
|
+
* Whether the hierarchy has been built for this entity.
|
|
842
1019
|
*/
|
|
843
|
-
this.
|
|
1020
|
+
this._built = false;
|
|
1021
|
+
this._entity = null;
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* The PlayCanvas entity instance. Available once the element is ready — await
|
|
1025
|
+
* {@link whenReady} or the element's `ready()` promise before accessing it.
|
|
1026
|
+
* @returns The entity instance.
|
|
1027
|
+
*/
|
|
1028
|
+
get entity() {
|
|
1029
|
+
return this._entity;
|
|
844
1030
|
}
|
|
845
1031
|
createEntity(app) {
|
|
846
1032
|
// Guard against double creation. When a subtree is inserted at runtime (e.g. cloning a
|
|
847
1033
|
// `<template>`), an ancestor's connectedCallback eagerly creates descendant entities; the
|
|
848
1034
|
// descendants' own connectedCallbacks would otherwise create them a second time.
|
|
849
|
-
if (this.
|
|
1035
|
+
if (this._entity) {
|
|
850
1036
|
return;
|
|
851
1037
|
}
|
|
852
1038
|
// Create a new entity
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
if (position) {
|
|
860
|
-
this.entity.setLocalPosition(parseVec3(position));
|
|
861
|
-
}
|
|
862
|
-
const rotation = this.getAttribute('rotation');
|
|
863
|
-
if (rotation) {
|
|
864
|
-
this.entity.setLocalEulerAngles(parseVec3(rotation));
|
|
865
|
-
}
|
|
866
|
-
const scale = this.getAttribute('scale');
|
|
867
|
-
if (scale) {
|
|
868
|
-
this.entity.setLocalScale(parseVec3(scale));
|
|
869
|
-
}
|
|
1039
|
+
const entity = new playcanvas.Entity(this.getAttribute('name') || this._name, app);
|
|
1040
|
+
this._entity = entity;
|
|
1041
|
+
entity.enabled = parseBool(this.getAttribute('enabled'), true);
|
|
1042
|
+
entity.setLocalPosition(parseVec3(this.getAttribute('position'), playcanvas.Vec3.ZERO, 'position'));
|
|
1043
|
+
entity.setLocalEulerAngles(parseVec3(this.getAttribute('rotation'), playcanvas.Vec3.ZERO, 'rotation'));
|
|
1044
|
+
entity.setLocalScale(parseVec3(this.getAttribute('scale'), playcanvas.Vec3.ONE, 'scale'));
|
|
870
1045
|
const tags = this.getAttribute('tags');
|
|
871
1046
|
if (tags) {
|
|
872
|
-
|
|
1047
|
+
entity.tags.add(tags.split(',').map(tag => tag.trim()));
|
|
873
1048
|
}
|
|
874
|
-
// Handle pointer events
|
|
875
|
-
const pointerEvents = [
|
|
876
|
-
'onpointerenter',
|
|
877
|
-
'onpointerleave',
|
|
878
|
-
'onpointerdown',
|
|
879
|
-
'onpointerup',
|
|
880
|
-
'onpointermove'
|
|
881
|
-
];
|
|
882
|
-
pointerEvents.forEach((eventName) => {
|
|
883
|
-
const handler = this.getAttribute(eventName);
|
|
884
|
-
if (handler) {
|
|
885
|
-
const eventType = eventName.substring(2); // remove 'on' prefix
|
|
886
|
-
const eventHandler = (event) => {
|
|
887
|
-
try {
|
|
888
|
-
/* eslint-disable-next-line no-new-func */
|
|
889
|
-
new Function('event', handler).call(this, event);
|
|
890
|
-
}
|
|
891
|
-
catch (e) {
|
|
892
|
-
console.error('Error in event handler:', e);
|
|
893
|
-
}
|
|
894
|
-
};
|
|
895
|
-
this.addEventListener(eventType, eventHandler);
|
|
896
|
-
}
|
|
897
|
-
});
|
|
898
1049
|
}
|
|
899
1050
|
buildHierarchy(app) {
|
|
900
1051
|
if (!this.entity || this._built)
|
|
@@ -934,11 +1085,11 @@
|
|
|
934
1085
|
// Notify all children that their entities are about to become invalid
|
|
935
1086
|
const children = this.querySelectorAll('pc-entity');
|
|
936
1087
|
children.forEach((child) => {
|
|
937
|
-
child.
|
|
1088
|
+
child._entity = null;
|
|
938
1089
|
});
|
|
939
1090
|
// Destroy the entity
|
|
940
1091
|
this.entity.destroy();
|
|
941
|
-
this.
|
|
1092
|
+
this._entity = null;
|
|
942
1093
|
this._built = false;
|
|
943
1094
|
}
|
|
944
1095
|
}
|
|
@@ -1045,6 +1196,30 @@
|
|
|
1045
1196
|
get tags() {
|
|
1046
1197
|
return this._tags;
|
|
1047
1198
|
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Tracks whether an inline `onpointer*` attribute is present. The browser itself compiles and
|
|
1201
|
+
* runs these attributes — they are standard `GlobalEventHandlers`, so setting one replaces
|
|
1202
|
+
* the previous handler and removing it removes the handler, exactly like `onclick` on any
|
|
1203
|
+
* HTML element. But because they bypass {@link addEventListener}, the connect/disconnect
|
|
1204
|
+
* bookkeeping that lets the application lazily attach its canvas pointer handlers must be
|
|
1205
|
+
* kept in sync here.
|
|
1206
|
+
*
|
|
1207
|
+
* @param name - The attribute name (e.g. 'onpointerdown').
|
|
1208
|
+
* @param value - The attribute value, or `null` when the attribute has been removed.
|
|
1209
|
+
*/
|
|
1210
|
+
_updateInlineHandler(name, value) {
|
|
1211
|
+
const type = name.substring(2);
|
|
1212
|
+
const had = this._inlineHandlerTypes.has(type);
|
|
1213
|
+
const has = value !== null;
|
|
1214
|
+
if (has && !had) {
|
|
1215
|
+
this._inlineHandlerTypes.add(type);
|
|
1216
|
+
this.dispatchEvent(new CustomEvent(`${type}:connect`, { bubbles: true }));
|
|
1217
|
+
}
|
|
1218
|
+
else if (!has && had) {
|
|
1219
|
+
this._inlineHandlerTypes.delete(type);
|
|
1220
|
+
this.dispatchEvent(new CustomEvent(`${type}:disconnect`, { bubbles: true }));
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1048
1223
|
static get observedAttributes() {
|
|
1049
1224
|
return [
|
|
1050
1225
|
'enabled',
|
|
@@ -1063,19 +1238,19 @@
|
|
|
1063
1238
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
1064
1239
|
switch (name) {
|
|
1065
1240
|
case 'enabled':
|
|
1066
|
-
this.enabled = newValue
|
|
1241
|
+
this.enabled = parseBool(newValue, true);
|
|
1067
1242
|
break;
|
|
1068
1243
|
case 'name':
|
|
1069
1244
|
this.name = newValue;
|
|
1070
1245
|
break;
|
|
1071
1246
|
case 'position':
|
|
1072
|
-
this.position = parseVec3(newValue);
|
|
1247
|
+
this.position = parseVec3(newValue, playcanvas.Vec3.ZERO, name);
|
|
1073
1248
|
break;
|
|
1074
1249
|
case 'rotation':
|
|
1075
|
-
this.rotation = parseVec3(newValue);
|
|
1250
|
+
this.rotation = parseVec3(newValue, playcanvas.Vec3.ZERO, name);
|
|
1076
1251
|
break;
|
|
1077
1252
|
case 'scale':
|
|
1078
|
-
this.scale = parseVec3(newValue);
|
|
1253
|
+
this.scale = parseVec3(newValue, playcanvas.Vec3.ONE, name);
|
|
1079
1254
|
break;
|
|
1080
1255
|
case 'tags':
|
|
1081
1256
|
this.tags = newValue.split(',').map(tag => tag.trim());
|
|
@@ -1085,21 +1260,7 @@
|
|
|
1085
1260
|
case 'onpointerdown':
|
|
1086
1261
|
case 'onpointerup':
|
|
1087
1262
|
case 'onpointermove':
|
|
1088
|
-
|
|
1089
|
-
const eventName = name.substring(2);
|
|
1090
|
-
// Use Function.prototype.bind to avoid new Function
|
|
1091
|
-
const handler = (event) => {
|
|
1092
|
-
try {
|
|
1093
|
-
const handlerStr = this.getAttribute(eventName) || '';
|
|
1094
|
-
/* eslint-disable-next-line no-new-func */
|
|
1095
|
-
new Function('event', handlerStr).call(this, event);
|
|
1096
|
-
}
|
|
1097
|
-
catch (e) {
|
|
1098
|
-
console.error('Error in event handler:', e);
|
|
1099
|
-
}
|
|
1100
|
-
};
|
|
1101
|
-
this.addEventListener(eventName, handler);
|
|
1102
|
-
}
|
|
1263
|
+
this._updateInlineHandler(name, newValue);
|
|
1103
1264
|
break;
|
|
1104
1265
|
}
|
|
1105
1266
|
}
|
|
@@ -1124,7 +1285,7 @@
|
|
|
1124
1285
|
}
|
|
1125
1286
|
hasListeners(type) {
|
|
1126
1287
|
var _a;
|
|
1127
|
-
return Boolean((_a = this._listeners[type]) === null || _a === void 0 ? void 0 : _a.length);
|
|
1288
|
+
return Boolean((_a = this._listeners[type]) === null || _a === void 0 ? void 0 : _a.length) || this._inlineHandlerTypes.has(type);
|
|
1128
1289
|
}
|
|
1129
1290
|
}
|
|
1130
1291
|
customElements.define('pc-entity', EntityElement);
|
|
@@ -1356,16 +1517,57 @@
|
|
|
1356
1517
|
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-asset/ | `<pc-asset>`} elements.
|
|
1357
1518
|
* The AssetElement interface also inherits the properties and methods of the
|
|
1358
1519
|
* {@link HTMLElement} interface.
|
|
1520
|
+
*
|
|
1521
|
+
* The element becomes ready once the containing application has started and the asset is in the
|
|
1522
|
+
* state declared by the markup: loaded for preloaded assets (even if loading failed — check the
|
|
1523
|
+
* asset's `resource`), or registered and awaiting a load for `lazy` assets. Elements inserted
|
|
1524
|
+
* while the application is running are created and registered on insertion, and begin loading
|
|
1525
|
+
* immediately unless `lazy`. A `pc-asset` must be a direct child of `pc-app` — elements placed
|
|
1526
|
+
* elsewhere, or with an unsupported asset type, never become ready.
|
|
1359
1527
|
*/
|
|
1360
|
-
class AssetElement extends
|
|
1528
|
+
class AssetElement extends AsyncElement {
|
|
1361
1529
|
constructor() {
|
|
1362
1530
|
super(...arguments);
|
|
1363
1531
|
this._lazy = false;
|
|
1364
1532
|
/**
|
|
1365
|
-
* The asset that is loaded.
|
|
1533
|
+
* The asset that is loaded. Available once the element is ready — await
|
|
1534
|
+
* {@link whenReady} or the element's `ready()` promise before accessing it.
|
|
1366
1535
|
*/
|
|
1367
1536
|
this.asset = null;
|
|
1368
1537
|
}
|
|
1538
|
+
async connectedCallback() {
|
|
1539
|
+
var _a;
|
|
1540
|
+
const appElement = this.closestApp;
|
|
1541
|
+
if (!appElement)
|
|
1542
|
+
return;
|
|
1543
|
+
// Assets must be direct children of pc-app (matches the boot query ':scope > pc-asset')
|
|
1544
|
+
if (this.parentElement !== appElement) {
|
|
1545
|
+
console.warn(`pc-asset '${(_a = this.getAttribute('id')) !== null && _a !== void 0 ? _a : this.getAttribute('src')}' must be a direct child of pc-app - asset not created`);
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1548
|
+
await appElement.ready();
|
|
1549
|
+
// The element may have been removed or re-parented while waiting for the app
|
|
1550
|
+
if (!this.isConnected || this.parentElement !== appElement)
|
|
1551
|
+
return;
|
|
1552
|
+
// Assets present at startup are created by AppElement's boot; this branch handles
|
|
1553
|
+
// elements inserted (or re-inserted) after the app is already running
|
|
1554
|
+
if (!this.asset) {
|
|
1555
|
+
const app = appElement.app;
|
|
1556
|
+
if (!app)
|
|
1557
|
+
return; // pc-app is re-connecting; its own boot will create this asset
|
|
1558
|
+
this.createAsset();
|
|
1559
|
+
if (this.asset) {
|
|
1560
|
+
app.assets.add(this.asset); // add() auto-loads when preload is true
|
|
1561
|
+
if (!this.lazy) {
|
|
1562
|
+
app.assets.load(this.asset);
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
// Never ready if createAsset failed (unsupported asset type)
|
|
1567
|
+
if (this.asset) {
|
|
1568
|
+
this._onReady();
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1369
1571
|
disconnectedCallback() {
|
|
1370
1572
|
this.destroyAsset();
|
|
1371
1573
|
}
|
|
@@ -1444,11 +1646,11 @@
|
|
|
1444
1646
|
}
|
|
1445
1647
|
const pixelsPerUnit = this.getAttribute('pixels-per-unit');
|
|
1446
1648
|
if (pixelsPerUnit !== null) {
|
|
1447
|
-
data.pixelsPerUnit =
|
|
1649
|
+
data.pixelsPerUnit = parseNumber(pixelsPerUnit, 1, 'pixels-per-unit');
|
|
1448
1650
|
}
|
|
1449
1651
|
const renderMode = this.getAttribute('render-mode');
|
|
1450
1652
|
if (renderMode !== null) {
|
|
1451
|
-
data.renderMode = parseEnum(renderMode, renderModes,
|
|
1653
|
+
data.renderMode = renderModes.get(parseEnum(renderMode, renderModes, 'simple', 'render-mode'));
|
|
1452
1654
|
}
|
|
1453
1655
|
// Apply engine defaults for any values not supplied.
|
|
1454
1656
|
data.renderMode = (_b = data.renderMode) !== null && _b !== void 0 ? _b : playcanvas.SPRITE_RENDERMODE_SIMPLE;
|
|
@@ -1458,7 +1660,10 @@
|
|
|
1458
1660
|
return data;
|
|
1459
1661
|
}
|
|
1460
1662
|
destroyAsset() {
|
|
1663
|
+
var _a;
|
|
1461
1664
|
if (this.asset) {
|
|
1665
|
+
// Deregister first so unload() can still notify the registry
|
|
1666
|
+
(_a = this.asset.registry) === null || _a === void 0 ? void 0 : _a.remove(this.asset);
|
|
1462
1667
|
this.asset.unload();
|
|
1463
1668
|
this.asset = null;
|
|
1464
1669
|
}
|
|
@@ -1487,9 +1692,9 @@
|
|
|
1487
1692
|
static get observedAttributes() {
|
|
1488
1693
|
return ['lazy'];
|
|
1489
1694
|
}
|
|
1490
|
-
attributeChangedCallback(name, _oldValue,
|
|
1695
|
+
attributeChangedCallback(name, _oldValue, newValue) {
|
|
1491
1696
|
if (name === 'lazy') {
|
|
1492
|
-
this.lazy =
|
|
1697
|
+
this.lazy = parseBool(newValue, false);
|
|
1493
1698
|
}
|
|
1494
1699
|
}
|
|
1495
1700
|
}
|
|
@@ -1511,6 +1716,7 @@
|
|
|
1511
1716
|
super();
|
|
1512
1717
|
this._enabled = true;
|
|
1513
1718
|
this._component = null;
|
|
1719
|
+
this._appElement = null;
|
|
1514
1720
|
this._componentName = componentName;
|
|
1515
1721
|
}
|
|
1516
1722
|
// Method to be overridden by subclasses to provide initial component data
|
|
@@ -1519,28 +1725,43 @@
|
|
|
1519
1725
|
}
|
|
1520
1726
|
async addComponent() {
|
|
1521
1727
|
const entityElement = this.closestEntity;
|
|
1522
|
-
if (entityElement) {
|
|
1523
|
-
|
|
1524
|
-
//
|
|
1525
|
-
const
|
|
1526
|
-
this.
|
|
1728
|
+
if (!entityElement) {
|
|
1729
|
+
// A component can only exist on an entity, so an element placed outside one is inert.
|
|
1730
|
+
// It still becomes ready (with a null `component`), so warn rather than fail silently
|
|
1731
|
+
const label = this.id ? ` '${this.id}'` : '';
|
|
1732
|
+
console.warn(`${this.tagName.toLowerCase()}${label} must be a descendant of pc-entity - component not added`);
|
|
1733
|
+
return;
|
|
1527
1734
|
}
|
|
1735
|
+
await entityElement.ready();
|
|
1736
|
+
// Add the component to the entity
|
|
1737
|
+
const data = this.getInitialComponentData();
|
|
1738
|
+
this._component = entityElement.entity.addComponent(this._componentName, data);
|
|
1528
1739
|
}
|
|
1529
1740
|
initComponent() { }
|
|
1530
1741
|
async connectedCallback() {
|
|
1531
|
-
var _a;
|
|
1532
|
-
|
|
1742
|
+
var _a, _b;
|
|
1743
|
+
this._appElement = (_a = this.closestApp) !== null && _a !== void 0 ? _a : null;
|
|
1744
|
+
await ((_b = this._appElement) === null || _b === void 0 ? void 0 : _b.ready());
|
|
1533
1745
|
await this.addComponent();
|
|
1534
1746
|
this.initComponent();
|
|
1535
1747
|
this._onReady();
|
|
1536
1748
|
}
|
|
1537
1749
|
disconnectedCallback() {
|
|
1538
|
-
|
|
1539
|
-
|
|
1750
|
+
var _a, _b;
|
|
1751
|
+
// Remove the component when the element is disconnected. Skip this when the owning
|
|
1752
|
+
// application has already been destroyed — removing a <pc-app> disconnects it before
|
|
1753
|
+
// its children, taking the component systems with it.
|
|
1754
|
+
if (((_a = this._appElement) === null || _a === void 0 ? void 0 : _a.app) && ((_b = this._component) === null || _b === void 0 ? void 0 : _b.entity)) {
|
|
1540
1755
|
this._component.entity.removeComponent(this._componentName);
|
|
1541
|
-
this._component = null;
|
|
1542
1756
|
}
|
|
1757
|
+
this._component = null;
|
|
1758
|
+
this._appElement = null;
|
|
1543
1759
|
}
|
|
1760
|
+
/**
|
|
1761
|
+
* The PlayCanvas component instance. Available once the element is ready — await
|
|
1762
|
+
* {@link whenReady} or the element's `ready()` promise before accessing it.
|
|
1763
|
+
* @returns The component instance.
|
|
1764
|
+
*/
|
|
1544
1765
|
get component() {
|
|
1545
1766
|
return this._component;
|
|
1546
1767
|
}
|
|
@@ -1567,7 +1788,7 @@
|
|
|
1567
1788
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
1568
1789
|
switch (name) {
|
|
1569
1790
|
case 'enabled':
|
|
1570
|
-
this.enabled = newValue
|
|
1791
|
+
this.enabled = parseBool(newValue, true);
|
|
1571
1792
|
break;
|
|
1572
1793
|
}
|
|
1573
1794
|
}
|
|
@@ -1615,7 +1836,7 @@
|
|
|
1615
1836
|
this._active = true;
|
|
1616
1837
|
this._image = '';
|
|
1617
1838
|
this._hitPadding = new playcanvas.Vec4(0, 0, 0, 0);
|
|
1618
|
-
this._transitionMode =
|
|
1839
|
+
this._transitionMode = 'tint';
|
|
1619
1840
|
this._hoverTint = new playcanvas.Color(1, 1, 1, 1);
|
|
1620
1841
|
this._pressedTint = new playcanvas.Color(1, 1, 1, 1);
|
|
1621
1842
|
this._inactiveTint = new playcanvas.Color(1, 1, 1, 1);
|
|
@@ -1632,7 +1853,7 @@
|
|
|
1632
1853
|
const data = {
|
|
1633
1854
|
active: this._active,
|
|
1634
1855
|
hitPadding: this._hitPadding,
|
|
1635
|
-
transitionMode: this._transitionMode,
|
|
1856
|
+
transitionMode: transitionModes.get(this._transitionMode),
|
|
1636
1857
|
hoverTint: this._hoverTint,
|
|
1637
1858
|
pressedTint: this._pressedTint,
|
|
1638
1859
|
inactiveTint: this._inactiveTint,
|
|
@@ -1722,13 +1943,15 @@
|
|
|
1722
1943
|
return this._hitPadding;
|
|
1723
1944
|
}
|
|
1724
1945
|
/**
|
|
1725
|
-
* Sets how the button reacts to being hovered/pressed. Can be `tint`
|
|
1946
|
+
* Sets how the button reacts to being hovered/pressed. Can be `tint` or `sprite`. Defaults to
|
|
1947
|
+
* `tint`.
|
|
1726
1948
|
* @param value - The transition mode.
|
|
1727
1949
|
*/
|
|
1728
1950
|
set transitionMode(value) {
|
|
1951
|
+
var _a;
|
|
1729
1952
|
this._transitionMode = value;
|
|
1730
1953
|
if (this.component) {
|
|
1731
|
-
this.component.transitionMode = value;
|
|
1954
|
+
this.component.transitionMode = (_a = transitionModes.get(value)) !== null && _a !== void 0 ? _a : playcanvas.BUTTON_TRANSITION_MODE_TINT;
|
|
1732
1955
|
}
|
|
1733
1956
|
}
|
|
1734
1957
|
/**
|
|
@@ -1940,46 +2163,46 @@
|
|
|
1940
2163
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
1941
2164
|
switch (name) {
|
|
1942
2165
|
case 'active':
|
|
1943
|
-
this.active = newValue
|
|
2166
|
+
this.active = parseBool(newValue, true);
|
|
1944
2167
|
break;
|
|
1945
2168
|
case 'image':
|
|
1946
2169
|
this.image = newValue;
|
|
1947
2170
|
break;
|
|
1948
2171
|
case 'hit-padding':
|
|
1949
|
-
this.hitPadding = parseVec4(newValue);
|
|
2172
|
+
this.hitPadding = parseVec4(newValue, playcanvas.Vec4.ZERO, name);
|
|
1950
2173
|
break;
|
|
1951
2174
|
case 'transition-mode':
|
|
1952
|
-
this.transitionMode = parseEnum(newValue, transitionModes,
|
|
2175
|
+
this.transitionMode = parseEnum(newValue, transitionModes, 'tint', name);
|
|
1953
2176
|
break;
|
|
1954
2177
|
case 'hover-tint':
|
|
1955
|
-
this.hoverTint = parseColor(newValue);
|
|
2178
|
+
this.hoverTint = parseColor(newValue, playcanvas.Color.WHITE, name);
|
|
1956
2179
|
break;
|
|
1957
2180
|
case 'pressed-tint':
|
|
1958
|
-
this.pressedTint = parseColor(newValue);
|
|
2181
|
+
this.pressedTint = parseColor(newValue, playcanvas.Color.WHITE, name);
|
|
1959
2182
|
break;
|
|
1960
2183
|
case 'inactive-tint':
|
|
1961
|
-
this.inactiveTint = parseColor(newValue);
|
|
2184
|
+
this.inactiveTint = parseColor(newValue, playcanvas.Color.WHITE, name);
|
|
1962
2185
|
break;
|
|
1963
2186
|
case 'fade-duration':
|
|
1964
|
-
this.fadeDuration =
|
|
2187
|
+
this.fadeDuration = parseNumber(newValue, 0, name);
|
|
1965
2188
|
break;
|
|
1966
2189
|
case 'hover-sprite-asset':
|
|
1967
2190
|
this.hoverSpriteAsset = newValue;
|
|
1968
2191
|
break;
|
|
1969
2192
|
case 'hover-sprite-frame':
|
|
1970
|
-
this.hoverSpriteFrame =
|
|
2193
|
+
this.hoverSpriteFrame = parseNumber(newValue, 0, name);
|
|
1971
2194
|
break;
|
|
1972
2195
|
case 'pressed-sprite-asset':
|
|
1973
2196
|
this.pressedSpriteAsset = newValue;
|
|
1974
2197
|
break;
|
|
1975
2198
|
case 'pressed-sprite-frame':
|
|
1976
|
-
this.pressedSpriteFrame =
|
|
2199
|
+
this.pressedSpriteFrame = parseNumber(newValue, 0, name);
|
|
1977
2200
|
break;
|
|
1978
2201
|
case 'inactive-sprite-asset':
|
|
1979
2202
|
this.inactiveSpriteAsset = newValue;
|
|
1980
2203
|
break;
|
|
1981
2204
|
case 'inactive-sprite-frame':
|
|
1982
|
-
this.inactiveSpriteFrame =
|
|
2205
|
+
this.inactiveSpriteFrame = parseNumber(newValue, 0, name);
|
|
1983
2206
|
break;
|
|
1984
2207
|
}
|
|
1985
2208
|
}
|
|
@@ -2040,7 +2263,7 @@
|
|
|
2040
2263
|
gammaCorrection: this._gamma === 'srgb' ? playcanvas.GAMMA_SRGB : playcanvas.GAMMA_NONE,
|
|
2041
2264
|
horizontalFov: this._horizontalFov,
|
|
2042
2265
|
nearClip: this._nearClip,
|
|
2043
|
-
|
|
2266
|
+
projection: this._orthographic ? playcanvas.PROJECTION_ORTHOGRAPHIC : playcanvas.PROJECTION_PERSPECTIVE,
|
|
2044
2267
|
orthoHeight: this._orthoHeight,
|
|
2045
2268
|
priority: this._priority,
|
|
2046
2269
|
rect: this._rect,
|
|
@@ -2418,58 +2641,58 @@
|
|
|
2418
2641
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
2419
2642
|
switch (name) {
|
|
2420
2643
|
case 'clear-color':
|
|
2421
|
-
this.clearColor = parseColor(newValue);
|
|
2644
|
+
this.clearColor = parseColor(newValue, new playcanvas.Color(0.75, 0.75, 0.75, 1), name);
|
|
2422
2645
|
break;
|
|
2423
2646
|
case 'clear-color-buffer':
|
|
2424
|
-
this.clearColorBuffer = newValue
|
|
2647
|
+
this.clearColorBuffer = parseBool(newValue, true);
|
|
2425
2648
|
break;
|
|
2426
2649
|
case 'clear-depth-buffer':
|
|
2427
|
-
this.clearDepthBuffer = newValue
|
|
2650
|
+
this.clearDepthBuffer = parseBool(newValue, true);
|
|
2428
2651
|
break;
|
|
2429
2652
|
case 'clear-stencil-buffer':
|
|
2430
|
-
this.clearStencilBuffer = newValue
|
|
2653
|
+
this.clearStencilBuffer = parseBool(newValue, false);
|
|
2431
2654
|
break;
|
|
2432
2655
|
case 'cull-faces':
|
|
2433
|
-
this.cullFaces = newValue
|
|
2656
|
+
this.cullFaces = parseBool(newValue, true);
|
|
2434
2657
|
break;
|
|
2435
2658
|
case 'far-clip':
|
|
2436
|
-
this.farClip =
|
|
2659
|
+
this.farClip = parseNumber(newValue, 1000, name);
|
|
2437
2660
|
break;
|
|
2438
2661
|
case 'flip-faces':
|
|
2439
|
-
this.flipFaces = newValue
|
|
2662
|
+
this.flipFaces = parseBool(newValue, false);
|
|
2440
2663
|
break;
|
|
2441
2664
|
case 'fov':
|
|
2442
|
-
this.fov =
|
|
2665
|
+
this.fov = parseNumber(newValue, 45, name);
|
|
2443
2666
|
break;
|
|
2444
2667
|
case 'frustum-culling':
|
|
2445
|
-
this.frustumCulling = newValue
|
|
2668
|
+
this.frustumCulling = parseBool(newValue, true);
|
|
2446
2669
|
break;
|
|
2447
2670
|
case 'gamma':
|
|
2448
|
-
this.gamma = newValue;
|
|
2671
|
+
this.gamma = parseEnum(newValue, ['linear', 'srgb'], 'srgb', name);
|
|
2449
2672
|
break;
|
|
2450
2673
|
case 'horizontal-fov':
|
|
2451
|
-
this.horizontalFov =
|
|
2674
|
+
this.horizontalFov = parseBool(newValue, false);
|
|
2452
2675
|
break;
|
|
2453
2676
|
case 'near-clip':
|
|
2454
|
-
this.nearClip =
|
|
2677
|
+
this.nearClip = parseNumber(newValue, 0.1, name);
|
|
2455
2678
|
break;
|
|
2456
2679
|
case 'orthographic':
|
|
2457
|
-
this.orthographic =
|
|
2680
|
+
this.orthographic = parseBool(newValue, false);
|
|
2458
2681
|
break;
|
|
2459
2682
|
case 'ortho-height':
|
|
2460
|
-
this.orthoHeight =
|
|
2683
|
+
this.orthoHeight = parseNumber(newValue, 10, name);
|
|
2461
2684
|
break;
|
|
2462
2685
|
case 'priority':
|
|
2463
|
-
this.priority =
|
|
2686
|
+
this.priority = parseNumber(newValue, 0, name);
|
|
2464
2687
|
break;
|
|
2465
2688
|
case 'rect':
|
|
2466
|
-
this.rect = parseVec4(newValue);
|
|
2689
|
+
this.rect = parseVec4(newValue, new playcanvas.Vec4(0, 0, 1, 1), name);
|
|
2467
2690
|
break;
|
|
2468
2691
|
case 'scissor-rect':
|
|
2469
|
-
this.scissorRect = parseVec4(newValue);
|
|
2692
|
+
this.scissorRect = parseVec4(newValue, new playcanvas.Vec4(0, 0, 1, 1), name);
|
|
2470
2693
|
break;
|
|
2471
2694
|
case 'tonemap':
|
|
2472
|
-
this.tonemap = newValue;
|
|
2695
|
+
this.tonemap = parseEnum(newValue, tonemaps, 'none', name);
|
|
2473
2696
|
break;
|
|
2474
2697
|
}
|
|
2475
2698
|
}
|
|
@@ -2595,28 +2818,28 @@
|
|
|
2595
2818
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
2596
2819
|
switch (name) {
|
|
2597
2820
|
case 'angular-offset':
|
|
2598
|
-
this.angularOffset = parseQuat(newValue);
|
|
2821
|
+
this.angularOffset = parseQuat(newValue, playcanvas.Quat.IDENTITY, name);
|
|
2599
2822
|
break;
|
|
2600
2823
|
case 'axis':
|
|
2601
|
-
this.axis =
|
|
2824
|
+
this.axis = parseNumber(newValue, 1, name);
|
|
2602
2825
|
break;
|
|
2603
2826
|
case 'convex-hull':
|
|
2604
|
-
this.convexHull =
|
|
2827
|
+
this.convexHull = parseBool(newValue, false);
|
|
2605
2828
|
break;
|
|
2606
2829
|
case 'half-extents':
|
|
2607
|
-
this.halfExtents = parseVec3(newValue);
|
|
2830
|
+
this.halfExtents = parseVec3(newValue, new playcanvas.Vec3(0.5, 0.5, 0.5), name);
|
|
2608
2831
|
break;
|
|
2609
2832
|
case 'height':
|
|
2610
|
-
this.height =
|
|
2833
|
+
this.height = parseNumber(newValue, 2, name);
|
|
2611
2834
|
break;
|
|
2612
2835
|
case 'linear-offset':
|
|
2613
|
-
this.linearOffset = parseVec3(newValue);
|
|
2836
|
+
this.linearOffset = parseVec3(newValue, playcanvas.Vec3.ZERO, name);
|
|
2614
2837
|
break;
|
|
2615
2838
|
case 'radius':
|
|
2616
|
-
this.radius =
|
|
2839
|
+
this.radius = parseNumber(newValue, 0.5, name);
|
|
2617
2840
|
break;
|
|
2618
2841
|
case 'type':
|
|
2619
|
-
this.type = newValue;
|
|
2842
|
+
this.type = parseEnum(newValue, ['box', 'capsule', 'compound', 'cone', 'cylinder', 'mesh', 'sphere'], 'box', name);
|
|
2620
2843
|
break;
|
|
2621
2844
|
}
|
|
2622
2845
|
}
|
|
@@ -2636,13 +2859,13 @@
|
|
|
2636
2859
|
constructor() {
|
|
2637
2860
|
super('element');
|
|
2638
2861
|
this._anchor = new playcanvas.Vec4(0.5, 0.5, 0.5, 0.5);
|
|
2639
|
-
this._asset = '';
|
|
2640
2862
|
this._autoWidth = true;
|
|
2641
2863
|
this._autoHeight = true;
|
|
2642
2864
|
this._autoFitWidth = false;
|
|
2643
2865
|
this._autoFitHeight = false;
|
|
2644
2866
|
this._color = new playcanvas.Color(1, 1, 1, 1);
|
|
2645
2867
|
this._enableMarkup = false;
|
|
2868
|
+
this._fontAsset = '';
|
|
2646
2869
|
this._fontSize = 32;
|
|
2647
2870
|
this._maxFontSize = 32;
|
|
2648
2871
|
this._minFontSize = 8;
|
|
@@ -2705,7 +2928,7 @@
|
|
|
2705
2928
|
};
|
|
2706
2929
|
// Asset references are resolved from `<pc-asset>` element ids to engine asset ids. They are
|
|
2707
2930
|
// only included when they resolve, so image/group elements (with no font) don't error.
|
|
2708
|
-
const fontAsset = AssetElement.get(this.
|
|
2931
|
+
const fontAsset = AssetElement.get(this._fontAsset);
|
|
2709
2932
|
if (fontAsset) {
|
|
2710
2933
|
data.fontAsset = fontAsset.id;
|
|
2711
2934
|
}
|
|
@@ -2751,24 +2974,6 @@
|
|
|
2751
2974
|
get anchor() {
|
|
2752
2975
|
return this._anchor;
|
|
2753
2976
|
}
|
|
2754
|
-
/**
|
|
2755
|
-
* Sets the id of the `pc-asset` to use for the font (text elements).
|
|
2756
|
-
* @param value - The asset ID.
|
|
2757
|
-
*/
|
|
2758
|
-
set asset(value) {
|
|
2759
|
-
this._asset = value;
|
|
2760
|
-
const asset = AssetElement.get(value);
|
|
2761
|
-
if (this.component && asset) {
|
|
2762
|
-
this.component.fontAsset = asset.id;
|
|
2763
|
-
}
|
|
2764
|
-
}
|
|
2765
|
-
/**
|
|
2766
|
-
* Gets the id of the `pc-asset` to use for the font.
|
|
2767
|
-
* @returns The asset ID.
|
|
2768
|
-
*/
|
|
2769
|
-
get asset() {
|
|
2770
|
-
return this._asset;
|
|
2771
|
-
}
|
|
2772
2977
|
/**
|
|
2773
2978
|
* Sets whether the element component should automatically adjust its width to the text content
|
|
2774
2979
|
* (text elements only).
|
|
@@ -2839,6 +3044,24 @@
|
|
|
2839
3044
|
get enableMarkup() {
|
|
2840
3045
|
return this._enableMarkup;
|
|
2841
3046
|
}
|
|
3047
|
+
/**
|
|
3048
|
+
* Sets the id of the `pc-asset` to use for the font (text elements).
|
|
3049
|
+
* @param value - The font asset ID.
|
|
3050
|
+
*/
|
|
3051
|
+
set fontAsset(value) {
|
|
3052
|
+
this._fontAsset = value;
|
|
3053
|
+
const asset = AssetElement.get(value);
|
|
3054
|
+
if (this.component && asset) {
|
|
3055
|
+
this.component.fontAsset = asset.id;
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
/**
|
|
3059
|
+
* Gets the id of the `pc-asset` to use for the font.
|
|
3060
|
+
* @returns The font asset ID.
|
|
3061
|
+
*/
|
|
3062
|
+
get fontAsset() {
|
|
3063
|
+
return this._fontAsset;
|
|
3064
|
+
}
|
|
2842
3065
|
/**
|
|
2843
3066
|
* Sets the font size of the element component.
|
|
2844
3067
|
* @param value - The font size.
|
|
@@ -3188,13 +3411,13 @@
|
|
|
3188
3411
|
return [
|
|
3189
3412
|
...super.observedAttributes,
|
|
3190
3413
|
'anchor',
|
|
3191
|
-
'asset',
|
|
3192
3414
|
'auto-width',
|
|
3193
3415
|
'auto-height',
|
|
3194
3416
|
'auto-fit-width',
|
|
3195
3417
|
'auto-fit-height',
|
|
3196
3418
|
'color',
|
|
3197
3419
|
'enable-markup',
|
|
3420
|
+
'font-asset',
|
|
3198
3421
|
'font-size',
|
|
3199
3422
|
'max-font-size',
|
|
3200
3423
|
'min-font-size',
|
|
@@ -3219,64 +3442,64 @@
|
|
|
3219
3442
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
3220
3443
|
switch (name) {
|
|
3221
3444
|
case 'anchor':
|
|
3222
|
-
this.anchor = parseVec4(newValue);
|
|
3223
|
-
break;
|
|
3224
|
-
case 'asset':
|
|
3225
|
-
this.asset = newValue;
|
|
3445
|
+
this.anchor = parseVec4(newValue, new playcanvas.Vec4(0.5, 0.5, 0.5, 0.5), name);
|
|
3226
3446
|
break;
|
|
3227
3447
|
case 'auto-width':
|
|
3228
|
-
this.autoWidth = newValue
|
|
3448
|
+
this.autoWidth = parseBool(newValue, true);
|
|
3229
3449
|
break;
|
|
3230
3450
|
case 'auto-height':
|
|
3231
|
-
this.autoHeight = newValue
|
|
3451
|
+
this.autoHeight = parseBool(newValue, true);
|
|
3232
3452
|
break;
|
|
3233
3453
|
case 'auto-fit-width':
|
|
3234
|
-
this.autoFitWidth = newValue
|
|
3454
|
+
this.autoFitWidth = parseBool(newValue, false);
|
|
3235
3455
|
break;
|
|
3236
3456
|
case 'auto-fit-height':
|
|
3237
|
-
this.autoFitHeight = newValue
|
|
3457
|
+
this.autoFitHeight = parseBool(newValue, false);
|
|
3238
3458
|
break;
|
|
3239
3459
|
case 'color':
|
|
3240
|
-
this.color = parseColor(newValue);
|
|
3460
|
+
this.color = parseColor(newValue, playcanvas.Color.WHITE, name);
|
|
3241
3461
|
break;
|
|
3242
3462
|
case 'enable-markup':
|
|
3243
|
-
this.enableMarkup =
|
|
3463
|
+
this.enableMarkup = parseBool(newValue, false);
|
|
3464
|
+
break;
|
|
3465
|
+
case 'font-asset':
|
|
3466
|
+
this.fontAsset = newValue;
|
|
3244
3467
|
break;
|
|
3245
3468
|
case 'font-size':
|
|
3246
|
-
this.fontSize =
|
|
3469
|
+
this.fontSize = parseNumber(newValue, 32, name);
|
|
3247
3470
|
break;
|
|
3248
3471
|
case 'max-font-size':
|
|
3249
|
-
this.maxFontSize =
|
|
3472
|
+
this.maxFontSize = parseNumber(newValue, 32, name);
|
|
3250
3473
|
break;
|
|
3251
3474
|
case 'min-font-size':
|
|
3252
|
-
this.minFontSize =
|
|
3475
|
+
this.minFontSize = parseNumber(newValue, 8, name);
|
|
3253
3476
|
break;
|
|
3254
3477
|
case 'height':
|
|
3255
|
-
this.height =
|
|
3478
|
+
this.height = parseNumber(newValue, 0, name);
|
|
3256
3479
|
break;
|
|
3257
3480
|
case 'line-height':
|
|
3258
|
-
this.lineHeight =
|
|
3481
|
+
this.lineHeight = parseNumber(newValue, 32, name);
|
|
3259
3482
|
break;
|
|
3260
3483
|
case 'margin':
|
|
3261
|
-
this.margin = parseVec4(newValue);
|
|
3484
|
+
this.margin = parseVec4(newValue, null, name);
|
|
3262
3485
|
break;
|
|
3263
3486
|
case 'mask':
|
|
3264
|
-
this.mask =
|
|
3487
|
+
this.mask = parseBool(newValue, false);
|
|
3265
3488
|
break;
|
|
3266
3489
|
case 'opacity':
|
|
3267
|
-
this.opacity =
|
|
3490
|
+
this.opacity = parseNumber(newValue, 1, name);
|
|
3268
3491
|
break;
|
|
3269
3492
|
case 'pivot':
|
|
3270
|
-
this.pivot = parseVec2(newValue);
|
|
3493
|
+
this.pivot = parseVec2(newValue, new playcanvas.Vec2(0.5, 0.5), name);
|
|
3271
3494
|
break;
|
|
3272
3495
|
case 'pixels-per-unit':
|
|
3273
|
-
this.pixelsPerUnit =
|
|
3496
|
+
this.pixelsPerUnit = parseNumber(newValue, null, name);
|
|
3274
3497
|
break;
|
|
3275
3498
|
case 'sprite-asset':
|
|
3276
3499
|
this.spriteAsset = newValue;
|
|
3277
3500
|
break;
|
|
3278
3501
|
case 'sprite-frame':
|
|
3279
|
-
this.spriteFrame =
|
|
3502
|
+
this.spriteFrame = parseNumber(newValue, 0, name);
|
|
3280
3503
|
break;
|
|
3281
3504
|
case 'text':
|
|
3282
3505
|
this.text = newValue;
|
|
@@ -3285,16 +3508,16 @@
|
|
|
3285
3508
|
this.textureAsset = newValue;
|
|
3286
3509
|
break;
|
|
3287
3510
|
case 'type':
|
|
3288
|
-
this.type = newValue;
|
|
3511
|
+
this.type = parseEnum(newValue, ['group', 'image', 'text'], 'group', name);
|
|
3289
3512
|
break;
|
|
3290
3513
|
case 'use-input':
|
|
3291
|
-
this.useInput =
|
|
3514
|
+
this.useInput = parseBool(newValue, false);
|
|
3292
3515
|
break;
|
|
3293
3516
|
case 'width':
|
|
3294
|
-
this.width =
|
|
3517
|
+
this.width = parseNumber(newValue, 0, name);
|
|
3295
3518
|
break;
|
|
3296
3519
|
case 'wrap-lines':
|
|
3297
|
-
this.wrapLines =
|
|
3520
|
+
this.wrapLines = parseBool(newValue, false);
|
|
3298
3521
|
break;
|
|
3299
3522
|
}
|
|
3300
3523
|
}
|
|
@@ -3476,25 +3699,25 @@
|
|
|
3476
3699
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
3477
3700
|
switch (name) {
|
|
3478
3701
|
case 'min-width':
|
|
3479
|
-
this.minWidth =
|
|
3702
|
+
this.minWidth = parseNumber(newValue, 0, name);
|
|
3480
3703
|
break;
|
|
3481
3704
|
case 'min-height':
|
|
3482
|
-
this.minHeight =
|
|
3705
|
+
this.minHeight = parseNumber(newValue, 0, name);
|
|
3483
3706
|
break;
|
|
3484
3707
|
case 'max-width':
|
|
3485
|
-
this.maxWidth = newValue
|
|
3708
|
+
this.maxWidth = parseNumber(newValue, null, name);
|
|
3486
3709
|
break;
|
|
3487
3710
|
case 'max-height':
|
|
3488
|
-
this.maxHeight = newValue
|
|
3711
|
+
this.maxHeight = parseNumber(newValue, null, name);
|
|
3489
3712
|
break;
|
|
3490
3713
|
case 'fit-width-proportion':
|
|
3491
|
-
this.fitWidthProportion =
|
|
3714
|
+
this.fitWidthProportion = parseNumber(newValue, 0, name);
|
|
3492
3715
|
break;
|
|
3493
3716
|
case 'fit-height-proportion':
|
|
3494
|
-
this.fitHeightProportion =
|
|
3717
|
+
this.fitHeightProportion = parseNumber(newValue, 0, name);
|
|
3495
3718
|
break;
|
|
3496
3719
|
case 'exclude-from-layout':
|
|
3497
|
-
this.excludeFromLayout = newValue
|
|
3720
|
+
this.excludeFromLayout = parseBool(newValue, false);
|
|
3498
3721
|
break;
|
|
3499
3722
|
}
|
|
3500
3723
|
}
|
|
@@ -3523,26 +3746,26 @@
|
|
|
3523
3746
|
/** @ignore */
|
|
3524
3747
|
constructor() {
|
|
3525
3748
|
super('layoutgroup');
|
|
3526
|
-
this._orientation =
|
|
3749
|
+
this._orientation = 'horizontal';
|
|
3527
3750
|
this._reverseX = false;
|
|
3528
3751
|
this._reverseY = false;
|
|
3529
3752
|
this._alignment = new playcanvas.Vec2(0, 1);
|
|
3530
3753
|
this._padding = new playcanvas.Vec4(0, 0, 0, 0);
|
|
3531
3754
|
this._spacing = new playcanvas.Vec2(0, 0);
|
|
3532
|
-
this._widthFitting =
|
|
3533
|
-
this._heightFitting =
|
|
3755
|
+
this._widthFitting = 'none';
|
|
3756
|
+
this._heightFitting = 'none';
|
|
3534
3757
|
this._wrap = false;
|
|
3535
3758
|
}
|
|
3536
3759
|
getInitialComponentData() {
|
|
3537
3760
|
return {
|
|
3538
|
-
orientation: this._orientation,
|
|
3761
|
+
orientation: orientations$1.get(this._orientation),
|
|
3539
3762
|
reverseX: this._reverseX,
|
|
3540
3763
|
reverseY: this._reverseY,
|
|
3541
3764
|
alignment: this._alignment,
|
|
3542
3765
|
padding: this._padding,
|
|
3543
3766
|
spacing: this._spacing,
|
|
3544
|
-
widthFitting: this._widthFitting,
|
|
3545
|
-
heightFitting: this._heightFitting,
|
|
3767
|
+
widthFitting: fittings.get(this._widthFitting),
|
|
3768
|
+
heightFitting: fittings.get(this._heightFitting),
|
|
3546
3769
|
wrap: this._wrap
|
|
3547
3770
|
};
|
|
3548
3771
|
}
|
|
@@ -3554,13 +3777,15 @@
|
|
|
3554
3777
|
return super.component;
|
|
3555
3778
|
}
|
|
3556
3779
|
/**
|
|
3557
|
-
* Sets the orientation of the layout group. Can be `horizontal`
|
|
3780
|
+
* Sets the orientation of the layout group. Can be `horizontal` or `vertical`. Defaults to
|
|
3781
|
+
* `horizontal`.
|
|
3558
3782
|
* @param value - The orientation.
|
|
3559
3783
|
*/
|
|
3560
3784
|
set orientation(value) {
|
|
3785
|
+
var _a;
|
|
3561
3786
|
this._orientation = value;
|
|
3562
3787
|
if (this.component) {
|
|
3563
|
-
this.component.orientation = value;
|
|
3788
|
+
this.component.orientation = (_a = orientations$1.get(value)) !== null && _a !== void 0 ? _a : playcanvas.ORIENTATION_HORIZONTAL;
|
|
3564
3789
|
}
|
|
3565
3790
|
}
|
|
3566
3791
|
/**
|
|
@@ -3656,14 +3881,15 @@
|
|
|
3656
3881
|
return this._spacing;
|
|
3657
3882
|
}
|
|
3658
3883
|
/**
|
|
3659
|
-
* Sets the fitting mode along the horizontal axis. Can be `none
|
|
3660
|
-
*
|
|
3884
|
+
* Sets the fitting mode along the horizontal axis. Can be `none`, `stretch`, `shrink` or
|
|
3885
|
+
* `both`. Defaults to `none`.
|
|
3661
3886
|
* @param value - The width fitting mode.
|
|
3662
3887
|
*/
|
|
3663
3888
|
set widthFitting(value) {
|
|
3889
|
+
var _a;
|
|
3664
3890
|
this._widthFitting = value;
|
|
3665
3891
|
if (this.component) {
|
|
3666
|
-
this.component.widthFitting = value;
|
|
3892
|
+
this.component.widthFitting = (_a = fittings.get(value)) !== null && _a !== void 0 ? _a : playcanvas.FITTING_NONE;
|
|
3667
3893
|
}
|
|
3668
3894
|
}
|
|
3669
3895
|
/**
|
|
@@ -3674,14 +3900,15 @@
|
|
|
3674
3900
|
return this._widthFitting;
|
|
3675
3901
|
}
|
|
3676
3902
|
/**
|
|
3677
|
-
* Sets the fitting mode along the vertical axis. Can be `none
|
|
3678
|
-
*
|
|
3903
|
+
* Sets the fitting mode along the vertical axis. Can be `none`, `stretch`, `shrink` or
|
|
3904
|
+
* `both`. Defaults to `none`.
|
|
3679
3905
|
* @param value - The height fitting mode.
|
|
3680
3906
|
*/
|
|
3681
3907
|
set heightFitting(value) {
|
|
3908
|
+
var _a;
|
|
3682
3909
|
this._heightFitting = value;
|
|
3683
3910
|
if (this.component) {
|
|
3684
|
-
this.component.heightFitting = value;
|
|
3911
|
+
this.component.heightFitting = (_a = fittings.get(value)) !== null && _a !== void 0 ? _a : playcanvas.FITTING_NONE;
|
|
3685
3912
|
}
|
|
3686
3913
|
}
|
|
3687
3914
|
/**
|
|
@@ -3726,31 +3953,31 @@
|
|
|
3726
3953
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
3727
3954
|
switch (name) {
|
|
3728
3955
|
case 'orientation':
|
|
3729
|
-
this.orientation = parseEnum(newValue, orientations$1,
|
|
3956
|
+
this.orientation = parseEnum(newValue, orientations$1, 'horizontal', name);
|
|
3730
3957
|
break;
|
|
3731
3958
|
case 'reverse-x':
|
|
3732
|
-
this.reverseX = newValue
|
|
3959
|
+
this.reverseX = parseBool(newValue, false);
|
|
3733
3960
|
break;
|
|
3734
3961
|
case 'reverse-y':
|
|
3735
|
-
this.reverseY = newValue
|
|
3962
|
+
this.reverseY = parseBool(newValue, false);
|
|
3736
3963
|
break;
|
|
3737
3964
|
case 'alignment':
|
|
3738
|
-
this.alignment = parseVec2(newValue);
|
|
3965
|
+
this.alignment = parseVec2(newValue, new playcanvas.Vec2(0, 1), name);
|
|
3739
3966
|
break;
|
|
3740
3967
|
case 'padding':
|
|
3741
|
-
this.padding = parseVec4(newValue);
|
|
3968
|
+
this.padding = parseVec4(newValue, playcanvas.Vec4.ZERO, name);
|
|
3742
3969
|
break;
|
|
3743
3970
|
case 'spacing':
|
|
3744
|
-
this.spacing = parseVec2(newValue);
|
|
3971
|
+
this.spacing = parseVec2(newValue, playcanvas.Vec2.ZERO, name);
|
|
3745
3972
|
break;
|
|
3746
3973
|
case 'width-fitting':
|
|
3747
|
-
this.widthFitting = parseEnum(newValue, fittings,
|
|
3974
|
+
this.widthFitting = parseEnum(newValue, fittings, 'none', name);
|
|
3748
3975
|
break;
|
|
3749
3976
|
case 'height-fitting':
|
|
3750
|
-
this.heightFitting = parseEnum(newValue, fittings,
|
|
3977
|
+
this.heightFitting = parseEnum(newValue, fittings, 'none', name);
|
|
3751
3978
|
break;
|
|
3752
3979
|
case 'wrap':
|
|
3753
|
-
this.wrap = newValue
|
|
3980
|
+
this.wrap = parseBool(newValue, false);
|
|
3754
3981
|
break;
|
|
3755
3982
|
}
|
|
3756
3983
|
}
|
|
@@ -4046,14 +4273,11 @@
|
|
|
4046
4273
|
return this._shadowType;
|
|
4047
4274
|
}
|
|
4048
4275
|
/**
|
|
4049
|
-
* Sets the type of the light.
|
|
4276
|
+
* Sets the type of the light. Can be `directional`, `omni` or `spot`. Defaults to
|
|
4277
|
+
* `directional`.
|
|
4050
4278
|
* @param value - The type.
|
|
4051
4279
|
*/
|
|
4052
4280
|
set type(value) {
|
|
4053
|
-
if (!['directional', 'omni', 'spot'].includes(value)) {
|
|
4054
|
-
console.warn(`Invalid light type '${value}', using default type '${this._type}'.`);
|
|
4055
|
-
return;
|
|
4056
|
-
}
|
|
4057
4281
|
this._type = value;
|
|
4058
4282
|
if (this.component) {
|
|
4059
4283
|
this.component.type = value;
|
|
@@ -4196,61 +4420,61 @@
|
|
|
4196
4420
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
4197
4421
|
switch (name) {
|
|
4198
4422
|
case 'color':
|
|
4199
|
-
this.color = parseColor(newValue);
|
|
4423
|
+
this.color = parseColor(newValue, playcanvas.Color.WHITE, name);
|
|
4200
4424
|
break;
|
|
4201
4425
|
case 'cast-shadows':
|
|
4202
|
-
this.castShadows =
|
|
4426
|
+
this.castShadows = parseBool(newValue, false);
|
|
4203
4427
|
break;
|
|
4204
4428
|
case 'inner-cone-angle':
|
|
4205
|
-
this.innerConeAngle =
|
|
4429
|
+
this.innerConeAngle = parseNumber(newValue, 40, name);
|
|
4206
4430
|
break;
|
|
4207
4431
|
case 'intensity':
|
|
4208
|
-
this.intensity =
|
|
4432
|
+
this.intensity = parseNumber(newValue, 1, name);
|
|
4209
4433
|
break;
|
|
4210
4434
|
case 'normal-offset-bias':
|
|
4211
|
-
this.normalOffsetBias =
|
|
4435
|
+
this.normalOffsetBias = parseNumber(newValue, 0.05, name);
|
|
4212
4436
|
break;
|
|
4213
4437
|
case 'outer-cone-angle':
|
|
4214
|
-
this.outerConeAngle =
|
|
4438
|
+
this.outerConeAngle = parseNumber(newValue, 45, name);
|
|
4215
4439
|
break;
|
|
4216
4440
|
case 'penumbra-falloff':
|
|
4217
|
-
this.penumbraFalloff =
|
|
4441
|
+
this.penumbraFalloff = parseNumber(newValue, 1, name);
|
|
4218
4442
|
break;
|
|
4219
4443
|
case 'penumbra-size':
|
|
4220
|
-
this.penumbraSize =
|
|
4444
|
+
this.penumbraSize = parseNumber(newValue, 1, name);
|
|
4221
4445
|
break;
|
|
4222
4446
|
case 'range':
|
|
4223
|
-
this.range =
|
|
4447
|
+
this.range = parseNumber(newValue, 10, name);
|
|
4224
4448
|
break;
|
|
4225
4449
|
case 'shadow-bias':
|
|
4226
|
-
this.shadowBias =
|
|
4450
|
+
this.shadowBias = parseNumber(newValue, 0.2, name);
|
|
4227
4451
|
break;
|
|
4228
4452
|
case 'shadow-distance':
|
|
4229
|
-
this.shadowDistance =
|
|
4453
|
+
this.shadowDistance = parseNumber(newValue, 16, name);
|
|
4230
4454
|
break;
|
|
4231
4455
|
case 'shadow-blocker-samples':
|
|
4232
|
-
this.shadowBlockerSamples =
|
|
4456
|
+
this.shadowBlockerSamples = parseNumber(newValue, 16, name);
|
|
4233
4457
|
break;
|
|
4234
4458
|
case 'shadow-resolution':
|
|
4235
|
-
this.shadowResolution =
|
|
4459
|
+
this.shadowResolution = parseNumber(newValue, 1024, name);
|
|
4236
4460
|
break;
|
|
4237
4461
|
case 'shadow-intensity':
|
|
4238
|
-
this.shadowIntensity =
|
|
4462
|
+
this.shadowIntensity = parseNumber(newValue, 1, name);
|
|
4239
4463
|
break;
|
|
4240
4464
|
case 'shadow-samples':
|
|
4241
|
-
this.shadowSamples =
|
|
4465
|
+
this.shadowSamples = parseNumber(newValue, 16, name);
|
|
4242
4466
|
break;
|
|
4243
4467
|
case 'shadow-type':
|
|
4244
|
-
this.shadowType = newValue;
|
|
4468
|
+
this.shadowType = parseEnum(newValue, shadowTypes, 'pcf3-32f', name);
|
|
4245
4469
|
break;
|
|
4246
4470
|
case 'type':
|
|
4247
|
-
this.type = newValue;
|
|
4471
|
+
this.type = parseEnum(newValue, ['directional', 'omni', 'spot'], 'directional', name);
|
|
4248
4472
|
break;
|
|
4249
4473
|
case 'vsm-bias':
|
|
4250
|
-
this.vsmBias =
|
|
4474
|
+
this.vsmBias = parseNumber(newValue, 0.01, name);
|
|
4251
4475
|
break;
|
|
4252
4476
|
case 'vsm-blur-size':
|
|
4253
|
-
this.vsmBlurSize =
|
|
4477
|
+
this.vsmBlurSize = parseNumber(newValue, 11, name);
|
|
4254
4478
|
break;
|
|
4255
4479
|
}
|
|
4256
4480
|
}
|
|
@@ -4394,6 +4618,10 @@
|
|
|
4394
4618
|
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-material/ | `<pc-material>`} elements.
|
|
4395
4619
|
* The MaterialElement interface also inherits the properties and methods of the
|
|
4396
4620
|
* {@link HTMLElement} interface.
|
|
4621
|
+
*
|
|
4622
|
+
* A `pc-material` must be a direct child of `pc-app` — elements placed elsewhere log a warning
|
|
4623
|
+
* and never create a material. Elements inserted while the application is already running are
|
|
4624
|
+
* created on insertion.
|
|
4397
4625
|
*/
|
|
4398
4626
|
class MaterialElement extends HTMLElement {
|
|
4399
4627
|
constructor() {
|
|
@@ -4405,6 +4633,26 @@
|
|
|
4405
4633
|
this._roughnessMap = '';
|
|
4406
4634
|
this.material = null;
|
|
4407
4635
|
}
|
|
4636
|
+
async connectedCallback() {
|
|
4637
|
+
var _a, _b;
|
|
4638
|
+
const appElement = (_b = (_a = this.parentElement) === null || _a === void 0 ? void 0 : _a.closest('pc-app')) !== null && _b !== void 0 ? _b : null;
|
|
4639
|
+
// Materials must be direct children of pc-app (matches the boot query ':scope > pc-material')
|
|
4640
|
+
if (!appElement || this.parentElement !== appElement) {
|
|
4641
|
+
console.warn(`pc-material '${this.id}' must be a direct child of pc-app - material not created`);
|
|
4642
|
+
return;
|
|
4643
|
+
}
|
|
4644
|
+
await appElement.ready();
|
|
4645
|
+
// The element may have been removed or re-parented while waiting for the app
|
|
4646
|
+
if (!this.isConnected || this.parentElement !== appElement)
|
|
4647
|
+
return;
|
|
4648
|
+
// Materials present at startup are created by AppElement's boot; this branch handles
|
|
4649
|
+
// elements inserted (or re-inserted) after the app is already running
|
|
4650
|
+
if (!this.material) {
|
|
4651
|
+
if (!appElement.app)
|
|
4652
|
+
return; // pc-app is re-connecting; its own boot will create this
|
|
4653
|
+
this.createMaterial();
|
|
4654
|
+
}
|
|
4655
|
+
}
|
|
4408
4656
|
createMaterial() {
|
|
4409
4657
|
this.material = new playcanvas.StandardMaterial();
|
|
4410
4658
|
this.material.glossInvert = false;
|
|
@@ -4487,7 +4735,7 @@
|
|
|
4487
4735
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
4488
4736
|
switch (name) {
|
|
4489
4737
|
case 'diffuse':
|
|
4490
|
-
this.diffuse = parseColor(newValue);
|
|
4738
|
+
this.diffuse = parseColor(newValue, playcanvas.Color.WHITE, name);
|
|
4491
4739
|
break;
|
|
4492
4740
|
case 'diffuse-map':
|
|
4493
4741
|
this.diffuseMap = newValue;
|
|
@@ -4512,6 +4760,10 @@
|
|
|
4512
4760
|
* The RenderComponentElement interface also inherits the properties and methods of the
|
|
4513
4761
|
* {@link HTMLElement} interface.
|
|
4514
4762
|
*
|
|
4763
|
+
* This element renders one of the engine's built-in primitives, selected with `type` (defaulting
|
|
4764
|
+
* to `box`). It does not cover the engine's `asset` render type, since there is no way to supply
|
|
4765
|
+
* a render asset here — use `pc-model` for glTF content instead.
|
|
4766
|
+
*
|
|
4515
4767
|
* @category Components
|
|
4516
4768
|
*/
|
|
4517
4769
|
class RenderComponentElement extends ComponentElement {
|
|
@@ -4521,7 +4773,7 @@
|
|
|
4521
4773
|
this._castShadows = true;
|
|
4522
4774
|
this._material = '';
|
|
4523
4775
|
this._receiveShadows = true;
|
|
4524
|
-
this._type = '
|
|
4776
|
+
this._type = 'box';
|
|
4525
4777
|
}
|
|
4526
4778
|
getInitialComponentData() {
|
|
4527
4779
|
return {
|
|
@@ -4613,16 +4865,16 @@
|
|
|
4613
4865
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
4614
4866
|
switch (name) {
|
|
4615
4867
|
case 'cast-shadows':
|
|
4616
|
-
this.castShadows = newValue
|
|
4868
|
+
this.castShadows = parseBool(newValue, true);
|
|
4617
4869
|
break;
|
|
4618
4870
|
case 'material':
|
|
4619
4871
|
this.material = newValue;
|
|
4620
4872
|
break;
|
|
4621
4873
|
case 'receive-shadows':
|
|
4622
|
-
this.receiveShadows = newValue
|
|
4874
|
+
this.receiveShadows = parseBool(newValue, true);
|
|
4623
4875
|
break;
|
|
4624
4876
|
case 'type':
|
|
4625
|
-
this.type = newValue;
|
|
4877
|
+
this.type = parseEnum(newValue, ['box', 'capsule', 'cone', 'cylinder', 'plane', 'sphere'], 'box', name);
|
|
4626
4878
|
break;
|
|
4627
4879
|
}
|
|
4628
4880
|
}
|
|
@@ -4786,31 +5038,31 @@
|
|
|
4786
5038
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
4787
5039
|
switch (name) {
|
|
4788
5040
|
case 'angular-damping':
|
|
4789
|
-
this.angularDamping =
|
|
5041
|
+
this.angularDamping = parseNumber(newValue, 0, name);
|
|
4790
5042
|
break;
|
|
4791
5043
|
case 'angular-factor':
|
|
4792
|
-
this.angularFactor = parseVec3(newValue);
|
|
5044
|
+
this.angularFactor = parseVec3(newValue, playcanvas.Vec3.ONE, name);
|
|
4793
5045
|
break;
|
|
4794
5046
|
case 'friction':
|
|
4795
|
-
this.friction =
|
|
5047
|
+
this.friction = parseNumber(newValue, 0.5, name);
|
|
4796
5048
|
break;
|
|
4797
5049
|
case 'linear-damping':
|
|
4798
|
-
this.linearDamping =
|
|
5050
|
+
this.linearDamping = parseNumber(newValue, 0, name);
|
|
4799
5051
|
break;
|
|
4800
5052
|
case 'linear-factor':
|
|
4801
|
-
this.linearFactor = parseVec3(newValue);
|
|
5053
|
+
this.linearFactor = parseVec3(newValue, playcanvas.Vec3.ONE, name);
|
|
4802
5054
|
break;
|
|
4803
5055
|
case 'mass':
|
|
4804
|
-
this.mass =
|
|
5056
|
+
this.mass = parseNumber(newValue, 1, name);
|
|
4805
5057
|
break;
|
|
4806
5058
|
case 'restitution':
|
|
4807
|
-
this.restitution =
|
|
5059
|
+
this.restitution = parseNumber(newValue, 0, name);
|
|
4808
5060
|
break;
|
|
4809
5061
|
case 'rolling-friction':
|
|
4810
|
-
this.rollingFriction =
|
|
5062
|
+
this.rollingFriction = parseNumber(newValue, 0, name);
|
|
4811
5063
|
break;
|
|
4812
5064
|
case 'type':
|
|
4813
|
-
this.type = newValue;
|
|
5065
|
+
this.type = parseEnum(newValue, ['static', 'dynamic', 'kinematic'], 'static', name);
|
|
4814
5066
|
break;
|
|
4815
5067
|
}
|
|
4816
5068
|
}
|
|
@@ -4922,22 +5174,22 @@
|
|
|
4922
5174
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
4923
5175
|
switch (name) {
|
|
4924
5176
|
case 'priority':
|
|
4925
|
-
this.priority =
|
|
5177
|
+
this.priority = parseNumber(newValue, 0, name);
|
|
4926
5178
|
break;
|
|
4927
5179
|
case 'reference-resolution':
|
|
4928
|
-
this.referenceResolution = parseVec2(newValue);
|
|
5180
|
+
this.referenceResolution = parseVec2(newValue, new playcanvas.Vec2(640, 320), name);
|
|
4929
5181
|
break;
|
|
4930
5182
|
case 'resolution':
|
|
4931
|
-
this.resolution = parseVec2(newValue);
|
|
5183
|
+
this.resolution = parseVec2(newValue, new playcanvas.Vec2(640, 320), name);
|
|
4932
5184
|
break;
|
|
4933
5185
|
case 'scale-blend':
|
|
4934
|
-
this.scaleBlend =
|
|
5186
|
+
this.scaleBlend = parseNumber(newValue, 0.5, name);
|
|
4935
5187
|
break;
|
|
4936
5188
|
case 'blend':
|
|
4937
|
-
this.blend =
|
|
5189
|
+
this.blend = parseBool(newValue, false);
|
|
4938
5190
|
break;
|
|
4939
5191
|
case 'screen-space':
|
|
4940
|
-
this.screenSpace =
|
|
5192
|
+
this.screenSpace = parseBool(newValue, false);
|
|
4941
5193
|
break;
|
|
4942
5194
|
}
|
|
4943
5195
|
}
|
|
@@ -4960,14 +5212,14 @@
|
|
|
4960
5212
|
/** @ignore */
|
|
4961
5213
|
constructor() {
|
|
4962
5214
|
super('scrollbar');
|
|
4963
|
-
this._orientation =
|
|
5215
|
+
this._orientation = 'horizontal';
|
|
4964
5216
|
this._value = 0;
|
|
4965
5217
|
this._handleSize = 0.5;
|
|
4966
5218
|
this._handle = '';
|
|
4967
5219
|
}
|
|
4968
5220
|
getInitialComponentData() {
|
|
4969
5221
|
const data = {
|
|
4970
|
-
orientation: this._orientation,
|
|
5222
|
+
orientation: orientations.get(this._orientation),
|
|
4971
5223
|
value: this._value,
|
|
4972
5224
|
handleSize: this._handleSize
|
|
4973
5225
|
};
|
|
@@ -4985,13 +5237,15 @@
|
|
|
4985
5237
|
return super.component;
|
|
4986
5238
|
}
|
|
4987
5239
|
/**
|
|
4988
|
-
* Sets the orientation of the scrollbar. Can be `horizontal`
|
|
5240
|
+
* Sets the orientation of the scrollbar. Can be `horizontal` or `vertical`. Defaults to
|
|
5241
|
+
* `horizontal`.
|
|
4989
5242
|
* @param value - The orientation.
|
|
4990
5243
|
*/
|
|
4991
5244
|
set orientation(value) {
|
|
5245
|
+
var _a;
|
|
4992
5246
|
this._orientation = value;
|
|
4993
5247
|
if (this.component) {
|
|
4994
|
-
this.component.orientation = value;
|
|
5248
|
+
this.component.orientation = (_a = orientations.get(value)) !== null && _a !== void 0 ? _a : playcanvas.ORIENTATION_HORIZONTAL;
|
|
4995
5249
|
}
|
|
4996
5250
|
}
|
|
4997
5251
|
/**
|
|
@@ -5067,13 +5321,13 @@
|
|
|
5067
5321
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
5068
5322
|
switch (name) {
|
|
5069
5323
|
case 'orientation':
|
|
5070
|
-
this.orientation = parseEnum(newValue, orientations,
|
|
5324
|
+
this.orientation = parseEnum(newValue, orientations, 'horizontal', name);
|
|
5071
5325
|
break;
|
|
5072
5326
|
case 'value':
|
|
5073
|
-
this.value =
|
|
5327
|
+
this.value = parseNumber(newValue, 0, name);
|
|
5074
5328
|
break;
|
|
5075
5329
|
case 'handle-size':
|
|
5076
|
-
this.handleSize =
|
|
5330
|
+
this.handleSize = parseNumber(newValue, 0.5, name);
|
|
5077
5331
|
break;
|
|
5078
5332
|
case 'handle':
|
|
5079
5333
|
this.handle = newValue;
|
|
@@ -5106,13 +5360,13 @@
|
|
|
5106
5360
|
super('scrollview');
|
|
5107
5361
|
this._horizontal = true;
|
|
5108
5362
|
this._vertical = true;
|
|
5109
|
-
this._scrollMode =
|
|
5363
|
+
this._scrollMode = 'bounce';
|
|
5110
5364
|
this._bounceAmount = 0.1;
|
|
5111
5365
|
this._friction = 0.05;
|
|
5112
5366
|
this._useMouseWheel = true;
|
|
5113
5367
|
this._mouseWheelSensitivity = new playcanvas.Vec2(1, 1);
|
|
5114
|
-
this._horizontalScrollbarVisibility =
|
|
5115
|
-
this._verticalScrollbarVisibility =
|
|
5368
|
+
this._horizontalScrollbarVisibility = 'when-required';
|
|
5369
|
+
this._verticalScrollbarVisibility = 'when-required';
|
|
5116
5370
|
this._viewport = '';
|
|
5117
5371
|
this._content = '';
|
|
5118
5372
|
this._horizontalScrollbar = '';
|
|
@@ -5122,13 +5376,13 @@
|
|
|
5122
5376
|
const data = {
|
|
5123
5377
|
horizontal: this._horizontal,
|
|
5124
5378
|
vertical: this._vertical,
|
|
5125
|
-
scrollMode: this._scrollMode,
|
|
5379
|
+
scrollMode: scrollModes.get(this._scrollMode),
|
|
5126
5380
|
bounceAmount: this._bounceAmount,
|
|
5127
5381
|
friction: this._friction,
|
|
5128
5382
|
useMouseWheel: this._useMouseWheel,
|
|
5129
5383
|
mouseWheelSensitivity: this._mouseWheelSensitivity,
|
|
5130
|
-
horizontalScrollbarVisibility: this._horizontalScrollbarVisibility,
|
|
5131
|
-
verticalScrollbarVisibility: this._verticalScrollbarVisibility
|
|
5384
|
+
horizontalScrollbarVisibility: visibilities.get(this._horizontalScrollbarVisibility),
|
|
5385
|
+
verticalScrollbarVisibility: visibilities.get(this._verticalScrollbarVisibility)
|
|
5132
5386
|
};
|
|
5133
5387
|
const viewport = getEntity(this._viewport);
|
|
5134
5388
|
if (viewport) {
|
|
@@ -5191,13 +5445,14 @@
|
|
|
5191
5445
|
}
|
|
5192
5446
|
/**
|
|
5193
5447
|
* Sets how the scroll view should behave when the content is scrolled beyond its bounds. Can be
|
|
5194
|
-
* `clamp
|
|
5448
|
+
* `clamp`, `bounce` or `infinite`. Defaults to `bounce`.
|
|
5195
5449
|
* @param value - The scroll mode.
|
|
5196
5450
|
*/
|
|
5197
5451
|
set scrollMode(value) {
|
|
5452
|
+
var _a;
|
|
5198
5453
|
this._scrollMode = value;
|
|
5199
5454
|
if (this.component) {
|
|
5200
|
-
this.component.scrollMode = value;
|
|
5455
|
+
this.component.scrollMode = (_a = scrollModes.get(value)) !== null && _a !== void 0 ? _a : playcanvas.SCROLL_MODE_BOUNCE;
|
|
5201
5456
|
}
|
|
5202
5457
|
}
|
|
5203
5458
|
/**
|
|
@@ -5278,13 +5533,15 @@
|
|
|
5278
5533
|
return this._mouseWheelSensitivity;
|
|
5279
5534
|
}
|
|
5280
5535
|
/**
|
|
5281
|
-
* Sets the visibility of the horizontal scrollbar. Can be `always`
|
|
5536
|
+
* Sets the visibility of the horizontal scrollbar. Can be `always` or `when-required`.
|
|
5537
|
+
* Defaults to `when-required`.
|
|
5282
5538
|
* @param value - The horizontal scrollbar visibility.
|
|
5283
5539
|
*/
|
|
5284
5540
|
set horizontalScrollbarVisibility(value) {
|
|
5541
|
+
var _a;
|
|
5285
5542
|
this._horizontalScrollbarVisibility = value;
|
|
5286
5543
|
if (this.component) {
|
|
5287
|
-
this.component.horizontalScrollbarVisibility = value;
|
|
5544
|
+
this.component.horizontalScrollbarVisibility = (_a = visibilities.get(value)) !== null && _a !== void 0 ? _a : playcanvas.SCROLLBAR_VISIBILITY_SHOW_WHEN_REQUIRED;
|
|
5288
5545
|
}
|
|
5289
5546
|
}
|
|
5290
5547
|
/**
|
|
@@ -5295,13 +5552,15 @@
|
|
|
5295
5552
|
return this._horizontalScrollbarVisibility;
|
|
5296
5553
|
}
|
|
5297
5554
|
/**
|
|
5298
|
-
* Sets the visibility of the vertical scrollbar. Can be `always`
|
|
5555
|
+
* Sets the visibility of the vertical scrollbar. Can be `always` or `when-required`.
|
|
5556
|
+
* Defaults to `when-required`.
|
|
5299
5557
|
* @param value - The vertical scrollbar visibility.
|
|
5300
5558
|
*/
|
|
5301
5559
|
set verticalScrollbarVisibility(value) {
|
|
5560
|
+
var _a;
|
|
5302
5561
|
this._verticalScrollbarVisibility = value;
|
|
5303
5562
|
if (this.component) {
|
|
5304
|
-
this.component.verticalScrollbarVisibility = value;
|
|
5563
|
+
this.component.verticalScrollbarVisibility = (_a = visibilities.get(value)) !== null && _a !== void 0 ? _a : playcanvas.SCROLLBAR_VISIBILITY_SHOW_WHEN_REQUIRED;
|
|
5305
5564
|
}
|
|
5306
5565
|
}
|
|
5307
5566
|
/**
|
|
@@ -5409,31 +5668,31 @@
|
|
|
5409
5668
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
5410
5669
|
switch (name) {
|
|
5411
5670
|
case 'horizontal':
|
|
5412
|
-
this.horizontal = newValue
|
|
5671
|
+
this.horizontal = parseBool(newValue, true);
|
|
5413
5672
|
break;
|
|
5414
5673
|
case 'vertical':
|
|
5415
|
-
this.vertical = newValue
|
|
5674
|
+
this.vertical = parseBool(newValue, true);
|
|
5416
5675
|
break;
|
|
5417
5676
|
case 'scroll-mode':
|
|
5418
|
-
this.scrollMode = parseEnum(newValue, scrollModes,
|
|
5677
|
+
this.scrollMode = parseEnum(newValue, scrollModes, 'bounce', name);
|
|
5419
5678
|
break;
|
|
5420
5679
|
case 'bounce-amount':
|
|
5421
|
-
this.bounceAmount =
|
|
5680
|
+
this.bounceAmount = parseNumber(newValue, 0.1, name);
|
|
5422
5681
|
break;
|
|
5423
5682
|
case 'friction':
|
|
5424
|
-
this.friction =
|
|
5683
|
+
this.friction = parseNumber(newValue, 0.05, name);
|
|
5425
5684
|
break;
|
|
5426
5685
|
case 'use-mouse-wheel':
|
|
5427
|
-
this.useMouseWheel = newValue
|
|
5686
|
+
this.useMouseWheel = parseBool(newValue, true);
|
|
5428
5687
|
break;
|
|
5429
5688
|
case 'mouse-wheel-sensitivity':
|
|
5430
|
-
this.mouseWheelSensitivity = parseVec2(newValue);
|
|
5689
|
+
this.mouseWheelSensitivity = parseVec2(newValue, playcanvas.Vec2.ONE, name);
|
|
5431
5690
|
break;
|
|
5432
5691
|
case 'horizontal-scrollbar-visibility':
|
|
5433
|
-
this.horizontalScrollbarVisibility = parseEnum(newValue, visibilities,
|
|
5692
|
+
this.horizontalScrollbarVisibility = parseEnum(newValue, visibilities, 'when-required', name);
|
|
5434
5693
|
break;
|
|
5435
5694
|
case 'vertical-scrollbar-visibility':
|
|
5436
|
-
this.verticalScrollbarVisibility = parseEnum(newValue, visibilities,
|
|
5695
|
+
this.verticalScrollbarVisibility = parseEnum(newValue, visibilities, 'when-required', name);
|
|
5437
5696
|
break;
|
|
5438
5697
|
case 'viewport':
|
|
5439
5698
|
this.viewport = newValue;
|
|
@@ -5441,17 +5700,347 @@
|
|
|
5441
5700
|
case 'content':
|
|
5442
5701
|
this.content = newValue;
|
|
5443
5702
|
break;
|
|
5444
|
-
case 'horizontal-scrollbar':
|
|
5445
|
-
this.horizontalScrollbar = newValue;
|
|
5703
|
+
case 'horizontal-scrollbar':
|
|
5704
|
+
this.horizontalScrollbar = newValue;
|
|
5705
|
+
break;
|
|
5706
|
+
case 'vertical-scrollbar':
|
|
5707
|
+
this.verticalScrollbar = newValue;
|
|
5708
|
+
break;
|
|
5709
|
+
}
|
|
5710
|
+
}
|
|
5711
|
+
}
|
|
5712
|
+
customElements.define('pc-scrollview', ScrollViewComponentElement);
|
|
5713
|
+
|
|
5714
|
+
/**
|
|
5715
|
+
* The ScriptElement interface provides properties and methods for manipulating
|
|
5716
|
+
* `<pc-script>` elements. The ScriptElement interface also inherits the properties and
|
|
5717
|
+
* methods of the {@link AsyncElement} interface.
|
|
5718
|
+
*
|
|
5719
|
+
* Script attributes can be supplied through two channels:
|
|
5720
|
+
*
|
|
5721
|
+
* - **Per-property attributes**: any non-reserved attribute on the element maps to the script
|
|
5722
|
+
* attribute of the same name (kebab-case to camelCase, e.g. `focus-point` → `focusPoint`).
|
|
5723
|
+
* Values are parsed according to the type of the attribute's current value — initially the
|
|
5724
|
+
* script's declared default (numbers, booleans, strings, Vec2/3/4, Color, Quat as Euler
|
|
5725
|
+
* angles) — and the `asset:`/`entity:`/`vec2:`/`vec3:`/`vec4:`/`color:` prefixes may be used
|
|
5726
|
+
* to be explicit.
|
|
5727
|
+
* - **The `attributes` JSON attribute**: an object supporting nested structures and attribute
|
|
5728
|
+
* names that collide with reserved HTML attribute names (e.g. `title`).
|
|
5729
|
+
*
|
|
5730
|
+
* When both specify the same attribute, the per-property attribute wins — at creation and
|
|
5731
|
+
* whenever either channel changes at runtime. The element's own `name` and `enabled`
|
|
5732
|
+
* attributes configure the element itself and are not script attributes.
|
|
5733
|
+
*
|
|
5734
|
+
* Changing `name` on a live element destroys the old-name script instance and creates the
|
|
5735
|
+
* new-name one, re-applying both attribute channels to it.
|
|
5736
|
+
*
|
|
5737
|
+
* The element becomes ready once its script instance has been created by the parent
|
|
5738
|
+
* `<pc-scripts>` element.
|
|
5739
|
+
*/
|
|
5740
|
+
class ScriptElement extends AsyncElement {
|
|
5741
|
+
constructor() {
|
|
5742
|
+
super(...arguments);
|
|
5743
|
+
this._attributes = {};
|
|
5744
|
+
this._enabled = true;
|
|
5745
|
+
/**
|
|
5746
|
+
* Whether readiness has been signalled. Creation can happen more than once over an
|
|
5747
|
+
* element's life (a runtime `name` change recreates the instance), but `ready` is a
|
|
5748
|
+
* one-shot signal, so only the first successful creation fires it.
|
|
5749
|
+
*/
|
|
5750
|
+
this._readySignalled = false;
|
|
5751
|
+
/**
|
|
5752
|
+
* The Script instance created for this element by its parent `<pc-scripts>` element.
|
|
5753
|
+
* @ignore
|
|
5754
|
+
*/
|
|
5755
|
+
this._script = null;
|
|
5756
|
+
}
|
|
5757
|
+
/**
|
|
5758
|
+
* Sets the attributes of the script as an object. Values are converted with the same rules
|
|
5759
|
+
* as the `attributes` attribute: `asset:`/`entity:` references and `vec2:`/`vec3:`/`vec4:`/
|
|
5760
|
+
* `color:` prefixed strings are resolved, and a plain numeric array is converted to the
|
|
5761
|
+
* type of the attribute it targets when that attribute currently holds a Vec2, Vec3, Vec4
|
|
5762
|
+
* or Color.
|
|
5763
|
+
* @param value - The attributes of the script.
|
|
5764
|
+
*/
|
|
5765
|
+
set scriptAttributes(value) {
|
|
5766
|
+
this._attributes = value !== null && value !== void 0 ? value : {};
|
|
5767
|
+
this.dispatchEvent(new CustomEvent('scriptattributeschange', {
|
|
5768
|
+
detail: { attributes: this._attributes },
|
|
5769
|
+
bubbles: true
|
|
5770
|
+
}));
|
|
5771
|
+
}
|
|
5772
|
+
/**
|
|
5773
|
+
* Gets the attributes of the script.
|
|
5774
|
+
* @returns The attributes of the script.
|
|
5775
|
+
*/
|
|
5776
|
+
get scriptAttributes() {
|
|
5777
|
+
return this._attributes;
|
|
5778
|
+
}
|
|
5779
|
+
/**
|
|
5780
|
+
* Sets the enabled state of the script.
|
|
5781
|
+
* @param value - The enabled state of the script.
|
|
5782
|
+
*/
|
|
5783
|
+
set enabled(value) {
|
|
5784
|
+
this._enabled = value;
|
|
5785
|
+
this.dispatchEvent(new CustomEvent('scriptenablechange', {
|
|
5786
|
+
detail: { enabled: value },
|
|
5787
|
+
bubbles: true
|
|
5788
|
+
}));
|
|
5789
|
+
}
|
|
5790
|
+
/**
|
|
5791
|
+
* Gets the enabled state of the script.
|
|
5792
|
+
* @returns The enabled state of the script.
|
|
5793
|
+
*/
|
|
5794
|
+
get enabled() {
|
|
5795
|
+
return this._enabled;
|
|
5796
|
+
}
|
|
5797
|
+
/**
|
|
5798
|
+
* Sets the name of the script to create. The `name` attribute is the single source of truth
|
|
5799
|
+
* (it is what the parent `<pc-scripts>` element reads when creating the instance), so the
|
|
5800
|
+
* property writes through to it — assigning before insertion works as expected:
|
|
5801
|
+
*
|
|
5802
|
+
* ```js
|
|
5803
|
+
* const script = document.createElement('pc-script');
|
|
5804
|
+
* script.name = 'rotate';
|
|
5805
|
+
* scriptsElement.appendChild(script);
|
|
5806
|
+
* await script.ready();
|
|
5807
|
+
* ```
|
|
5808
|
+
* @param value - The name.
|
|
5809
|
+
*/
|
|
5810
|
+
set name(value) {
|
|
5811
|
+
this.setAttribute('name', value);
|
|
5812
|
+
}
|
|
5813
|
+
/**
|
|
5814
|
+
* Gets the name of the script.
|
|
5815
|
+
* @returns The name.
|
|
5816
|
+
*/
|
|
5817
|
+
get name() {
|
|
5818
|
+
var _a;
|
|
5819
|
+
return (_a = this.getAttribute('name')) !== null && _a !== void 0 ? _a : '';
|
|
5820
|
+
}
|
|
5821
|
+
/**
|
|
5822
|
+
* Gets the {@link Script} instance created for this element. Returns `null` until the
|
|
5823
|
+
* instance exists — await {@link whenReady} or the element's `ready()` promise before
|
|
5824
|
+
* accessing it.
|
|
5825
|
+
* @returns The script instance, or `null`.
|
|
5826
|
+
*/
|
|
5827
|
+
get script() {
|
|
5828
|
+
return this._script;
|
|
5829
|
+
}
|
|
5830
|
+
connectedCallback() {
|
|
5831
|
+
var _a;
|
|
5832
|
+
// Script instances are created by the parent pc-scripts element, so an element placed
|
|
5833
|
+
// anywhere else is inert and never becomes ready - warn rather than hang silently
|
|
5834
|
+
if (((_a = this.parentElement) === null || _a === void 0 ? void 0 : _a.tagName) !== 'PC-SCRIPTS') {
|
|
5835
|
+
console.warn(`pc-script '${this.getAttribute('name')}' must be a direct child of pc-scripts - script not created`);
|
|
5836
|
+
}
|
|
5837
|
+
}
|
|
5838
|
+
/**
|
|
5839
|
+
* Called by the parent `<pc-scripts>` element when the script instance has been created.
|
|
5840
|
+
* @ignore
|
|
5841
|
+
*/
|
|
5842
|
+
_onScriptCreated() {
|
|
5843
|
+
if (this._readySignalled)
|
|
5844
|
+
return;
|
|
5845
|
+
this._readySignalled = true;
|
|
5846
|
+
this._onReady();
|
|
5847
|
+
}
|
|
5848
|
+
static get observedAttributes() {
|
|
5849
|
+
return ['attributes', 'enabled', 'name'];
|
|
5850
|
+
}
|
|
5851
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
5852
|
+
switch (name) {
|
|
5853
|
+
case 'attributes':
|
|
5854
|
+
if (newValue === null) {
|
|
5855
|
+
this.scriptAttributes = {};
|
|
5856
|
+
break;
|
|
5857
|
+
}
|
|
5858
|
+
try {
|
|
5859
|
+
this.scriptAttributes = JSON.parse(newValue);
|
|
5860
|
+
}
|
|
5861
|
+
catch (error) {
|
|
5862
|
+
console.warn(`Invalid 'attributes' JSON on pc-script '${this.getAttribute('name')}': ${error.message}`);
|
|
5863
|
+
}
|
|
5864
|
+
break;
|
|
5865
|
+
case 'enabled':
|
|
5866
|
+
this.enabled = parseBool(newValue, true);
|
|
5446
5867
|
break;
|
|
5447
|
-
case '
|
|
5448
|
-
|
|
5868
|
+
case 'name':
|
|
5869
|
+
// The first set is handled by the parent's creation paths (the boot query and
|
|
5870
|
+
// the added-node mutation), so only a genuine rename is signalled here. Note
|
|
5871
|
+
// that setAttribute fires this callback even when the value is unchanged.
|
|
5872
|
+
if (oldValue !== null && oldValue !== newValue) {
|
|
5873
|
+
this.dispatchEvent(new CustomEvent('scriptnamechange', {
|
|
5874
|
+
detail: { oldName: oldValue, newName: newValue },
|
|
5875
|
+
bubbles: true
|
|
5876
|
+
}));
|
|
5877
|
+
}
|
|
5449
5878
|
break;
|
|
5450
5879
|
}
|
|
5451
5880
|
}
|
|
5452
5881
|
}
|
|
5453
|
-
customElements.define('pc-
|
|
5882
|
+
customElements.define('pc-script', ScriptElement);
|
|
5454
5883
|
|
|
5884
|
+
/**
|
|
5885
|
+
* Attributes on `pc-script` that never map to script attributes: the element's own API (derived
|
|
5886
|
+
* from its observed attributes) plus reserved and global HTML attribute names.
|
|
5887
|
+
*/
|
|
5888
|
+
const RESERVED_ATTRIBUTES = new Set([
|
|
5889
|
+
...ScriptElement.observedAttributes,
|
|
5890
|
+
'accesskey', 'autocapitalize', 'autofocus', 'class', 'contenteditable', 'dir', 'draggable',
|
|
5891
|
+
'exportparts', 'hidden', 'id', 'inert', 'is', 'itemid', 'itemprop', 'itemref', 'itemscope',
|
|
5892
|
+
'itemtype', 'lang', 'nonce', 'part', 'popover', 'role', 'slot', 'spellcheck', 'style',
|
|
5893
|
+
'tabindex', 'title', 'translate'
|
|
5894
|
+
]);
|
|
5895
|
+
/**
|
|
5896
|
+
* Checks whether a `pc-script` attribute name is reserved (and so never maps to a script
|
|
5897
|
+
* attribute). Reserved names are the element's own API, global HTML attribute names, `data-*`
|
|
5898
|
+
* and `aria-*` attributes, names starting with `_` (framework-stamped attributes), and real
|
|
5899
|
+
* inline event handler names (`onclick` etc. — detected via the platform, so script attributes
|
|
5900
|
+
* that merely start with 'on', like `once`, still map).
|
|
5901
|
+
* @param name - The attribute name.
|
|
5902
|
+
* @returns Whether the attribute name is reserved.
|
|
5903
|
+
*/
|
|
5904
|
+
const isReservedAttribute = (name) => {
|
|
5905
|
+
return RESERVED_ATTRIBUTES.has(name) ||
|
|
5906
|
+
name.startsWith('data-') ||
|
|
5907
|
+
name.startsWith('aria-') ||
|
|
5908
|
+
name.startsWith('_') ||
|
|
5909
|
+
(name.startsWith('on') && name in HTMLElement.prototype);
|
|
5910
|
+
};
|
|
5911
|
+
/**
|
|
5912
|
+
* Script API members that per-property attributes must never overwrite: the engine bindings and
|
|
5913
|
+
* the (optional, so possibly undefined) lifecycle methods.
|
|
5914
|
+
*/
|
|
5915
|
+
const SCRIPT_API_MEMBERS = new Set([
|
|
5916
|
+
'app', 'entity', 'destroy', 'initialize', 'postInitialize', 'postUpdate', 'swap', 'update'
|
|
5917
|
+
]);
|
|
5918
|
+
/**
|
|
5919
|
+
* Converts a kebab-case attribute name to the camelCase script attribute name.
|
|
5920
|
+
* @param name - The attribute name.
|
|
5921
|
+
* @returns The camelCase name.
|
|
5922
|
+
*/
|
|
5923
|
+
const kebabToCamel = (name) => {
|
|
5924
|
+
return name.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
|
|
5925
|
+
};
|
|
5926
|
+
/**
|
|
5927
|
+
* Converts a camelCase script attribute name to its kebab-case attribute spelling.
|
|
5928
|
+
* @param name - The camelCase name.
|
|
5929
|
+
* @returns The kebab-case name.
|
|
5930
|
+
*/
|
|
5931
|
+
const camelToKebab = (name) => {
|
|
5932
|
+
return name.replace(/[A-Z]/g, char => `-${char.toLowerCase()}`);
|
|
5933
|
+
};
|
|
5934
|
+
/**
|
|
5935
|
+
* Resolves an `asset:` prefix to the Asset created by the `pc-asset` element with that id.
|
|
5936
|
+
* @param rest - The asset id.
|
|
5937
|
+
* @param raw - The raw value, returned unchanged when the id does not resolve.
|
|
5938
|
+
* @returns The asset, or `raw`.
|
|
5939
|
+
*/
|
|
5940
|
+
const assetConversion = (rest, raw) => {
|
|
5941
|
+
const asset = AssetElement.get(rest);
|
|
5942
|
+
if (asset) {
|
|
5943
|
+
return asset;
|
|
5944
|
+
}
|
|
5945
|
+
console.warn(`Unable to resolve '${raw}' in script attributes - no pc-asset found with id '${rest}'.`);
|
|
5946
|
+
return raw;
|
|
5947
|
+
};
|
|
5948
|
+
/**
|
|
5949
|
+
* Resolves an `entity:` prefix to the Entity backing a `pc-entity` element. The reference can be a
|
|
5950
|
+
* CSS selector, an element id or an entity name.
|
|
5951
|
+
* @param rest - The entity reference.
|
|
5952
|
+
* @param raw - The raw value, returned unchanged when the reference does not resolve.
|
|
5953
|
+
* @returns The entity, or `raw`.
|
|
5954
|
+
*/
|
|
5955
|
+
const entityConversion = (rest, raw) => {
|
|
5956
|
+
const entity = getEntity(rest);
|
|
5957
|
+
if (entity) {
|
|
5958
|
+
return entity;
|
|
5959
|
+
}
|
|
5960
|
+
console.warn(`Unable to resolve '${raw}' in script attributes - no pc-entity found matching '${rest}'.`);
|
|
5961
|
+
return raw;
|
|
5962
|
+
};
|
|
5963
|
+
/**
|
|
5964
|
+
* Builds the conversion for a `vec2:`/`vec3:`/`vec4:` prefix.
|
|
5965
|
+
* @param length - The number of components the prefix carries.
|
|
5966
|
+
* @param Ctor - The vector type to construct.
|
|
5967
|
+
* @returns The conversion.
|
|
5968
|
+
*/
|
|
5969
|
+
const vectorConversion = (length, Ctor) => {
|
|
5970
|
+
return (rest, raw) => {
|
|
5971
|
+
const components = parseComponents(rest, length);
|
|
5972
|
+
if (components) {
|
|
5973
|
+
return new Ctor(components);
|
|
5974
|
+
}
|
|
5975
|
+
console.warn(`Invalid script attribute value '${raw}'. Expected ${length} space-separated numbers after 'vec${length}:'.`);
|
|
5976
|
+
return raw;
|
|
5977
|
+
};
|
|
5978
|
+
};
|
|
5979
|
+
/**
|
|
5980
|
+
* Converts a `color:` prefix to a Color, accepting 3 or 4 components.
|
|
5981
|
+
* @param rest - The space-separated components.
|
|
5982
|
+
* @param raw - The raw value, returned unchanged when the components do not parse.
|
|
5983
|
+
* @returns The color, or `raw`.
|
|
5984
|
+
*/
|
|
5985
|
+
const colorConversion = (rest, raw) => {
|
|
5986
|
+
var _a;
|
|
5987
|
+
const components = (_a = parseComponents(rest, 4)) !== null && _a !== void 0 ? _a : parseComponents(rest, 3);
|
|
5988
|
+
if (components) {
|
|
5989
|
+
return new playcanvas.Color(components);
|
|
5990
|
+
}
|
|
5991
|
+
console.warn(`Invalid script attribute value '${raw}'. Expected 3 or 4 space-separated numbers after 'color:'.`);
|
|
5992
|
+
return raw;
|
|
5993
|
+
};
|
|
5994
|
+
/**
|
|
5995
|
+
* The conversion prefixes recognised in script attribute values, mapped to the conversion each
|
|
5996
|
+
* performs. These keys are the single source of truth for the prefix vocabulary: they drive both
|
|
5997
|
+
* the conversion in `convertAttributes` and the has-a-prefix test in `setScriptProperty`, so a
|
|
5998
|
+
* prefix added here is automatically known to both.
|
|
5999
|
+
*/
|
|
6000
|
+
const CONVERSIONS = new Map([
|
|
6001
|
+
['asset', assetConversion],
|
|
6002
|
+
['entity', entityConversion],
|
|
6003
|
+
['vec2', vectorConversion(2, playcanvas.Vec2)],
|
|
6004
|
+
['vec3', vectorConversion(3, playcanvas.Vec3)],
|
|
6005
|
+
['vec4', vectorConversion(4, playcanvas.Vec4)],
|
|
6006
|
+
['color', colorConversion]
|
|
6007
|
+
]);
|
|
6008
|
+
/**
|
|
6009
|
+
* Matches a value against the conversion prefixes. A prefix is the text before the first colon,
|
|
6010
|
+
* so a value whose remainder itself contains colons (`asset:a:b`) still resolves, and a value
|
|
6011
|
+
* with an unrecognised prefix (`https://...`) or no colon does not match.
|
|
6012
|
+
* @param value - The value to inspect.
|
|
6013
|
+
* @returns The matching converter and the text after the prefix, or `null` if the value carries
|
|
6014
|
+
* no recognised prefix.
|
|
6015
|
+
*/
|
|
6016
|
+
const matchConversion = (value) => {
|
|
6017
|
+
const index = value.indexOf(':');
|
|
6018
|
+
if (index <= 0) {
|
|
6019
|
+
return null;
|
|
6020
|
+
}
|
|
6021
|
+
const convert = CONVERSIONS.get(value.slice(0, index));
|
|
6022
|
+
return convert ? { convert, rest: value.slice(index + 1) } : null;
|
|
6023
|
+
};
|
|
6024
|
+
/**
|
|
6025
|
+
* Finds a script property whose name matches `key` case-insensitively (but not exactly). Used
|
|
6026
|
+
* to suggest the kebab-case spelling when a camelCase attribute has been lowercased by the HTML
|
|
6027
|
+
* parser (e.g. `focusPoint` arriving as 'focuspoint').
|
|
6028
|
+
* @param script - The script instance to search.
|
|
6029
|
+
* @param key - The lowercased key that failed to match.
|
|
6030
|
+
* @returns The matching property name, or `null`.
|
|
6031
|
+
*/
|
|
6032
|
+
const findCaseMatch = (script, key) => {
|
|
6033
|
+
const names = new Set(Object.keys(script));
|
|
6034
|
+
for (const name of Object.getOwnPropertyNames(Object.getPrototypeOf(script))) {
|
|
6035
|
+
names.add(name);
|
|
6036
|
+
}
|
|
6037
|
+
for (const name of names) {
|
|
6038
|
+
if (name !== key && name.toLowerCase() === key.toLowerCase()) {
|
|
6039
|
+
return name;
|
|
6040
|
+
}
|
|
6041
|
+
}
|
|
6042
|
+
return null;
|
|
6043
|
+
};
|
|
5455
6044
|
/**
|
|
5456
6045
|
* The ScriptComponentElement interface provides properties and methods for manipulating
|
|
5457
6046
|
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-scripts/ | `<pc-scripts>`} elements.
|
|
@@ -5466,83 +6055,46 @@
|
|
|
5466
6055
|
super('script');
|
|
5467
6056
|
// Create mutation observer to watch for child script elements
|
|
5468
6057
|
this.observer = new MutationObserver(this.handleMutations.bind(this));
|
|
5469
|
-
|
|
5470
|
-
childList: true
|
|
5471
|
-
});
|
|
5472
|
-
// Listen for script attribute and enable changes
|
|
6058
|
+
// Listen for script attribute, enable and name changes
|
|
5473
6059
|
this.addEventListener('scriptattributeschange', this.handleScriptAttributesChange.bind(this));
|
|
5474
6060
|
this.addEventListener('scriptenablechange', this.handleScriptEnableChange.bind(this));
|
|
6061
|
+
this.addEventListener('scriptnamechange', this.handleScriptNameChange.bind(this));
|
|
6062
|
+
}
|
|
6063
|
+
connectedCallback() {
|
|
6064
|
+
// (Re-)observe on every connection - disconnectedCallback disconnects the observer.
|
|
6065
|
+
// Attribute changes on child pc-script elements are watched here too: per-property
|
|
6066
|
+
// script attributes are not statically known, so they cannot use observedAttributes.
|
|
6067
|
+
this.observer.observe(this, { childList: true, subtree: true, attributes: true });
|
|
6068
|
+
return super.connectedCallback();
|
|
5475
6069
|
}
|
|
5476
6070
|
initComponent() {
|
|
5477
6071
|
// Handle initial script elements
|
|
5478
6072
|
this.querySelectorAll(':scope > pc-script').forEach((scriptElement) => {
|
|
5479
|
-
|
|
5480
|
-
const attributes = scriptElement.getAttribute('attributes');
|
|
5481
|
-
if (scriptName) {
|
|
5482
|
-
this.createScript(scriptName, attributes);
|
|
5483
|
-
}
|
|
6073
|
+
this.createScript(scriptElement);
|
|
5484
6074
|
});
|
|
5485
6075
|
}
|
|
5486
6076
|
/**
|
|
5487
6077
|
* Recursively converts raw attribute data into proper PlayCanvas types. Supported conversions:
|
|
5488
|
-
* - "asset:
|
|
5489
|
-
* - "entity:
|
|
5490
|
-
*
|
|
5491
|
-
* - "
|
|
5492
|
-
* - "
|
|
5493
|
-
* - "
|
|
6078
|
+
* - "asset:id" → the Asset created by the `pc-asset` element with that id
|
|
6079
|
+
* - "entity:ref" → the Entity backing a `pc-entity` element. The reference can be a CSS
|
|
6080
|
+
* selector, an element id or an entity name.
|
|
6081
|
+
* - "vec2:1 2" → new Vec2(1, 2)
|
|
6082
|
+
* - "vec3:1 2 3" → new Vec3(1, 2, 3)
|
|
6083
|
+
* - "vec4:1 2 3 4" → new Vec4(1, 2, 3, 4)
|
|
6084
|
+
* - "color:1 0.5 0.5 1" → new Color(1, 0.5, 0.5, 1)
|
|
6085
|
+
*
|
|
6086
|
+
* A prefixed string that fails to resolve or parse logs a warning and is left as the raw
|
|
6087
|
+
* string.
|
|
5494
6088
|
* @param item - The item to convert.
|
|
5495
6089
|
* @returns The converted item.
|
|
5496
6090
|
*/
|
|
5497
6091
|
convertAttributes(item) {
|
|
5498
6092
|
if (typeof item === 'string') {
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
const assetElement = document.querySelector(`pc-asset#${assetId}`);
|
|
5502
|
-
if (assetElement) {
|
|
5503
|
-
return assetElement.asset;
|
|
5504
|
-
}
|
|
5505
|
-
}
|
|
5506
|
-
if (item.startsWith('entity:')) {
|
|
5507
|
-
const entityId = item.slice(7);
|
|
5508
|
-
const entityElement = document.querySelector(`pc-entity[name="${entityId}"]`);
|
|
5509
|
-
if (entityElement) {
|
|
5510
|
-
return entityElement.entity;
|
|
5511
|
-
}
|
|
5512
|
-
}
|
|
5513
|
-
if (item.startsWith('vec2:')) {
|
|
5514
|
-
const parts = item.slice(5).split(',').map(Number);
|
|
5515
|
-
if (parts.length === 2 && parts.every(v => !isNaN(v))) {
|
|
5516
|
-
return new playcanvas.Vec2(parts[0], parts[1]);
|
|
5517
|
-
}
|
|
5518
|
-
}
|
|
5519
|
-
if (item.startsWith('vec3:')) {
|
|
5520
|
-
const parts = item.slice(5).split(',').map(Number);
|
|
5521
|
-
if (parts.length === 3 && parts.every(v => !isNaN(v))) {
|
|
5522
|
-
return new playcanvas.Vec3(parts[0], parts[1], parts[2]);
|
|
5523
|
-
}
|
|
5524
|
-
}
|
|
5525
|
-
if (item.startsWith('vec4:')) {
|
|
5526
|
-
const parts = item.slice(5).split(',').map(Number);
|
|
5527
|
-
if (parts.length === 4 && parts.every(v => !isNaN(v))) {
|
|
5528
|
-
return new playcanvas.Vec4(parts[0], parts[1], parts[2], parts[3]);
|
|
5529
|
-
}
|
|
5530
|
-
}
|
|
5531
|
-
if (item.startsWith('color:')) {
|
|
5532
|
-
const parts = item.slice(6).split(',').map(Number);
|
|
5533
|
-
if (parts.length === 4 && parts.every(v => !isNaN(v))) {
|
|
5534
|
-
return new playcanvas.Color(parts[0], parts[1], parts[2], parts[3]);
|
|
5535
|
-
}
|
|
5536
|
-
}
|
|
5537
|
-
return item;
|
|
6093
|
+
const match = matchConversion(item);
|
|
6094
|
+
return match ? match.convert(match.rest, item) : item;
|
|
5538
6095
|
}
|
|
5539
6096
|
if (Array.isArray(item)) {
|
|
5540
|
-
|
|
5541
|
-
if (item.length > 0 && typeof item[0] === 'object') {
|
|
5542
|
-
return item.map((el) => this.convertAttributes(el));
|
|
5543
|
-
}
|
|
5544
|
-
// Otherwise, leave the numeric array unchanged but process each element.
|
|
5545
|
-
return item.map((el) => this.convertAttributes(el));
|
|
6097
|
+
return item.map((element) => this.convertAttributes(element));
|
|
5546
6098
|
}
|
|
5547
6099
|
if (item && typeof item === 'object') {
|
|
5548
6100
|
const result = {};
|
|
@@ -5554,87 +6106,301 @@
|
|
|
5554
6106
|
return item;
|
|
5555
6107
|
}
|
|
5556
6108
|
/**
|
|
5557
|
-
*
|
|
5558
|
-
*
|
|
5559
|
-
*
|
|
5560
|
-
|
|
5561
|
-
preprocessAttributes(attrs) {
|
|
5562
|
-
return this.convertAttributes(attrs);
|
|
5563
|
-
}
|
|
5564
|
-
/**
|
|
5565
|
-
* Recursively merge properties from source into target.
|
|
6109
|
+
* Recursively merge properties from source into target. When the target value is a Vec2,
|
|
6110
|
+
* Vec3, Vec4 or Color and the source value is a plain numeric array, the array is converted
|
|
6111
|
+
* to the target's type — so script attributes with math-typed defaults can be written as
|
|
6112
|
+
* plain JSON arrays (e.g. `"focusPoint": [0, 1.75, 0]`).
|
|
5566
6113
|
* @param target - The target object to merge into.
|
|
5567
6114
|
* @param source - The source object to merge from.
|
|
5568
6115
|
* @returns The merged object.
|
|
5569
6116
|
*/
|
|
5570
6117
|
mergeDeep(target, source) {
|
|
5571
6118
|
for (const key in source) {
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
6119
|
+
const value = source[key];
|
|
6120
|
+
const current = target[key];
|
|
6121
|
+
if (this.isMathType(current) && Array.isArray(value)) {
|
|
6122
|
+
const converted = this.arrayToMathType(current, value, key);
|
|
6123
|
+
if (converted) {
|
|
6124
|
+
target[key] = converted;
|
|
6125
|
+
}
|
|
6126
|
+
continue;
|
|
6127
|
+
}
|
|
6128
|
+
// Only recurse into plain objects. Class instances (Vec3, Color, Asset, Entity...)
|
|
6129
|
+
// are leaf values assigned whole, so accessor-typed script attributes receive them
|
|
6130
|
+
// through their setters instead of having a getter's returned copy mutated.
|
|
6131
|
+
if (value && typeof value === 'object' && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype) {
|
|
6132
|
+
if (!current || typeof current !== 'object') {
|
|
5576
6133
|
target[key] = {};
|
|
5577
6134
|
}
|
|
5578
|
-
this.mergeDeep(target[key],
|
|
6135
|
+
this.mergeDeep(target[key], value);
|
|
5579
6136
|
}
|
|
5580
6137
|
else {
|
|
5581
|
-
target[key] =
|
|
6138
|
+
target[key] = value;
|
|
5582
6139
|
}
|
|
5583
6140
|
}
|
|
5584
6141
|
return target;
|
|
5585
6142
|
}
|
|
5586
6143
|
/**
|
|
5587
|
-
*
|
|
6144
|
+
* Checks whether a value is one of the math types that plain numeric arrays convert to.
|
|
6145
|
+
* @param value - The value to check.
|
|
6146
|
+
* @returns Whether the value is a math type.
|
|
6147
|
+
*/
|
|
6148
|
+
isMathType(value) {
|
|
6149
|
+
return value instanceof playcanvas.Vec2 || value instanceof playcanvas.Vec3 || value instanceof playcanvas.Vec4 || value instanceof playcanvas.Color || value instanceof playcanvas.Quat;
|
|
6150
|
+
}
|
|
6151
|
+
/**
|
|
6152
|
+
* Converts a plain numeric array to the math type of `current`. A 3-element array targeting
|
|
6153
|
+
* a Quat is interpreted as Euler angles in degrees, mirroring the `parseQuat` attribute
|
|
6154
|
+
* grammar. Returns `null` (and logs a warning) when the array's length or contents don't
|
|
6155
|
+
* match the type.
|
|
6156
|
+
* @param current - The current (typed) value of the property.
|
|
6157
|
+
* @param value - The incoming array.
|
|
6158
|
+
* @param key - The property name, used in the warning message.
|
|
6159
|
+
* @returns The converted value, or `null`.
|
|
6160
|
+
*/
|
|
6161
|
+
arrayToMathType(current, value, key) {
|
|
6162
|
+
if (value.every(component => typeof component === 'number' && Number.isFinite(component))) {
|
|
6163
|
+
if (current instanceof playcanvas.Vec2 && value.length === 2)
|
|
6164
|
+
return new playcanvas.Vec2(value);
|
|
6165
|
+
if (current instanceof playcanvas.Vec3 && value.length === 3)
|
|
6166
|
+
return new playcanvas.Vec3(value);
|
|
6167
|
+
if (current instanceof playcanvas.Vec4 && value.length === 4)
|
|
6168
|
+
return new playcanvas.Vec4(value);
|
|
6169
|
+
if (current instanceof playcanvas.Color && (value.length === 3 || value.length === 4))
|
|
6170
|
+
return new playcanvas.Color(value);
|
|
6171
|
+
if (current instanceof playcanvas.Quat && value.length === 3)
|
|
6172
|
+
return new playcanvas.Quat().setFromEulerAngles(value[0], value[1], value[2]);
|
|
6173
|
+
}
|
|
6174
|
+
console.warn(`Cannot convert script attribute '${key}' array [${value}] to ${current.constructor.name}. Keeping the current value.`);
|
|
6175
|
+
return null;
|
|
6176
|
+
}
|
|
6177
|
+
/**
|
|
6178
|
+
* Update script attributes by merging converted values into the script. `enabled` is always
|
|
6179
|
+
* excluded (it is configured through the element's `enabled` attribute, not the JSON blob),
|
|
6180
|
+
* as are any keys in `exclude` — used to keep per-property attributes authoritative over
|
|
6181
|
+
* the blob without writing a property twice.
|
|
5588
6182
|
* @param script - The script to update.
|
|
5589
6183
|
* @param attributes - The attributes to merge into the script.
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
6184
|
+
* @param exclude - Keys to strip from the merge.
|
|
6185
|
+
*/
|
|
6186
|
+
applyAttributes(script, attributes, exclude) {
|
|
6187
|
+
const converted = this.convertAttributes(attributes);
|
|
6188
|
+
if (converted && typeof converted === 'object') {
|
|
6189
|
+
delete converted.enabled;
|
|
6190
|
+
if (exclude) {
|
|
6191
|
+
for (const key of exclude) {
|
|
6192
|
+
delete converted[key];
|
|
6193
|
+
}
|
|
6194
|
+
}
|
|
5596
6195
|
}
|
|
5597
|
-
|
|
5598
|
-
|
|
6196
|
+
this.mergeDeep(script, converted);
|
|
6197
|
+
}
|
|
6198
|
+
/**
|
|
6199
|
+
* Returns the camelCase keys of the per-property attributes present on a `pc-script`
|
|
6200
|
+
* element.
|
|
6201
|
+
* @param scriptElement - The `pc-script` element.
|
|
6202
|
+
* @returns The camelCase keys.
|
|
6203
|
+
*/
|
|
6204
|
+
inlineKeys(scriptElement) {
|
|
6205
|
+
const keys = new Set();
|
|
6206
|
+
for (const attr of Array.from(scriptElement.attributes)) {
|
|
6207
|
+
if (!isReservedAttribute(attr.name)) {
|
|
6208
|
+
keys.add(kebabToCamel(attr.name));
|
|
6209
|
+
}
|
|
5599
6210
|
}
|
|
6211
|
+
return keys;
|
|
6212
|
+
}
|
|
6213
|
+
/**
|
|
6214
|
+
* Resolves the script instance owned by a `pc-script` element. Returns `null` when the
|
|
6215
|
+
* element has no created script, or when its name resolves to a script created by a
|
|
6216
|
+
* different element (e.g. a duplicate-named sibling).
|
|
6217
|
+
* @param scriptElement - The `pc-script` element.
|
|
6218
|
+
* @returns The owned script, or `null`.
|
|
6219
|
+
*/
|
|
6220
|
+
scriptFor(scriptElement) {
|
|
6221
|
+
const name = scriptElement.getAttribute('name');
|
|
6222
|
+
if (!name || !this.component)
|
|
6223
|
+
return null;
|
|
6224
|
+
const script = this.component.get(name);
|
|
6225
|
+
return script && script === scriptElement._script ? script : null;
|
|
5600
6226
|
}
|
|
5601
6227
|
handleScriptAttributesChange(event) {
|
|
5602
6228
|
const scriptElement = event.target;
|
|
5603
|
-
const
|
|
5604
|
-
if (!scriptName || !this.component)
|
|
5605
|
-
return;
|
|
5606
|
-
const script = this.component.get(scriptName);
|
|
6229
|
+
const script = this.scriptFor(scriptElement);
|
|
5607
6230
|
if (script) {
|
|
5608
|
-
|
|
6231
|
+
// Per-property attributes stay authoritative: keys they pin are excluded here
|
|
6232
|
+
this.applyAttributes(script, event.detail.attributes, this.inlineKeys(scriptElement));
|
|
5609
6233
|
}
|
|
5610
6234
|
}
|
|
5611
6235
|
handleScriptEnableChange(event) {
|
|
5612
6236
|
const scriptElement = event.target;
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
const script = this.
|
|
6237
|
+
// Apply any queued per-property changes first, so that initialize() (fired by the
|
|
6238
|
+
// engine on first effective enable) sees every attribute value set this tick
|
|
6239
|
+
this.handleMutations(this.observer.takeRecords());
|
|
6240
|
+
const script = this.scriptFor(scriptElement);
|
|
5617
6241
|
if (script) {
|
|
5618
6242
|
script.enabled = event.detail.enabled;
|
|
5619
6243
|
}
|
|
5620
6244
|
}
|
|
5621
|
-
|
|
6245
|
+
/**
|
|
6246
|
+
* Handles a runtime `name` change on a child `pc-script`, swapping the engine script instance
|
|
6247
|
+
* to match. Without this the element would keep pointing at the old-name instance: the old
|
|
6248
|
+
* script would go on running while every subsequent update (attribute changes, enable
|
|
6249
|
+
* changes, destruction on removal) resolved the new name and silently no-opped.
|
|
6250
|
+
*
|
|
6251
|
+
* The new instance is built by the normal creation path, so both attribute channels are
|
|
6252
|
+
* re-applied to it and the declared enabled state is restored.
|
|
6253
|
+
* @param event - The name change event.
|
|
6254
|
+
*/
|
|
6255
|
+
handleScriptNameChange(event) {
|
|
6256
|
+
const scriptElement = event.target;
|
|
6257
|
+
// Only direct children are managed, matching initComponent's ':scope > pc-script'
|
|
6258
|
+
// contract - the event bubbles, so a deeper pc-script must not be created here
|
|
6259
|
+
if (scriptElement.parentElement !== this)
|
|
6260
|
+
return;
|
|
6261
|
+
// Before the component exists there is nothing to swap: initComponent creates from
|
|
6262
|
+
// whatever the name is by then
|
|
5622
6263
|
if (!this.component)
|
|
6264
|
+
return;
|
|
6265
|
+
// Only tear down the old-name script if this element actually owns it - a duplicate-named
|
|
6266
|
+
// element whose own create() failed must not take down the live script on rename
|
|
6267
|
+
const { oldName } = event.detail;
|
|
6268
|
+
if (oldName && scriptElement._script && this.component.get(oldName) === scriptElement._script) {
|
|
6269
|
+
this.destroyScript(oldName);
|
|
6270
|
+
}
|
|
6271
|
+
scriptElement._script = null;
|
|
6272
|
+
this.createScript(scriptElement);
|
|
6273
|
+
}
|
|
6274
|
+
/**
|
|
6275
|
+
* Creates the script instance for a `pc-script` element. The instance is created disabled,
|
|
6276
|
+
* the element's converted attributes are merged over the instance's defaults (which is what
|
|
6277
|
+
* allows plain numeric arrays to be typed against those defaults), and only then is the
|
|
6278
|
+
* declared enabled state applied — so `initialize()` runs with every attribute in place.
|
|
6279
|
+
* @param scriptElement - The `pc-script` element to create the script instance for.
|
|
6280
|
+
* @returns The created script, or `null`.
|
|
6281
|
+
*/
|
|
6282
|
+
createScript(scriptElement) {
|
|
6283
|
+
const name = scriptElement.getAttribute('name');
|
|
6284
|
+
if (!name || !this.component)
|
|
5623
6285
|
return null;
|
|
5624
|
-
|
|
5625
|
-
if (
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
6286
|
+
const script = this.component.create(name, { enabled: false });
|
|
6287
|
+
if (!script)
|
|
6288
|
+
return null;
|
|
6289
|
+
scriptElement._script = script;
|
|
6290
|
+
// The JSON blob first with per-property-shadowed keys stripped, then the per-property
|
|
6291
|
+
// attributes: each property is written exactly once and individual attributes win
|
|
6292
|
+
this.applyAttributes(script, scriptElement.scriptAttributes, this.inlineKeys(scriptElement));
|
|
6293
|
+
this.applyInlineAttributes(script, scriptElement);
|
|
6294
|
+
script.enabled = scriptElement.enabled;
|
|
6295
|
+
scriptElement._onScriptCreated();
|
|
6296
|
+
return script;
|
|
6297
|
+
}
|
|
6298
|
+
/**
|
|
6299
|
+
* Applies the per-property attributes present on a `pc-script` element — any attribute that
|
|
6300
|
+
* is not part of the element's own API or a reserved HTML attribute name. These are applied
|
|
6301
|
+
* after the `attributes` JSON, so an individual attribute always takes precedence over the
|
|
6302
|
+
* blob.
|
|
6303
|
+
* @param script - The script to apply the attributes to.
|
|
6304
|
+
* @param scriptElement - The `pc-script` element holding the attributes.
|
|
6305
|
+
*/
|
|
6306
|
+
applyInlineAttributes(script, scriptElement) {
|
|
6307
|
+
var _a;
|
|
6308
|
+
const scriptName = (_a = scriptElement.getAttribute('name')) !== null && _a !== void 0 ? _a : '';
|
|
6309
|
+
for (const attr of Array.from(scriptElement.attributes)) {
|
|
6310
|
+
if (!isReservedAttribute(attr.name)) {
|
|
6311
|
+
this.setScriptProperty(script, scriptName, attr.name, attr.value);
|
|
5630
6312
|
}
|
|
5631
|
-
|
|
5632
|
-
|
|
6313
|
+
}
|
|
6314
|
+
}
|
|
6315
|
+
/**
|
|
6316
|
+
* Applies a single per-property attribute change to the script of a `pc-script` element.
|
|
6317
|
+
* When the attribute has been removed, the value from the `attributes` JSON (if any) takes
|
|
6318
|
+
* effect again.
|
|
6319
|
+
* @param scriptElement - The `pc-script` element whose attribute changed.
|
|
6320
|
+
* @param attributeName - The name of the changed attribute.
|
|
6321
|
+
*/
|
|
6322
|
+
applyScriptProperty(scriptElement, attributeName) {
|
|
6323
|
+
var _a;
|
|
6324
|
+
const script = this.scriptFor(scriptElement);
|
|
6325
|
+
if (!script)
|
|
6326
|
+
return;
|
|
6327
|
+
const value = scriptElement.getAttribute(attributeName);
|
|
6328
|
+
if (value === null) {
|
|
6329
|
+
const key = kebabToCamel(attributeName);
|
|
6330
|
+
const fallback = scriptElement.scriptAttributes[key];
|
|
6331
|
+
if (fallback !== undefined) {
|
|
6332
|
+
this.applyAttributes(script, { [key]: fallback });
|
|
5633
6333
|
}
|
|
6334
|
+
return;
|
|
6335
|
+
}
|
|
6336
|
+
this.setScriptProperty(script, (_a = scriptElement.getAttribute('name')) !== null && _a !== void 0 ? _a : '', attributeName, value);
|
|
6337
|
+
}
|
|
6338
|
+
/**
|
|
6339
|
+
* Applies one attribute string to a script property. A string-typed attribute takes the
|
|
6340
|
+
* value verbatim (so literals like 'color:red' are never hijacked by prefix conversion).
|
|
6341
|
+
* Otherwise, explicit prefixes (`asset:`, `entity:`, `vec2:`, `vec3:`, `vec4:`, `color:`)
|
|
6342
|
+
* carry their own type, and unprefixed values are parsed according to the type of the
|
|
6343
|
+
* attribute's current value. The Script API itself (methods, `entity`, `app`) is never
|
|
6344
|
+
* overwritten, invalid values keep the current value, and exceptions thrown by user
|
|
6345
|
+
* getters/setters are contained so one bad attribute cannot abort the rest of a batch.
|
|
6346
|
+
* @param script - The script to apply the value to.
|
|
6347
|
+
* @param scriptName - The script name, used in warning messages.
|
|
6348
|
+
* @param attributeName - The (kebab-case) element attribute name.
|
|
6349
|
+
* @param value - The attribute value.
|
|
6350
|
+
*/
|
|
6351
|
+
setScriptProperty(script, scriptName, attributeName, value) {
|
|
6352
|
+
const key = kebabToCamel(attributeName);
|
|
6353
|
+
try {
|
|
6354
|
+
const current = script[key];
|
|
6355
|
+
if (typeof current === 'function' || SCRIPT_API_MEMBERS.has(key)) {
|
|
6356
|
+
console.warn(`Ignoring attribute '${attributeName}' on pc-script '${scriptName}' - '${key}' is part of the Script API.`);
|
|
6357
|
+
return;
|
|
6358
|
+
}
|
|
6359
|
+
if (typeof current === 'string') {
|
|
6360
|
+
script[key] = value;
|
|
6361
|
+
}
|
|
6362
|
+
else if (matchConversion(value)) {
|
|
6363
|
+
const converted = this.convertAttributes(value);
|
|
6364
|
+
// A prefix that failed to resolve or parse comes back as the raw string
|
|
6365
|
+
// (convertAttributes already warned) - never clobber a typed value with it
|
|
6366
|
+
if (converted !== value || current === undefined || current === null) {
|
|
6367
|
+
script[key] = converted;
|
|
6368
|
+
}
|
|
6369
|
+
}
|
|
6370
|
+
else if (typeof current === 'number') {
|
|
6371
|
+
script[key] = parseNumber(value, current, attributeName);
|
|
6372
|
+
}
|
|
6373
|
+
else if (typeof current === 'boolean') {
|
|
6374
|
+
script[key] = parseBool(value, current);
|
|
6375
|
+
}
|
|
6376
|
+
else if (current instanceof playcanvas.Vec2) {
|
|
6377
|
+
script[key] = parseVec2(value, current, attributeName);
|
|
6378
|
+
}
|
|
6379
|
+
else if (current instanceof playcanvas.Vec3) {
|
|
6380
|
+
script[key] = parseVec3(value, current, attributeName);
|
|
6381
|
+
}
|
|
6382
|
+
else if (current instanceof playcanvas.Vec4) {
|
|
6383
|
+
script[key] = parseVec4(value, current, attributeName);
|
|
6384
|
+
}
|
|
6385
|
+
else if (current instanceof playcanvas.Color) {
|
|
6386
|
+
script[key] = parseColor(value, current, attributeName);
|
|
6387
|
+
}
|
|
6388
|
+
else if (current instanceof playcanvas.Quat) {
|
|
6389
|
+
script[key] = parseQuat(value, current, attributeName);
|
|
6390
|
+
}
|
|
6391
|
+
else {
|
|
6392
|
+
const match = findCaseMatch(script, key);
|
|
6393
|
+
if (match) {
|
|
6394
|
+
console.warn(`Script '${scriptName}' has no attribute '${key}' - did you mean '${camelToKebab(match)}'? Attribute names are kebab-case.`);
|
|
6395
|
+
return;
|
|
6396
|
+
}
|
|
6397
|
+
console.warn(`Script '${scriptName}' has no typed attribute '${key}' - assigning the raw string from '${attributeName}'.`);
|
|
6398
|
+
script[key] = value;
|
|
6399
|
+
}
|
|
6400
|
+
}
|
|
6401
|
+
catch (error) {
|
|
6402
|
+
console.warn(`Error applying attribute '${attributeName}' to script '${scriptName}': ${error.message}`);
|
|
5634
6403
|
}
|
|
5635
|
-
return this.component.create(name, {
|
|
5636
|
-
properties: attributesObject
|
|
5637
|
-
});
|
|
5638
6404
|
}
|
|
5639
6405
|
destroyScript(name) {
|
|
5640
6406
|
if (!this.component)
|
|
@@ -5643,23 +6409,40 @@
|
|
|
5643
6409
|
}
|
|
5644
6410
|
handleMutations(mutations) {
|
|
5645
6411
|
for (const mutation of mutations) {
|
|
5646
|
-
// Handle
|
|
5647
|
-
mutation.
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
6412
|
+
// Handle per-property attribute changes on child pc-script elements
|
|
6413
|
+
if (mutation.type === 'attributes') {
|
|
6414
|
+
const target = mutation.target;
|
|
6415
|
+
if (target instanceof ScriptElement &&
|
|
6416
|
+
target.parentElement === this &&
|
|
6417
|
+
mutation.attributeName &&
|
|
6418
|
+
!isReservedAttribute(mutation.attributeName)) {
|
|
6419
|
+
this.applyScriptProperty(target, mutation.attributeName);
|
|
5654
6420
|
}
|
|
5655
|
-
|
|
5656
|
-
|
|
6421
|
+
continue;
|
|
6422
|
+
}
|
|
6423
|
+
// Only direct children are managed - the observer watches the subtree for attribute
|
|
6424
|
+
// changes, but deeper childList records must not create or destroy scripts
|
|
6425
|
+
// (matching initComponent's ':scope > pc-script' contract)
|
|
6426
|
+
if (mutation.target !== this) {
|
|
6427
|
+
continue;
|
|
6428
|
+
}
|
|
6429
|
+
// Handle removed nodes first, so that replacing a pc-script with a same-named one
|
|
6430
|
+
// destroys the old script before the replacement is created. Only destroy a script
|
|
6431
|
+
// this element actually owns - a duplicate-named element whose own create() failed
|
|
6432
|
+
// must not take down the live script on removal.
|
|
5657
6433
|
mutation.removedNodes.forEach((node) => {
|
|
5658
|
-
if (node instanceof
|
|
6434
|
+
if (node instanceof ScriptElement) {
|
|
5659
6435
|
const scriptName = node.getAttribute('name');
|
|
5660
|
-
if (scriptName) {
|
|
6436
|
+
if (scriptName && node._script && this.component && this.component.get(scriptName) === node._script) {
|
|
5661
6437
|
this.destroyScript(scriptName);
|
|
5662
6438
|
}
|
|
6439
|
+
node._script = null;
|
|
6440
|
+
}
|
|
6441
|
+
});
|
|
6442
|
+
// Handle added nodes
|
|
6443
|
+
mutation.addedNodes.forEach((node) => {
|
|
6444
|
+
if (node instanceof ScriptElement) {
|
|
6445
|
+
this.createScript(node);
|
|
5663
6446
|
}
|
|
5664
6447
|
});
|
|
5665
6448
|
}
|
|
@@ -5679,87 +6462,6 @@
|
|
|
5679
6462
|
}
|
|
5680
6463
|
customElements.define('pc-scripts', ScriptComponentElement);
|
|
5681
6464
|
|
|
5682
|
-
/**
|
|
5683
|
-
* The ScriptElement interface provides properties and methods for manipulating
|
|
5684
|
-
* `<pc-script>` elements. The ScriptElement interface also inherits the properties and
|
|
5685
|
-
* methods of the {@link HTMLElement} interface.
|
|
5686
|
-
*/
|
|
5687
|
-
class ScriptElement extends HTMLElement {
|
|
5688
|
-
constructor() {
|
|
5689
|
-
super(...arguments);
|
|
5690
|
-
this._attributes = '{}';
|
|
5691
|
-
this._enabled = true;
|
|
5692
|
-
this._name = '';
|
|
5693
|
-
}
|
|
5694
|
-
/**
|
|
5695
|
-
* Sets the attributes of the script.
|
|
5696
|
-
* @param value - The attributes of the script.
|
|
5697
|
-
*/
|
|
5698
|
-
set scriptAttributes(value) {
|
|
5699
|
-
this._attributes = value;
|
|
5700
|
-
this.dispatchEvent(new CustomEvent('scriptattributeschange', {
|
|
5701
|
-
detail: { attributes: value },
|
|
5702
|
-
bubbles: true
|
|
5703
|
-
}));
|
|
5704
|
-
}
|
|
5705
|
-
/**
|
|
5706
|
-
* Gets the attributes of the script.
|
|
5707
|
-
* @returns The attributes of the script.
|
|
5708
|
-
*/
|
|
5709
|
-
get scriptAttributes() {
|
|
5710
|
-
return this._attributes;
|
|
5711
|
-
}
|
|
5712
|
-
/**
|
|
5713
|
-
* Sets the enabled state of the script.
|
|
5714
|
-
* @param value - The enabled state of the script.
|
|
5715
|
-
*/
|
|
5716
|
-
set enabled(value) {
|
|
5717
|
-
this._enabled = value;
|
|
5718
|
-
this.dispatchEvent(new CustomEvent('scriptenablechange', {
|
|
5719
|
-
detail: { enabled: value },
|
|
5720
|
-
bubbles: true
|
|
5721
|
-
}));
|
|
5722
|
-
}
|
|
5723
|
-
/**
|
|
5724
|
-
* Gets the enabled state of the script.
|
|
5725
|
-
* @returns The enabled state of the script.
|
|
5726
|
-
*/
|
|
5727
|
-
get enabled() {
|
|
5728
|
-
return this._enabled;
|
|
5729
|
-
}
|
|
5730
|
-
/**
|
|
5731
|
-
* Sets the name of the script to create.
|
|
5732
|
-
* @param value - The name.
|
|
5733
|
-
*/
|
|
5734
|
-
set name(value) {
|
|
5735
|
-
this._name = value;
|
|
5736
|
-
}
|
|
5737
|
-
/**
|
|
5738
|
-
* Gets the name of the script.
|
|
5739
|
-
* @returns The name.
|
|
5740
|
-
*/
|
|
5741
|
-
get name() {
|
|
5742
|
-
return this._name;
|
|
5743
|
-
}
|
|
5744
|
-
static get observedAttributes() {
|
|
5745
|
-
return ['attributes', 'enabled', 'name'];
|
|
5746
|
-
}
|
|
5747
|
-
attributeChangedCallback(name, _oldValue, newValue) {
|
|
5748
|
-
switch (name) {
|
|
5749
|
-
case 'attributes':
|
|
5750
|
-
this.scriptAttributes = newValue;
|
|
5751
|
-
break;
|
|
5752
|
-
case 'enabled':
|
|
5753
|
-
this.enabled = newValue !== 'false';
|
|
5754
|
-
break;
|
|
5755
|
-
case 'name':
|
|
5756
|
-
this.name = newValue;
|
|
5757
|
-
break;
|
|
5758
|
-
}
|
|
5759
|
-
}
|
|
5760
|
-
}
|
|
5761
|
-
customElements.define('pc-script', ScriptElement);
|
|
5762
|
-
|
|
5763
6465
|
/**
|
|
5764
6466
|
* The SoundComponentElement interface provides properties and methods for manipulating
|
|
5765
6467
|
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-sounds/ | `<pc-sounds>`} elements.
|
|
@@ -5933,25 +6635,25 @@
|
|
|
5933
6635
|
super.attributeChangedCallback(name, _oldValue, newValue);
|
|
5934
6636
|
switch (name) {
|
|
5935
6637
|
case 'distance-model':
|
|
5936
|
-
this.distanceModel = newValue;
|
|
6638
|
+
this.distanceModel = parseEnum(newValue, ['exponential', 'inverse', 'linear'], 'linear', name);
|
|
5937
6639
|
break;
|
|
5938
6640
|
case 'max-distance':
|
|
5939
|
-
this.maxDistance =
|
|
6641
|
+
this.maxDistance = parseNumber(newValue, 10000, name);
|
|
5940
6642
|
break;
|
|
5941
6643
|
case 'pitch':
|
|
5942
|
-
this.pitch =
|
|
6644
|
+
this.pitch = parseNumber(newValue, 1, name);
|
|
5943
6645
|
break;
|
|
5944
6646
|
case 'positional':
|
|
5945
|
-
this.positional =
|
|
6647
|
+
this.positional = parseBool(newValue, false);
|
|
5946
6648
|
break;
|
|
5947
6649
|
case 'ref-distance':
|
|
5948
|
-
this.refDistance =
|
|
6650
|
+
this.refDistance = parseNumber(newValue, 1, name);
|
|
5949
6651
|
break;
|
|
5950
6652
|
case 'roll-off-factor':
|
|
5951
|
-
this.rollOffFactor =
|
|
6653
|
+
this.rollOffFactor = parseNumber(newValue, 1, name);
|
|
5952
6654
|
break;
|
|
5953
6655
|
case 'volume':
|
|
5954
|
-
this.volume =
|
|
6656
|
+
this.volume = parseNumber(newValue, 1, name);
|
|
5955
6657
|
break;
|
|
5956
6658
|
}
|
|
5957
6659
|
}
|
|
@@ -6002,12 +6704,15 @@
|
|
|
6002
6704
|
this._onReady();
|
|
6003
6705
|
}
|
|
6004
6706
|
disconnectedCallback() {
|
|
6005
|
-
|
|
6707
|
+
var _a, _b;
|
|
6708
|
+
// The component is null if the parent <pc-sound> (or the whole <pc-app>) is being
|
|
6709
|
+
// torn down — parents disconnect first and have already removed the component.
|
|
6710
|
+
(_b = (_a = this.soundElement) === null || _a === void 0 ? void 0 : _a.component) === null || _b === void 0 ? void 0 : _b.removeSlot(this._name);
|
|
6006
6711
|
}
|
|
6007
6712
|
get soundElement() {
|
|
6008
6713
|
const soundElement = this.parentElement;
|
|
6009
6714
|
if (!(soundElement instanceof SoundComponentElement)) {
|
|
6010
|
-
console.warn('pc-sound
|
|
6715
|
+
console.warn('pc-sound must be a direct child of a pc-sounds element');
|
|
6011
6716
|
return null;
|
|
6012
6717
|
}
|
|
6013
6718
|
return soundElement;
|
|
@@ -6051,12 +6756,12 @@
|
|
|
6051
6756
|
return this._autoPlay;
|
|
6052
6757
|
}
|
|
6053
6758
|
/**
|
|
6054
|
-
* Sets the duration of the sound slot.
|
|
6759
|
+
* Sets the duration of the sound slot, in seconds (or `null` to play the whole clip).
|
|
6055
6760
|
* @param value - The duration.
|
|
6056
6761
|
*/
|
|
6057
6762
|
set duration(value) {
|
|
6058
6763
|
this._duration = value;
|
|
6059
|
-
if (this.soundSlot) {
|
|
6764
|
+
if (this.soundSlot && value !== null) {
|
|
6060
6765
|
this.soundSlot.duration = value;
|
|
6061
6766
|
}
|
|
6062
6767
|
}
|
|
@@ -6178,28 +6883,28 @@
|
|
|
6178
6883
|
this.asset = newValue;
|
|
6179
6884
|
break;
|
|
6180
6885
|
case 'auto-play':
|
|
6181
|
-
this.autoPlay =
|
|
6886
|
+
this.autoPlay = parseBool(newValue, false);
|
|
6182
6887
|
break;
|
|
6183
6888
|
case 'duration':
|
|
6184
|
-
this.duration =
|
|
6889
|
+
this.duration = parseNumber(newValue, null, name);
|
|
6185
6890
|
break;
|
|
6186
6891
|
case 'loop':
|
|
6187
|
-
this.loop =
|
|
6892
|
+
this.loop = parseBool(newValue, false);
|
|
6188
6893
|
break;
|
|
6189
6894
|
case 'name':
|
|
6190
6895
|
this.name = newValue;
|
|
6191
6896
|
break;
|
|
6192
6897
|
case 'overlap':
|
|
6193
|
-
this.overlap =
|
|
6898
|
+
this.overlap = parseBool(newValue, false);
|
|
6194
6899
|
break;
|
|
6195
6900
|
case 'pitch':
|
|
6196
|
-
this.pitch =
|
|
6901
|
+
this.pitch = parseNumber(newValue, 1, name);
|
|
6197
6902
|
break;
|
|
6198
6903
|
case 'start-time':
|
|
6199
|
-
this.startTime =
|
|
6904
|
+
this.startTime = parseNumber(newValue, 0, name);
|
|
6200
6905
|
break;
|
|
6201
6906
|
case 'volume':
|
|
6202
|
-
this.volume =
|
|
6907
|
+
this.volume = parseNumber(newValue, 1, name);
|
|
6203
6908
|
break;
|
|
6204
6909
|
}
|
|
6205
6910
|
}
|
|
@@ -6375,19 +7080,19 @@
|
|
|
6375
7080
|
this.asset = newValue;
|
|
6376
7081
|
break;
|
|
6377
7082
|
case 'cast-shadows':
|
|
6378
|
-
this.castShadows =
|
|
7083
|
+
this.castShadows = parseBool(newValue, false);
|
|
6379
7084
|
break;
|
|
6380
7085
|
case 'lod-base-distance':
|
|
6381
|
-
this.lodBaseDistance =
|
|
7086
|
+
this.lodBaseDistance = parseNumber(newValue, 5, name);
|
|
6382
7087
|
break;
|
|
6383
7088
|
case 'lod-multiplier':
|
|
6384
|
-
this.lodMultiplier =
|
|
7089
|
+
this.lodMultiplier = parseNumber(newValue, 3, name);
|
|
6385
7090
|
break;
|
|
6386
7091
|
case 'lod-range-min':
|
|
6387
|
-
this.lodRangeMin =
|
|
7092
|
+
this.lodRangeMin = parseNumber(newValue, 0, name);
|
|
6388
7093
|
break;
|
|
6389
7094
|
case 'lod-range-max':
|
|
6390
|
-
this.lodRangeMax =
|
|
7095
|
+
this.lodRangeMax = parseNumber(newValue, 99, name);
|
|
6391
7096
|
break;
|
|
6392
7097
|
}
|
|
6393
7098
|
}
|
|
@@ -6502,7 +7207,7 @@
|
|
|
6502
7207
|
/**
|
|
6503
7208
|
* The fog type of the scene.
|
|
6504
7209
|
*/
|
|
6505
|
-
this._fog = 'none';
|
|
7210
|
+
this._fog = 'none';
|
|
6506
7211
|
/**
|
|
6507
7212
|
* The color of the fog.
|
|
6508
7213
|
*/
|
|
@@ -6523,15 +7228,20 @@
|
|
|
6523
7228
|
* The gravity of the scene.
|
|
6524
7229
|
*/
|
|
6525
7230
|
this._gravity = new playcanvas.Vec3(0, -9.81, 0);
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
|
|
7231
|
+
this._scene = null;
|
|
7232
|
+
}
|
|
7233
|
+
/**
|
|
7234
|
+
* The PlayCanvas scene instance. Available once the element is ready — await
|
|
7235
|
+
* {@link whenReady} or the element's `ready()` promise before accessing it.
|
|
7236
|
+
* @returns The scene instance.
|
|
7237
|
+
*/
|
|
7238
|
+
get scene() {
|
|
7239
|
+
return this._scene;
|
|
6530
7240
|
}
|
|
6531
7241
|
async connectedCallback() {
|
|
6532
7242
|
var _a;
|
|
6533
7243
|
await ((_a = this.closestApp) === null || _a === void 0 ? void 0 : _a.ready());
|
|
6534
|
-
this.
|
|
7244
|
+
this._scene = this.closestApp.app.scene;
|
|
6535
7245
|
this.updateSceneSettings();
|
|
6536
7246
|
this._onReady();
|
|
6537
7247
|
}
|
|
@@ -6547,7 +7257,8 @@
|
|
|
6547
7257
|
}
|
|
6548
7258
|
}
|
|
6549
7259
|
/**
|
|
6550
|
-
* Sets the fog type of the scene.
|
|
7260
|
+
* Sets the fog type of the scene. Can be `none`, `linear`, `exp` or `exp2`. Defaults to
|
|
7261
|
+
* `none`.
|
|
6551
7262
|
* @param value - The fog type.
|
|
6552
7263
|
*/
|
|
6553
7264
|
set fog(value) {
|
|
@@ -6655,22 +7366,22 @@
|
|
|
6655
7366
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
6656
7367
|
switch (name) {
|
|
6657
7368
|
case 'fog':
|
|
6658
|
-
this.fog = newValue;
|
|
7369
|
+
this.fog = parseEnum(newValue, ['none', 'linear', 'exp', 'exp2'], 'none', name);
|
|
6659
7370
|
break;
|
|
6660
7371
|
case 'fog-color':
|
|
6661
|
-
this.fogColor = parseColor(newValue);
|
|
7372
|
+
this.fogColor = parseColor(newValue, playcanvas.Color.WHITE, name);
|
|
6662
7373
|
break;
|
|
6663
7374
|
case 'fog-density':
|
|
6664
|
-
this.fogDensity =
|
|
7375
|
+
this.fogDensity = parseNumber(newValue, 0, name);
|
|
6665
7376
|
break;
|
|
6666
7377
|
case 'fog-start':
|
|
6667
|
-
this.fogStart =
|
|
7378
|
+
this.fogStart = parseNumber(newValue, 0, name);
|
|
6668
7379
|
break;
|
|
6669
7380
|
case 'fog-end':
|
|
6670
|
-
this.fogEnd =
|
|
7381
|
+
this.fogEnd = parseNumber(newValue, 1000, name);
|
|
6671
7382
|
break;
|
|
6672
7383
|
case 'gravity':
|
|
6673
|
-
this.gravity = parseVec3(newValue);
|
|
7384
|
+
this.gravity = parseVec3(newValue, new playcanvas.Vec3(0, -9.81, 0), name);
|
|
6674
7385
|
break;
|
|
6675
7386
|
// ... handle other attributes as well
|
|
6676
7387
|
}
|
|
@@ -6695,6 +7406,7 @@
|
|
|
6695
7406
|
this._scale = new playcanvas.Vec3(100, 100, 100);
|
|
6696
7407
|
this._type = 'infinite';
|
|
6697
7408
|
this._scene = null;
|
|
7409
|
+
this._appElement = null;
|
|
6698
7410
|
}
|
|
6699
7411
|
connectedCallback() {
|
|
6700
7412
|
this._loadSkybox();
|
|
@@ -6702,6 +7414,7 @@
|
|
|
6702
7414
|
}
|
|
6703
7415
|
disconnectedCallback() {
|
|
6704
7416
|
this._unloadSkybox();
|
|
7417
|
+
this._appElement = null;
|
|
6705
7418
|
}
|
|
6706
7419
|
_generateSkybox(asset) {
|
|
6707
7420
|
if (!this._scene)
|
|
@@ -6729,9 +7442,10 @@
|
|
|
6729
7442
|
var _a;
|
|
6730
7443
|
const appElement = await ((_a = this.closestApp) === null || _a === void 0 ? void 0 : _a.ready());
|
|
6731
7444
|
const app = appElement === null || appElement === void 0 ? void 0 : appElement.app;
|
|
6732
|
-
if (!app) {
|
|
7445
|
+
if (!appElement || !app) {
|
|
6733
7446
|
return;
|
|
6734
7447
|
}
|
|
7448
|
+
this._appElement = appElement;
|
|
6735
7449
|
const asset = AssetElement.get(this._asset);
|
|
6736
7450
|
if (!asset) {
|
|
6737
7451
|
return;
|
|
@@ -6748,16 +7462,22 @@
|
|
|
6748
7462
|
}
|
|
6749
7463
|
}
|
|
6750
7464
|
_unloadSkybox() {
|
|
6751
|
-
var _a, _b;
|
|
6752
|
-
|
|
7465
|
+
var _a, _b, _c;
|
|
7466
|
+
const scene = this._scene;
|
|
7467
|
+
if (!scene)
|
|
7468
|
+
return;
|
|
7469
|
+
this._scene = null;
|
|
7470
|
+
// If the owning application has already been destroyed (removing a <pc-app>
|
|
7471
|
+
// disconnects it before its children), the scene, graphics device and skybox
|
|
7472
|
+
// textures have all been destroyed along with it — nothing left to clean up.
|
|
7473
|
+
if (!((_a = this._appElement) === null || _a === void 0 ? void 0 : _a.app))
|
|
6753
7474
|
return;
|
|
6754
|
-
(
|
|
7475
|
+
(_b = scene.skybox) === null || _b === void 0 ? void 0 : _b.destroy();
|
|
6755
7476
|
// @ts-ignore
|
|
6756
|
-
|
|
6757
|
-
(
|
|
7477
|
+
scene.skybox = null;
|
|
7478
|
+
(_c = scene.envAtlas) === null || _c === void 0 ? void 0 : _c.destroy();
|
|
6758
7479
|
// @ts-ignore
|
|
6759
|
-
|
|
6760
|
-
this._scene = null;
|
|
7480
|
+
scene.envAtlas = null;
|
|
6761
7481
|
}
|
|
6762
7482
|
/**
|
|
6763
7483
|
* Sets the id of the `pc-asset` to use for the skybox.
|
|
@@ -6905,25 +7625,25 @@
|
|
|
6905
7625
|
this.asset = newValue;
|
|
6906
7626
|
break;
|
|
6907
7627
|
case 'center':
|
|
6908
|
-
this.center = parseVec3(newValue);
|
|
7628
|
+
this.center = parseVec3(newValue, new playcanvas.Vec3(0, 0.01, 0), name);
|
|
6909
7629
|
break;
|
|
6910
7630
|
case 'intensity':
|
|
6911
|
-
this.intensity =
|
|
7631
|
+
this.intensity = parseNumber(newValue, 1, name);
|
|
6912
7632
|
break;
|
|
6913
7633
|
case 'level':
|
|
6914
|
-
this.level =
|
|
7634
|
+
this.level = parseNumber(newValue, 0, name);
|
|
6915
7635
|
break;
|
|
6916
7636
|
case 'lighting':
|
|
6917
|
-
this.lighting =
|
|
7637
|
+
this.lighting = parseBool(newValue, false);
|
|
6918
7638
|
break;
|
|
6919
7639
|
case 'rotation':
|
|
6920
|
-
this.rotation = parseVec3(newValue);
|
|
7640
|
+
this.rotation = parseVec3(newValue, playcanvas.Vec3.ZERO, name);
|
|
6921
7641
|
break;
|
|
6922
7642
|
case 'scale':
|
|
6923
|
-
this.scale = parseVec3(newValue);
|
|
7643
|
+
this.scale = parseVec3(newValue, new playcanvas.Vec3(100, 100, 100), name);
|
|
6924
7644
|
break;
|
|
6925
7645
|
case 'type':
|
|
6926
|
-
this.type = newValue;
|
|
7646
|
+
this.type = parseEnum(newValue, ['box', 'dome', 'infinite', 'none'], 'infinite', name);
|
|
6927
7647
|
break;
|
|
6928
7648
|
}
|
|
6929
7649
|
}
|
|
@@ -6959,6 +7679,7 @@
|
|
|
6959
7679
|
exports.SkyElement = SkyElement;
|
|
6960
7680
|
exports.SoundComponentElement = SoundComponentElement;
|
|
6961
7681
|
exports.SoundSlotElement = SoundSlotElement;
|
|
7682
|
+
exports.whenReady = whenReady;
|
|
6962
7683
|
|
|
6963
7684
|
}));
|
|
6964
7685
|
//# sourceMappingURL=pwc.js.map
|