@playcanvas/web-components 0.15.0 → 0.17.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.cts +14 -13
- package/dist/app.d.ts +14 -13
- package/dist/async-element.d.cts +13 -13
- package/dist/async-element.d.ts +13 -13
- package/dist/components/anim-clip.d.cts +127 -0
- package/dist/components/anim-clip.d.ts +127 -0
- package/dist/components/anim-component.d.cts +235 -0
- package/dist/components/anim-component.d.ts +235 -0
- package/dist/components/{listener-component.d.cts → audio-listener-component.d.cts} +7 -5
- package/dist/components/{listener-component.d.ts → audio-listener-component.d.ts} +7 -5
- package/dist/components/button-component.d.cts +5 -1
- package/dist/components/button-component.d.ts +5 -1
- package/dist/components/camera-component.d.cts +2 -0
- package/dist/components/camera-component.d.ts +2 -0
- package/dist/components/collision-component.d.cts +5 -1
- package/dist/components/collision-component.d.ts +5 -1
- package/dist/components/component.d.cts +3 -2
- package/dist/components/component.d.ts +3 -2
- package/dist/components/element-component.d.cts +7 -0
- package/dist/components/element-component.d.ts +7 -0
- package/dist/components/gsplat-component.d.cts +2 -0
- package/dist/components/gsplat-component.d.ts +2 -0
- package/dist/components/joint-component.d.cts +2 -0
- package/dist/components/joint-component.d.ts +2 -0
- package/dist/components/{layoutchild-component.d.cts → layout-child-component.d.cts} +3 -1
- package/dist/components/{layoutchild-component.d.ts → layout-child-component.d.ts} +3 -1
- package/dist/components/{layoutgroup-component.d.cts → layout-group-component.d.cts} +3 -1
- package/dist/components/{layoutgroup-component.d.ts → layout-group-component.d.ts} +3 -1
- package/dist/components/light-component.d.cts +2 -0
- package/dist/components/light-component.d.ts +2 -0
- package/dist/components/{particlesystem-component.d.cts → particle-system-component.d.cts} +3 -1
- package/dist/components/{particlesystem-component.d.ts → particle-system-component.d.ts} +3 -1
- package/dist/components/render-component.d.cts +2 -0
- package/dist/components/render-component.d.ts +2 -0
- package/dist/components/{rigidbody-component.d.cts → rigid-body-component.d.cts} +3 -1
- package/dist/components/{rigidbody-component.d.ts → rigid-body-component.d.ts} +3 -1
- package/dist/components/screen-component.d.cts +2 -0
- package/dist/components/screen-component.d.ts +2 -0
- package/dist/components/script-component.d.cts +23 -12
- package/dist/components/script-component.d.ts +23 -12
- package/dist/components/{script.d.cts → script-instance.d.cts} +7 -7
- package/dist/components/{script.d.ts → script-instance.d.ts} +7 -7
- package/dist/components/{scrollview-component.d.cts → scroll-view-component.d.cts} +3 -1
- package/dist/components/{scrollview-component.d.ts → scroll-view-component.d.ts} +3 -1
- package/dist/components/scrollbar-component.d.cts +2 -0
- package/dist/components/scrollbar-component.d.ts +2 -0
- package/dist/components/sound-component.d.cts +3 -1
- package/dist/components/sound-component.d.ts +3 -1
- package/dist/components/sound-slot.d.cts +2 -2
- package/dist/components/sound-slot.d.ts +2 -2
- package/dist/custom-elements.json +3154 -2005
- package/dist/entity-base.d.cts +6 -5
- package/dist/entity-base.d.ts +6 -5
- package/dist/entity-owner.d.cts +118 -0
- package/dist/entity-owner.d.ts +118 -0
- package/dist/entity.d.cts +8 -101
- package/dist/entity.d.ts +8 -101
- package/dist/index.d.cts +26 -21
- package/dist/index.d.ts +26 -21
- package/dist/model.d.cts +67 -24
- package/dist/model.d.ts +67 -24
- package/dist/pwc.cjs +1766 -619
- package/dist/pwc.cjs.map +1 -1
- package/dist/pwc.js +1766 -619
- 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 +1 -1
- package/dist/pwc.min.mjs.map +1 -1
- package/dist/pwc.mjs +1762 -618
- package/dist/pwc.mjs.map +1 -1
- package/dist/vscode.html-custom-data.json +203 -89
- package/dist/{module.d.cts → wasm.d.cts} +6 -6
- package/dist/{module.d.ts → wasm.d.ts} +6 -6
- package/dist/web-types.json +556 -273
- package/package.json +7 -7
- package/src/app.ts +45 -35
- package/src/async-element.ts +14 -14
- package/src/components/anim-clip.ts +395 -0
- package/src/components/anim-component.ts +719 -0
- package/src/components/{listener-component.ts → audio-listener-component.ts} +8 -6
- package/src/components/button-component.ts +5 -1
- package/src/components/camera-component.ts +2 -0
- package/src/components/collision-component.ts +5 -1
- package/src/components/component.ts +4 -3
- package/src/components/element-component.ts +7 -0
- package/src/components/gsplat-component.ts +2 -0
- package/src/components/joint-component.ts +2 -0
- package/src/components/{layoutchild-component.ts → layout-child-component.ts} +4 -2
- package/src/components/{layoutgroup-component.ts → layout-group-component.ts} +4 -2
- package/src/components/light-component.ts +2 -0
- package/src/components/{particlesystem-component.ts → particle-system-component.ts} +4 -2
- package/src/components/render-component.ts +2 -0
- package/src/components/{rigidbody-component.ts → rigid-body-component.ts} +4 -2
- package/src/components/screen-component.ts +2 -0
- package/src/components/script-component.ts +63 -42
- package/src/components/{script.ts → script-instance.ts} +14 -14
- package/src/components/{scrollview-component.ts → scroll-view-component.ts} +4 -2
- package/src/components/scrollbar-component.ts +2 -0
- package/src/components/sound-component.ts +4 -2
- package/src/components/sound-slot.ts +4 -4
- package/src/entity-base.ts +6 -5
- package/src/entity-owner.ts +298 -0
- package/src/entity.ts +15 -270
- package/src/index.ts +32 -24
- package/src/model.ts +159 -79
- package/src/node.ts +9 -5
- package/src/{module.ts → wasm.ts} +8 -8
package/src/model.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { ContainerResource, Entity, EventHandle } from 'playcanvas';
|
|
2
|
+
import { Vec3 } from 'playcanvas';
|
|
2
3
|
|
|
3
4
|
import { useAsset } from './asset';
|
|
4
|
-
import {
|
|
5
|
+
import { POINTER_ATTRIBUTES } from './entity-base';
|
|
6
|
+
import { buildDescendantEntities, EntityOwnerElement } from './entity-owner';
|
|
7
|
+
import { parseBool, parseTags, parseVec3 } from './parse';
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* One material assignment of a {@link HierarchyNode} with a render component: a mesh instance's
|
|
@@ -104,14 +107,42 @@ const formatHierarchy = (root: HierarchyNode, counts: ReadonlyMap<string, number
|
|
|
104
107
|
* The ModelElement interface also inherits the properties and methods of the
|
|
105
108
|
* {@link HTMLElement} interface.
|
|
106
109
|
*
|
|
107
|
-
* The element
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* hierarchy. A `pc-model` outside a `pc-app`, or referencing an unknown asset id, warns and never
|
|
113
|
-
* becomes ready.
|
|
110
|
+
* The element creates and fronts a stable host entity: `entity` is that host, created when the
|
|
111
|
+
* application builds its hierarchy and kept across `asset` changes, so the element's transform
|
|
112
|
+
* and tags are instance placement that composes with whatever transform the asset authored on
|
|
113
|
+
* its root. The instantiated content is parented beneath the host and exposed as
|
|
114
|
+
* {@link contentEntity}.
|
|
114
115
|
*
|
|
116
|
+
* The element becomes ready once its current asset selection has settled: the container asset
|
|
117
|
+
* has loaded and its content root has been parented beneath the host, the load has failed
|
|
118
|
+
* (`contentEntity` stays `null` — listen for `error`, or check `contentEntity`, to tell the
|
|
119
|
+
* outcomes apart), or no asset is assigned at all. Changing `asset` re-arms readiness and
|
|
120
|
+
* instantiates anew, so a `ready()` obtained after the change resolves against the new content.
|
|
121
|
+
* A `pc-model` outside a `pc-app`, or referencing an unknown asset id, warns and never becomes
|
|
122
|
+
* ready.
|
|
123
|
+
*
|
|
124
|
+
* The pointer events below are dispatched by the containing `<pc-app>` element when the pointer
|
|
125
|
+
* intersects the model's geometry, exactly as for `<pc-entity>` — a hit on a content node that no
|
|
126
|
+
* `pc-node` fronts resolves to this element.
|
|
127
|
+
*
|
|
128
|
+
* @attribute {boolean} enabled - The enabled state of the model.
|
|
129
|
+
* @attribute {string} name - The name of the model.
|
|
130
|
+
* @attribute {string} position - The position of the model.
|
|
131
|
+
* @attribute {string} rotation - The rotation of the model.
|
|
132
|
+
* @attribute {string} scale - The scale of the model.
|
|
133
|
+
* @attribute {string} tags - The tags of the model.
|
|
134
|
+
* @attribute {string} onpointerenter - Script to run when the pointer moves onto the model.
|
|
135
|
+
* @attribute {string} onpointerleave - Script to run when the pointer moves off the model.
|
|
136
|
+
* @attribute {string} onpointermove - Script to run when the pointer moves over the model.
|
|
137
|
+
* @attribute {string} onpointerdown - Script to run when a pointer button is pressed over the
|
|
138
|
+
* model.
|
|
139
|
+
* @attribute {string} onpointerup - Script to run when a pointer button is released over the
|
|
140
|
+
* model.
|
|
141
|
+
* @fires {PointerEvent} pointerenter - Fired when the pointer moves onto the model.
|
|
142
|
+
* @fires {PointerEvent} pointerleave - Fired when the pointer moves off the model.
|
|
143
|
+
* @fires {PointerEvent} pointermove - Fired when the pointer moves over the model.
|
|
144
|
+
* @fires {PointerEvent} pointerdown - Fired when a pointer button is pressed over the model.
|
|
145
|
+
* @fires {PointerEvent} pointerup - Fired when a pointer button is released over the model.
|
|
115
146
|
* @fires {Event} load - Fired each time a container asset finishes instantiating, including
|
|
116
147
|
* re-instantiation after `asset` changes. Does not bubble — listen on this element, or use a
|
|
117
148
|
* capture-phase listener on an ancestor.
|
|
@@ -119,16 +150,16 @@ const formatHierarchy = (root: HierarchyNode, counts: ReadonlyMap<string, number
|
|
|
119
150
|
* error in `message`. Does not bubble. The element still becomes ready — readiness means the load
|
|
120
151
|
* settled, not that it succeeded.
|
|
121
152
|
*/
|
|
122
|
-
class ModelElement extends
|
|
153
|
+
class ModelElement extends EntityOwnerElement {
|
|
123
154
|
private _asset = '';
|
|
124
155
|
|
|
125
|
-
private
|
|
156
|
+
private _contentEntity: Entity | null = null;
|
|
126
157
|
|
|
127
158
|
/**
|
|
128
|
-
* Incremented on every new load
|
|
129
|
-
* load that resumes from an await or a load callback abandons
|
|
130
|
-
* on, so a superseded load can neither instantiate a second
|
|
131
|
-
*
|
|
159
|
+
* Incremented on every new load, on disconnect, and when the host entity dies, and captured
|
|
160
|
+
* by a load when it starts. A load that resumes from an await or a load callback abandons
|
|
161
|
+
* itself if the value has moved on, so a superseded load can neither instantiate a second
|
|
162
|
+
* content root nor parent one under a host a newer cycle has already replaced.
|
|
132
163
|
*/
|
|
133
164
|
private _loadGeneration = 0;
|
|
134
165
|
|
|
@@ -142,12 +173,13 @@ class ModelElement extends AsyncElement {
|
|
|
142
173
|
private _errorHandle: EventHandle | null = null;
|
|
143
174
|
|
|
144
175
|
/**
|
|
145
|
-
* The root entity of the instantiated model
|
|
146
|
-
*
|
|
147
|
-
*
|
|
176
|
+
* The root entity of the instantiated model content, parented beneath the host entity.
|
|
177
|
+
* `null` until the container asset has loaded and been instantiated, after a failed load,
|
|
178
|
+
* and again once the element has been removed from the document.
|
|
179
|
+
* @returns The content root entity, or `null`.
|
|
148
180
|
*/
|
|
149
|
-
get
|
|
150
|
-
return this.
|
|
181
|
+
get contentEntity(): Entity | null {
|
|
182
|
+
return this._contentEntity;
|
|
151
183
|
}
|
|
152
184
|
|
|
153
185
|
/**
|
|
@@ -160,12 +192,13 @@ class ModelElement extends AsyncElement {
|
|
|
160
192
|
* is the printable form.
|
|
161
193
|
*
|
|
162
194
|
* The snapshot is plain data, computed afresh each call: it does not follow later changes
|
|
163
|
-
* to the hierarchy, and mutating it changes nothing.
|
|
195
|
+
* to the hierarchy, and mutating it changes nothing. It covers the instantiated content
|
|
196
|
+
* only — the host entity the element fronts is not part of the asset's node tree.
|
|
164
197
|
*
|
|
165
198
|
* @returns The root of the instantiated node tree, or `null`.
|
|
166
199
|
*/
|
|
167
200
|
hierarchy(): HierarchyNode | null {
|
|
168
|
-
const root = this.
|
|
201
|
+
const root = this._contentEntity;
|
|
169
202
|
if (!root) {
|
|
170
203
|
return null;
|
|
171
204
|
}
|
|
@@ -214,19 +247,59 @@ class ModelElement extends AsyncElement {
|
|
|
214
247
|
// A model outside an application is inert and never becomes ready, so awaiting it hangs.
|
|
215
248
|
// Warn rather than fail silently, naming the parent it requires, as every other misplaced
|
|
216
249
|
// element does.
|
|
217
|
-
|
|
250
|
+
const closestApp = this.closestApp;
|
|
251
|
+
if (!closestApp) {
|
|
218
252
|
const label = this._asset ? ` '${this._asset}'` : '';
|
|
219
253
|
console.warn(`pc-model${label} must be a descendant of pc-app - model not created`);
|
|
220
254
|
return;
|
|
221
255
|
}
|
|
222
|
-
|
|
256
|
+
|
|
257
|
+
// If the app is already running, create the host immediately; during a boot, the app's
|
|
258
|
+
// own sweep does it. Either way, _onBuilt starts the content load once the host is
|
|
259
|
+
// parented.
|
|
260
|
+
if (closestApp._hierarchyReady) {
|
|
261
|
+
const app = closestApp.app!;
|
|
262
|
+
|
|
263
|
+
this._createEntity(app);
|
|
264
|
+
this._buildHierarchy(app);
|
|
265
|
+
|
|
266
|
+
// A build that deferred (an unresolved pc-node above) defers the whole subtree with
|
|
267
|
+
// it - the node's bind sweeps it.
|
|
268
|
+
if (this._built) {
|
|
269
|
+
buildDescendantEntities(this, app);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
223
272
|
}
|
|
224
273
|
|
|
225
274
|
disconnectedCallback() {
|
|
275
|
+
// Destroying the host destroys the instantiated content with it, and the destroy hook
|
|
276
|
+
// resets the element. The generation guard comes first so a load suspended on an await
|
|
277
|
+
// cannot resume against the torn-down element.
|
|
226
278
|
this._loadGeneration++;
|
|
227
279
|
this._detachLoadHandlers();
|
|
228
|
-
this.
|
|
229
|
-
|
|
280
|
+
this._entity?.destroy();
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Starts (or restarts) the content load once the host has been parented. Readiness is not
|
|
285
|
+
* announced here — it tracks the content settling, not the host entering the scene graph.
|
|
286
|
+
*/
|
|
287
|
+
protected override _onBuilt() {
|
|
288
|
+
this._loadContent();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Extends the owner reset for the content: the engine's destroy cascade has already taken
|
|
293
|
+
* the content root down with the host subtree, so only the reference and the in-flight load
|
|
294
|
+
* are dropped here. The next build re-creates the host and re-instantiates the content.
|
|
295
|
+
*
|
|
296
|
+
* @param entity - The host entity that was destroyed.
|
|
297
|
+
*/
|
|
298
|
+
protected override _onEntityDestroy(entity: Entity) {
|
|
299
|
+
this._loadGeneration++;
|
|
300
|
+
this._detachLoadHandlers();
|
|
301
|
+
this._contentEntity = null;
|
|
302
|
+
super._onEntityDestroy(entity);
|
|
230
303
|
}
|
|
231
304
|
|
|
232
305
|
private _detachLoadHandlers() {
|
|
@@ -237,9 +310,9 @@ class ModelElement extends AsyncElement {
|
|
|
237
310
|
}
|
|
238
311
|
|
|
239
312
|
/**
|
|
240
|
-
* Resolves readiness and dispatches the `load` event. Called once the instantiated
|
|
241
|
-
* has been parented —
|
|
242
|
-
* model's
|
|
313
|
+
* Resolves readiness and dispatches the `load` event. Called once the instantiated content
|
|
314
|
+
* has been parented beneath the host — the host itself is already in the scene graph by
|
|
315
|
+
* then, so a ready model's content always has world transforms.
|
|
243
316
|
*/
|
|
244
317
|
private _announceLoad() {
|
|
245
318
|
this._onReady();
|
|
@@ -247,53 +320,29 @@ class ModelElement extends AsyncElement {
|
|
|
247
320
|
}
|
|
248
321
|
|
|
249
322
|
private _instantiate(container: ContainerResource) {
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
this.
|
|
254
|
-
|
|
255
|
-
// @ts-ignore
|
|
256
|
-
if (container.animations.length > 0) {
|
|
257
|
-
entity.addComponent('anim');
|
|
258
|
-
// @ts-ignore
|
|
259
|
-
entity.anim.assignAnimation('animation', container.animations[0].resource);
|
|
260
|
-
}
|
|
323
|
+
const content = container.instantiateRenderEntity();
|
|
324
|
+
this._contentEntity = content;
|
|
325
|
+
this._entity!.addChild(content);
|
|
326
|
+
this._announceLoad();
|
|
327
|
+
}
|
|
261
328
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
const parentEntityElement = this.closestEntity;
|
|
266
|
-
if (parentEntityElement) {
|
|
267
|
-
parentEntityElement.ready().then(() => {
|
|
268
|
-
if (generation !== this._loadGeneration) {
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
parentEntityElement.entity!.addChild(entity);
|
|
272
|
-
this._announceLoad();
|
|
273
|
-
});
|
|
274
|
-
} else {
|
|
275
|
-
const appElement = this.closestApp;
|
|
276
|
-
if (appElement) {
|
|
277
|
-
appElement.ready().then(() => {
|
|
278
|
-
if (generation !== this._loadGeneration) {
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
appElement.app!.root.addChild(entity);
|
|
282
|
-
this._announceLoad();
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
}
|
|
329
|
+
private _destroyContent() {
|
|
330
|
+
this._contentEntity?.destroy();
|
|
331
|
+
this._contentEntity = null;
|
|
286
332
|
}
|
|
287
333
|
|
|
288
|
-
private async
|
|
289
|
-
|
|
334
|
+
private async _loadContent() {
|
|
335
|
+
// The old content goes down synchronously, so a reader that checks after an asset change
|
|
336
|
+
// never sees the outgoing hierarchy. The host survives - components and child entities
|
|
337
|
+
// attached to it carry over to the new content.
|
|
338
|
+
this._destroyContent();
|
|
290
339
|
|
|
291
340
|
// Supersede any load already in flight - only the newest load may instantiate
|
|
292
341
|
const generation = ++this._loadGeneration;
|
|
293
342
|
this._detachLoadHandlers();
|
|
294
343
|
|
|
295
344
|
// Re-arm readiness so a waiter obtained after an asset change resolves against the new
|
|
296
|
-
//
|
|
345
|
+
// content. A no-op on first connection, where readiness is still pending.
|
|
297
346
|
this._resetReady();
|
|
298
347
|
|
|
299
348
|
const appElement = this.closestApp;
|
|
@@ -309,14 +358,25 @@ class ModelElement extends AsyncElement {
|
|
|
309
358
|
return;
|
|
310
359
|
}
|
|
311
360
|
|
|
361
|
+
// The host may not be parented yet - a model under a pc-node that has not bound, reached
|
|
362
|
+
// through the asset setter. Nothing settles here: _onBuilt re-runs this load once the
|
|
363
|
+
// host builds.
|
|
364
|
+
if (!this._entity || !this._built) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (this._asset === '') {
|
|
369
|
+
// No asset assigned is a settled selection: the element is a usable host (components
|
|
370
|
+
// attach, waiters resolve) with no content. Assigning an asset later re-arms.
|
|
371
|
+
this._onReady();
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
|
|
312
375
|
const asset = useAsset(this._asset);
|
|
313
376
|
if (!asset) {
|
|
314
|
-
//
|
|
315
|
-
// non-empty one that resolves to nothing is a dead end - say so rather than staying
|
|
377
|
+
// A non-empty id that resolves to nothing is a dead end - say so rather than staying
|
|
316
378
|
// silently pending.
|
|
317
|
-
|
|
318
|
-
console.warn(`pc-model could not find asset '${this._asset}' - model not created`);
|
|
319
|
-
}
|
|
379
|
+
console.warn(`pc-model could not find asset '${this._asset}' - model not created`);
|
|
320
380
|
return;
|
|
321
381
|
}
|
|
322
382
|
|
|
@@ -338,7 +398,7 @@ class ModelElement extends AsyncElement {
|
|
|
338
398
|
if (generation !== this._loadGeneration) {
|
|
339
399
|
return;
|
|
340
400
|
}
|
|
341
|
-
// A failed load settles readiness with a null
|
|
401
|
+
// A failed load settles readiness with a null contentEntity, mirroring pc-asset:
|
|
342
402
|
// readiness means the load settled, not that it succeeded.
|
|
343
403
|
this.dispatchEvent(
|
|
344
404
|
new ErrorEvent('error', {
|
|
@@ -350,11 +410,6 @@ class ModelElement extends AsyncElement {
|
|
|
350
410
|
}
|
|
351
411
|
}
|
|
352
412
|
|
|
353
|
-
private _unloadModel() {
|
|
354
|
-
this._entity?.destroy();
|
|
355
|
-
this._entity = null;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
413
|
/**
|
|
359
414
|
* Sets the id of the `pc-asset` to use for the model.
|
|
360
415
|
* @param value - The asset ID.
|
|
@@ -362,7 +417,7 @@ class ModelElement extends AsyncElement {
|
|
|
362
417
|
set asset(value: string) {
|
|
363
418
|
this._asset = value;
|
|
364
419
|
if (this.isConnected) {
|
|
365
|
-
this.
|
|
420
|
+
this._loadContent();
|
|
366
421
|
}
|
|
367
422
|
}
|
|
368
423
|
|
|
@@ -375,7 +430,7 @@ class ModelElement extends AsyncElement {
|
|
|
375
430
|
}
|
|
376
431
|
|
|
377
432
|
static get observedAttributes() {
|
|
378
|
-
return ['asset'];
|
|
433
|
+
return ['asset', 'enabled', 'name', 'position', 'rotation', 'scale', 'tags', ...POINTER_ATTRIBUTES];
|
|
379
434
|
}
|
|
380
435
|
|
|
381
436
|
attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null) {
|
|
@@ -383,6 +438,31 @@ class ModelElement extends AsyncElement {
|
|
|
383
438
|
case 'asset':
|
|
384
439
|
this.asset = newValue ?? '';
|
|
385
440
|
break;
|
|
441
|
+
case 'enabled':
|
|
442
|
+
this.enabled = parseBool(newValue, true);
|
|
443
|
+
break;
|
|
444
|
+
case 'name':
|
|
445
|
+
this.name = newValue ?? 'Untitled';
|
|
446
|
+
break;
|
|
447
|
+
case 'position':
|
|
448
|
+
this.position = parseVec3(newValue, Vec3.ZERO, name);
|
|
449
|
+
break;
|
|
450
|
+
case 'rotation':
|
|
451
|
+
this.rotation = parseVec3(newValue, Vec3.ZERO, name);
|
|
452
|
+
break;
|
|
453
|
+
case 'scale':
|
|
454
|
+
this.scale = parseVec3(newValue, Vec3.ONE, name);
|
|
455
|
+
break;
|
|
456
|
+
case 'tags':
|
|
457
|
+
this.tags = parseTags(newValue);
|
|
458
|
+
break;
|
|
459
|
+
case 'onpointerenter':
|
|
460
|
+
case 'onpointerleave':
|
|
461
|
+
case 'onpointerdown':
|
|
462
|
+
case 'onpointerup':
|
|
463
|
+
case 'onpointermove':
|
|
464
|
+
this._updateInlineHandler(name, newValue);
|
|
465
|
+
break;
|
|
386
466
|
}
|
|
387
467
|
}
|
|
388
468
|
}
|
package/src/node.ts
CHANGED
|
@@ -2,9 +2,9 @@ import type { Entity, EventHandle, GraphNode, Material, MeshInstance, Quat, Rend
|
|
|
2
2
|
import { Vec3 } from 'playcanvas';
|
|
3
3
|
|
|
4
4
|
import { ComponentElement } from './components/component';
|
|
5
|
-
import { buildDescendantEntities } from './entity';
|
|
6
|
-
import type { EntityElement } from './entity';
|
|
7
5
|
import { EntityBaseElement, POINTER_ATTRIBUTES } from './entity-base';
|
|
6
|
+
import { buildDescendantEntities } from './entity-owner';
|
|
7
|
+
import type { EntityOwnerElement } from './entity-owner';
|
|
8
8
|
import { MaterialElement } from './material';
|
|
9
9
|
import { ModelElement } from './model';
|
|
10
10
|
import { parseBool, parseTags, parseVec3 } from './parse';
|
|
@@ -318,7 +318,10 @@ class NodeElement extends EntityBaseElement {
|
|
|
318
318
|
* is retained untouched — a redundant edit must not flicker overrides through a revert.
|
|
319
319
|
*/
|
|
320
320
|
private _rebind() {
|
|
321
|
-
|
|
321
|
+
// A model fronts a host entity of its own; the names this element resolves are the
|
|
322
|
+
// asset's, so the search starts at the instantiated content root, not the wrapper.
|
|
323
|
+
const host = this._host;
|
|
324
|
+
const hostEntity = (host instanceof ModelElement ? host.contentEntity : host?.entity) ?? null;
|
|
322
325
|
|
|
323
326
|
if (!hostEntity || !this._name) {
|
|
324
327
|
// Host not instantiated (or nothing to look up yet): return to pending. An assigned
|
|
@@ -435,8 +438,9 @@ class NodeElement extends EntityBaseElement {
|
|
|
435
438
|
this._revertOverrides();
|
|
436
439
|
|
|
437
440
|
// Attachment points anchor to the bound node, so they cannot outlive the binding. Each
|
|
438
|
-
// destroyed entity resets its element, which the next _buildChildren re-creates
|
|
439
|
-
|
|
441
|
+
// destroyed entity resets its element, which the next _buildChildren re-creates - a
|
|
442
|
+
// model host among them re-instantiates its content when it rebuilds.
|
|
443
|
+
this.querySelectorAll<EntityOwnerElement>('pc-entity, pc-model').forEach((child) => {
|
|
440
444
|
if (child.closestEntity === this) {
|
|
441
445
|
child.entity?.destroy();
|
|
442
446
|
}
|
|
@@ -3,9 +3,9 @@ import { basisInitialize, WasmModule } from 'playcanvas';
|
|
|
3
3
|
import { AsyncElement } from './async-element';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* The
|
|
7
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-
|
|
8
|
-
* elements. The
|
|
6
|
+
* The WasmElement interface provides properties and methods for manipulating
|
|
7
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-wasm/ | `<pc-wasm>`}
|
|
8
|
+
* elements. The WasmElement interface also inherits the properties and methods of the
|
|
9
9
|
* {@link AsyncElement} interface.
|
|
10
10
|
*
|
|
11
11
|
* The attributes are read once, when the module starts loading - on the element's first
|
|
@@ -14,7 +14,7 @@ import { AsyncElement } from './async-element';
|
|
|
14
14
|
* modules configure engine-global state that never unloads, so readiness is not re-armed by
|
|
15
15
|
* removing the element, and a re-inserted element does not load again.
|
|
16
16
|
*
|
|
17
|
-
* A `<pc-
|
|
17
|
+
* A `<pc-wasm>` without a `name` warns and never becomes ready; a containing `<pc-app>` still
|
|
18
18
|
* boots.
|
|
19
19
|
*
|
|
20
20
|
* @attribute {string} name - The name of the WebAssembly module to configure, e.g. `Basis` or
|
|
@@ -24,7 +24,7 @@ import { AsyncElement } from './async-element';
|
|
|
24
24
|
* @attribute {string} fallback - The URL of the module's asm.js fallback script, used when
|
|
25
25
|
* WebAssembly is unavailable.
|
|
26
26
|
*/
|
|
27
|
-
class
|
|
27
|
+
class WasmElement extends AsyncElement {
|
|
28
28
|
private _loadPromise: Promise<void> | null = null;
|
|
29
29
|
|
|
30
30
|
connectedCallback() {
|
|
@@ -34,7 +34,7 @@ class ModuleElement extends AsyncElement {
|
|
|
34
34
|
private async _loadModule(): Promise<void> {
|
|
35
35
|
const name = this.getAttribute('name');
|
|
36
36
|
if (!name) {
|
|
37
|
-
console.warn("pc-
|
|
37
|
+
console.warn("pc-wasm requires a 'name' attribute - no module was configured");
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -74,6 +74,6 @@ class ModuleElement extends AsyncElement {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
customElements.define('pc-
|
|
77
|
+
customElements.define('pc-wasm', WasmElement);
|
|
78
78
|
|
|
79
|
-
export {
|
|
79
|
+
export { WasmElement };
|