@realitycollective/iwsdk-uiextensions 0.1.0-preview.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.

Potentially problematic release.


This version of @realitycollective/iwsdk-uiextensions might be problematic. Click here for more details.

Files changed (46) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/Examples/README.md +13 -0
  3. package/Examples/basic-window/main.ts +31 -0
  4. package/Examples/basic-window/window.uikitml +59 -0
  5. package/Examples/controls/controls.uikitml +50 -0
  6. package/Examples/controls/main.ts +44 -0
  7. package/Examples/dock-regions/main.ts +55 -0
  8. package/LICENSE +21 -0
  9. package/README.md +117 -0
  10. package/dist/components.d.ts +189 -0
  11. package/dist/components.js +97 -0
  12. package/dist/components.js.map +1 -0
  13. package/dist/factory.d.ts +55 -0
  14. package/dist/factory.js +63 -0
  15. package/dist/factory.js.map +1 -0
  16. package/dist/index.d.ts +24 -0
  17. package/dist/index.js +27 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/manager-registry.d.ts +8 -0
  20. package/dist/manager-registry.js +11 -0
  21. package/dist/manager-registry.js.map +1 -0
  22. package/dist/region-registry-store.d.ts +7 -0
  23. package/dist/region-registry-store.js +11 -0
  24. package/dist/region-registry-store.js.map +1 -0
  25. package/dist/register.d.ts +19 -0
  26. package/dist/register.js +20 -0
  27. package/dist/register.js.map +1 -0
  28. package/dist/scene-host.d.ts +23 -0
  29. package/dist/scene-host.js +145 -0
  30. package/dist/scene-host.js.map +1 -0
  31. package/dist/systems/controls-system.d.ts +24 -0
  32. package/dist/systems/controls-system.js +24 -0
  33. package/dist/systems/controls-system.js.map +1 -0
  34. package/dist/systems/dock-region-system.d.ts +230 -0
  35. package/dist/systems/dock-region-system.js +102 -0
  36. package/dist/systems/dock-region-system.js.map +1 -0
  37. package/dist/systems/dock-system.d.ts +205 -0
  38. package/dist/systems/dock-system.js +135 -0
  39. package/dist/systems/dock-system.js.map +1 -0
  40. package/dist/systems/drag-system.d.ts +280 -0
  41. package/dist/systems/drag-system.js +167 -0
  42. package/dist/systems/drag-system.js.map +1 -0
  43. package/dist/systems/window-system.d.ts +455 -0
  44. package/dist/systems/window-system.js +244 -0
  45. package/dist/systems/window-system.js.map +1 -0
  46. package/package.json +65 -0
@@ -0,0 +1,455 @@
1
+ /**
2
+ * UIWindowSystem - wires window chrome, keeps the `WindowManager` in sync
3
+ * with entities, applies focus ordering and minimize state.
4
+ *
5
+ * Reuse over recreation: the panel itself is loaded/rendered by the IWSDK's
6
+ * `PanelUISystem`; this system only discovers the chrome elements by their
7
+ * well-known ids and drives them.
8
+ */
9
+ import { type Entity } from '@iwsdk/core';
10
+ declare const UIWindowSystem_base: import("elics").SystemConstructor<import("elics").SystemSchema, {
11
+ pendingWindows: {
12
+ required: (import("elics").Component<{
13
+ windowId: {
14
+ type: import("@iwsdk/core").Types.String;
15
+ default: string;
16
+ };
17
+ title: {
18
+ type: import("@iwsdk/core").Types.String;
19
+ default: string;
20
+ };
21
+ dockMode: {
22
+ type: import("@iwsdk/core").Types.Enum;
23
+ enum: {
24
+ readonly WorldLocked: "world-locked";
25
+ readonly BodyFollow: "body-follow";
26
+ readonly HeadLocked: "head-locked";
27
+ };
28
+ default: "world-locked";
29
+ };
30
+ movable: {
31
+ type: import("@iwsdk/core").Types.Boolean;
32
+ default: true;
33
+ };
34
+ closable: {
35
+ type: import("@iwsdk/core").Types.Boolean;
36
+ default: true;
37
+ };
38
+ minimizable: {
39
+ type: import("@iwsdk/core").Types.Boolean;
40
+ default: true;
41
+ };
42
+ pinnable: {
43
+ type: import("@iwsdk/core").Types.Boolean;
44
+ default: true;
45
+ };
46
+ billboardWhileDragging: {
47
+ type: import("@iwsdk/core").Types.Boolean;
48
+ default: true;
49
+ };
50
+ dragDelay: {
51
+ type: import("@iwsdk/core").Types.Float32;
52
+ default: number;
53
+ };
54
+ followOffset: {
55
+ type: import("@iwsdk/core").Types.Vec3;
56
+ default: [number, number, number];
57
+ };
58
+ followSpeed: {
59
+ type: import("@iwsdk/core").Types.Float32;
60
+ default: number;
61
+ };
62
+ followTolerance: {
63
+ type: import("@iwsdk/core").Types.Float32;
64
+ default: number;
65
+ };
66
+ focusBias: {
67
+ type: import("@iwsdk/core").Types.Float32;
68
+ default: number;
69
+ };
70
+ targetWidth: {
71
+ type: import("@iwsdk/core").Types.Float32;
72
+ default: number;
73
+ };
74
+ targetHeight: {
75
+ type: import("@iwsdk/core").Types.Float32;
76
+ default: number;
77
+ };
78
+ }> | import("elics").Component<{
79
+ config: {
80
+ type: import("@iwsdk/core").Types.String;
81
+ default: string;
82
+ };
83
+ maxWidth: {
84
+ type: import("@iwsdk/core").Types.Float32;
85
+ default: number;
86
+ };
87
+ maxHeight: {
88
+ type: import("@iwsdk/core").Types.Float32;
89
+ default: number;
90
+ };
91
+ }> | import("elics").Component<{
92
+ document: {
93
+ type: import("@iwsdk/core").Types.Object;
94
+ default: undefined;
95
+ };
96
+ }>)[];
97
+ excluded: import("elics").Component<{
98
+ appliedDockMode: {
99
+ type: import("@iwsdk/core").Types.String;
100
+ default: string;
101
+ };
102
+ chromeWired: {
103
+ type: import("@iwsdk/core").Types.Boolean;
104
+ default: false;
105
+ };
106
+ homeDockMode: {
107
+ type: import("@iwsdk/core").Types.String;
108
+ default: string;
109
+ };
110
+ homeRegion: {
111
+ type: import("@iwsdk/core").Types.String;
112
+ default: string;
113
+ };
114
+ homePosition: {
115
+ type: import("@iwsdk/core").Types.Vec3;
116
+ default: [number, number, number];
117
+ };
118
+ homeYaw: {
119
+ type: import("@iwsdk/core").Types.Float32;
120
+ default: number;
121
+ };
122
+ }>[];
123
+ };
124
+ windows: {
125
+ required: (import("elics").Component<{
126
+ windowId: {
127
+ type: import("@iwsdk/core").Types.String;
128
+ default: string;
129
+ };
130
+ title: {
131
+ type: import("@iwsdk/core").Types.String;
132
+ default: string;
133
+ };
134
+ dockMode: {
135
+ type: import("@iwsdk/core").Types.Enum;
136
+ enum: {
137
+ readonly WorldLocked: "world-locked";
138
+ readonly BodyFollow: "body-follow";
139
+ readonly HeadLocked: "head-locked";
140
+ };
141
+ default: "world-locked";
142
+ };
143
+ movable: {
144
+ type: import("@iwsdk/core").Types.Boolean;
145
+ default: true;
146
+ };
147
+ closable: {
148
+ type: import("@iwsdk/core").Types.Boolean;
149
+ default: true;
150
+ };
151
+ minimizable: {
152
+ type: import("@iwsdk/core").Types.Boolean;
153
+ default: true;
154
+ };
155
+ pinnable: {
156
+ type: import("@iwsdk/core").Types.Boolean;
157
+ default: true;
158
+ };
159
+ billboardWhileDragging: {
160
+ type: import("@iwsdk/core").Types.Boolean;
161
+ default: true;
162
+ };
163
+ dragDelay: {
164
+ type: import("@iwsdk/core").Types.Float32;
165
+ default: number;
166
+ };
167
+ followOffset: {
168
+ type: import("@iwsdk/core").Types.Vec3;
169
+ default: [number, number, number];
170
+ };
171
+ followSpeed: {
172
+ type: import("@iwsdk/core").Types.Float32;
173
+ default: number;
174
+ };
175
+ followTolerance: {
176
+ type: import("@iwsdk/core").Types.Float32;
177
+ default: number;
178
+ };
179
+ focusBias: {
180
+ type: import("@iwsdk/core").Types.Float32;
181
+ default: number;
182
+ };
183
+ targetWidth: {
184
+ type: import("@iwsdk/core").Types.Float32;
185
+ default: number;
186
+ };
187
+ targetHeight: {
188
+ type: import("@iwsdk/core").Types.Float32;
189
+ default: number;
190
+ };
191
+ }> | import("elics").Component<{
192
+ appliedDockMode: {
193
+ type: import("@iwsdk/core").Types.String;
194
+ default: string;
195
+ };
196
+ chromeWired: {
197
+ type: import("@iwsdk/core").Types.Boolean;
198
+ default: false;
199
+ };
200
+ homeDockMode: {
201
+ type: import("@iwsdk/core").Types.String;
202
+ default: string;
203
+ };
204
+ homeRegion: {
205
+ type: import("@iwsdk/core").Types.String;
206
+ default: string;
207
+ };
208
+ homePosition: {
209
+ type: import("@iwsdk/core").Types.Vec3;
210
+ default: [number, number, number];
211
+ };
212
+ homeYaw: {
213
+ type: import("@iwsdk/core").Types.Float32;
214
+ default: number;
215
+ };
216
+ }> | import("elics").Component<{
217
+ document: {
218
+ type: import("@iwsdk/core").Types.Object;
219
+ default: undefined;
220
+ };
221
+ }>)[];
222
+ };
223
+ }, World, import("@iwsdk/core").System<import("elics").SystemSchema, {
224
+ pendingWindows: {
225
+ required: (import("elics").Component<{
226
+ windowId: {
227
+ type: import("@iwsdk/core").Types.String;
228
+ default: string;
229
+ };
230
+ title: {
231
+ type: import("@iwsdk/core").Types.String;
232
+ default: string;
233
+ };
234
+ dockMode: {
235
+ type: import("@iwsdk/core").Types.Enum;
236
+ enum: {
237
+ readonly WorldLocked: "world-locked";
238
+ readonly BodyFollow: "body-follow";
239
+ readonly HeadLocked: "head-locked";
240
+ };
241
+ default: "world-locked";
242
+ };
243
+ movable: {
244
+ type: import("@iwsdk/core").Types.Boolean;
245
+ default: true;
246
+ };
247
+ closable: {
248
+ type: import("@iwsdk/core").Types.Boolean;
249
+ default: true;
250
+ };
251
+ minimizable: {
252
+ type: import("@iwsdk/core").Types.Boolean;
253
+ default: true;
254
+ };
255
+ pinnable: {
256
+ type: import("@iwsdk/core").Types.Boolean;
257
+ default: true;
258
+ };
259
+ billboardWhileDragging: {
260
+ type: import("@iwsdk/core").Types.Boolean;
261
+ default: true;
262
+ };
263
+ dragDelay: {
264
+ type: import("@iwsdk/core").Types.Float32;
265
+ default: number;
266
+ };
267
+ followOffset: {
268
+ type: import("@iwsdk/core").Types.Vec3;
269
+ default: [number, number, number];
270
+ };
271
+ followSpeed: {
272
+ type: import("@iwsdk/core").Types.Float32;
273
+ default: number;
274
+ };
275
+ followTolerance: {
276
+ type: import("@iwsdk/core").Types.Float32;
277
+ default: number;
278
+ };
279
+ focusBias: {
280
+ type: import("@iwsdk/core").Types.Float32;
281
+ default: number;
282
+ };
283
+ targetWidth: {
284
+ type: import("@iwsdk/core").Types.Float32;
285
+ default: number;
286
+ };
287
+ targetHeight: {
288
+ type: import("@iwsdk/core").Types.Float32;
289
+ default: number;
290
+ };
291
+ }> | import("elics").Component<{
292
+ config: {
293
+ type: import("@iwsdk/core").Types.String;
294
+ default: string;
295
+ };
296
+ maxWidth: {
297
+ type: import("@iwsdk/core").Types.Float32;
298
+ default: number;
299
+ };
300
+ maxHeight: {
301
+ type: import("@iwsdk/core").Types.Float32;
302
+ default: number;
303
+ };
304
+ }> | import("elics").Component<{
305
+ document: {
306
+ type: import("@iwsdk/core").Types.Object;
307
+ default: undefined;
308
+ };
309
+ }>)[];
310
+ excluded: import("elics").Component<{
311
+ appliedDockMode: {
312
+ type: import("@iwsdk/core").Types.String;
313
+ default: string;
314
+ };
315
+ chromeWired: {
316
+ type: import("@iwsdk/core").Types.Boolean;
317
+ default: false;
318
+ };
319
+ homeDockMode: {
320
+ type: import("@iwsdk/core").Types.String;
321
+ default: string;
322
+ };
323
+ homeRegion: {
324
+ type: import("@iwsdk/core").Types.String;
325
+ default: string;
326
+ };
327
+ homePosition: {
328
+ type: import("@iwsdk/core").Types.Vec3;
329
+ default: [number, number, number];
330
+ };
331
+ homeYaw: {
332
+ type: import("@iwsdk/core").Types.Float32;
333
+ default: number;
334
+ };
335
+ }>[];
336
+ };
337
+ windows: {
338
+ required: (import("elics").Component<{
339
+ windowId: {
340
+ type: import("@iwsdk/core").Types.String;
341
+ default: string;
342
+ };
343
+ title: {
344
+ type: import("@iwsdk/core").Types.String;
345
+ default: string;
346
+ };
347
+ dockMode: {
348
+ type: import("@iwsdk/core").Types.Enum;
349
+ enum: {
350
+ readonly WorldLocked: "world-locked";
351
+ readonly BodyFollow: "body-follow";
352
+ readonly HeadLocked: "head-locked";
353
+ };
354
+ default: "world-locked";
355
+ };
356
+ movable: {
357
+ type: import("@iwsdk/core").Types.Boolean;
358
+ default: true;
359
+ };
360
+ closable: {
361
+ type: import("@iwsdk/core").Types.Boolean;
362
+ default: true;
363
+ };
364
+ minimizable: {
365
+ type: import("@iwsdk/core").Types.Boolean;
366
+ default: true;
367
+ };
368
+ pinnable: {
369
+ type: import("@iwsdk/core").Types.Boolean;
370
+ default: true;
371
+ };
372
+ billboardWhileDragging: {
373
+ type: import("@iwsdk/core").Types.Boolean;
374
+ default: true;
375
+ };
376
+ dragDelay: {
377
+ type: import("@iwsdk/core").Types.Float32;
378
+ default: number;
379
+ };
380
+ followOffset: {
381
+ type: import("@iwsdk/core").Types.Vec3;
382
+ default: [number, number, number];
383
+ };
384
+ followSpeed: {
385
+ type: import("@iwsdk/core").Types.Float32;
386
+ default: number;
387
+ };
388
+ followTolerance: {
389
+ type: import("@iwsdk/core").Types.Float32;
390
+ default: number;
391
+ };
392
+ focusBias: {
393
+ type: import("@iwsdk/core").Types.Float32;
394
+ default: number;
395
+ };
396
+ targetWidth: {
397
+ type: import("@iwsdk/core").Types.Float32;
398
+ default: number;
399
+ };
400
+ targetHeight: {
401
+ type: import("@iwsdk/core").Types.Float32;
402
+ default: number;
403
+ };
404
+ }> | import("elics").Component<{
405
+ appliedDockMode: {
406
+ type: import("@iwsdk/core").Types.String;
407
+ default: string;
408
+ };
409
+ chromeWired: {
410
+ type: import("@iwsdk/core").Types.Boolean;
411
+ default: false;
412
+ };
413
+ homeDockMode: {
414
+ type: import("@iwsdk/core").Types.String;
415
+ default: string;
416
+ };
417
+ homeRegion: {
418
+ type: import("@iwsdk/core").Types.String;
419
+ default: string;
420
+ };
421
+ homePosition: {
422
+ type: import("@iwsdk/core").Types.Vec3;
423
+ default: [number, number, number];
424
+ };
425
+ homeYaw: {
426
+ type: import("@iwsdk/core").Types.Float32;
427
+ default: number;
428
+ };
429
+ }> | import("elics").Component<{
430
+ document: {
431
+ type: import("@iwsdk/core").Types.Object;
432
+ default: undefined;
433
+ };
434
+ }>)[];
435
+ };
436
+ }>>;
437
+ export declare class UIWindowSystem extends UIWindowSystem_base {
438
+ private manager;
439
+ private entitiesById;
440
+ private localCamera;
441
+ init(): void;
442
+ update(): void;
443
+ entityFor(windowId: string): Entity | undefined;
444
+ private adoptWindow;
445
+ /** Return a window to its home: spawn region, or original placement/mode. */
446
+ returnHome(entity: Entity): void;
447
+ /** MIN when open, MAX when minimized - the label names the next action. */
448
+ private syncMinimizeLabel;
449
+ private syncPinLabel;
450
+ private releaseWindow;
451
+ private wireChrome;
452
+ private applyMinimized;
453
+ private documentOf;
454
+ }
455
+ export {};
@@ -0,0 +1,244 @@
1
+ /**
2
+ * UIWindowSystem - wires window chrome, keeps the `WindowManager` in sync
3
+ * with entities, applies focus ordering and minimize state.
4
+ *
5
+ * Reuse over recreation: the panel itself is loaded/rendered by the IWSDK's
6
+ * `PanelUISystem`; this system only discovers the chrome elements by their
7
+ * well-known ids and drives them.
8
+ */
9
+ import { PanelDocument, PanelUI, Vector3, createSystem, } from '@iwsdk/core';
10
+ import { UIDockedTo, UIWindow, UIWindowState } from '../components.js';
11
+ import { WINDOW_CHROME_IDS } from '@realitycollective/webxr-uiextensions';
12
+ import { windowManagerFor } from '../manager-registry.js';
13
+ import { minimizeLabelFor, pinLabelFor, } from '@realitycollective/webxr-uiextensions';
14
+ import { DockMode, isDockMode } from '@realitycollective/webxr-uiextensions';
15
+ let autoId = 0;
16
+ export class UIWindowSystem extends createSystem({
17
+ pendingWindows: {
18
+ required: [UIWindow, PanelUI, PanelDocument],
19
+ excluded: [UIWindowState],
20
+ },
21
+ windows: { required: [UIWindow, UIWindowState, PanelDocument] },
22
+ }) {
23
+ manager;
24
+ entitiesById = new Map();
25
+ localCamera = new Vector3();
26
+ init() {
27
+ this.manager = windowManagerFor(this.world);
28
+ this.cleanupFuncs.push(this.queries.pendingWindows.subscribe('qualify', (entity) => {
29
+ this.adoptWindow(entity);
30
+ }), this.queries.windows.subscribe('disqualify', (entity) => {
31
+ this.releaseWindow(entity);
32
+ }), this.manager.events.on('minimized', ({ id }) => this.applyMinimized(id, true)), this.manager.events.on('restored', ({ id }) => this.applyMinimized(id, false)), this.manager.events.on('minimized', (record) => this.syncMinimizeLabel(record)), this.manager.events.on('restored', (record) => this.syncMinimizeLabel(record)), this.manager.events.on('dockChanged', ({ window }) => {
33
+ const entity = this.entitiesById.get(window.id);
34
+ if (entity && entity.getValue(UIWindow, 'dockMode') !== window.dockMode) {
35
+ entity.setValue(UIWindow, 'dockMode', window.dockMode);
36
+ }
37
+ this.syncPinLabel(window);
38
+ }), this.manager.events.on('dragStarted', (window) => this.syncPinLabel(window)), this.manager.events.on('dragEnded', (window) => this.syncPinLabel(window)));
39
+ }
40
+ update() {
41
+ // Focus bias: nudge each window's document toward the viewer by a small
42
+ // amount inversely related to focus depth, so overlapping windows resolve
43
+ // in focus order. Computed in entity-local space so it holds for any
44
+ // window orientation.
45
+ for (const entity of this.queries.windows.entities) {
46
+ const id = entity.getValue(UIWindow, 'windowId');
47
+ if (!this.manager.has(id)) {
48
+ continue;
49
+ }
50
+ const document = this.documentOf(entity);
51
+ const object = entity.object3D;
52
+ if (!document || !object) {
53
+ continue;
54
+ }
55
+ const bias = entity.getValue(UIWindow, 'focusBias');
56
+ const depth = this.manager.orderOf(id);
57
+ const amount = bias * Math.max(0, this.manager.count - 1 - depth);
58
+ if (amount === 0) {
59
+ document.position.set(0, 0, 0);
60
+ continue;
61
+ }
62
+ this.camera.getWorldPosition(this.localCamera);
63
+ object.worldToLocal(this.localCamera);
64
+ if (this.localCamera.lengthSq() === 0) {
65
+ continue;
66
+ }
67
+ document.position.copy(this.localCamera.normalize().multiplyScalar(amount));
68
+ }
69
+ }
70
+ entityFor(windowId) {
71
+ return this.entitiesById.get(windowId);
72
+ }
73
+ adoptWindow(entity) {
74
+ let id = entity.getValue(UIWindow, 'windowId');
75
+ if (!id) {
76
+ id = `uix-window-${autoId++}`;
77
+ entity.setValue(UIWindow, 'windowId', id);
78
+ }
79
+ const title = entity.getValue(UIWindow, 'title');
80
+ const dockMode = entity.getValue(UIWindow, 'dockMode');
81
+ this.entitiesById.set(id, entity);
82
+ if (!this.manager.has(id)) {
83
+ this.manager.open(id, { title, dockMode });
84
+ }
85
+ this.wireChrome(entity, id, title);
86
+ // Snapshot "home" so the DOCK button can return the window: the spawn
87
+ // region if it was born docked, otherwise its placement + dock mode.
88
+ const object = entity.object3D;
89
+ entity.addComponent(UIWindowState, {
90
+ chromeWired: true,
91
+ appliedDockMode: '',
92
+ homeDockMode: dockMode,
93
+ homeRegion: entity.hasComponent(UIDockedTo)
94
+ ? entity.getValue(UIDockedTo, 'regionId')
95
+ : '',
96
+ homePosition: object ? [object.position.x, object.position.y, object.position.z] : [0, 0, 0],
97
+ homeYaw: object ? object.rotation.y : 0,
98
+ });
99
+ this.syncPinLabel({ id, dockMode, dragging: false });
100
+ }
101
+ /** Return a window to its home: spawn region, or original placement/mode. */
102
+ returnHome(entity) {
103
+ const homeRegion = entity.getValue(UIWindowState, 'homeRegion');
104
+ if (homeRegion) {
105
+ if (entity.hasComponent(UIDockedTo) &&
106
+ entity.getValue(UIDockedTo, 'regionId') === homeRegion) {
107
+ return; // already home
108
+ }
109
+ if (entity.hasComponent(UIDockedTo)) {
110
+ entity.removeComponent(UIDockedTo);
111
+ }
112
+ entity.addComponent(UIDockedTo, { regionId: homeRegion });
113
+ return;
114
+ }
115
+ if (entity.hasComponent(UIDockedTo)) {
116
+ entity.removeComponent(UIDockedTo);
117
+ }
118
+ const homeDockMode = entity.getValue(UIWindowState, 'homeDockMode');
119
+ if (isDockMode(homeDockMode)) {
120
+ entity.setValue(UIWindow, 'dockMode', homeDockMode);
121
+ }
122
+ if (homeDockMode === DockMode.WorldLocked) {
123
+ const object = entity.object3D;
124
+ const home = entity.getVectorView(UIWindowState, 'homePosition');
125
+ if (object) {
126
+ object.position.set(home[0] ?? 0, home[1] ?? 0, home[2] ?? 0);
127
+ object.rotation.set(0, entity.getValue(UIWindowState, 'homeYaw'), 0);
128
+ }
129
+ }
130
+ // Follow modes re-snap on their own (the dock system syncs the Follower).
131
+ }
132
+ /** MIN when open, MAX when minimized - the label names the next action. */
133
+ syncMinimizeLabel(record) {
134
+ const entity = this.entitiesById.get(record.id);
135
+ const minimize = entity
136
+ ? this.documentOf(entity)?.getElementById(WINDOW_CHROME_IDS.minimize)
137
+ : undefined;
138
+ minimize?.setProperties({ text: minimizeLabelFor(record) });
139
+ }
140
+ syncPinLabel(record) {
141
+ const entity = this.entitiesById.get(record.id);
142
+ const pin = entity
143
+ ? this.documentOf(entity)?.getElementById(WINDOW_CHROME_IDS.pin)
144
+ : undefined;
145
+ pin?.setProperties({ text: pinLabelFor(record) });
146
+ }
147
+ releaseWindow(entity) {
148
+ const id = entity.getValue(UIWindow, 'windowId');
149
+ if (id && this.entitiesById.get(id) === entity) {
150
+ this.entitiesById.delete(id);
151
+ if (this.manager.has(id)) {
152
+ this.manager.close(id);
153
+ }
154
+ }
155
+ }
156
+ wireChrome(entity, id, title) {
157
+ const document = this.documentOf(entity);
158
+ if (!document) {
159
+ return;
160
+ }
161
+ // IWSDK 0.5 removed PanelUI.maxWidth/maxHeight; world size is now the
162
+ // document's own concern. Fit into the requested box, preserving aspect
163
+ // ratio. Zero means "leave intrinsic" so the entity transform owns scale.
164
+ const targetWidth = entity.getValue(UIWindow, 'targetWidth') ?? 0;
165
+ const targetHeight = entity.getValue(UIWindow, 'targetHeight') ?? 0;
166
+ if (targetWidth > 0 && targetHeight > 0) {
167
+ document.setTargetDimensions(targetWidth, targetHeight);
168
+ }
169
+ const element = (elementId) => document.getElementById(elementId);
170
+ const titleEl = element(WINDOW_CHROME_IDS.title);
171
+ if (titleEl && title) {
172
+ titleEl.setProperties({ text: title });
173
+ }
174
+ // Chrome buttons live on the drag surface - keep their presses out of
175
+ // the title-bar drag handle so clicks never turn into (or arm) drags.
176
+ const swallowPress = (button) => {
177
+ button?.addEventListener('pointerdown', (event) => {
178
+ event?.stopPropagation?.();
179
+ });
180
+ };
181
+ swallowPress(element(WINDOW_CHROME_IDS.pin));
182
+ swallowPress(element(WINDOW_CHROME_IDS.dock));
183
+ swallowPress(element(WINDOW_CHROME_IDS.minimize));
184
+ swallowPress(element(WINDOW_CHROME_IDS.close));
185
+ // Any press anywhere on the window brings it to the front.
186
+ const root = element(WINDOW_CHROME_IDS.window);
187
+ root?.addEventListener('pointerdown', () => {
188
+ if (this.manager.has(id)) {
189
+ this.manager.focus(id);
190
+ }
191
+ });
192
+ const close = element(WINDOW_CHROME_IDS.close);
193
+ if (close) {
194
+ if (entity.getValue(UIWindow, 'closable')) {
195
+ close.addEventListener('click', () => {
196
+ // Destroying the entity disqualifies it everywhere; releaseWindow
197
+ // then closes the manager record.
198
+ entity.destroy();
199
+ });
200
+ }
201
+ else {
202
+ close.setProperties({ display: 'none' });
203
+ }
204
+ }
205
+ const minimize = element(WINDOW_CHROME_IDS.minimize);
206
+ if (minimize) {
207
+ if (entity.getValue(UIWindow, 'minimizable')) {
208
+ minimize.addEventListener('click', () => {
209
+ if (this.manager.has(id)) {
210
+ this.manager.toggleMinimized(id);
211
+ }
212
+ });
213
+ }
214
+ else {
215
+ minimize.setProperties({ display: 'none' });
216
+ }
217
+ }
218
+ const pin = element(WINDOW_CHROME_IDS.pin);
219
+ if (pin) {
220
+ if (entity.getValue(UIWindow, 'pinnable')) {
221
+ pin.addEventListener('click', () => {
222
+ if (this.manager.has(id)) {
223
+ this.manager.togglePin(id);
224
+ }
225
+ });
226
+ }
227
+ else {
228
+ pin.setProperties({ display: 'none' });
229
+ }
230
+ }
231
+ const dock = element(WINDOW_CHROME_IDS.dock);
232
+ dock?.addEventListener('click', () => this.returnHome(entity));
233
+ }
234
+ applyMinimized(id, minimized) {
235
+ const entity = this.entitiesById.get(id);
236
+ const document = entity ? this.documentOf(entity) : undefined;
237
+ const content = document?.getElementById(WINDOW_CHROME_IDS.content);
238
+ content?.setProperties({ display: minimized ? 'none' : 'flex' });
239
+ }
240
+ documentOf(entity) {
241
+ return PanelDocument.data.document[entity.index];
242
+ }
243
+ }
244
+ //# sourceMappingURL=window-system.js.map