@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/scene.d.ts
CHANGED
|
@@ -31,22 +31,26 @@ declare class SceneElement extends AsyncElement {
|
|
|
31
31
|
* The gravity of the scene.
|
|
32
32
|
*/
|
|
33
33
|
private _gravity;
|
|
34
|
+
private _scene;
|
|
34
35
|
/**
|
|
35
|
-
* The PlayCanvas scene instance.
|
|
36
|
+
* The PlayCanvas scene instance. Available once the element is ready — await
|
|
37
|
+
* {@link whenReady} or the element's `ready()` promise before accessing it.
|
|
38
|
+
* @returns The scene instance.
|
|
36
39
|
*/
|
|
37
|
-
scene: Scene
|
|
40
|
+
get scene(): Scene;
|
|
38
41
|
connectedCallback(): Promise<void>;
|
|
39
42
|
updateSceneSettings(): void;
|
|
40
43
|
/**
|
|
41
|
-
* Sets the fog type of the scene.
|
|
44
|
+
* Sets the fog type of the scene. Can be `none`, `linear`, `exp` or `exp2`. Defaults to
|
|
45
|
+
* `none`.
|
|
42
46
|
* @param value - The fog type.
|
|
43
47
|
*/
|
|
44
|
-
set fog(value:
|
|
48
|
+
set fog(value: "linear" | "none" | "exp" | "exp2");
|
|
45
49
|
/**
|
|
46
50
|
* Gets the fog type of the scene.
|
|
47
51
|
* @returns The fog type.
|
|
48
52
|
*/
|
|
49
|
-
get fog():
|
|
53
|
+
get fog(): "linear" | "none" | "exp" | "exp2";
|
|
50
54
|
/**
|
|
51
55
|
* Sets the fog color of the scene.
|
|
52
56
|
* @param value - The fog color.
|
|
@@ -100,4 +104,9 @@ declare class SceneElement extends AsyncElement {
|
|
|
100
104
|
static get observedAttributes(): string[];
|
|
101
105
|
attributeChangedCallback(name: string, _oldValue: string, newValue: string): void;
|
|
102
106
|
}
|
|
107
|
+
declare global {
|
|
108
|
+
interface HTMLElementTagNameMap {
|
|
109
|
+
'pc-scene': SceneElement;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
103
112
|
export { SceneElement };
|
package/dist/sky.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ declare class SkyElement extends AsyncElement {
|
|
|
15
15
|
private _scale;
|
|
16
16
|
private _type;
|
|
17
17
|
private _scene;
|
|
18
|
+
private _appElement;
|
|
18
19
|
connectedCallback(): void;
|
|
19
20
|
disconnectedCallback(): void;
|
|
20
21
|
private _generateSkybox;
|
|
@@ -103,4 +104,9 @@ declare class SkyElement extends AsyncElement {
|
|
|
103
104
|
static get observedAttributes(): string[];
|
|
104
105
|
attributeChangedCallback(name: string, _oldValue: string, newValue: string): void;
|
|
105
106
|
}
|
|
107
|
+
declare global {
|
|
108
|
+
interface HTMLElementTagNameMap {
|
|
109
|
+
'pc-sky': SkyElement;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
106
112
|
export { SkyElement };
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,50 +1,108 @@
|
|
|
1
1
|
import { Color, Entity, Quat, Vec2, Vec3, Vec4 } from 'playcanvas';
|
|
2
2
|
/**
|
|
3
|
-
* Parse a
|
|
4
|
-
* '#rrggbb', '#rrggbbaa', or a string of 3 or 4 comma-delimited numbers.
|
|
3
|
+
* Parse a boolean attribute value. The same rules apply to every boolean attribute:
|
|
5
4
|
*
|
|
6
|
-
*
|
|
5
|
+
* - Attribute absent (or removed): the supplied default is used.
|
|
6
|
+
* - Attribute set to the string 'false': `false`.
|
|
7
|
+
* - Attribute present with any other value, including the empty string of a bare boolean
|
|
8
|
+
* attribute (e.g. `<pc-light cast-shadows>`): `true`.
|
|
9
|
+
*
|
|
10
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
11
|
+
* @param defaultValue - The value to use when the attribute is absent or removed.
|
|
12
|
+
* @returns The parsed boolean.
|
|
13
|
+
*/
|
|
14
|
+
export declare const parseBool: (value: string | null, defaultValue: boolean) => boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Splits an attribute value into exactly `count` numeric components. Returns `null` when the
|
|
17
|
+
* value does not consist of exactly `count` whitespace-separated finite numbers.
|
|
18
|
+
*
|
|
19
|
+
* @param value - The value to split.
|
|
20
|
+
* @param count - The required number of components.
|
|
21
|
+
* @returns The parsed components, or `null`.
|
|
22
|
+
* @ignore
|
|
23
|
+
*/
|
|
24
|
+
export declare const parseComponents: (value: string, count: number) => number[] | null;
|
|
25
|
+
/**
|
|
26
|
+
* Parse a color attribute value. The expected format is a CSS color name (e.g. 'rebeccapurple'),
|
|
27
|
+
* a hex color (e.g. '#ff0000' or '#f00'), or 3 or 4 space-separated numbers in the range 0 to 1
|
|
28
|
+
* (e.g. '1 0.5 0.5' or '1 0.5 0.5 0.5'). Returns `defaultValue` (cloned, when it is a color)
|
|
29
|
+
* when the attribute is absent (`null`), or when the value is malformed — the latter also logs
|
|
30
|
+
* a warning.
|
|
31
|
+
*
|
|
32
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
33
|
+
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
34
|
+
* @param attribute - The attribute name, used in the warning message.
|
|
7
35
|
* @returns The parsed Color object.
|
|
8
36
|
*/
|
|
9
|
-
export declare const parseColor: (value: string) => Color;
|
|
37
|
+
export declare const parseColor: <T extends Color | null>(value: string | null, defaultValue: T, attribute: string) => Color | T;
|
|
10
38
|
/**
|
|
11
|
-
* Parse an Euler
|
|
39
|
+
* Parse an Euler-angles attribute value into a quaternion. The expected format is 3
|
|
40
|
+
* space-separated angles in degrees (e.g. '0 90 0'). Returns `defaultValue` (cloned, when it is
|
|
41
|
+
* a quaternion) when the attribute is absent (`null`), or when the value is malformed — the
|
|
42
|
+
* latter also logs a warning.
|
|
12
43
|
*
|
|
13
|
-
* @param value - The
|
|
44
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
45
|
+
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
46
|
+
* @param attribute - The attribute name, used in the warning message.
|
|
14
47
|
* @returns The parsed Quat object.
|
|
15
48
|
*/
|
|
16
|
-
export declare const parseQuat: (value: string) => Quat;
|
|
49
|
+
export declare const parseQuat: <T extends Quat | null>(value: string | null, defaultValue: T, attribute: string) => Quat | T;
|
|
17
50
|
/**
|
|
18
|
-
* Parse a Vec2
|
|
51
|
+
* Parse a Vec2 attribute value. The expected format is 2 space-separated numbers (e.g. '1 2').
|
|
52
|
+
* Returns `defaultValue` (cloned, when it is a vector) when the attribute is absent (`null`),
|
|
53
|
+
* or when the value is malformed — the latter also logs a warning.
|
|
19
54
|
*
|
|
20
|
-
* @param value - The
|
|
55
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
56
|
+
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
57
|
+
* @param attribute - The attribute name, used in the warning message.
|
|
21
58
|
* @returns The parsed Vec2 object.
|
|
22
59
|
*/
|
|
23
|
-
export declare const parseVec2: (value: string) => Vec2;
|
|
60
|
+
export declare const parseVec2: <T extends Vec2 | null>(value: string | null, defaultValue: T, attribute: string) => Vec2 | T;
|
|
24
61
|
/**
|
|
25
|
-
* Parse a Vec3
|
|
62
|
+
* Parse a Vec3 attribute value. The expected format is 3 space-separated numbers (e.g. '1 2 3').
|
|
63
|
+
* Returns `defaultValue` (cloned, when it is a vector) when the attribute is absent (`null`),
|
|
64
|
+
* or when the value is malformed — the latter also logs a warning.
|
|
26
65
|
*
|
|
27
|
-
* @param value - The
|
|
66
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
67
|
+
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
68
|
+
* @param attribute - The attribute name, used in the warning message.
|
|
28
69
|
* @returns The parsed Vec3 object.
|
|
29
70
|
*/
|
|
30
|
-
export declare const parseVec3: (value: string) => Vec3;
|
|
71
|
+
export declare const parseVec3: <T extends Vec3 | null>(value: string | null, defaultValue: T, attribute: string) => Vec3 | T;
|
|
31
72
|
/**
|
|
32
|
-
* Parse a Vec4
|
|
73
|
+
* Parse a Vec4 attribute value. The expected format is 4 space-separated numbers
|
|
74
|
+
* (e.g. '1 2 3 4'). Returns `defaultValue` (cloned, when it is a vector) when the attribute is
|
|
75
|
+
* absent (`null`), or when the value is malformed — the latter also logs a warning.
|
|
33
76
|
*
|
|
34
|
-
* @param value - The
|
|
77
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
78
|
+
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
79
|
+
* @param attribute - The attribute name, used in the warning message.
|
|
35
80
|
* @returns The parsed Vec4 object.
|
|
36
81
|
*/
|
|
37
|
-
export declare const parseVec4: (value: string) => Vec4;
|
|
82
|
+
export declare const parseVec4: <T extends Vec4 | null>(value: string | null, defaultValue: T, attribute: string) => Vec4 | T;
|
|
83
|
+
/**
|
|
84
|
+
* Resolves an enum attribute value against its set of valid names. Returns the value when it is
|
|
85
|
+
* one of the valid names. Returns `defaultValue` when the attribute is absent (`null`), or when
|
|
86
|
+
* the value is invalid — the latter also logs a warning listing the valid names.
|
|
87
|
+
*
|
|
88
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
89
|
+
* @param valid - The valid names: an array, or a map whose keys are the valid names.
|
|
90
|
+
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
91
|
+
* @param attribute - The attribute name, used in the warning message.
|
|
92
|
+
* @returns The resolved enum name.
|
|
93
|
+
*/
|
|
94
|
+
export declare const parseEnum: <T extends string>(value: string | null, valid: readonly T[] | ReadonlyMap<T, number>, defaultValue: T, attribute: string) => T;
|
|
38
95
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
96
|
+
* Parses a number attribute value. Returns the parsed number when the value is a finite number.
|
|
97
|
+
* Returns `defaultValue` when the attribute is absent (`null`), or when the value is not a
|
|
98
|
+
* finite number — the latter also logs a warning.
|
|
41
99
|
*
|
|
42
|
-
* @param value - The attribute value to parse.
|
|
43
|
-
* @param
|
|
44
|
-
* @param
|
|
45
|
-
* @returns The
|
|
100
|
+
* @param value - The attribute value to parse (`null` when the attribute is absent).
|
|
101
|
+
* @param defaultValue - The value to use when the attribute is absent or invalid.
|
|
102
|
+
* @param attribute - The attribute name, used in the warning message.
|
|
103
|
+
* @returns The parsed number.
|
|
46
104
|
*/
|
|
47
|
-
export declare const
|
|
105
|
+
export declare const parseNumber: <T extends number | null>(value: string | null, defaultValue: T, attribute: string) => number | T;
|
|
48
106
|
/**
|
|
49
107
|
* Resolves a reference string to the {@link Entity} backing a `<pc-entity>` element. The reference
|
|
50
108
|
* can be a CSS selector (e.g. `#my-id`, `pc-entity[name="Foo"]`), a bare element id, or a bare
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playcanvas/web-components",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"author": "PlayCanvas <support@playcanvas.com>",
|
|
5
5
|
"homepage": "https://playcanvas.com",
|
|
6
6
|
"description": "Web Components for the PlayCanvas Engine",
|
|
@@ -27,12 +27,22 @@
|
|
|
27
27
|
"module": "dist/pwc.mjs",
|
|
28
28
|
"browser": "dist/pwc.js",
|
|
29
29
|
"types": "dist/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"import": "./dist/pwc.mjs",
|
|
34
|
+
"require": "./dist/pwc.cjs"
|
|
35
|
+
},
|
|
36
|
+
"./dist/*": "./dist/*",
|
|
37
|
+
"./package.json": "./package.json"
|
|
38
|
+
},
|
|
30
39
|
"type": "module",
|
|
31
40
|
"files": [
|
|
32
41
|
"dist",
|
|
33
42
|
"src"
|
|
34
43
|
],
|
|
35
44
|
"scripts": {
|
|
45
|
+
"prebuild": "node -e \"fs.rmSync('dist', { recursive: true, force: true })\"",
|
|
36
46
|
"build": "rollup -c",
|
|
37
47
|
"dev": "concurrently \"npm run watch\" \"npm run serve\"",
|
|
38
48
|
"docs": "typedoc",
|
|
@@ -48,28 +58,28 @@
|
|
|
48
58
|
"playcanvas": "^2.20.1"
|
|
49
59
|
},
|
|
50
60
|
"devDependencies": {
|
|
51
|
-
"@mediapipe/tasks-vision": "0.
|
|
61
|
+
"@mediapipe/tasks-vision": "1.0.0",
|
|
52
62
|
"@playcanvas/eslint-config": "2.1.0",
|
|
53
63
|
"@rollup/plugin-commonjs": "29.0.3",
|
|
54
64
|
"@rollup/plugin-node-resolve": "16.0.3",
|
|
55
65
|
"@rollup/plugin-terser": "1.0.0",
|
|
56
66
|
"@rollup/plugin-typescript": "12.3.0",
|
|
57
67
|
"@tweenjs/tween.js": "25.0.0",
|
|
58
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
59
|
-
"@typescript-eslint/parser": "8.
|
|
60
|
-
"concurrently": "10.0.
|
|
61
|
-
"earcut": "3.2.
|
|
62
|
-
"eslint": "9.39.
|
|
68
|
+
"@typescript-eslint/eslint-plugin": "8.65.0",
|
|
69
|
+
"@typescript-eslint/parser": "8.65.0",
|
|
70
|
+
"concurrently": "10.0.4",
|
|
71
|
+
"earcut": "3.2.3",
|
|
72
|
+
"eslint": "9.39.5",
|
|
63
73
|
"eslint-import-resolver-typescript": "4.4.5",
|
|
64
|
-
"globals": "17.
|
|
65
|
-
"mediabunny": "1.
|
|
74
|
+
"globals": "17.8.0",
|
|
75
|
+
"mediabunny": "1.51.0",
|
|
66
76
|
"opentype.js": "2.0.0",
|
|
67
|
-
"playcanvas": "2.
|
|
68
|
-
"publint": "0.3.
|
|
69
|
-
"rollup": "4.62.
|
|
77
|
+
"playcanvas": "2.21.3",
|
|
78
|
+
"publint": "0.3.22",
|
|
79
|
+
"rollup": "4.62.3",
|
|
70
80
|
"serve": "14.2.6",
|
|
71
81
|
"tslib": "2.8.1",
|
|
72
|
-
"typedoc": "0.28.
|
|
82
|
+
"typedoc": "0.28.20",
|
|
73
83
|
"typedoc-plugin-mdn-links": "5.1.1",
|
|
74
84
|
"typescript": "6.0.3"
|
|
75
85
|
}
|
package/src/app.ts
CHANGED
|
@@ -71,6 +71,7 @@ import { AsyncElement } from './async-element';
|
|
|
71
71
|
import { EntityElement } from './entity';
|
|
72
72
|
import { MaterialElement } from './material';
|
|
73
73
|
import { ModuleElement } from './module';
|
|
74
|
+
import { parseBool, parseEnum } from './utils';
|
|
74
75
|
|
|
75
76
|
/**
|
|
76
77
|
* The AppElement interface provides properties and methods for manipulating
|
|
@@ -116,10 +117,16 @@ class AppElement extends AsyncElement {
|
|
|
116
117
|
pointerup: null
|
|
117
118
|
};
|
|
118
119
|
|
|
120
|
+
private _app: AppBase | null = null;
|
|
121
|
+
|
|
119
122
|
/**
|
|
120
|
-
* The PlayCanvas application instance.
|
|
123
|
+
* The PlayCanvas application instance. Available once the element is ready — await
|
|
124
|
+
* {@link whenReady} or the element's `ready()` promise before accessing it.
|
|
125
|
+
* @returns The application instance.
|
|
121
126
|
*/
|
|
122
|
-
app: AppBase
|
|
127
|
+
get app(): AppBase {
|
|
128
|
+
return this._app!;
|
|
129
|
+
}
|
|
123
130
|
|
|
124
131
|
/**
|
|
125
132
|
* Creates a new AppElement instance.
|
|
@@ -227,7 +234,7 @@ class AppElement extends AsyncElement {
|
|
|
227
234
|
createOptions.batchManager = BatchManager;
|
|
228
235
|
createOptions.xr = XrManager;
|
|
229
236
|
|
|
230
|
-
this.
|
|
237
|
+
this._app = new AppBase(this._canvas);
|
|
231
238
|
this.app.init(createOptions);
|
|
232
239
|
|
|
233
240
|
this.app.setCanvasFillMode(FILLMODE_FILL_WINDOW);
|
|
@@ -282,7 +289,7 @@ class AppElement extends AsyncElement {
|
|
|
282
289
|
// Clean up the application
|
|
283
290
|
if (this.app) {
|
|
284
291
|
this.app.destroy();
|
|
285
|
-
this.
|
|
292
|
+
this._app = null;
|
|
286
293
|
}
|
|
287
294
|
|
|
288
295
|
// Remove event listeners
|
|
@@ -314,6 +321,14 @@ class AppElement extends AsyncElement {
|
|
|
314
321
|
['pointermove', 'pointerdown', 'pointerup', 'pointerenter', 'pointerleave'].forEach((type) => {
|
|
315
322
|
this.addEventListener(`${type}:connect`, () => this._onPointerListenerAdded(type));
|
|
316
323
|
this.addEventListener(`${type}:disconnect`, () => this._onPointerListenerRemoved(type));
|
|
324
|
+
|
|
325
|
+
// Attach canvas handlers for listeners registered before this point (e.g. handlers
|
|
326
|
+
// created from onpointer* attributes when their elements were first upgraded)
|
|
327
|
+
const anyListeners = Array.from(this.querySelectorAll<EntityElement>('pc-entity'))
|
|
328
|
+
.some(entity => entity.hasListeners(type));
|
|
329
|
+
if (anyListeners) {
|
|
330
|
+
this._onPointerListenerAdded(type);
|
|
331
|
+
}
|
|
317
332
|
});
|
|
318
333
|
}
|
|
319
334
|
|
|
@@ -332,6 +347,13 @@ class AppElement extends AsyncElement {
|
|
|
332
347
|
pointerdown: null,
|
|
333
348
|
pointerup: null
|
|
334
349
|
};
|
|
350
|
+
this._hasPointerListeners = {
|
|
351
|
+
pointerenter: false,
|
|
352
|
+
pointerleave: false,
|
|
353
|
+
pointerdown: false,
|
|
354
|
+
pointerup: false,
|
|
355
|
+
pointermove: false
|
|
356
|
+
};
|
|
335
357
|
}
|
|
336
358
|
|
|
337
359
|
// New helper to convert CSS coordinates to canvas (picker) coordinates
|
|
@@ -589,24 +611,22 @@ class AppElement extends AsyncElement {
|
|
|
589
611
|
attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
|
|
590
612
|
switch (name) {
|
|
591
613
|
case 'alpha':
|
|
592
|
-
this.alpha = newValue
|
|
614
|
+
this.alpha = parseBool(newValue, true);
|
|
593
615
|
break;
|
|
594
616
|
case 'antialias':
|
|
595
|
-
this.antialias = newValue
|
|
617
|
+
this.antialias = parseBool(newValue, true);
|
|
596
618
|
break;
|
|
597
619
|
case 'backend':
|
|
598
|
-
|
|
599
|
-
this.backend = newValue;
|
|
600
|
-
}
|
|
620
|
+
this.backend = parseEnum(newValue, ['webgpu', 'webgl2', 'null'], 'webgl2', name);
|
|
601
621
|
break;
|
|
602
622
|
case 'depth':
|
|
603
|
-
this.depth = newValue
|
|
623
|
+
this.depth = parseBool(newValue, true);
|
|
604
624
|
break;
|
|
605
625
|
case 'high-resolution':
|
|
606
|
-
this.highResolution = newValue
|
|
626
|
+
this.highResolution = parseBool(newValue, true);
|
|
607
627
|
break;
|
|
608
628
|
case 'stencil':
|
|
609
|
-
this.stencil = newValue
|
|
629
|
+
this.stencil = parseBool(newValue, true);
|
|
610
630
|
break;
|
|
611
631
|
}
|
|
612
632
|
}
|
|
@@ -614,4 +634,10 @@ class AppElement extends AsyncElement {
|
|
|
614
634
|
|
|
615
635
|
customElements.define('pc-app', AppElement);
|
|
616
636
|
|
|
637
|
+
declare global {
|
|
638
|
+
interface HTMLElementTagNameMap {
|
|
639
|
+
'pc-app': AppElement;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
617
643
|
export { AppElement };
|
package/src/asset.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Asset, SPRITE_RENDERMODE_SIMPLE, SPRITE_RENDERMODE_SLICED, SPRITE_RENDERMODE_TILED } from 'playcanvas';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { AsyncElement } from './async-element';
|
|
4
|
+
import { parseBool, parseEnum, parseNumber } from './utils';
|
|
4
5
|
import { MeshoptDecoder } from '../lib/meshopt_decoder.module.js';
|
|
5
6
|
|
|
6
|
-
const renderModes = new Map<
|
|
7
|
+
const renderModes = new Map<'simple' | 'sliced' | 'tiled', number>([
|
|
7
8
|
['simple', SPRITE_RENDERMODE_SIMPLE],
|
|
8
9
|
['sliced', SPRITE_RENDERMODE_SLICED],
|
|
9
10
|
['tiled', SPRITE_RENDERMODE_TILED]
|
|
@@ -74,15 +75,59 @@ const processBufferView = (
|
|
|
74
75
|
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-asset/ | `<pc-asset>`} elements.
|
|
75
76
|
* The AssetElement interface also inherits the properties and methods of the
|
|
76
77
|
* {@link HTMLElement} interface.
|
|
78
|
+
*
|
|
79
|
+
* The element becomes ready once the containing application has started and the asset is in the
|
|
80
|
+
* state declared by the markup: loaded for preloaded assets (even if loading failed — check the
|
|
81
|
+
* asset's `resource`), or registered and awaiting a load for `lazy` assets. Elements inserted
|
|
82
|
+
* while the application is running are created and registered on insertion, and begin loading
|
|
83
|
+
* immediately unless `lazy`. A `pc-asset` must be a direct child of `pc-app` — elements placed
|
|
84
|
+
* elsewhere, or with an unsupported asset type, never become ready.
|
|
77
85
|
*/
|
|
78
|
-
class AssetElement extends
|
|
86
|
+
class AssetElement extends AsyncElement {
|
|
79
87
|
private _lazy: boolean = false;
|
|
80
88
|
|
|
81
89
|
/**
|
|
82
|
-
* The asset that is loaded.
|
|
90
|
+
* The asset that is loaded. Available once the element is ready — await
|
|
91
|
+
* {@link whenReady} or the element's `ready()` promise before accessing it.
|
|
83
92
|
*/
|
|
84
93
|
asset: Asset | null = null;
|
|
85
94
|
|
|
95
|
+
async connectedCallback() {
|
|
96
|
+
const appElement = this.closestApp;
|
|
97
|
+
if (!appElement) return;
|
|
98
|
+
|
|
99
|
+
// Assets must be direct children of pc-app (matches the boot query ':scope > pc-asset')
|
|
100
|
+
if (this.parentElement !== appElement) {
|
|
101
|
+
console.warn(`pc-asset '${this.getAttribute('id') ?? this.getAttribute('src')}' must be a direct child of pc-app - asset not created`);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
await appElement.ready();
|
|
106
|
+
|
|
107
|
+
// The element may have been removed or re-parented while waiting for the app
|
|
108
|
+
if (!this.isConnected || this.parentElement !== appElement) return;
|
|
109
|
+
|
|
110
|
+
// Assets present at startup are created by AppElement's boot; this branch handles
|
|
111
|
+
// elements inserted (or re-inserted) after the app is already running
|
|
112
|
+
if (!this.asset) {
|
|
113
|
+
const app = appElement.app;
|
|
114
|
+
if (!app) return; // pc-app is re-connecting; its own boot will create this asset
|
|
115
|
+
|
|
116
|
+
this.createAsset();
|
|
117
|
+
if (this.asset) {
|
|
118
|
+
app.assets.add(this.asset); // add() auto-loads when preload is true
|
|
119
|
+
if (!this.lazy) {
|
|
120
|
+
app.assets.load(this.asset);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Never ready if createAsset failed (unsupported asset type)
|
|
126
|
+
if (this.asset) {
|
|
127
|
+
this._onReady();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
86
131
|
disconnectedCallback() {
|
|
87
132
|
this.destroyAsset();
|
|
88
133
|
}
|
|
@@ -167,12 +212,12 @@ class AssetElement extends HTMLElement {
|
|
|
167
212
|
|
|
168
213
|
const pixelsPerUnit = this.getAttribute('pixels-per-unit');
|
|
169
214
|
if (pixelsPerUnit !== null) {
|
|
170
|
-
data.pixelsPerUnit =
|
|
215
|
+
data.pixelsPerUnit = parseNumber(pixelsPerUnit, 1, 'pixels-per-unit');
|
|
171
216
|
}
|
|
172
217
|
|
|
173
218
|
const renderMode = this.getAttribute('render-mode');
|
|
174
219
|
if (renderMode !== null) {
|
|
175
|
-
data.renderMode = parseEnum(renderMode, renderModes,
|
|
220
|
+
data.renderMode = renderModes.get(parseEnum(renderMode, renderModes, 'simple', 'render-mode'));
|
|
176
221
|
}
|
|
177
222
|
|
|
178
223
|
// Apply engine defaults for any values not supplied.
|
|
@@ -187,6 +232,8 @@ class AssetElement extends HTMLElement {
|
|
|
187
232
|
|
|
188
233
|
destroyAsset() {
|
|
189
234
|
if (this.asset) {
|
|
235
|
+
// Deregister first so unload() can still notify the registry
|
|
236
|
+
this.asset.registry?.remove(this.asset);
|
|
190
237
|
this.asset.unload();
|
|
191
238
|
this.asset = null;
|
|
192
239
|
}
|
|
@@ -220,13 +267,19 @@ class AssetElement extends HTMLElement {
|
|
|
220
267
|
return ['lazy'];
|
|
221
268
|
}
|
|
222
269
|
|
|
223
|
-
attributeChangedCallback(name: string, _oldValue: string,
|
|
270
|
+
attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
|
|
224
271
|
if (name === 'lazy') {
|
|
225
|
-
this.lazy =
|
|
272
|
+
this.lazy = parseBool(newValue, false);
|
|
226
273
|
}
|
|
227
274
|
}
|
|
228
275
|
}
|
|
229
276
|
|
|
230
277
|
customElements.define('pc-asset', AssetElement);
|
|
231
278
|
|
|
279
|
+
declare global {
|
|
280
|
+
interface HTMLElementTagNameMap {
|
|
281
|
+
'pc-asset': AssetElement;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
232
285
|
export { AssetElement };
|
package/src/async-element.ts
CHANGED
|
@@ -26,16 +26,18 @@ class AsyncElement extends HTMLElement {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
* Called when the element is fully initialized and ready.
|
|
30
|
-
*
|
|
29
|
+
* Called when the element is fully initialized and ready. Subclasses should call this when
|
|
30
|
+
* they're ready. Resolves the ready promise and dispatches a bubbling, composed `ready`
|
|
31
|
+
* event.
|
|
31
32
|
*/
|
|
32
33
|
protected _onReady() {
|
|
33
34
|
this._readyResolve();
|
|
34
|
-
this.dispatchEvent(new CustomEvent('ready'));
|
|
35
|
+
this.dispatchEvent(new CustomEvent('ready', { bubbles: true, composed: true }));
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
|
-
* Returns a promise that resolves with this element when it's ready.
|
|
39
|
+
* Returns a promise that resolves with this element when it's ready. This is the low-level
|
|
40
|
+
* primitive underlying {@link whenReady}, which is the recommended way to wait for elements.
|
|
39
41
|
* @returns A promise that resolves with this element when it's ready.
|
|
40
42
|
*/
|
|
41
43
|
ready(): Promise<this> {
|
|
@@ -43,4 +45,83 @@ class AsyncElement extends HTMLElement {
|
|
|
43
45
|
}
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
/**
|
|
49
|
+
* A union of the tag names of all elements that initialize asynchronously (i.e. elements whose
|
|
50
|
+
* classes extend {@link AsyncElement}).
|
|
51
|
+
*/
|
|
52
|
+
type AsyncElementTagName = {
|
|
53
|
+
[K in keyof HTMLElementTagNameMap]: HTMLElementTagNameMap[K] extends AsyncElement ? K : never
|
|
54
|
+
}[keyof HTMLElementTagNameMap];
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Waits for the first element matching the given tag name to be fully initialized. Note that the
|
|
58
|
+
* promise never settles if the element cannot finish initializing (for example, a `<pc-script>`
|
|
59
|
+
* that is not a direct child of `<pc-scripts>`). A component element outside a `<pc-entity>` is
|
|
60
|
+
* the exception: it still becomes ready, but its `component` is `null`. Either way, a misplaced
|
|
61
|
+
* element logs a warning naming the parent it requires.
|
|
62
|
+
* @param target - The tag name of the element to wait for (e.g. `'pc-app'`).
|
|
63
|
+
* @returns A promise that resolves with the element once it's ready.
|
|
64
|
+
* @example
|
|
65
|
+
* const { app } = await whenReady('pc-app');
|
|
66
|
+
*/
|
|
67
|
+
function whenReady<K extends AsyncElementTagName>(target: K): Promise<HTMLElementTagNameMap[K]>;
|
|
68
|
+
/**
|
|
69
|
+
* Waits for the given element to be fully initialized. Note that the promise never settles if
|
|
70
|
+
* the element cannot finish initializing (for example, an element that is never added to the
|
|
71
|
+
* document).
|
|
72
|
+
* @param target - The element to wait for.
|
|
73
|
+
* @returns A promise that resolves with the element once it's ready.
|
|
74
|
+
* @example
|
|
75
|
+
* const appElement = document.createElement('pc-app');
|
|
76
|
+
* document.body.appendChild(appElement);
|
|
77
|
+
* const { app } = await whenReady(appElement);
|
|
78
|
+
*/
|
|
79
|
+
function whenReady<T extends AsyncElement>(target: T): Promise<T>;
|
|
80
|
+
/**
|
|
81
|
+
* Waits for the first element matching the given CSS selector to be fully initialized. Note that
|
|
82
|
+
* the promise never settles if the element cannot finish initializing (for example, a `<pc-script>`
|
|
83
|
+
* that is not a direct child of `<pc-scripts>`). A component element outside a `<pc-entity>` is
|
|
84
|
+
* the exception: it still becomes ready, but its `component` is `null`. Either way, a misplaced
|
|
85
|
+
* element logs a warning naming the parent it requires.
|
|
86
|
+
* @param target - A CSS selector matching the element to wait for (e.g. `'#my-app'`).
|
|
87
|
+
* @returns A promise that resolves with the element once it's ready.
|
|
88
|
+
* @example
|
|
89
|
+
* // In TypeScript, supply the element type when using an arbitrary selector
|
|
90
|
+
* const { entity } = await whenReady<EntityElement>('pc-entity[name="camera"]');
|
|
91
|
+
*/
|
|
92
|
+
function whenReady<T extends AsyncElement = AsyncElement, S extends string = string>(
|
|
93
|
+
target: S extends Exclude<keyof HTMLElementTagNameMap, AsyncElementTagName> ? never : S
|
|
94
|
+
): Promise<T>;
|
|
95
|
+
async function whenReady(target: string | AsyncElement): Promise<AsyncElement> {
|
|
96
|
+
let element: Element | null;
|
|
97
|
+
if (typeof target === 'string') {
|
|
98
|
+
if (document.readyState === 'loading') {
|
|
99
|
+
await new Promise((resolve) => {
|
|
100
|
+
document.addEventListener('DOMContentLoaded', resolve, { once: true });
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
element = document.querySelector(target);
|
|
106
|
+
} catch {
|
|
107
|
+
throw new Error(`whenReady: '${target}' is not a valid CSS selector`);
|
|
108
|
+
}
|
|
109
|
+
if (!element) {
|
|
110
|
+
throw new Error(`whenReady: no element found matching '${target}'`);
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
element = target;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!(element instanceof AsyncElement)) {
|
|
117
|
+
const description = element instanceof Element ? `<${element.tagName.toLowerCase()}>` : String(target);
|
|
118
|
+
throw new Error(`whenReady: ${description} does not initialize asynchronously`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
await element.ready();
|
|
122
|
+
|
|
123
|
+
return element;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export { AsyncElement, whenReady };
|
|
127
|
+
export type { AsyncElementTagName };
|