@playcanvas/web-components 0.2.12 → 0.5.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/LICENSE +21 -21
- package/README.md +84 -84
- package/dist/components/element-component.d.ts +12 -0
- package/dist/components/light-component.d.ts +48 -0
- package/dist/components/splat-component.d.ts +0 -13
- package/dist/pwc.cjs +298 -207
- package/dist/pwc.cjs.map +1 -1
- package/dist/pwc.js +298 -207
- 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 +299 -208
- package/dist/pwc.mjs.map +1 -1
- package/package.json +76 -64
- package/src/app.ts +612 -606
- package/src/asset.ts +159 -159
- package/src/async-element.ts +46 -46
- package/src/colors.ts +150 -150
- package/src/components/camera-component.ts +557 -557
- package/src/components/collision-component.ts +183 -183
- package/src/components/component.ts +97 -97
- package/src/components/element-component.ts +367 -341
- package/src/components/light-component.ts +570 -466
- package/src/components/listener-component.ts +30 -30
- package/src/components/particlesystem-component.ts +155 -155
- package/src/components/render-component.ts +147 -147
- package/src/components/rigidbody-component.ts +227 -227
- package/src/components/screen-component.ts +157 -157
- package/src/components/script-component.ts +270 -270
- package/src/components/script.ts +90 -90
- package/src/components/sound-component.ts +230 -230
- package/src/components/sound-slot.ts +288 -288
- package/src/components/splat-component.ts +102 -133
- package/src/entity.ts +360 -360
- package/src/index.ts +63 -63
- package/src/material.ts +141 -141
- package/src/model.ts +111 -111
- package/src/module.ts +43 -43
- package/src/scene.ts +217 -217
- package/src/sky.ts +293 -293
- package/src/utils.ts +71 -71
|
@@ -1,270 +1,270 @@
|
|
|
1
|
-
import { Color, ScriptComponent, Script, Vec2, Vec3, Vec4 } from 'playcanvas';
|
|
2
|
-
|
|
3
|
-
import { AssetElement } from '../asset';
|
|
4
|
-
import { ComponentElement } from './component';
|
|
5
|
-
import { EntityElement } from '../entity';
|
|
6
|
-
import { ScriptElement } from './script';
|
|
7
|
-
|
|
8
|
-
// Add these interfaces at the top of the file, after the imports
|
|
9
|
-
interface ScriptAttributesChangeEvent extends CustomEvent {
|
|
10
|
-
detail: { attributes: any };
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface ScriptEnableChangeEvent extends CustomEvent {
|
|
14
|
-
detail: { enabled: boolean };
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Add this interface before the ScriptComponentElement class
|
|
18
|
-
declare global {
|
|
19
|
-
interface HTMLElementEventMap {
|
|
20
|
-
'scriptattributeschange': ScriptAttributesChangeEvent;
|
|
21
|
-
'scriptenablechange': ScriptEnableChangeEvent;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* The ScriptComponentElement interface provides properties and methods for manipulating
|
|
27
|
-
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-scripts/ | `<pc-scripts>`} elements.
|
|
28
|
-
* The ScriptComponentElement interface also inherits the properties and methods of the
|
|
29
|
-
* {@link HTMLElement} interface.
|
|
30
|
-
*
|
|
31
|
-
* @category Components
|
|
32
|
-
*/
|
|
33
|
-
class ScriptComponentElement extends ComponentElement {
|
|
34
|
-
private observer: MutationObserver;
|
|
35
|
-
|
|
36
|
-
/** @ignore */
|
|
37
|
-
constructor() {
|
|
38
|
-
super('script');
|
|
39
|
-
|
|
40
|
-
// Create mutation observer to watch for child script elements
|
|
41
|
-
this.observer = new MutationObserver(this.handleMutations.bind(this));
|
|
42
|
-
this.observer.observe(this, {
|
|
43
|
-
childList: true
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// Listen for script attribute and enable changes
|
|
47
|
-
this.addEventListener('scriptattributeschange', this.handleScriptAttributesChange.bind(this));
|
|
48
|
-
this.addEventListener('scriptenablechange', this.handleScriptEnableChange.bind(this));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
initComponent() {
|
|
52
|
-
// Handle initial script elements
|
|
53
|
-
this.querySelectorAll<ScriptElement>(':scope > pc-script').forEach((scriptElement) => {
|
|
54
|
-
const scriptName = scriptElement.getAttribute('name');
|
|
55
|
-
const attributes = scriptElement.getAttribute('attributes');
|
|
56
|
-
if (scriptName) {
|
|
57
|
-
this.createScript(scriptName, attributes);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Recursively converts raw attribute data into proper PlayCanvas types. Supported conversions:
|
|
64
|
-
* - "asset:assetId" → resolves to an Asset instance
|
|
65
|
-
* - "entity:entityId" → resolves to an Entity instance
|
|
66
|
-
* - "vec2:1,2" → new Vec2(1,2)
|
|
67
|
-
* - "vec3:1,2,3" → new Vec3(1,2,3)
|
|
68
|
-
* - "vec4:1,2,3,4" → new Vec4(1,2,3,4)
|
|
69
|
-
* - "color:1,0.5,0.5,1" → new Color(1,0.5,0.5,1)
|
|
70
|
-
* @param item - The item to convert.
|
|
71
|
-
* @returns The converted item.
|
|
72
|
-
*/
|
|
73
|
-
private convertAttributes(item: any): any {
|
|
74
|
-
if (typeof item === 'string') {
|
|
75
|
-
if (item.startsWith('asset:')) {
|
|
76
|
-
const assetId = item.slice(6);
|
|
77
|
-
const assetElement = document.querySelector(`pc-asset#${assetId}`) as AssetElement;
|
|
78
|
-
if (assetElement) {
|
|
79
|
-
return assetElement.asset;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
if (item.startsWith('entity:')) {
|
|
83
|
-
const entityId = item.slice(7);
|
|
84
|
-
const entityElement = document.querySelector(`pc-entity[name="${entityId}"]`) as EntityElement;
|
|
85
|
-
if (entityElement) {
|
|
86
|
-
return entityElement.entity;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
if (item.startsWith('vec2:')) {
|
|
90
|
-
const parts = item.slice(5).split(',').map(Number);
|
|
91
|
-
if (parts.length === 2 && parts.every(v => !isNaN(v))) {
|
|
92
|
-
return new Vec2(parts[0], parts[1]);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
if (item.startsWith('vec3:')) {
|
|
96
|
-
const parts = item.slice(5).split(',').map(Number);
|
|
97
|
-
if (parts.length === 3 && parts.every(v => !isNaN(v))) {
|
|
98
|
-
return new Vec3(parts[0], parts[1], parts[2]);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
if (item.startsWith('vec4:')) {
|
|
102
|
-
const parts = item.slice(5).split(',').map(Number);
|
|
103
|
-
if (parts.length === 4 && parts.every(v => !isNaN(v))) {
|
|
104
|
-
return new Vec4(parts[0], parts[1], parts[2], parts[3]);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
if (item.startsWith('color:')) {
|
|
108
|
-
const parts = item.slice(6).split(',').map(Number);
|
|
109
|
-
if (parts.length === 4 && parts.every(v => !isNaN(v))) {
|
|
110
|
-
return new Color(parts[0], parts[1], parts[2], parts[3]);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return item;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (Array.isArray(item)) {
|
|
117
|
-
// If it's an array of objects, convert each element individually.
|
|
118
|
-
if (item.length > 0 && typeof item[0] === 'object') {
|
|
119
|
-
return item.map((el: any) => this.convertAttributes(el));
|
|
120
|
-
}
|
|
121
|
-
// Otherwise, leave the numeric array unchanged but process each element.
|
|
122
|
-
return item.map((el: any) => this.convertAttributes(el));
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (item && typeof item === 'object') {
|
|
126
|
-
const result: any = {};
|
|
127
|
-
for (const key in item) {
|
|
128
|
-
result[key] = this.convertAttributes(item[key]);
|
|
129
|
-
}
|
|
130
|
-
return result;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return item;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Preprocess the attributes object by converting its values.
|
|
138
|
-
* @param attrs - The attributes object to preprocess.
|
|
139
|
-
* @returns The preprocessed attributes object.
|
|
140
|
-
*/
|
|
141
|
-
private preprocessAttributes(attrs: any): any {
|
|
142
|
-
return this.convertAttributes(attrs);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Recursively merge properties from source into target.
|
|
147
|
-
* @param target - The target object to merge into.
|
|
148
|
-
* @param source - The source object to merge from.
|
|
149
|
-
* @returns The merged object.
|
|
150
|
-
*/
|
|
151
|
-
private mergeDeep(target: any, source: any): any {
|
|
152
|
-
for (const key in source) {
|
|
153
|
-
if (
|
|
154
|
-
source[key] &&
|
|
155
|
-
typeof source[key] === 'object' &&
|
|
156
|
-
!Array.isArray(source[key])
|
|
157
|
-
) {
|
|
158
|
-
if (!target[key] || typeof target[key] !== 'object') {
|
|
159
|
-
target[key] = {};
|
|
160
|
-
}
|
|
161
|
-
this.mergeDeep(target[key], source[key]);
|
|
162
|
-
} else {
|
|
163
|
-
target[key] = source[key];
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return target;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Update script attributes by merging preprocessed values into the script.
|
|
171
|
-
* @param script - The script to update.
|
|
172
|
-
* @param attributes - The attributes to merge into the script.
|
|
173
|
-
*/
|
|
174
|
-
private applyAttributes(script: any, attributes: string | null) {
|
|
175
|
-
try {
|
|
176
|
-
const attributesObject = attributes ? JSON.parse(attributes) : {};
|
|
177
|
-
const converted = this.convertAttributes(attributesObject);
|
|
178
|
-
this.mergeDeep(script, converted);
|
|
179
|
-
} catch (error) {
|
|
180
|
-
console.error(`Error parsing attributes JSON string ${attributes}:`, error);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
private handleScriptAttributesChange(event: ScriptAttributesChangeEvent) {
|
|
185
|
-
const scriptElement = event.target as ScriptElement;
|
|
186
|
-
const scriptName = scriptElement.getAttribute('name');
|
|
187
|
-
if (!scriptName || !this.component) return;
|
|
188
|
-
|
|
189
|
-
const script = this.component.get(scriptName);
|
|
190
|
-
if (script) {
|
|
191
|
-
this.applyAttributes(script, event.detail.attributes);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
private handleScriptEnableChange(event: ScriptEnableChangeEvent) {
|
|
196
|
-
const scriptElement = event.target as ScriptElement;
|
|
197
|
-
const scriptName = scriptElement.getAttribute('name');
|
|
198
|
-
if (!scriptName || !this.component) return;
|
|
199
|
-
|
|
200
|
-
const script = this.component.get(scriptName);
|
|
201
|
-
if (script) {
|
|
202
|
-
script.enabled = event.detail.enabled;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
private createScript(name: string, attributes: string | null): Script | null {
|
|
207
|
-
if (!this.component) return null;
|
|
208
|
-
|
|
209
|
-
let attributesObject = {};
|
|
210
|
-
if (attributes) {
|
|
211
|
-
try {
|
|
212
|
-
attributesObject = JSON.parse(attributes);
|
|
213
|
-
// Preprocess attributes: convert arrays or strings into vectors, colors, asset references, etc.
|
|
214
|
-
attributesObject = this.preprocessAttributes(attributesObject);
|
|
215
|
-
} catch (error) {
|
|
216
|
-
console.error(`Error parsing attributes JSON string ${attributes}:`, error);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
return this.component.create(name, {
|
|
220
|
-
properties: attributesObject
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
private destroyScript(name: string): void {
|
|
225
|
-
if (!this.component) return;
|
|
226
|
-
this.component.destroy(name);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
private handleMutations(mutations: MutationRecord[]) {
|
|
230
|
-
for (const mutation of mutations) {
|
|
231
|
-
// Handle added nodes
|
|
232
|
-
mutation.addedNodes.forEach((node) => {
|
|
233
|
-
if (node instanceof HTMLElement && node.tagName.toLowerCase() === 'pc-script') {
|
|
234
|
-
const scriptName = node.getAttribute('name');
|
|
235
|
-
const attributes = node.getAttribute('attributes');
|
|
236
|
-
if (scriptName) {
|
|
237
|
-
this.createScript(scriptName, attributes);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
// Handle removed nodes
|
|
243
|
-
mutation.removedNodes.forEach((node) => {
|
|
244
|
-
if (node instanceof HTMLElement && node.tagName.toLowerCase() === 'pc-script') {
|
|
245
|
-
const scriptName = node.getAttribute('name');
|
|
246
|
-
if (scriptName) {
|
|
247
|
-
this.destroyScript(scriptName);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
disconnectedCallback() {
|
|
255
|
-
this.observer.disconnect();
|
|
256
|
-
super.disconnectedCallback?.();
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Gets the underlying PlayCanvas script component.
|
|
261
|
-
* @returns The script component.
|
|
262
|
-
*/
|
|
263
|
-
get component(): ScriptComponent | null {
|
|
264
|
-
return super.component as ScriptComponent | null;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
customElements.define('pc-scripts', ScriptComponentElement);
|
|
269
|
-
|
|
270
|
-
export { ScriptComponentElement };
|
|
1
|
+
import { Color, ScriptComponent, Script, Vec2, Vec3, Vec4 } from 'playcanvas';
|
|
2
|
+
|
|
3
|
+
import { AssetElement } from '../asset';
|
|
4
|
+
import { ComponentElement } from './component';
|
|
5
|
+
import { EntityElement } from '../entity';
|
|
6
|
+
import { ScriptElement } from './script';
|
|
7
|
+
|
|
8
|
+
// Add these interfaces at the top of the file, after the imports
|
|
9
|
+
interface ScriptAttributesChangeEvent extends CustomEvent {
|
|
10
|
+
detail: { attributes: any };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface ScriptEnableChangeEvent extends CustomEvent {
|
|
14
|
+
detail: { enabled: boolean };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Add this interface before the ScriptComponentElement class
|
|
18
|
+
declare global {
|
|
19
|
+
interface HTMLElementEventMap {
|
|
20
|
+
'scriptattributeschange': ScriptAttributesChangeEvent;
|
|
21
|
+
'scriptenablechange': ScriptEnableChangeEvent;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The ScriptComponentElement interface provides properties and methods for manipulating
|
|
27
|
+
* {@link https://developer.playcanvas.com/user-manual/web-components/tags/pc-scripts/ | `<pc-scripts>`} elements.
|
|
28
|
+
* The ScriptComponentElement interface also inherits the properties and methods of the
|
|
29
|
+
* {@link HTMLElement} interface.
|
|
30
|
+
*
|
|
31
|
+
* @category Components
|
|
32
|
+
*/
|
|
33
|
+
class ScriptComponentElement extends ComponentElement {
|
|
34
|
+
private observer: MutationObserver;
|
|
35
|
+
|
|
36
|
+
/** @ignore */
|
|
37
|
+
constructor() {
|
|
38
|
+
super('script');
|
|
39
|
+
|
|
40
|
+
// Create mutation observer to watch for child script elements
|
|
41
|
+
this.observer = new MutationObserver(this.handleMutations.bind(this));
|
|
42
|
+
this.observer.observe(this, {
|
|
43
|
+
childList: true
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Listen for script attribute and enable changes
|
|
47
|
+
this.addEventListener('scriptattributeschange', this.handleScriptAttributesChange.bind(this));
|
|
48
|
+
this.addEventListener('scriptenablechange', this.handleScriptEnableChange.bind(this));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
initComponent() {
|
|
52
|
+
// Handle initial script elements
|
|
53
|
+
this.querySelectorAll<ScriptElement>(':scope > pc-script').forEach((scriptElement) => {
|
|
54
|
+
const scriptName = scriptElement.getAttribute('name');
|
|
55
|
+
const attributes = scriptElement.getAttribute('attributes');
|
|
56
|
+
if (scriptName) {
|
|
57
|
+
this.createScript(scriptName, attributes);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Recursively converts raw attribute data into proper PlayCanvas types. Supported conversions:
|
|
64
|
+
* - "asset:assetId" → resolves to an Asset instance
|
|
65
|
+
* - "entity:entityId" → resolves to an Entity instance
|
|
66
|
+
* - "vec2:1,2" → new Vec2(1,2)
|
|
67
|
+
* - "vec3:1,2,3" → new Vec3(1,2,3)
|
|
68
|
+
* - "vec4:1,2,3,4" → new Vec4(1,2,3,4)
|
|
69
|
+
* - "color:1,0.5,0.5,1" → new Color(1,0.5,0.5,1)
|
|
70
|
+
* @param item - The item to convert.
|
|
71
|
+
* @returns The converted item.
|
|
72
|
+
*/
|
|
73
|
+
private convertAttributes(item: any): any {
|
|
74
|
+
if (typeof item === 'string') {
|
|
75
|
+
if (item.startsWith('asset:')) {
|
|
76
|
+
const assetId = item.slice(6);
|
|
77
|
+
const assetElement = document.querySelector(`pc-asset#${assetId}`) as AssetElement;
|
|
78
|
+
if (assetElement) {
|
|
79
|
+
return assetElement.asset;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (item.startsWith('entity:')) {
|
|
83
|
+
const entityId = item.slice(7);
|
|
84
|
+
const entityElement = document.querySelector(`pc-entity[name="${entityId}"]`) as EntityElement;
|
|
85
|
+
if (entityElement) {
|
|
86
|
+
return entityElement.entity;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (item.startsWith('vec2:')) {
|
|
90
|
+
const parts = item.slice(5).split(',').map(Number);
|
|
91
|
+
if (parts.length === 2 && parts.every(v => !isNaN(v))) {
|
|
92
|
+
return new Vec2(parts[0], parts[1]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (item.startsWith('vec3:')) {
|
|
96
|
+
const parts = item.slice(5).split(',').map(Number);
|
|
97
|
+
if (parts.length === 3 && parts.every(v => !isNaN(v))) {
|
|
98
|
+
return new Vec3(parts[0], parts[1], parts[2]);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (item.startsWith('vec4:')) {
|
|
102
|
+
const parts = item.slice(5).split(',').map(Number);
|
|
103
|
+
if (parts.length === 4 && parts.every(v => !isNaN(v))) {
|
|
104
|
+
return new Vec4(parts[0], parts[1], parts[2], parts[3]);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (item.startsWith('color:')) {
|
|
108
|
+
const parts = item.slice(6).split(',').map(Number);
|
|
109
|
+
if (parts.length === 4 && parts.every(v => !isNaN(v))) {
|
|
110
|
+
return new Color(parts[0], parts[1], parts[2], parts[3]);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return item;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (Array.isArray(item)) {
|
|
117
|
+
// If it's an array of objects, convert each element individually.
|
|
118
|
+
if (item.length > 0 && typeof item[0] === 'object') {
|
|
119
|
+
return item.map((el: any) => this.convertAttributes(el));
|
|
120
|
+
}
|
|
121
|
+
// Otherwise, leave the numeric array unchanged but process each element.
|
|
122
|
+
return item.map((el: any) => this.convertAttributes(el));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (item && typeof item === 'object') {
|
|
126
|
+
const result: any = {};
|
|
127
|
+
for (const key in item) {
|
|
128
|
+
result[key] = this.convertAttributes(item[key]);
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return item;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Preprocess the attributes object by converting its values.
|
|
138
|
+
* @param attrs - The attributes object to preprocess.
|
|
139
|
+
* @returns The preprocessed attributes object.
|
|
140
|
+
*/
|
|
141
|
+
private preprocessAttributes(attrs: any): any {
|
|
142
|
+
return this.convertAttributes(attrs);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Recursively merge properties from source into target.
|
|
147
|
+
* @param target - The target object to merge into.
|
|
148
|
+
* @param source - The source object to merge from.
|
|
149
|
+
* @returns The merged object.
|
|
150
|
+
*/
|
|
151
|
+
private mergeDeep(target: any, source: any): any {
|
|
152
|
+
for (const key in source) {
|
|
153
|
+
if (
|
|
154
|
+
source[key] &&
|
|
155
|
+
typeof source[key] === 'object' &&
|
|
156
|
+
!Array.isArray(source[key])
|
|
157
|
+
) {
|
|
158
|
+
if (!target[key] || typeof target[key] !== 'object') {
|
|
159
|
+
target[key] = {};
|
|
160
|
+
}
|
|
161
|
+
this.mergeDeep(target[key], source[key]);
|
|
162
|
+
} else {
|
|
163
|
+
target[key] = source[key];
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return target;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Update script attributes by merging preprocessed values into the script.
|
|
171
|
+
* @param script - The script to update.
|
|
172
|
+
* @param attributes - The attributes to merge into the script.
|
|
173
|
+
*/
|
|
174
|
+
private applyAttributes(script: any, attributes: string | null) {
|
|
175
|
+
try {
|
|
176
|
+
const attributesObject = attributes ? JSON.parse(attributes) : {};
|
|
177
|
+
const converted = this.convertAttributes(attributesObject);
|
|
178
|
+
this.mergeDeep(script, converted);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
console.error(`Error parsing attributes JSON string ${attributes}:`, error);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private handleScriptAttributesChange(event: ScriptAttributesChangeEvent) {
|
|
185
|
+
const scriptElement = event.target as ScriptElement;
|
|
186
|
+
const scriptName = scriptElement.getAttribute('name');
|
|
187
|
+
if (!scriptName || !this.component) return;
|
|
188
|
+
|
|
189
|
+
const script = this.component.get(scriptName);
|
|
190
|
+
if (script) {
|
|
191
|
+
this.applyAttributes(script, event.detail.attributes);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private handleScriptEnableChange(event: ScriptEnableChangeEvent) {
|
|
196
|
+
const scriptElement = event.target as ScriptElement;
|
|
197
|
+
const scriptName = scriptElement.getAttribute('name');
|
|
198
|
+
if (!scriptName || !this.component) return;
|
|
199
|
+
|
|
200
|
+
const script = this.component.get(scriptName);
|
|
201
|
+
if (script) {
|
|
202
|
+
script.enabled = event.detail.enabled;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private createScript(name: string, attributes: string | null): Script | null {
|
|
207
|
+
if (!this.component) return null;
|
|
208
|
+
|
|
209
|
+
let attributesObject = {};
|
|
210
|
+
if (attributes) {
|
|
211
|
+
try {
|
|
212
|
+
attributesObject = JSON.parse(attributes);
|
|
213
|
+
// Preprocess attributes: convert arrays or strings into vectors, colors, asset references, etc.
|
|
214
|
+
attributesObject = this.preprocessAttributes(attributesObject);
|
|
215
|
+
} catch (error) {
|
|
216
|
+
console.error(`Error parsing attributes JSON string ${attributes}:`, error);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return this.component.create(name, {
|
|
220
|
+
properties: attributesObject
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private destroyScript(name: string): void {
|
|
225
|
+
if (!this.component) return;
|
|
226
|
+
this.component.destroy(name);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private handleMutations(mutations: MutationRecord[]) {
|
|
230
|
+
for (const mutation of mutations) {
|
|
231
|
+
// Handle added nodes
|
|
232
|
+
mutation.addedNodes.forEach((node) => {
|
|
233
|
+
if (node instanceof HTMLElement && node.tagName.toLowerCase() === 'pc-script') {
|
|
234
|
+
const scriptName = node.getAttribute('name');
|
|
235
|
+
const attributes = node.getAttribute('attributes');
|
|
236
|
+
if (scriptName) {
|
|
237
|
+
this.createScript(scriptName, attributes);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Handle removed nodes
|
|
243
|
+
mutation.removedNodes.forEach((node) => {
|
|
244
|
+
if (node instanceof HTMLElement && node.tagName.toLowerCase() === 'pc-script') {
|
|
245
|
+
const scriptName = node.getAttribute('name');
|
|
246
|
+
if (scriptName) {
|
|
247
|
+
this.destroyScript(scriptName);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
disconnectedCallback() {
|
|
255
|
+
this.observer.disconnect();
|
|
256
|
+
super.disconnectedCallback?.();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Gets the underlying PlayCanvas script component.
|
|
261
|
+
* @returns The script component.
|
|
262
|
+
*/
|
|
263
|
+
get component(): ScriptComponent | null {
|
|
264
|
+
return super.component as ScriptComponent | null;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
customElements.define('pc-scripts', ScriptComponentElement);
|
|
269
|
+
|
|
270
|
+
export { ScriptComponentElement };
|