@playcanvas/web-components 0.9.0 → 0.10.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.
Files changed (72) hide show
  1. package/README.md +18 -0
  2. package/dist/app.d.ts +3 -2
  3. package/dist/asset.d.ts +16 -1
  4. package/dist/async-element.d.ts +3 -0
  5. package/dist/components/button-component.d.ts +1 -1
  6. package/dist/components/camera-component.d.ts +1 -1
  7. package/dist/components/collision-component.d.ts +1 -1
  8. package/dist/components/component.d.ts +1 -1
  9. package/dist/components/element-component.d.ts +1 -1
  10. package/dist/components/gsplat-component.d.ts +1 -1
  11. package/dist/components/layoutchild-component.d.ts +1 -1
  12. package/dist/components/layoutgroup-component.d.ts +1 -1
  13. package/dist/components/light-component.d.ts +1 -1
  14. package/dist/components/particlesystem-component.d.ts +1 -1
  15. package/dist/components/render-component.d.ts +1 -1
  16. package/dist/components/rigidbody-component.d.ts +1 -1
  17. package/dist/components/screen-component.d.ts +1 -1
  18. package/dist/components/script.d.ts +8 -1
  19. package/dist/components/scrollbar-component.d.ts +1 -1
  20. package/dist/components/scrollview-component.d.ts +1 -1
  21. package/dist/components/sound-component.d.ts +1 -1
  22. package/dist/components/sound-slot.d.ts +9 -1
  23. package/dist/custom-elements.json +16231 -0
  24. package/dist/entity.d.ts +19 -1
  25. package/dist/material.d.ts +966 -4
  26. package/dist/model.d.ts +1 -1
  27. package/dist/module.d.ts +10 -0
  28. package/dist/{utils.d.ts → parse.d.ts} +63 -33
  29. package/dist/pwc.cjs +2677 -586
  30. package/dist/pwc.cjs.map +1 -1
  31. package/dist/pwc.js +2677 -586
  32. package/dist/pwc.js.map +1 -1
  33. package/dist/pwc.min.js +1 -1
  34. package/dist/pwc.min.js.map +1 -1
  35. package/dist/pwc.min.mjs +2 -0
  36. package/dist/pwc.min.mjs.map +1 -0
  37. package/dist/pwc.mjs +2678 -587
  38. package/dist/pwc.mjs.map +1 -1
  39. package/dist/scene.d.ts +1 -1
  40. package/dist/sky.d.ts +1 -1
  41. package/dist/vscode.html-custom-data.json +1795 -0
  42. package/dist/web-types.json +3592 -0
  43. package/package.json +29 -11
  44. package/src/app.ts +6 -5
  45. package/src/asset.ts +19 -2
  46. package/src/async-element.ts +3 -0
  47. package/src/components/button-component.ts +6 -6
  48. package/src/components/camera-component.ts +2 -2
  49. package/src/components/collision-component.ts +2 -2
  50. package/src/components/component.ts +2 -2
  51. package/src/components/element-component.ts +6 -6
  52. package/src/components/gsplat-component.ts +3 -3
  53. package/src/components/layoutchild-component.ts +2 -2
  54. package/src/components/layoutgroup-component.ts +2 -2
  55. package/src/components/light-component.ts +2 -2
  56. package/src/components/particlesystem-component.ts +2 -2
  57. package/src/components/render-component.ts +10 -5
  58. package/src/components/rigidbody-component.ts +2 -2
  59. package/src/components/screen-component.ts +2 -2
  60. package/src/components/script-component.ts +4 -4
  61. package/src/components/script.ts +9 -2
  62. package/src/components/scrollbar-component.ts +3 -3
  63. package/src/components/scrollview-component.ts +6 -6
  64. package/src/components/sound-component.ts +2 -2
  65. package/src/components/sound-slot.ts +31 -9
  66. package/src/entity.ts +25 -7
  67. package/src/material.ts +2396 -59
  68. package/src/model.ts +2 -2
  69. package/src/module.ts +10 -0
  70. package/src/{utils.ts → parse.ts} +104 -65
  71. package/src/scene.ts +2 -2
  72. package/src/sky.ts +3 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcanvas/web-components",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "author": "PlayCanvas <support@playcanvas.com>",
5
5
  "homepage": "https://playcanvas.com",
6
6
  "description": "Web Components for the PlayCanvas Engine",
@@ -25,8 +25,11 @@
25
25
  },
26
26
  "main": "dist/pwc.cjs",
27
27
  "module": "dist/pwc.mjs",
28
- "browser": "dist/pwc.js",
28
+ "unpkg": "dist/pwc.min.js",
29
+ "jsdelivr": "dist/pwc.min.js",
29
30
  "types": "dist/index.d.ts",
31
+ "customElements": "dist/custom-elements.json",
32
+ "web-types": "dist/web-types.json",
30
33
  "exports": {
31
34
  ".": {
32
35
  "types": "./dist/index.d.ts",
@@ -44,21 +47,31 @@
44
47
  "scripts": {
45
48
  "prebuild": "node -e \"fs.rmSync('dist', { recursive: true, force: true })\"",
46
49
  "build": "rollup -c",
50
+ "postbuild": "npm run cem",
51
+ "cem": "cem analyze && node utils/cem/validate.mjs",
47
52
  "dev": "concurrently \"npm run watch\" \"npm run serve\"",
48
53
  "docs": "typedoc",
49
- "lint": "eslint examples/js examples/assets/scripts src",
54
+ "lint": "eslint examples/js examples/assets/scripts src test vitest.config.ts",
50
55
  "serve": "serve",
51
- "test": "echo \"Error: no test specified\" && exit 1",
56
+ "test": "vitest run",
57
+ "test:watch": "vitest",
58
+ "test:coverage": "vitest run --coverage",
59
+ "test:unit": "vitest run --project unit",
60
+ "test:elements": "vitest run --project elements",
61
+ "test:integration": "vitest run --project integration",
52
62
  "publint": "publint",
53
- "type-check": "tsc --noEmit",
54
- "type-check:watch": "npm run type-check -- --watch",
63
+ "type-check": "npm run type-check:src && npm run type-check:test",
64
+ "type-check:src": "tsc --noEmit -p tsconfig.json",
65
+ "type-check:test": "tsc --noEmit -p tsconfig.test.json",
66
+ "type-check:watch": "npm run type-check:src -- --watch",
55
67
  "watch": "rollup -c -w"
56
68
  },
57
69
  "peerDependencies": {
58
70
  "playcanvas": "^2.20.1"
59
71
  },
60
72
  "devDependencies": {
61
- "@mediapipe/tasks-vision": "1.0.0",
73
+ "@custom-elements-manifest/analyzer": "0.11.0",
74
+ "@mediapipe/tasks-vision": "1.0.1",
62
75
  "@playcanvas/eslint-config": "2.1.0",
63
76
  "@rollup/plugin-commonjs": "29.0.3",
64
77
  "@rollup/plugin-node-resolve": "16.0.3",
@@ -67,20 +80,25 @@
67
80
  "@tweenjs/tween.js": "25.0.0",
68
81
  "@typescript-eslint/eslint-plugin": "8.65.0",
69
82
  "@typescript-eslint/parser": "8.65.0",
83
+ "@vitest/coverage-v8": "4.1.10",
70
84
  "concurrently": "10.0.4",
85
+ "custom-element-jet-brains-integration": "1.7.0",
86
+ "custom-element-vs-code-integration": "1.5.0",
71
87
  "earcut": "3.2.3",
72
88
  "eslint": "9.39.5",
73
89
  "eslint-import-resolver-typescript": "4.4.5",
74
- "globals": "17.8.0",
75
- "mediabunny": "1.51.0",
90
+ "globals": "17.9.0",
91
+ "jsdom": "30.0.1",
92
+ "mediabunny": "1.52.2",
76
93
  "opentype.js": "2.0.0",
77
94
  "playcanvas": "2.21.3",
78
95
  "publint": "0.3.22",
79
- "rollup": "4.62.3",
96
+ "rollup": "4.62.4",
80
97
  "serve": "14.2.6",
81
98
  "tslib": "2.8.1",
82
99
  "typedoc": "0.28.20",
83
100
  "typedoc-plugin-mdn-links": "5.1.1",
84
- "typescript": "6.0.3"
101
+ "typescript": "6.0.3",
102
+ "vitest": "4.1.10"
85
103
  }
86
104
  }
package/src/app.ts CHANGED
@@ -71,7 +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
+ import { parseBool, parseEnum } from './parse';
75
75
 
76
76
  /**
77
77
  * The AppElement interface provides properties and methods for manipulating
@@ -87,7 +87,7 @@ class AppElement extends AsyncElement {
87
87
 
88
88
  private _alpha = true;
89
89
 
90
- private _backend: 'webgpu' | 'webgl2' | 'null' = 'webgl2';
90
+ private _backend: 'webgpu' | 'webgl2' | 'null' = 'webgpu';
91
91
 
92
92
  private _antialias = true;
93
93
 
@@ -528,7 +528,8 @@ class AppElement extends AsyncElement {
528
528
  }
529
529
 
530
530
  /**
531
- * Sets the graphics backend.
531
+ * Sets the graphics backend. Defaults to 'webgpu', which falls back to 'webgl2' if WebGPU
532
+ * is not supported by the browser.
532
533
  * @param value - The graphics backend ('webgpu', 'webgl2', or 'null').
533
534
  */
534
535
  set backend(value: 'webgpu' | 'webgl2' | 'null') {
@@ -608,7 +609,7 @@ class AppElement extends AsyncElement {
608
609
  return ['alpha', 'antialias', 'backend', 'depth', 'stencil', 'high-resolution'];
609
610
  }
610
611
 
611
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
612
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
612
613
  switch (name) {
613
614
  case 'alpha':
614
615
  this.alpha = parseBool(newValue, true);
@@ -617,7 +618,7 @@ class AppElement extends AsyncElement {
617
618
  this.antialias = parseBool(newValue, true);
618
619
  break;
619
620
  case 'backend':
620
- this.backend = parseEnum(newValue, ['webgpu', 'webgl2', 'null'], 'webgl2', name);
621
+ this.backend = parseEnum(newValue, ['webgpu', 'webgl2', 'null'], 'webgpu', name);
621
622
  break;
622
623
  case 'depth':
623
624
  this.depth = parseBool(newValue, true);
package/src/asset.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Asset, SPRITE_RENDERMODE_SIMPLE, SPRITE_RENDERMODE_SLICED, SPRITE_RENDERMODE_TILED } from 'playcanvas';
2
2
 
3
3
  import { AsyncElement } from './async-element';
4
- import { parseBool, parseEnum, parseNumber } from './utils';
4
+ import { parseBool, parseEnum, parseNumber } from './parse';
5
5
  import { MeshoptDecoder } from '../lib/meshopt_decoder.module.js';
6
6
 
7
7
  const renderModes = new Map<'simple' | 'sliced' | 'tiled', number>([
@@ -16,11 +16,13 @@ const extToType = new Map([
16
16
  ['frag', 'shader'],
17
17
  ['glb', 'container'],
18
18
  ['glsl', 'shader'],
19
+ ['gltf', 'container'],
19
20
  ['hdr', 'texture'],
20
21
  ['html', 'html'],
21
22
  ['jpg', 'texture'],
22
23
  ['js', 'script'],
23
24
  ['json', 'json'],
25
+ ['ktx2', 'texture'],
24
26
  ['mp3', 'audio'],
25
27
  ['mjs', 'script'],
26
28
  ['ply', 'gsplat'],
@@ -82,6 +84,21 @@ const processBufferView = (
82
84
  * while the application is running are created and registered on insertion, and begin loading
83
85
  * immediately unless `lazy`. A `pc-asset` must be a direct child of `pc-app` — elements placed
84
86
  * elsewhere, or with an unsupported asset type, never become ready.
87
+ *
88
+ * Apart from `lazy`, these attributes are read once when the asset is created, so changing them
89
+ * later has no effect.
90
+ *
91
+ * @attribute {string} id - The identifier used to reference the asset from other elements.
92
+ * @attribute {string} src - The URL of the asset to load.
93
+ * @attribute {string} type - The asset type. Inferred from the `src` file extension when omitted.
94
+ * @attribute {string} data - Additional asset data, as a JSON object.
95
+ * @attribute {string} atlas - For a `sprite` asset, the `id` of the texture atlas asset it uses.
96
+ * The atlas must be declared before the sprite.
97
+ * @attribute {string} frame-keys - For a `sprite` asset, the atlas frame keys it uses, separated
98
+ * by spaces or commas.
99
+ * @attribute {number} pixels-per-unit - For a `sprite` asset, the number of pixels per world unit.
100
+ * @attribute {'simple' | 'sliced' | 'tiled'} render-mode - For a `sprite` asset, how the sprite is
101
+ * rendered when resized.
85
102
  */
86
103
  class AssetElement extends AsyncElement {
87
104
  private _lazy: boolean = false;
@@ -267,7 +284,7 @@ class AssetElement extends AsyncElement {
267
284
  return ['lazy'];
268
285
  }
269
286
 
270
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
287
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
271
288
  if (name === 'lazy') {
272
289
  this.lazy = parseBool(newValue, false);
273
290
  }
@@ -3,6 +3,9 @@ import { EntityElement } from './entity';
3
3
 
4
4
  /**
5
5
  * Base class for all PlayCanvas Web Components that initialize asynchronously.
6
+ *
7
+ * @fires {CustomEvent} ready - Fired once the element is fully initialized. Bubbles and is
8
+ * composed.
6
9
  */
7
10
  class AsyncElement extends HTMLElement {
8
11
  private _readyPromise: Promise<void>;
@@ -2,7 +2,7 @@ import { BUTTON_TRANSITION_MODE_SPRITE_CHANGE, BUTTON_TRANSITION_MODE_TINT, Butt
2
2
 
3
3
  import { AssetElement } from '../asset';
4
4
  import { ComponentElement } from './component';
5
- import { getEntity, parseBool, parseColor, parseEnum, parseNumber, parseVec4 } from '../utils';
5
+ import { getEntity, parseBool, parseColor, parseEnum, parseNumber, parseVec4 } from '../parse';
6
6
 
7
7
  const transitionModes = new Map<'tint' | 'sprite', number>([
8
8
  ['tint', BUTTON_TRANSITION_MODE_TINT],
@@ -396,7 +396,7 @@ class ButtonComponentElement extends ComponentElement {
396
396
  ];
397
397
  }
398
398
 
399
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
399
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
400
400
  super.attributeChangedCallback(name, _oldValue, newValue);
401
401
 
402
402
  switch (name) {
@@ -404,7 +404,7 @@ class ButtonComponentElement extends ComponentElement {
404
404
  this.active = parseBool(newValue, true);
405
405
  break;
406
406
  case 'image':
407
- this.image = newValue;
407
+ this.image = newValue ?? '';
408
408
  break;
409
409
  case 'hit-padding':
410
410
  this.hitPadding = parseVec4(newValue, Vec4.ZERO, name);
@@ -425,19 +425,19 @@ class ButtonComponentElement extends ComponentElement {
425
425
  this.fadeDuration = parseNumber(newValue, 0, name);
426
426
  break;
427
427
  case 'hover-sprite-asset':
428
- this.hoverSpriteAsset = newValue;
428
+ this.hoverSpriteAsset = newValue ?? '';
429
429
  break;
430
430
  case 'hover-sprite-frame':
431
431
  this.hoverSpriteFrame = parseNumber(newValue, 0, name);
432
432
  break;
433
433
  case 'pressed-sprite-asset':
434
- this.pressedSpriteAsset = newValue;
434
+ this.pressedSpriteAsset = newValue ?? '';
435
435
  break;
436
436
  case 'pressed-sprite-frame':
437
437
  this.pressedSpriteFrame = parseNumber(newValue, 0, name);
438
438
  break;
439
439
  case 'inactive-sprite-asset':
440
- this.inactiveSpriteAsset = newValue;
440
+ this.inactiveSpriteAsset = newValue ?? '';
441
441
  break;
442
442
  case 'inactive-sprite-frame':
443
443
  this.inactiveSpriteFrame = parseNumber(newValue, 0, name);
@@ -1,7 +1,7 @@
1
1
  import { CameraComponent, Color, Vec4, GAMMA_NONE, GAMMA_SRGB, PROJECTION_ORTHOGRAPHIC, PROJECTION_PERSPECTIVE, TONEMAP_LINEAR, TONEMAP_FILMIC, TONEMAP_NEUTRAL, TONEMAP_ACES2, TONEMAP_ACES, TONEMAP_HEJL, TONEMAP_NONE, XRTYPE_VR } from 'playcanvas';
2
2
 
3
3
  import { ComponentElement } from './component';
4
- import { parseBool, parseColor, parseEnum, parseNumber, parseVec4 } from '../utils';
4
+ import { parseBool, parseColor, parseEnum, parseNumber, parseVec4 } from '../parse';
5
5
 
6
6
  const tonemaps = new Map<'none' | 'linear' | 'filmic' | 'hejl' | 'aces' | 'aces2' | 'neutral', number>([
7
7
  ['none', TONEMAP_NONE],
@@ -490,7 +490,7 @@ class CameraComponentElement extends ComponentElement {
490
490
  ];
491
491
  }
492
492
 
493
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
493
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
494
494
  super.attributeChangedCallback(name, _oldValue, newValue);
495
495
 
496
496
  switch (name) {
@@ -1,7 +1,7 @@
1
1
  import { CollisionComponent, Quat, Vec3 } from 'playcanvas';
2
2
 
3
3
  import { ComponentElement } from './component';
4
- import { parseBool, parseEnum, parseNumber, parseQuat, parseVec3 } from '../utils';
4
+ import { parseBool, parseEnum, parseNumber, parseQuat, parseVec3 } from '../parse';
5
5
 
6
6
  /**
7
7
  * The CollisionComponentElement interface provides properties and methods for manipulating
@@ -146,7 +146,7 @@ class CollisionComponentElement extends ComponentElement {
146
146
  return [...super.observedAttributes, 'angular-offset', 'axis', 'convex-hull', 'half-extents', 'height', 'linear-offset', 'radius', 'type'];
147
147
  }
148
148
 
149
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
149
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
150
150
  super.attributeChangedCallback(name, _oldValue, newValue);
151
151
 
152
152
  switch (name) {
@@ -2,7 +2,7 @@ import { Component } from 'playcanvas';
2
2
 
3
3
  import { AppElement } from '../app';
4
4
  import { AsyncElement } from '../async-element';
5
- import { parseBool } from '../utils';
5
+ import { parseBool } from '../parse';
6
6
 
7
7
  /**
8
8
  * Represents a component in the PlayCanvas engine.
@@ -104,7 +104,7 @@ class ComponentElement extends AsyncElement {
104
104
  return ['enabled'];
105
105
  }
106
106
 
107
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
107
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
108
108
  switch (name) {
109
109
  case 'enabled':
110
110
  this.enabled = parseBool(newValue, true);
@@ -2,7 +2,7 @@ import { Color, ElementComponent, Vec2, Vec4 } from 'playcanvas';
2
2
 
3
3
  import { AssetElement } from '../asset';
4
4
  import { ComponentElement } from './component';
5
- import { parseBool, parseColor, parseEnum, parseNumber, parseVec2, parseVec4 } from '../utils';
5
+ import { parseBool, parseColor, parseEnum, parseNumber, parseVec2, parseVec4 } from '../parse';
6
6
 
7
7
  /**
8
8
  * The ElementComponentElement interface provides properties and methods for manipulating
@@ -686,7 +686,7 @@ class ElementComponentElement extends ComponentElement {
686
686
  ];
687
687
  }
688
688
 
689
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
689
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
690
690
  super.attributeChangedCallback(name, _oldValue, newValue);
691
691
 
692
692
  switch (name) {
@@ -712,7 +712,7 @@ class ElementComponentElement extends ComponentElement {
712
712
  this.enableMarkup = parseBool(newValue, false);
713
713
  break;
714
714
  case 'font-asset':
715
- this.fontAsset = newValue;
715
+ this.fontAsset = newValue ?? '';
716
716
  break;
717
717
  case 'font-size':
718
718
  this.fontSize = parseNumber(newValue, 32, name);
@@ -745,16 +745,16 @@ class ElementComponentElement extends ComponentElement {
745
745
  this.pixelsPerUnit = parseNumber(newValue, null, name);
746
746
  break;
747
747
  case 'sprite-asset':
748
- this.spriteAsset = newValue;
748
+ this.spriteAsset = newValue ?? '';
749
749
  break;
750
750
  case 'sprite-frame':
751
751
  this.spriteFrame = parseNumber(newValue, 0, name);
752
752
  break;
753
753
  case 'text':
754
- this.text = newValue;
754
+ this.text = newValue ?? '';
755
755
  break;
756
756
  case 'texture-asset':
757
- this.textureAsset = newValue;
757
+ this.textureAsset = newValue ?? '';
758
758
  break;
759
759
  case 'type':
760
760
  this.type = parseEnum(newValue, ['group', 'image', 'text'], 'group', name);
@@ -2,7 +2,7 @@ import { GSplatComponent } from 'playcanvas';
2
2
 
3
3
  import { ComponentElement } from './component';
4
4
  import { AssetElement } from '../asset';
5
- import { parseBool, parseNumber } from '../utils';
5
+ import { parseBool, parseNumber } from '../parse';
6
6
 
7
7
  /**
8
8
  * The GSplatComponentElement interface provides properties and methods for manipulating
@@ -188,12 +188,12 @@ class GSplatComponentElement extends ComponentElement {
188
188
  ];
189
189
  }
190
190
 
191
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
191
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
192
192
  super.attributeChangedCallback(name, _oldValue, newValue);
193
193
 
194
194
  switch (name) {
195
195
  case 'asset':
196
- this.asset = newValue;
196
+ this.asset = newValue ?? '';
197
197
  break;
198
198
  case 'cast-shadows':
199
199
  this.castShadows = parseBool(newValue, false);
@@ -1,7 +1,7 @@
1
1
  import { LayoutChildComponent } from 'playcanvas';
2
2
 
3
3
  import { ComponentElement } from './component';
4
- import { parseBool, parseNumber } from '../utils';
4
+ import { parseBool, parseNumber } from '../parse';
5
5
 
6
6
  /**
7
7
  * The LayoutChildComponentElement interface provides properties and methods for manipulating
@@ -199,7 +199,7 @@ class LayoutChildComponentElement extends ComponentElement {
199
199
  ];
200
200
  }
201
201
 
202
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
202
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
203
203
  super.attributeChangedCallback(name, _oldValue, newValue);
204
204
 
205
205
  switch (name) {
@@ -1,7 +1,7 @@
1
1
  import { FITTING_NONE, FITTING_STRETCH, FITTING_SHRINK, FITTING_BOTH, LayoutGroupComponent, ORIENTATION_HORIZONTAL, ORIENTATION_VERTICAL, Vec2, Vec4 } from 'playcanvas';
2
2
 
3
3
  import { ComponentElement } from './component';
4
- import { parseBool, parseEnum, parseVec2, parseVec4 } from '../utils';
4
+ import { parseBool, parseEnum, parseVec2, parseVec4 } from '../parse';
5
5
 
6
6
  const orientations = new Map<'horizontal' | 'vertical', number>([
7
7
  ['horizontal', ORIENTATION_HORIZONTAL],
@@ -258,7 +258,7 @@ class LayoutGroupComponentElement extends ComponentElement {
258
258
  ];
259
259
  }
260
260
 
261
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
261
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
262
262
  super.attributeChangedCallback(name, _oldValue, newValue);
263
263
 
264
264
  switch (name) {
@@ -1,7 +1,7 @@
1
1
  import { Color, LightComponent, SHADOW_PCF1_16F, SHADOW_PCF1_32F, SHADOW_PCF3_16F, SHADOW_PCF3_32F, SHADOW_PCF5_16F, SHADOW_PCF5_32F, SHADOW_PCSS_32F, SHADOW_VSM_16F, SHADOW_VSM_32F } from 'playcanvas';
2
2
 
3
3
  import { ComponentElement } from './component';
4
- import { parseBool, parseColor, parseEnum, parseNumber } from '../utils';
4
+ import { parseBool, parseColor, parseEnum, parseNumber } from '../parse';
5
5
 
6
6
  const shadowTypes = new Map<'pcf1-16f' | 'pcf1-32f' | 'pcf3-16f' | 'pcf3-32f' | 'pcf5-16f' | 'pcf5-32f' | 'vsm-16f' | 'vsm-32f' | 'pcss-32f', number>([
7
7
  ['pcf1-16f', SHADOW_PCF1_16F],
@@ -496,7 +496,7 @@ class LightComponentElement extends ComponentElement {
496
496
  ];
497
497
  }
498
498
 
499
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
499
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
500
500
  super.attributeChangedCallback(name, _oldValue, newValue);
501
501
 
502
502
  switch (name) {
@@ -139,12 +139,12 @@ class ParticleSystemComponentElement extends ComponentElement {
139
139
  ];
140
140
  }
141
141
 
142
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
142
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
143
143
  super.attributeChangedCallback(name, _oldValue, newValue);
144
144
 
145
145
  switch (name) {
146
146
  case 'asset':
147
- this.asset = newValue;
147
+ this.asset = newValue ?? '';
148
148
  break;
149
149
  }
150
150
  }
@@ -2,7 +2,7 @@ import { RenderComponent, StandardMaterial } from 'playcanvas';
2
2
 
3
3
  import { ComponentElement } from './component';
4
4
  import { MaterialElement } from '../material';
5
- import { parseBool, parseEnum } from '../utils';
5
+ import { parseBool, parseEnum } from '../parse';
6
6
 
7
7
  /**
8
8
  * The RenderComponentElement interface provides properties and methods for manipulating
@@ -91,8 +91,13 @@ class RenderComponentElement extends ComponentElement {
91
91
  */
92
92
  set material(value: string) {
93
93
  this._material = value;
94
- if (this.component) {
95
- this.component.material = MaterialElement.get(value) as StandardMaterial;
94
+ const material = MaterialElement.get(value);
95
+ // Guarded like every other reference attribute in the library. Assigning an unresolved
96
+ // lookup used to write `undefined` straight through to every mesh instance, and the
97
+ // engine's MeshInstance setter takes that literally - it clears the material and skips
98
+ // the ref/transparency/key bookkeeping, leaving the mesh with no material at all.
99
+ if (this.component && material) {
100
+ this.component.material = material as StandardMaterial;
96
101
  }
97
102
  }
98
103
 
@@ -127,7 +132,7 @@ class RenderComponentElement extends ComponentElement {
127
132
  return [...super.observedAttributes, 'cast-shadows', 'material', 'receive-shadows', 'type'];
128
133
  }
129
134
 
130
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
135
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
131
136
  super.attributeChangedCallback(name, _oldValue, newValue);
132
137
 
133
138
  switch (name) {
@@ -135,7 +140,7 @@ class RenderComponentElement extends ComponentElement {
135
140
  this.castShadows = parseBool(newValue, true);
136
141
  break;
137
142
  case 'material':
138
- this.material = newValue;
143
+ this.material = newValue ?? '';
139
144
  break;
140
145
  case 'receive-shadows':
141
146
  this.receiveShadows = parseBool(newValue, true);
@@ -1,7 +1,7 @@
1
1
  import { RigidBodyComponent, Vec3 } from 'playcanvas';
2
2
 
3
3
  import { ComponentElement } from './component';
4
- import { parseEnum, parseNumber, parseVec3 } from '../utils';
4
+ import { parseEnum, parseNumber, parseVec3 } from '../parse';
5
5
 
6
6
  /**
7
7
  * The RigidBodyComponentElement interface provides properties and methods for manipulating
@@ -187,7 +187,7 @@ class RigidBodyComponentElement extends ComponentElement {
187
187
  return [...super.observedAttributes, 'angular-damping', 'angular-factor', 'friction', 'linear-damping', 'linear-factor', 'mass', 'restitution', 'rolling-friction', 'type'];
188
188
  }
189
189
 
190
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
190
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
191
191
  super.attributeChangedCallback(name, _oldValue, newValue);
192
192
 
193
193
  switch (name) {
@@ -1,7 +1,7 @@
1
1
  import { SCALEMODE_BLEND, SCALEMODE_NONE, ScreenComponent, Vec2 } from 'playcanvas';
2
2
 
3
3
  import { ComponentElement } from './component';
4
- import { parseBool, parseNumber, parseVec2 } from '../utils';
4
+ import { parseBool, parseNumber, parseVec2 } from '../parse';
5
5
 
6
6
  /**
7
7
  * The ScreenComponentElement interface provides properties and methods for manipulating
@@ -126,7 +126,7 @@ class ScreenComponentElement extends ComponentElement {
126
126
  ];
127
127
  }
128
128
 
129
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
129
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
130
130
  super.attributeChangedCallback(name, _oldValue, newValue);
131
131
 
132
132
  switch (name) {
@@ -3,7 +3,7 @@ import { Color, Quat, ScriptComponent, Script, Vec2, Vec3, Vec4 } from 'playcanv
3
3
  import { AssetElement } from '../asset';
4
4
  import { ComponentElement } from './component';
5
5
  import { ScriptElement } from './script';
6
- import { getEntity, parseBool, parseColor, parseComponents, parseNumber, parseQuat, parseVec2, parseVec3, parseVec4 } from '../utils';
6
+ import { getEntity, parseBool, parseColor, parseComponents, parseNumber, parseQuat, parseVec2, parseVec3, parseVec4 } from '../parse';
7
7
 
8
8
  /**
9
9
  * Attributes on `pc-script` that never map to script attributes: the element's own API (derived
@@ -131,7 +131,7 @@ const colorConversion: Conversion = (rest, raw) => {
131
131
  };
132
132
 
133
133
  /**
134
- * The conversion prefixes recognised in script attribute values, mapped to the conversion each
134
+ * The conversion prefixes recognized in script attribute values, mapped to the conversion each
135
135
  * performs. These keys are the single source of truth for the prefix vocabulary: they drive both
136
136
  * the conversion in `convertAttributes` and the has-a-prefix test in `setScriptProperty`, so a
137
137
  * prefix added here is automatically known to both.
@@ -148,10 +148,10 @@ const CONVERSIONS = new Map<string, Conversion>([
148
148
  /**
149
149
  * Matches a value against the conversion prefixes. A prefix is the text before the first colon,
150
150
  * so a value whose remainder itself contains colons (`asset:a:b`) still resolves, and a value
151
- * with an unrecognised prefix (`https://...`) or no colon does not match.
151
+ * with an unrecognized prefix (`https://...`) or no colon does not match.
152
152
  * @param value - The value to inspect.
153
153
  * @returns The matching converter and the text after the prefix, or `null` if the value carries
154
- * no recognised prefix.
154
+ * no recognized prefix.
155
155
  */
156
156
  const matchConversion = (value: string) => {
157
157
  const index = value.indexOf(':');
@@ -1,7 +1,7 @@
1
1
  import { Script } from 'playcanvas';
2
2
 
3
3
  import { AsyncElement } from '../async-element';
4
- import { parseBool } from '../utils';
4
+ import { parseBool } from '../parse';
5
5
 
6
6
  /**
7
7
  * The ScriptElement interface provides properties and methods for manipulating
@@ -28,6 +28,13 @@ import { parseBool } from '../utils';
28
28
  *
29
29
  * The element becomes ready once its script instance has been created by the parent
30
30
  * `<pc-scripts>` element.
31
+ *
32
+ * @fires {CustomEvent} scriptattributeschange - Fired when the script's attributes change. The
33
+ * `detail` carries the new `attributes` object. Bubbles.
34
+ * @fires {CustomEvent} scriptenablechange - Fired when the script's enabled state changes. The
35
+ * `detail` carries the new `enabled` state. Bubbles.
36
+ * @fires {CustomEvent} scriptnamechange - Fired when the script is renamed on a live element. The
37
+ * `detail` carries `oldName` and `newName`. Bubbles.
31
38
  */
32
39
  class ScriptElement extends AsyncElement {
33
40
  private _attributes: Record<string, any> = {};
@@ -148,7 +155,7 @@ class ScriptElement extends AsyncElement {
148
155
  return ['attributes', 'enabled', 'name'];
149
156
  }
150
157
 
151
- attributeChangedCallback(name: string, oldValue: string, newValue: string) {
158
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {
152
159
  switch (name) {
153
160
  case 'attributes':
154
161
  if (newValue === null) {
@@ -1,7 +1,7 @@
1
1
  import { ORIENTATION_HORIZONTAL, ORIENTATION_VERTICAL, ScrollbarComponent } from 'playcanvas';
2
2
 
3
3
  import { ComponentElement } from './component';
4
- import { getEntity, parseEnum, parseNumber } from '../utils';
4
+ import { getEntity, parseEnum, parseNumber } from '../parse';
5
5
 
6
6
  const orientations = new Map<'horizontal' | 'vertical', number>([
7
7
  ['horizontal', ORIENTATION_HORIZONTAL],
@@ -142,7 +142,7 @@ class ScrollbarComponentElement extends ComponentElement {
142
142
  ];
143
143
  }
144
144
 
145
- attributeChangedCallback(name: string, _oldValue: string, newValue: string) {
145
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
146
146
  super.attributeChangedCallback(name, _oldValue, newValue);
147
147
 
148
148
  switch (name) {
@@ -156,7 +156,7 @@ class ScrollbarComponentElement extends ComponentElement {
156
156
  this.handleSize = parseNumber(newValue, 0.5, name);
157
157
  break;
158
158
  case 'handle':
159
- this.handle = newValue;
159
+ this.handle = newValue ?? '';
160
160
  break;
161
161
  }
162
162
  }