@playcanvas/web-components 0.9.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/dist/app.d.ts +55 -9
- package/dist/asset.d.ts +25 -1
- package/dist/async-element.d.ts +15 -2
- package/dist/components/button-component.d.ts +1 -1
- package/dist/components/camera-component.d.ts +1 -1
- package/dist/components/collision-component.d.ts +1 -1
- package/dist/components/component.d.ts +6 -5
- package/dist/components/element-component.d.ts +1 -1
- package/dist/components/gsplat-component.d.ts +1 -1
- package/dist/components/layoutchild-component.d.ts +1 -1
- package/dist/components/layoutgroup-component.d.ts +1 -1
- package/dist/components/light-component.d.ts +1 -1
- package/dist/components/particlesystem-component.d.ts +1 -1
- package/dist/components/render-component.d.ts +1 -1
- package/dist/components/rigidbody-component.d.ts +1 -1
- package/dist/components/screen-component.d.ts +1 -1
- package/dist/components/script.d.ts +8 -1
- package/dist/components/scrollbar-component.d.ts +1 -1
- package/dist/components/scrollview-component.d.ts +1 -1
- package/dist/components/sound-component.d.ts +1 -1
- package/dist/components/sound-slot.d.ts +9 -1
- package/dist/custom-elements.json +16704 -0
- package/dist/entity.d.ts +24 -5
- package/dist/loading-bar.d.ts +35 -0
- package/dist/material.d.ts +972 -4
- package/dist/model.d.ts +1 -1
- package/dist/module.d.ts +10 -0
- package/dist/{utils.d.ts → parse.d.ts} +63 -33
- package/dist/pwc.cjs +3070 -699
- package/dist/pwc.cjs.map +1 -1
- package/dist/pwc.js +3070 -699
- 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.min.mjs +2 -0
- package/dist/pwc.min.mjs.map +1 -0
- package/dist/pwc.mjs +3071 -700
- package/dist/pwc.mjs.map +1 -1
- package/dist/scene.d.ts +12 -4
- package/dist/sky.d.ts +1 -1
- package/dist/vscode.html-custom-data.json +1800 -0
- package/dist/web-types.json +3836 -0
- package/package.json +29 -11
- package/src/app.ts +178 -78
- package/src/asset.ts +44 -2
- package/src/async-element.ts +17 -4
- package/src/components/button-component.ts +6 -6
- package/src/components/camera-component.ts +2 -2
- package/src/components/collision-component.ts +2 -2
- package/src/components/component.ts +8 -7
- package/src/components/element-component.ts +6 -6
- package/src/components/gsplat-component.ts +3 -3
- package/src/components/layoutchild-component.ts +2 -2
- package/src/components/layoutgroup-component.ts +2 -2
- package/src/components/light-component.ts +2 -2
- package/src/components/particlesystem-component.ts +2 -2
- package/src/components/render-component.ts +10 -5
- package/src/components/rigidbody-component.ts +2 -2
- package/src/components/screen-component.ts +2 -2
- package/src/components/script-component.ts +4 -4
- package/src/components/script.ts +9 -2
- package/src/components/scrollbar-component.ts +3 -3
- package/src/components/scrollview-component.ts +6 -6
- package/src/components/sound-component.ts +2 -2
- package/src/components/sound-slot.ts +31 -9
- package/src/entity.ts +56 -22
- package/src/loading-bar.ts +122 -0
- package/src/material.ts +2402 -59
- package/src/model.ts +2 -2
- package/src/module.ts +10 -0
- package/src/{utils.ts → parse.ts} +104 -65
- package/src/scene.ts +51 -21
- package/src/sky.ts +3 -3
package/src/entity.ts
CHANGED
|
@@ -1,13 +1,31 @@
|
|
|
1
1
|
import { AppBase, Entity, Vec3 } from 'playcanvas';
|
|
2
2
|
|
|
3
3
|
import { AsyncElement } from './async-element';
|
|
4
|
-
import { parseBool, parseVec3 } from './
|
|
4
|
+
import { parseBool, parseTags, parseVec3 } from './parse';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* The EntityElement interface provides properties and methods for manipulating
|
|
8
8
|
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-entity/ | `<pc-entity>`} elements.
|
|
9
9
|
* The EntityElement interface also inherits the properties and methods of the
|
|
10
10
|
* {@link HTMLElement} interface.
|
|
11
|
+
*
|
|
12
|
+
* The pointer events below are dispatched by the containing `<pc-app>` element when the pointer
|
|
13
|
+
* intersects this entity's geometry. They are only generated while the entity has a listener for
|
|
14
|
+
* them, registered either with {@link addEventListener} or with the matching inline `onpointer*`
|
|
15
|
+
* attribute.
|
|
16
|
+
*
|
|
17
|
+
* @attribute {string} onpointerenter - Script to run when the pointer moves onto the entity.
|
|
18
|
+
* @attribute {string} onpointerleave - Script to run when the pointer moves off the entity.
|
|
19
|
+
* @attribute {string} onpointermove - Script to run when the pointer moves over the entity.
|
|
20
|
+
* @attribute {string} onpointerdown - Script to run when a pointer button is pressed over the
|
|
21
|
+
* entity.
|
|
22
|
+
* @attribute {string} onpointerup - Script to run when a pointer button is released over the
|
|
23
|
+
* entity.
|
|
24
|
+
* @fires {PointerEvent} pointerenter - Fired when the pointer moves onto the entity.
|
|
25
|
+
* @fires {PointerEvent} pointerleave - Fired when the pointer moves off the entity.
|
|
26
|
+
* @fires {PointerEvent} pointermove - Fired when the pointer moves over the entity.
|
|
27
|
+
* @fires {PointerEvent} pointerdown - Fired when a pointer button is pressed over the entity.
|
|
28
|
+
* @fires {PointerEvent} pointerup - Fired when a pointer button is released over the entity.
|
|
11
29
|
*/
|
|
12
30
|
class EntityElement extends AsyncElement {
|
|
13
31
|
/**
|
|
@@ -58,12 +76,13 @@ class EntityElement extends AsyncElement {
|
|
|
58
76
|
private _entity: Entity | null = null;
|
|
59
77
|
|
|
60
78
|
/**
|
|
61
|
-
* The PlayCanvas entity instance.
|
|
62
|
-
* {@link whenReady} or the element's `ready()`
|
|
63
|
-
*
|
|
79
|
+
* The PlayCanvas entity instance. `null` until the element is ready, and again once it has
|
|
80
|
+
* been removed from the document — await {@link whenReady} or the element's `ready()`
|
|
81
|
+
* promise before accessing it.
|
|
82
|
+
* @returns The entity instance, or `null`.
|
|
64
83
|
*/
|
|
65
|
-
get entity(): Entity {
|
|
66
|
-
return this._entity
|
|
84
|
+
get entity(): Entity | null {
|
|
85
|
+
return this._entity;
|
|
67
86
|
}
|
|
68
87
|
|
|
69
88
|
createEntity(app: AppBase) {
|
|
@@ -74,18 +93,20 @@ class EntityElement extends AsyncElement {
|
|
|
74
93
|
return;
|
|
75
94
|
}
|
|
76
95
|
|
|
77
|
-
//
|
|
78
|
-
|
|
96
|
+
// Seed from the cached fields rather than re-reading the attributes. Every observed
|
|
97
|
+
// attribute is routed through its property setter by attributeChangedCallback, so the field
|
|
98
|
+
// already holds the parsed attribute value - and it also holds anything assigned through the
|
|
99
|
+
// property API before the app booted, which reading the attribute back would discard.
|
|
100
|
+
const entity = new Entity(this._name, app);
|
|
79
101
|
this._entity = entity;
|
|
80
102
|
|
|
81
|
-
entity.enabled =
|
|
82
|
-
entity.setLocalPosition(
|
|
83
|
-
entity.setLocalEulerAngles(
|
|
84
|
-
entity.setLocalScale(
|
|
103
|
+
entity.enabled = this._enabled;
|
|
104
|
+
entity.setLocalPosition(this._position);
|
|
105
|
+
entity.setLocalEulerAngles(this._rotation);
|
|
106
|
+
entity.setLocalScale(this._scale);
|
|
85
107
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
entity.tags.add(tags.split(',').map(tag => tag.trim()));
|
|
108
|
+
if (this._tags.length > 0) {
|
|
109
|
+
entity.tags.add(this._tags);
|
|
89
110
|
}
|
|
90
111
|
}
|
|
91
112
|
|
|
@@ -106,7 +127,15 @@ class EntityElement extends AsyncElement {
|
|
|
106
127
|
connectedCallback() {
|
|
107
128
|
// Wait for app to be ready
|
|
108
129
|
const closestApp = this.closestApp;
|
|
109
|
-
if (!closestApp)
|
|
130
|
+
if (!closestApp) {
|
|
131
|
+
// An entity outside an application is inert and never becomes ready, so awaiting it
|
|
132
|
+
// hangs. Warn rather than fail silently, naming the parent it requires, as every other
|
|
133
|
+
// misplaced element does.
|
|
134
|
+
const name = this.getAttribute('name');
|
|
135
|
+
const label = name ? ` '${name}'` : '';
|
|
136
|
+
console.warn(`pc-entity${label} must be a descendant of pc-app - entity not created`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
110
139
|
|
|
111
140
|
// If app is already running, create entity immediately
|
|
112
141
|
if (closestApp.hierarchyReady) {
|
|
@@ -128,10 +157,15 @@ class EntityElement extends AsyncElement {
|
|
|
128
157
|
|
|
129
158
|
disconnectedCallback() {
|
|
130
159
|
if (this.entity) {
|
|
131
|
-
// Notify all children that their entities are about to become invalid
|
|
132
|
-
|
|
160
|
+
// Notify all children that their entities are about to become invalid. Both fields have
|
|
161
|
+
// to be reset here, not just _entity: a descendant's own disconnectedCallback runs after
|
|
162
|
+
// this one and skips its reset behind the `if (this.entity)` guard, because we have
|
|
163
|
+
// already nulled the entity it tests. Leaving _built set would make buildHierarchy bail
|
|
164
|
+
// on re-insertion, so the descendant would get a fresh entity that is never parented.
|
|
165
|
+
const children = this.querySelectorAll<EntityElement>('pc-entity');
|
|
133
166
|
children.forEach((child) => {
|
|
134
|
-
|
|
167
|
+
child._entity = null;
|
|
168
|
+
child._built = false;
|
|
135
169
|
});
|
|
136
170
|
|
|
137
171
|
// Destroy the entity
|
|
@@ -297,13 +331,13 @@ class EntityElement extends AsyncElement {
|
|
|
297
331
|
];
|
|
298
332
|
}
|
|
299
333
|
|
|
300
|
-
attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
|
|
334
|
+
attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
|
|
301
335
|
switch (name) {
|
|
302
336
|
case 'enabled':
|
|
303
337
|
this.enabled = parseBool(newValue, true);
|
|
304
338
|
break;
|
|
305
339
|
case 'name':
|
|
306
|
-
this.name = newValue;
|
|
340
|
+
this.name = newValue ?? 'Untitled';
|
|
307
341
|
break;
|
|
308
342
|
case 'position':
|
|
309
343
|
this.position = parseVec3(newValue, Vec3.ZERO, name);
|
|
@@ -315,7 +349,7 @@ class EntityElement extends AsyncElement {
|
|
|
315
349
|
this.scale = parseVec3(newValue, Vec3.ONE, name);
|
|
316
350
|
break;
|
|
317
351
|
case 'tags':
|
|
318
|
-
this.tags = newValue
|
|
352
|
+
this.tags = parseTags(newValue);
|
|
319
353
|
break;
|
|
320
354
|
case 'onpointerenter':
|
|
321
355
|
case 'onpointerleave':
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/** Covers the 0.2s opacity transition; jsdom never fires transitionend, so removal is timed. */
|
|
2
|
+
const REMOVAL_DELAY_MS = 250;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The slim progress bar `<pc-app>` shows while it boots and preloads. An implementation detail of
|
|
6
|
+
* AppElement rather than a custom element, so its shape can change without a breaking change.
|
|
7
|
+
*
|
|
8
|
+
* All styling is inline, so the library injects no stylesheet. The colors and height resolve CSS
|
|
9
|
+
* custom properties — `--pc-loading-bar-color`, `--pc-loading-bar-background` and
|
|
10
|
+
* `--pc-loading-bar-height` — so a page can theme the bar from `pc-app` or `:root`.
|
|
11
|
+
*/
|
|
12
|
+
class LoadingBar {
|
|
13
|
+
private _track: HTMLDivElement;
|
|
14
|
+
|
|
15
|
+
private _fill: HTMLDivElement;
|
|
16
|
+
|
|
17
|
+
private _sweep: Animation | null = null;
|
|
18
|
+
|
|
19
|
+
private _removal: ReturnType<typeof setTimeout> | null = null;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Creates the bar and appends it to `parent`, starting in the indeterminate state.
|
|
23
|
+
* @param parent - The element to append the bar to.
|
|
24
|
+
*/
|
|
25
|
+
constructor(parent: HTMLElement) {
|
|
26
|
+
this._track = document.createElement('div');
|
|
27
|
+
this._track.setAttribute('role', 'progressbar');
|
|
28
|
+
this._track.setAttribute('aria-label', 'Loading');
|
|
29
|
+
this._track.setAttribute('aria-valuemin', '0');
|
|
30
|
+
this._track.setAttribute('aria-valuemax', '100');
|
|
31
|
+
// Fixed positioning matches the canvas, which always fills the window (FILLMODE_FILL_WINDOW)
|
|
32
|
+
this._track.style.cssText = [
|
|
33
|
+
'position: fixed',
|
|
34
|
+
'top: 0',
|
|
35
|
+
'left: 0',
|
|
36
|
+
'width: 100%',
|
|
37
|
+
'height: var(--pc-loading-bar-height, 3px)',
|
|
38
|
+
'background: var(--pc-loading-bar-background, rgba(0, 0, 0, 0.1))',
|
|
39
|
+
'z-index: 10000',
|
|
40
|
+
'pointer-events: none',
|
|
41
|
+
'opacity: 1',
|
|
42
|
+
'transition: opacity 0.2s ease'
|
|
43
|
+
].join('; ');
|
|
44
|
+
|
|
45
|
+
this._fill = document.createElement('div');
|
|
46
|
+
this._fill.style.cssText = [
|
|
47
|
+
'width: 100%',
|
|
48
|
+
'height: 100%',
|
|
49
|
+
'transform-origin: left center',
|
|
50
|
+
'transform: scaleX(0)',
|
|
51
|
+
'background: var(--pc-loading-bar-color, #f60)',
|
|
52
|
+
'transition: transform 0.2s ease'
|
|
53
|
+
].join('; ');
|
|
54
|
+
|
|
55
|
+
this._track.appendChild(this._fill);
|
|
56
|
+
parent.appendChild(this._track);
|
|
57
|
+
|
|
58
|
+
// Indeterminate sweep until the first progress() call reports a real total. No
|
|
59
|
+
// aria-valuenow is set, which is what marks a progressbar indeterminate. jsdom has no Web
|
|
60
|
+
// Animations API, so the guard degrades to a static bar there rather than crashing boot.
|
|
61
|
+
if (typeof this._fill.animate === 'function') {
|
|
62
|
+
this._sweep = this._fill.animate([
|
|
63
|
+
{ transform: 'scaleX(0.25) translateX(-100%)' },
|
|
64
|
+
{ transform: 'scaleX(0.25) translateX(500%)' }
|
|
65
|
+
], {
|
|
66
|
+
duration: 1000,
|
|
67
|
+
iterations: Infinity,
|
|
68
|
+
easing: 'ease-in-out'
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Reflects preload progress, switching the bar from indeterminate to determinate on the first
|
|
75
|
+
* call.
|
|
76
|
+
* @param loaded - The number of assets that have finished loading.
|
|
77
|
+
* @param total - The number of assets being preloaded.
|
|
78
|
+
*/
|
|
79
|
+
progress(loaded: number, total: number) {
|
|
80
|
+
if (this._sweep) {
|
|
81
|
+
this._sweep.cancel();
|
|
82
|
+
this._sweep = null;
|
|
83
|
+
}
|
|
84
|
+
const fraction = total === 0 ? 1 : loaded / total;
|
|
85
|
+
this._track.setAttribute('aria-valuenow', String(Math.round(fraction * 100)));
|
|
86
|
+
this._fill.style.transform = `scaleX(${fraction})`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Fills the bar, fades it out and removes it. Idempotent.
|
|
91
|
+
*/
|
|
92
|
+
complete() {
|
|
93
|
+
if (this._removal !== null) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (this._sweep) {
|
|
97
|
+
this._sweep.cancel();
|
|
98
|
+
this._sweep = null;
|
|
99
|
+
}
|
|
100
|
+
this._track.setAttribute('aria-valuenow', '100');
|
|
101
|
+
this._fill.style.transform = 'scaleX(1)';
|
|
102
|
+
this._track.style.opacity = '0';
|
|
103
|
+
this._removal = setTimeout(() => this._track.remove(), REMOVAL_DELAY_MS);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Removes the bar immediately, cancelling any pending fade. Idempotent.
|
|
108
|
+
*/
|
|
109
|
+
destroy() {
|
|
110
|
+
if (this._sweep) {
|
|
111
|
+
this._sweep.cancel();
|
|
112
|
+
this._sweep = null;
|
|
113
|
+
}
|
|
114
|
+
if (this._removal !== null) {
|
|
115
|
+
clearTimeout(this._removal);
|
|
116
|
+
this._removal = null;
|
|
117
|
+
}
|
|
118
|
+
this._track.remove();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export { LoadingBar };
|