@jamesyong42/infinite-canvas 1.0.0 → 1.2.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 (54) hide show
  1. package/README.md +170 -9
  2. package/dist/SelectionRenderer-CR2PBQwx.d.cts +105 -0
  3. package/dist/SelectionRenderer-CR2PBQwx.d.cts.map +1 -0
  4. package/dist/SelectionRenderer-DlsBstAq.d.mts +105 -0
  5. package/dist/SelectionRenderer-DlsBstAq.d.mts.map +1 -0
  6. package/dist/WebGLWidgetLayer-BBMuwzHq.cjs +3560 -0
  7. package/dist/WebGLWidgetLayer-BBMuwzHq.cjs.map +1 -0
  8. package/dist/WebGLWidgetLayer-C3p1tnpm.mjs +3375 -0
  9. package/dist/WebGLWidgetLayer-C3p1tnpm.mjs.map +1 -0
  10. package/dist/advanced.cjs +110 -165
  11. package/dist/advanced.cjs.map +1 -1
  12. package/dist/advanced.d.cts +58 -40
  13. package/dist/advanced.d.cts.map +1 -0
  14. package/dist/advanced.d.mts +99 -0
  15. package/dist/advanced.d.mts.map +1 -0
  16. package/dist/advanced.mjs +105 -0
  17. package/dist/advanced.mjs.map +1 -0
  18. package/dist/devtools.cjs +654 -0
  19. package/dist/devtools.cjs.map +1 -0
  20. package/dist/devtools.d.cts +23 -0
  21. package/dist/devtools.d.cts.map +1 -0
  22. package/dist/devtools.d.mts +23 -0
  23. package/dist/devtools.d.mts.map +1 -0
  24. package/dist/devtools.mjs +652 -0
  25. package/dist/devtools.mjs.map +1 -0
  26. package/dist/engine-BfbvWXSk.d.mts +982 -0
  27. package/dist/engine-BfbvWXSk.d.mts.map +1 -0
  28. package/dist/engine-CCjuFMC-.d.cts +982 -0
  29. package/dist/engine-CCjuFMC-.d.cts.map +1 -0
  30. package/dist/hooks-BwY7rRHg.mjs +425 -0
  31. package/dist/hooks-BwY7rRHg.mjs.map +1 -0
  32. package/dist/hooks-DHShH86C.cjs +707 -0
  33. package/dist/hooks-DHShH86C.cjs.map +1 -0
  34. package/dist/index.cjs +909 -803
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +199 -67
  37. package/dist/index.d.cts.map +1 -0
  38. package/dist/index.d.mts +258 -0
  39. package/dist/index.d.mts.map +1 -0
  40. package/dist/index.mjs +855 -0
  41. package/dist/index.mjs.map +1 -0
  42. package/package.json +47 -15
  43. package/dist/SelectionRenderer-CeWSNZT8.d.cts +0 -891
  44. package/dist/SelectionRenderer-CeWSNZT8.d.ts +0 -891
  45. package/dist/advanced.d.ts +0 -81
  46. package/dist/advanced.js +0 -124
  47. package/dist/advanced.js.map +0 -1
  48. package/dist/chunk-VSHXWTJH.cjs +0 -3228
  49. package/dist/chunk-VSHXWTJH.cjs.map +0 -1
  50. package/dist/chunk-Z6JQQOWL.js +0 -3142
  51. package/dist/chunk-Z6JQQOWL.js.map +0 -1
  52. package/dist/index.d.ts +0 -126
  53. package/dist/index.js +0 -602
  54. package/dist/index.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,821 +1,927 @@
1
- 'use strict';
2
-
3
- var chunkVSHXWTJH_cjs = require('./chunk-VSHXWTJH.cjs');
4
- var React = require('react');
5
- var three = require('three');
6
- var jsxRuntime = require('react/jsx-runtime');
7
-
8
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
-
10
- var React__default = /*#__PURE__*/_interopDefault(React);
11
-
12
- function WidgetProvider({ engine, children }) {
13
- const resolver = React.useCallback(
14
- (_entityId, widgetType) => {
15
- const def = engine.getWidget(widgetType);
16
- if (!def) return null;
17
- if (chunkVSHXWTJH_cjs.isR3FWidget(def)) {
18
- return { surface: "webgl", component: def.component };
19
- }
20
- return { surface: "dom", component: def.component };
21
- },
22
- [engine]
23
- );
24
- return /* @__PURE__ */ jsxRuntime.jsx(chunkVSHXWTJH_cjs.WidgetResolverProvider, { value: resolver, children });
25
- }
26
- var InfiniteCanvas = React__default.default.forwardRef(
27
- function InfiniteCanvas2({
28
- engine,
29
- grid,
30
- selection,
31
- onSelectionChange,
32
- onCameraChange,
33
- onNavigationChange,
34
- className,
35
- style,
36
- children
37
- }, ref) {
38
- const containerRef = React.useRef(null);
39
- const onSelectionChangeRef = React.useRef(onSelectionChange);
40
- const onCameraChangeRef = React.useRef(onCameraChange);
41
- const onNavigationChangeRef = React.useRef(onNavigationChange);
42
- React.useEffect(() => {
43
- onSelectionChangeRef.current = onSelectionChange;
44
- }, [onSelectionChange]);
45
- React.useEffect(() => {
46
- onCameraChangeRef.current = onCameraChange;
47
- }, [onCameraChange]);
48
- React.useEffect(() => {
49
- onNavigationChangeRef.current = onNavigationChange;
50
- }, [onNavigationChange]);
51
- React.useImperativeHandle(
52
- ref,
53
- () => ({
54
- panTo: (x, y) => {
55
- engine.panTo(x, y);
56
- engine.markDirty();
57
- },
58
- zoomTo: (zoom) => {
59
- engine.zoomTo(zoom);
60
- engine.markDirty();
61
- },
62
- zoomToFit: (padding) => {
63
- engine.zoomToFit(void 0, padding);
64
- engine.markDirty();
65
- },
66
- undo: () => {
67
- engine.undo();
68
- engine.markDirty();
69
- },
70
- redo: () => {
71
- engine.redo();
72
- engine.markDirty();
73
- },
74
- getEngine: () => engine
75
- }),
76
- [engine]
77
- );
78
- const webglCanvasRef = React.useRef(null);
79
- const gridRendererRef = React.useRef(null);
80
- const selectionRendererRef = React.useRef(null);
81
- const cameraLayerRef = React.useRef(null);
82
- const slotRefs = React.useRef(/* @__PURE__ */ new Map());
83
- const [visibleEntities, setVisibleEntities] = React.useState([]);
84
- const registerSlotRef = React.useCallback((entityId, el) => {
85
- if (el) {
86
- slotRefs.current.set(entityId, el);
87
- } else {
88
- slotRefs.current.delete(entityId);
89
- }
90
- }, []);
91
- React.useLayoutEffect(() => {
92
- const container = containerRef.current;
93
- const canvas = webglCanvasRef.current;
94
- if (!container || !canvas) return;
95
- const gridEnabled = grid !== false;
96
- let gridInst = null;
97
- if (gridEnabled) {
98
- gridInst = new chunkVSHXWTJH_cjs.GridRenderer(canvas);
99
- gridRendererRef.current = gridInst;
100
- }
101
- const selInst = new chunkVSHXWTJH_cjs.SelectionRenderer();
102
- selectionRendererRef.current = selInst;
103
- const updateSize = () => {
104
- const rect = container.getBoundingClientRect();
105
- const dpr = window.devicePixelRatio;
106
- engine.setViewport(rect.width, rect.height, dpr);
107
- canvas.style.width = `${rect.width}px`;
108
- canvas.style.height = `${rect.height}px`;
109
- if (gridInst) {
110
- gridInst.setSize(rect.width, rect.height, dpr);
111
- }
112
- selInst.setSize(new three.Vector2(rect.width * dpr, rect.height * dpr), dpr);
113
- };
114
- updateSize();
115
- const observer = new ResizeObserver(updateSize);
116
- observer.observe(container);
117
- return () => {
118
- observer.disconnect();
119
- if (gridInst) {
120
- gridInst.dispose();
121
- gridRendererRef.current = null;
122
- }
123
- selInst.dispose();
124
- selectionRendererRef.current = null;
125
- };
126
- }, [engine, grid]);
127
- React.useEffect(() => {
128
- const gridR = gridRendererRef.current;
129
- if (gridR && grid !== false) {
130
- const isDark = document.documentElement.classList.contains("dark");
131
- gridR.setConfig({
132
- dotColor: isDark ? [1, 1, 1] : [0, 0, 0],
133
- dotAlpha: isDark ? 0.12 : 0.18,
134
- ...grid
135
- });
136
- }
137
- const selR = selectionRendererRef.current;
138
- if (selR && selection) {
139
- selR.setConfig(selection);
140
- }
141
- engine.markDirty();
142
- }, [engine, grid, selection]);
143
- React.useEffect(() => {
144
- const container = containerRef.current;
145
- if (!container) return;
146
- const onWheel = (e) => {
147
- e.preventDefault();
148
- if (e.ctrlKey || e.metaKey) {
149
- const rect = container.getBoundingClientRect();
150
- engine.zoomAtPoint(e.clientX - rect.left, e.clientY - rect.top, -e.deltaY * 0.01);
151
- } else {
152
- engine.panBy(-e.deltaX, -e.deltaY);
153
- }
154
- };
155
- container.addEventListener("wheel", onWheel, { passive: false });
156
- return () => container.removeEventListener("wheel", onWheel);
157
- }, [engine]);
158
- React.useEffect(() => {
159
- const container = containerRef.current;
160
- if (!container) return;
161
- let gesture = { type: "idle" };
162
- let lastTapTime = 0;
163
- let lastTapX = 0;
164
- let lastTapY = 0;
165
- const DOUBLE_TAP_MS = 300;
166
- const DOUBLE_TAP_DIST = 30;
167
- function isOnWidget(target) {
168
- let el = target;
169
- while (el && el !== container) {
170
- if (el.hasAttribute("data-widget-slot")) return true;
171
- el = el.parentElement;
172
- }
173
- return false;
174
- }
175
- function isInteractive(target) {
176
- const el = target;
177
- if (!el) return false;
178
- const tag = el.tagName;
179
- return tag === "INPUT" || tag === "TEXTAREA" || tag === "BUTTON" || tag === "SELECT" || el.isContentEditable || el.closest("button") !== null;
180
- }
181
- function getRect() {
182
- return container?.getBoundingClientRect() ?? new DOMRect();
183
- }
184
- function touchDist(t1, t2) {
185
- const dx = t1.clientX - t2.clientX;
186
- const dy = t1.clientY - t2.clientY;
187
- return Math.sqrt(dx * dx + dy * dy);
188
- }
189
- function touchCenter(t1, t2, rect) {
190
- return {
191
- x: (t1.clientX + t2.clientX) / 2 - rect.left,
192
- y: (t1.clientY + t2.clientY) / 2 - rect.top
193
- };
194
- }
195
- function cancelEngineGesture() {
196
- if (gesture.type === "pending-entity" || gesture.type === "entity-dragging") {
197
- engine.handlePointerUp();
198
- }
199
- }
200
- const noMods = { shift: false, ctrl: false, alt: false, meta: false };
201
- function onTouchStart(e) {
202
- const rect = getRect();
203
- const touches = e.touches;
204
- if (touches.length >= 2) {
205
- e.preventDefault();
206
- cancelEngineGesture();
207
- const dist = touchDist(touches[0], touches[1]);
208
- const center = touchCenter(touches[0], touches[1], rect);
209
- gesture = { type: "pinching", lastDist: dist, lastCx: center.x, lastCy: center.y };
210
- return;
211
- }
212
- const touch = touches[0];
213
- const x = touch.clientX - rect.left;
214
- const y = touch.clientY - rect.top;
215
- if (isInteractive(e.target)) return;
216
- e.preventDefault();
217
- const now = Date.now();
218
- if (now - lastTapTime < DOUBLE_TAP_MS && Math.abs(x - lastTapX) < DOUBLE_TAP_DIST && Math.abs(y - lastTapY) < DOUBLE_TAP_DIST) {
219
- lastTapTime = 0;
220
- const directive = engine.handlePointerDown(x, y, 0, noMods);
221
- try {
222
- if (directive.action === "passthrough-track-drag") {
223
- const selected = engine.getSelectedEntities();
224
- if (selected.length === 1) {
225
- engine.enterContainer(selected[0]);
226
- }
227
- } else {
228
- const camera = engine.getCamera();
229
- const target = camera.zoom < 0.9 ? 1 : camera.zoom < 1.8 ? 2 : 1;
230
- engine.zoomAtPoint(x, y, (target - camera.zoom) / camera.zoom);
231
- }
232
- } finally {
233
- engine.handlePointerUp();
234
- engine.markDirty();
235
- }
236
- gesture = { type: "idle" };
237
- return;
238
- }
239
- if (isOnWidget(e.target)) {
240
- engine.handlePointerDown(x, y, 0, noMods);
241
- gesture = { type: "pending-entity", x, y, time: now };
242
- } else {
243
- gesture = { type: "pending-pan", x, y, time: now };
244
- }
245
- }
246
- function onTouchMove(e) {
247
- e.preventDefault();
248
- const rect = getRect();
249
- const touches = e.touches;
250
- if (gesture.type === "pinching" && touches.length >= 2) {
251
- const dist = touchDist(touches[0], touches[1]);
252
- const center = touchCenter(touches[0], touches[1], rect);
253
- const scale = dist / gesture.lastDist;
254
- engine.zoomAtPoint(center.x, center.y, scale - 1);
255
- engine.panBy(center.x - gesture.lastCx, center.y - gesture.lastCy);
256
- gesture.lastDist = dist;
257
- gesture.lastCx = center.x;
258
- gesture.lastCy = center.y;
259
- return;
260
- }
261
- if (touches.length >= 2) {
262
- cancelEngineGesture();
263
- const dist = touchDist(touches[0], touches[1]);
264
- const center = touchCenter(touches[0], touches[1], rect);
265
- gesture = { type: "pinching", lastDist: dist, lastCx: center.x, lastCy: center.y };
266
- return;
267
- }
268
- if (touches.length < 1) return;
269
- const touch = touches[0];
270
- const x = touch.clientX - rect.left;
271
- const y = touch.clientY - rect.top;
272
- if (gesture.type === "pending-pan") {
273
- if (Math.abs(x - gesture.x) > chunkVSHXWTJH_cjs.DEAD_ZONE_TOUCH_PX || Math.abs(y - gesture.y) > chunkVSHXWTJH_cjs.DEAD_ZONE_TOUCH_PX) {
274
- gesture = { type: "panning", lastX: x, lastY: y };
275
- }
276
- return;
277
- }
278
- if (gesture.type === "panning") {
279
- engine.panBy(x - gesture.lastX, y - gesture.lastY);
280
- gesture.lastX = x;
281
- gesture.lastY = y;
282
- return;
283
- }
284
- if (gesture.type === "pending-entity" || gesture.type === "entity-dragging") {
285
- engine.handlePointerMove(x, y, noMods);
286
- if (gesture.type === "pending-entity") {
287
- if (Math.abs(x - gesture.x) > chunkVSHXWTJH_cjs.DEAD_ZONE_TOUCH_PX || Math.abs(y - gesture.y) > chunkVSHXWTJH_cjs.DEAD_ZONE_TOUCH_PX) {
288
- gesture = { type: "entity-dragging" };
289
- }
290
- }
291
- }
292
- }
293
- function onTouchEnd(e) {
294
- e.preventDefault();
295
- const remaining = e.touches.length;
296
- const rect = getRect();
297
- if (gesture.type === "pinching") {
298
- if (remaining === 1) {
299
- const t = e.touches[0];
300
- gesture = {
301
- type: "panning",
302
- lastX: t.clientX - rect.left,
303
- lastY: t.clientY - rect.top
304
- };
305
- } else if (remaining === 0) {
306
- gesture = { type: "idle" };
307
- }
308
- return;
309
- }
310
- if (remaining > 0) return;
311
- if (gesture.type === "pending-pan") {
312
- engine.handlePointerDown(gesture.x, gesture.y, 0, noMods);
313
- engine.handlePointerUp();
314
- engine.markDirty();
315
- lastTapTime = Date.now();
316
- lastTapX = gesture.x;
317
- lastTapY = gesture.y;
318
- }
319
- if (gesture.type === "pending-entity") {
320
- engine.handlePointerUp();
321
- engine.markDirty();
322
- lastTapTime = Date.now();
323
- lastTapX = gesture.x;
324
- lastTapY = gesture.y;
325
- }
326
- if (gesture.type === "entity-dragging") {
327
- engine.handlePointerUp();
328
- engine.markDirty();
329
- }
330
- gesture = { type: "idle" };
331
- }
332
- function onTouchCancel(_e) {
333
- gesture = { type: "idle" };
334
- engine.handlePointerCancel();
335
- }
336
- container.addEventListener("touchstart", onTouchStart, { passive: false });
337
- container.addEventListener("touchmove", onTouchMove, { passive: false });
338
- container.addEventListener("touchend", onTouchEnd, { passive: false });
339
- container.addEventListener("touchcancel", onTouchCancel, { passive: true });
340
- return () => {
341
- container.removeEventListener("touchstart", onTouchStart);
342
- container.removeEventListener("touchmove", onTouchMove);
343
- container.removeEventListener("touchend", onTouchEnd);
344
- container.removeEventListener("touchcancel", onTouchCancel);
345
- };
346
- }, [engine]);
347
- const onCanvasPointerDown = React.useCallback(
348
- (e) => {
349
- const target = e.target;
350
- if (target?.closest("button, input, textarea, select, [contenteditable]")) return;
351
- const rect = containerRef.current?.getBoundingClientRect();
352
- if (!rect) return;
353
- const directive = engine.handlePointerDown(
354
- e.clientX - rect.left,
355
- e.clientY - rect.top,
356
- e.button,
357
- {
358
- shift: e.shiftKey,
359
- ctrl: e.ctrlKey,
360
- alt: e.altKey,
361
- meta: e.metaKey
362
- }
363
- );
364
- if (directive.action === "capture-resize" || directive.action === "passthrough-track-drag") {
365
- containerRef.current?.setPointerCapture(e.pointerId);
366
- }
367
- if (directive.action === "capture-resize") e.preventDefault();
368
- },
369
- [engine]
370
- );
371
- const onCanvasPointerMove = React.useCallback(
372
- (e) => {
373
- const target = e.target;
374
- if (target.closest?.("[data-widget-slot]") && target !== containerRef.current) {
375
- return;
376
- }
377
- const rect = containerRef.current?.getBoundingClientRect();
378
- if (!rect) return;
379
- engine.handlePointerMove(e.clientX - rect.left, e.clientY - rect.top, {
380
- shift: e.shiftKey,
381
- ctrl: e.ctrlKey,
382
- alt: e.altKey,
383
- meta: e.metaKey
384
- });
385
- },
386
- [engine]
387
- );
388
- const onCanvasPointerUp = React.useCallback(
389
- (e) => {
390
- if (containerRef.current?.hasPointerCapture(e.pointerId)) {
391
- containerRef.current.releasePointerCapture(e.pointerId);
392
- }
393
- engine.handlePointerUp();
394
- },
395
- [engine]
396
- );
397
- React.useEffect(() => {
398
- let rafId;
399
- let running = true;
400
- function loop() {
401
- if (!running) return;
402
- const didTick = engine.flushIfDirty();
403
- if (didTick) {
404
- const camera2 = engine.getCamera();
405
- const changes = engine.getFrameChanges();
406
- if (cameraLayerRef.current) {
407
- cameraLayerRef.current.style.transform = `scale(${camera2.zoom}) translate(${-camera2.x}px, ${-camera2.y}px)`;
408
- }
409
- const cursor = engine.world.getResource(chunkVSHXWTJH_cjs.CursorResource).cursor;
410
- if (containerRef.current && containerRef.current.style.cursor !== cursor) {
411
- containerRef.current.style.cursor = cursor;
412
- }
413
- if (gridRendererRef.current) {
414
- gridRendererRef.current.render(camera2.x, camera2.y, camera2.zoom);
415
- }
416
- if (selectionRendererRef.current && gridRendererRef.current) {
417
- const selected = engine.getSelectedEntities();
418
- const selBounds = [];
419
- for (const id of selected) {
420
- const wb = engine.get(id, chunkVSHXWTJH_cjs.WorldBounds);
421
- if (wb)
422
- selBounds.push({
423
- x: wb.worldX,
424
- y: wb.worldY,
425
- width: wb.worldWidth,
426
- height: wb.worldHeight
427
- });
428
- }
429
- const hovId = engine.getHoveredEntity();
430
- let hovBounds = null;
431
- if (hovId !== null) {
432
- const wb = engine.get(hovId, chunkVSHXWTJH_cjs.WorldBounds);
433
- if (wb)
434
- hovBounds = {
435
- x: wb.worldX,
436
- y: wb.worldY,
437
- width: wb.worldWidth,
438
- height: wb.worldHeight
439
- };
440
- }
441
- selectionRendererRef.current.render(
442
- gridRendererRef.current.getWebGLRenderer(),
443
- camera2.x,
444
- camera2.y,
445
- camera2.zoom,
446
- selBounds,
447
- hovBounds,
448
- engine.getSnapGuides(),
449
- engine.getEqualSpacing()
450
- );
451
- }
452
- for (const entityId of changes.positionsChanged) {
453
- const el = slotRefs.current.get(entityId);
454
- if (!el) continue;
455
- const wb = engine.get(entityId, chunkVSHXWTJH_cjs.WorldBounds);
456
- if (!wb) continue;
457
- el.style.transform = `translate(${wb.worldX}px, ${wb.worldY}px)`;
458
- el.style.width = `${wb.worldWidth}px`;
459
- el.style.height = `${wb.worldHeight}px`;
460
- }
461
- if (changes.entered.length > 0 || changes.exited.length > 0) {
462
- const visible2 = engine.getVisibleEntities();
463
- setVisibleEntities(visible2.map((v) => v.entityId));
464
- }
465
- if (changes.selectionChanged && onSelectionChangeRef.current) {
466
- onSelectionChangeRef.current(engine.getSelectedEntities());
467
- }
468
- if (changes.cameraChanged && onCameraChangeRef.current) {
469
- onCameraChangeRef.current({ x: camera2.x, y: camera2.y, zoom: camera2.zoom });
470
- }
471
- if (changes.navigationChanged && onNavigationChangeRef.current) {
472
- const navStack = engine.world.getResource(chunkVSHXWTJH_cjs.NavigationStackResource);
473
- const depth = navStack.frames.length - 1;
474
- const containerId = navStack.frames[navStack.frames.length - 1].containerId;
475
- onNavigationChangeRef.current(depth, containerId);
476
- }
477
- }
478
- rafId = requestAnimationFrame(loop);
479
- }
480
- engine.tick();
481
- const visible = engine.getVisibleEntities();
482
- setVisibleEntities(visible.map((v) => v.entityId));
483
- const camera = engine.getCamera();
484
- if (cameraLayerRef.current) {
485
- cameraLayerRef.current.style.transform = `scale(${camera.zoom}) translate(${-camera.x}px, ${-camera.y}px)`;
486
- }
487
- if (gridRendererRef.current) {
488
- gridRendererRef.current.render(camera.x, camera.y, camera.zoom);
489
- }
490
- for (const v of visible) {
491
- const el = slotRefs.current.get(v.entityId);
492
- if (!el) continue;
493
- el.style.transform = `translate(${v.worldX}px, ${v.worldY}px)`;
494
- el.style.width = `${v.worldWidth}px`;
495
- el.style.height = `${v.worldHeight}px`;
496
- }
497
- rafId = requestAnimationFrame(loop);
498
- return () => {
499
- running = false;
500
- cancelAnimationFrame(rafId);
501
- };
502
- }, [engine]);
503
- React.useLayoutEffect(() => {
504
- for (const entityId of visibleEntities) {
505
- const el = slotRefs.current.get(entityId);
506
- if (!el) continue;
507
- const wb = engine.get(entityId, chunkVSHXWTJH_cjs.WorldBounds);
508
- if (!wb) continue;
509
- el.style.transform = `translate(${wb.worldX}px, ${wb.worldY}px)`;
510
- el.style.width = `${wb.worldWidth}px`;
511
- el.style.height = `${wb.worldHeight}px`;
512
- }
513
- }, [visibleEntities, engine]);
514
- const { domEntities, webglEntities } = React.useMemo(() => {
515
- const dom = [];
516
- const webgl = [];
517
- for (const id of visibleEntities) {
518
- const w = engine.get(id, chunkVSHXWTJH_cjs.Widget);
519
- if (w?.surface === "webgl") {
520
- webgl.push(id);
521
- } else {
522
- dom.push(id);
523
- }
524
- }
525
- return { domEntities: dom, webglEntities: webgl };
526
- }, [visibleEntities, engine]);
527
- const canvasContent = /* @__PURE__ */ jsxRuntime.jsxs(
528
- "div",
529
- {
530
- ref: containerRef,
531
- className: `relative overflow-hidden ${className ?? ""}`,
532
- style: {
533
- ...style,
534
- touchAction: "none",
535
- backgroundColor: "var(--canvas-bg, #fafafa)"
536
- },
537
- onPointerDown: onCanvasPointerDown,
538
- onPointerMove: onCanvasPointerMove,
539
- onPointerUp: onCanvasPointerUp,
540
- children: [
541
- /* @__PURE__ */ jsxRuntime.jsx("canvas", { ref: webglCanvasRef, className: "absolute inset-0 pointer-events-none" }),
542
- webglEntities.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(WebGLWidgetBridge, { engine, entities: webglEntities }),
543
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 pointer-events-none" }),
544
- /* @__PURE__ */ jsxRuntime.jsxs(
545
- "div",
546
- {
547
- ref: cameraLayerRef,
548
- className: "absolute left-0 top-0 origin-top-left will-change-transform",
549
- children: [
550
- domEntities.map((entityId) => /* @__PURE__ */ jsxRuntime.jsx(chunkVSHXWTJH_cjs.WidgetSlot, { entityId, slotRef: registerSlotRef }, entityId)),
551
- webglEntities.map((entityId) => /* @__PURE__ */ jsxRuntime.jsx(chunkVSHXWTJH_cjs.SelectionOverlaySlot, { entityId, slotRef: registerSlotRef }, entityId))
552
- ]
553
- }
554
- ),
555
- children
556
- ]
557
- }
558
- );
559
- return /* @__PURE__ */ jsxRuntime.jsx(chunkVSHXWTJH_cjs.EngineProvider, { value: engine, children: /* @__PURE__ */ jsxRuntime.jsx(chunkVSHXWTJH_cjs.ContainerRefProvider, { value: containerRef, children: /* @__PURE__ */ jsxRuntime.jsx(WidgetProvider, { engine, children: canvasContent }) }) });
560
- }
561
- );
562
- function WebGLWidgetBridge({ engine, entities }) {
563
- const resolver = chunkVSHXWTJH_cjs.useWidgetResolver();
564
- const resolve = React.useCallback(
565
- (entityId) => {
566
- if (!resolver) return null;
567
- const w = engine.get(entityId, chunkVSHXWTJH_cjs.Widget);
568
- return resolver(entityId, w?.type ?? "");
569
- },
570
- [resolver, engine]
571
- );
572
- if (!resolver) return null;
573
- return /* @__PURE__ */ jsxRuntime.jsx(chunkVSHXWTJH_cjs.WebGLWidgetLayer, { engine, entities, resolve });
574
- }
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_WebGLWidgetLayer = require("./WebGLWidgetLayer-BBMuwzHq.cjs");
3
+ const require_hooks = require("./hooks-DHShH86C.cjs");
4
+ let react = require("react");
5
+ react = require_WebGLWidgetLayer.__toESM(react, 1);
6
+ let react_jsx_runtime = require("react/jsx-runtime");
7
+ let _react_three_fiber = require("@react-three/fiber");
8
+ let three = require("three");
9
+ //#region src/react/widget-hooks.ts
10
+ /**
11
+ * Returns the custom data attached to a widget entity.
12
+ * Use the generic parameter for type safety: `useWidgetData<MyData>(entityId)`. Re-renders when data changes.
13
+ */
575
14
  function useWidgetData(entityId) {
576
- const comp = chunkVSHXWTJH_cjs.useComponent(entityId, chunkVSHXWTJH_cjs.WidgetData);
577
- return comp?.data ?? {};
15
+ return require_hooks.useComponent(entityId, require_hooks.WidgetData)?.data ?? {};
578
16
  }
17
+ /**
18
+ * Returns the current responsive breakpoint for a widget based on its screen-space size.
19
+ * Re-renders when the breakpoint changes.
20
+ */
579
21
  function useBreakpoint(entityId) {
580
- const comp = chunkVSHXWTJH_cjs.useComponent(entityId, chunkVSHXWTJH_cjs.WidgetBreakpoint);
581
- return comp?.current ?? "normal";
22
+ return require_hooks.useComponent(entityId, require_hooks.WidgetBreakpoint)?.current ?? "normal";
582
23
  }
24
+ /**
25
+ * Returns child entity IDs of a container entity.
26
+ * Re-renders when children are added or removed.
27
+ */
583
28
  function useChildren(entityId) {
584
- const comp = chunkVSHXWTJH_cjs.useComponent(entityId, chunkVSHXWTJH_cjs.Children);
585
- return comp?.ids ?? [];
29
+ return require_hooks.useComponent(entityId, require_hooks.Children)?.ids ?? [];
586
30
  }
31
+ /**
32
+ * Returns whether the entity is currently selected.
33
+ * Re-renders when the entity's selection state changes.
34
+ */
587
35
  function useIsSelected(entityId) {
588
- return chunkVSHXWTJH_cjs.useTag(entityId, chunkVSHXWTJH_cjs.Selected);
36
+ return require_hooks.useTag(entityId, require_hooks.Selected);
589
37
  }
38
+ /**
39
+ * Returns a function to update the widget's custom data.
40
+ * Merges the patch into existing data via shallow spread.
41
+ */
590
42
  function useUpdateWidget(entityId) {
591
- const engine = chunkVSHXWTJH_cjs.useLayoutEngine();
592
- return React.useCallback(
593
- (patch) => {
594
- const existing = engine.get(entityId, chunkVSHXWTJH_cjs.WidgetData);
595
- if (existing) {
596
- engine.set(entityId, chunkVSHXWTJH_cjs.WidgetData, {
597
- data: { ...existing.data, ...patch }
598
- });
599
- }
600
- },
601
- [engine, entityId]
602
- );
43
+ const engine = require_hooks.useLayoutEngine();
44
+ return (0, react.useCallback)((patch) => {
45
+ const existing = engine.get(entityId, require_hooks.WidgetData);
46
+ if (existing) engine.set(entityId, require_hooks.WidgetData, { data: {
47
+ ...existing.data,
48
+ ...patch
49
+ } });
50
+ }, [engine, entityId]);
603
51
  }
604
-
605
- Object.defineProperty(exports, "Active", {
606
- enumerable: true,
607
- get: function () { return chunkVSHXWTJH_cjs.Active; }
608
- });
609
- Object.defineProperty(exports, "BreakpointConfigResource", {
610
- enumerable: true,
611
- get: function () { return chunkVSHXWTJH_cjs.BreakpointConfigResource; }
612
- });
613
- Object.defineProperty(exports, "CameraResource", {
614
- enumerable: true,
615
- get: function () { return chunkVSHXWTJH_cjs.CameraResource; }
616
- });
617
- Object.defineProperty(exports, "Children", {
618
- enumerable: true,
619
- get: function () { return chunkVSHXWTJH_cjs.Children; }
620
- });
621
- Object.defineProperty(exports, "CommandBuffer", {
622
- enumerable: true,
623
- get: function () { return chunkVSHXWTJH_cjs.CommandBuffer; }
624
- });
625
- Object.defineProperty(exports, "Container", {
626
- enumerable: true,
627
- get: function () { return chunkVSHXWTJH_cjs.Container; }
628
- });
629
- Object.defineProperty(exports, "CursorHint", {
630
- enumerable: true,
631
- get: function () { return chunkVSHXWTJH_cjs.CursorHint; }
632
- });
633
- Object.defineProperty(exports, "CursorResource", {
634
- enumerable: true,
635
- get: function () { return chunkVSHXWTJH_cjs.CursorResource; }
636
- });
637
- Object.defineProperty(exports, "DEFAULT_GRID_CONFIG", {
638
- enumerable: true,
639
- get: function () { return chunkVSHXWTJH_cjs.DEFAULT_GRID_CONFIG; }
640
- });
641
- Object.defineProperty(exports, "DEFAULT_SELECTION_CONFIG", {
642
- enumerable: true,
643
- get: function () { return chunkVSHXWTJH_cjs.DEFAULT_SELECTION_CONFIG; }
644
- });
645
- Object.defineProperty(exports, "Draggable", {
646
- enumerable: true,
647
- get: function () { return chunkVSHXWTJH_cjs.Draggable; }
648
- });
649
- Object.defineProperty(exports, "HandleSet", {
650
- enumerable: true,
651
- get: function () { return chunkVSHXWTJH_cjs.HandleSet; }
652
- });
653
- Object.defineProperty(exports, "Hitbox", {
654
- enumerable: true,
655
- get: function () { return chunkVSHXWTJH_cjs.Hitbox; }
656
- });
657
- Object.defineProperty(exports, "InteractionRole", {
658
- enumerable: true,
659
- get: function () { return chunkVSHXWTJH_cjs.InteractionRole; }
660
- });
661
- Object.defineProperty(exports, "Locked", {
662
- enumerable: true,
663
- get: function () { return chunkVSHXWTJH_cjs.Locked; }
664
- });
665
- Object.defineProperty(exports, "MoveCommand", {
666
- enumerable: true,
667
- get: function () { return chunkVSHXWTJH_cjs.MoveCommand; }
668
- });
669
- Object.defineProperty(exports, "NavigationStackResource", {
670
- enumerable: true,
671
- get: function () { return chunkVSHXWTJH_cjs.NavigationStackResource; }
672
- });
673
- Object.defineProperty(exports, "Parent", {
674
- enumerable: true,
675
- get: function () { return chunkVSHXWTJH_cjs.Parent; }
676
- });
677
- Object.defineProperty(exports, "Resizable", {
678
- enumerable: true,
679
- get: function () { return chunkVSHXWTJH_cjs.Resizable; }
680
- });
681
- Object.defineProperty(exports, "ResizeCommand", {
682
- enumerable: true,
683
- get: function () { return chunkVSHXWTJH_cjs.ResizeCommand; }
684
- });
685
- Object.defineProperty(exports, "Selectable", {
686
- enumerable: true,
687
- get: function () { return chunkVSHXWTJH_cjs.Selectable; }
688
- });
689
- Object.defineProperty(exports, "Selected", {
690
- enumerable: true,
691
- get: function () { return chunkVSHXWTJH_cjs.Selected; }
692
- });
693
- Object.defineProperty(exports, "SetComponentCommand", {
694
- enumerable: true,
695
- get: function () { return chunkVSHXWTJH_cjs.SetComponentCommand; }
696
- });
697
- Object.defineProperty(exports, "Transform2D", {
698
- enumerable: true,
699
- get: function () { return chunkVSHXWTJH_cjs.Transform2D; }
700
- });
701
- Object.defineProperty(exports, "ViewportResource", {
702
- enumerable: true,
703
- get: function () { return chunkVSHXWTJH_cjs.ViewportResource; }
704
- });
705
- Object.defineProperty(exports, "Visible", {
706
- enumerable: true,
707
- get: function () { return chunkVSHXWTJH_cjs.Visible; }
708
- });
709
- Object.defineProperty(exports, "Widget", {
710
- enumerable: true,
711
- get: function () { return chunkVSHXWTJH_cjs.Widget; }
712
- });
713
- Object.defineProperty(exports, "WidgetBreakpoint", {
714
- enumerable: true,
715
- get: function () { return chunkVSHXWTJH_cjs.WidgetBreakpoint; }
716
- });
717
- Object.defineProperty(exports, "WidgetData", {
718
- enumerable: true,
719
- get: function () { return chunkVSHXWTJH_cjs.WidgetData; }
720
- });
721
- Object.defineProperty(exports, "WidgetResolverProvider", {
722
- enumerable: true,
723
- get: function () { return chunkVSHXWTJH_cjs.WidgetResolverProvider; }
724
- });
725
- Object.defineProperty(exports, "WorldBounds", {
726
- enumerable: true,
727
- get: function () { return chunkVSHXWTJH_cjs.WorldBounds; }
728
- });
729
- Object.defineProperty(exports, "ZIndex", {
730
- enumerable: true,
731
- get: function () { return chunkVSHXWTJH_cjs.ZIndex; }
732
- });
733
- Object.defineProperty(exports, "ZoomConfigResource", {
734
- enumerable: true,
735
- get: function () { return chunkVSHXWTJH_cjs.ZoomConfigResource; }
736
- });
737
- Object.defineProperty(exports, "clamp", {
738
- enumerable: true,
739
- get: function () { return chunkVSHXWTJH_cjs.clamp; }
740
- });
741
- Object.defineProperty(exports, "createArchetypeRegistry", {
742
- enumerable: true,
743
- get: function () { return chunkVSHXWTJH_cjs.createArchetypeRegistry; }
744
- });
745
- Object.defineProperty(exports, "createLayoutEngine", {
746
- enumerable: true,
747
- get: function () { return chunkVSHXWTJH_cjs.createLayoutEngine; }
748
- });
749
- Object.defineProperty(exports, "createWidgetRegistry", {
750
- enumerable: true,
751
- get: function () { return chunkVSHXWTJH_cjs.createWidgetRegistry; }
752
- });
753
- Object.defineProperty(exports, "intersectsAABB", {
754
- enumerable: true,
755
- get: function () { return chunkVSHXWTJH_cjs.intersectsAABB; }
756
- });
757
- Object.defineProperty(exports, "isR3FWidget", {
758
- enumerable: true,
759
- get: function () { return chunkVSHXWTJH_cjs.isR3FWidget; }
760
- });
761
- Object.defineProperty(exports, "pointInAABB", {
762
- enumerable: true,
763
- get: function () { return chunkVSHXWTJH_cjs.pointInAABB; }
764
- });
765
- Object.defineProperty(exports, "screenToWorld", {
766
- enumerable: true,
767
- get: function () { return chunkVSHXWTJH_cjs.screenToWorld; }
768
- });
769
- Object.defineProperty(exports, "useCamera", {
770
- enumerable: true,
771
- get: function () { return chunkVSHXWTJH_cjs.useCamera; }
772
- });
773
- Object.defineProperty(exports, "useComponent", {
774
- enumerable: true,
775
- get: function () { return chunkVSHXWTJH_cjs.useComponent; }
776
- });
777
- Object.defineProperty(exports, "useContainerRef", {
778
- enumerable: true,
779
- get: function () { return chunkVSHXWTJH_cjs.useContainerRef; }
780
- });
781
- Object.defineProperty(exports, "useLayoutEngine", {
782
- enumerable: true,
783
- get: function () { return chunkVSHXWTJH_cjs.useLayoutEngine; }
784
- });
785
- Object.defineProperty(exports, "useQuery", {
786
- enumerable: true,
787
- get: function () { return chunkVSHXWTJH_cjs.useQuery; }
788
- });
789
- Object.defineProperty(exports, "useResource", {
790
- enumerable: true,
791
- get: function () { return chunkVSHXWTJH_cjs.useResource; }
792
- });
793
- Object.defineProperty(exports, "useTag", {
794
- enumerable: true,
795
- get: function () { return chunkVSHXWTJH_cjs.useTag; }
796
- });
797
- Object.defineProperty(exports, "useTaggedEntities", {
798
- enumerable: true,
799
- get: function () { return chunkVSHXWTJH_cjs.useTaggedEntities; }
800
- });
801
- Object.defineProperty(exports, "useWidgetResolver", {
802
- enumerable: true,
803
- get: function () { return chunkVSHXWTJH_cjs.useWidgetResolver; }
804
- });
805
- Object.defineProperty(exports, "worldBoundsToAABB", {
806
- enumerable: true,
807
- get: function () { return chunkVSHXWTJH_cjs.worldBoundsToAABB; }
808
- });
809
- Object.defineProperty(exports, "worldToScreen", {
810
- enumerable: true,
811
- get: function () { return chunkVSHXWTJH_cjs.worldToScreen; }
812
- });
52
+ //#endregion
53
+ //#region src/react/card.tsx
54
+ /**
55
+ * Built-in preset sizes, matching `CardPresetsResource` defaults.
56
+ * Used by `createCardWidget` to set `defaultSize` at widget-registration
57
+ * time (before the engine is constructed).
58
+ */
59
+ const DEFAULT_CARD_PRESET_SIZES$1 = {
60
+ small: {
61
+ width: 155,
62
+ height: 155
63
+ },
64
+ medium: {
65
+ width: 329,
66
+ height: 155
67
+ },
68
+ large: {
69
+ width: 329,
70
+ height: 345
71
+ },
72
+ xl: {
73
+ width: 329,
74
+ height: 535
75
+ }
76
+ };
77
+ /**
78
+ * Visual chrome for an iOS-style card: rounded corners, hairline ring,
79
+ * soft drop shadow, and a subtle lift (scale + stronger shadow) while
80
+ * the entity carries the `Dragging` tag.
81
+ *
82
+ * Uses CSS transitions — no animation library dependency.
83
+ */
84
+ function CardFrame({ entityId, children, className, style }) {
85
+ const dragging = require_hooks.useTag(entityId, require_hooks.Dragging);
86
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
87
+ className,
88
+ style: {
89
+ width: "100%",
90
+ height: "100%",
91
+ borderRadius: "21.67px",
92
+ overflow: "hidden",
93
+ boxShadow: dragging ? "0 30px 60px rgba(0,0,0,0.22), 0 0 0 1px rgba(0,0,0,0.06)" : "0 20px 40px rgba(0,0,0,0.15), 0 0 0 1px rgba(0,0,0,0.05)",
94
+ transform: dragging ? "scale(1.05)" : "scale(1)",
95
+ transformOrigin: "center center",
96
+ transition: "transform 180ms cubic-bezier(0.2, 0.9, 0.3, 1.2), box-shadow 180ms cubic-bezier(0.2, 0.9, 0.3, 1.2)",
97
+ willChange: dragging ? "transform, box-shadow" : void 0,
98
+ ...style
99
+ },
100
+ children
101
+ });
102
+ }
103
+ /**
104
+ * Returns a paired widget + archetype for an iOS-style card. Register both
105
+ * with `createLayoutEngine({ widgets: [card.widget], archetypes: [card.archetype] })`
106
+ * (or via `engine.registerWidget` / `engine.registerArchetype`) and spawn with
107
+ * `engine.spawn('your-card-type', { at, data })`.
108
+ *
109
+ * The produced widget is non-resizable (Selectable + Draggable only), wrapped
110
+ * in `<CardFrame>`, and spawns with a `Card` component so `cardSystem` enforces
111
+ * the preset size each tick.
112
+ */
113
+ function createCardWidget(opts) {
114
+ const defaultSize = DEFAULT_CARD_PRESET_SIZES$1[opts.size];
115
+ const Render = opts.render;
116
+ const Component = ({ entityId }) => {
117
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardFrame, {
118
+ entityId,
119
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Render, {
120
+ entityId,
121
+ data: useWidgetData(entityId)
122
+ })
123
+ });
124
+ };
125
+ return {
126
+ widget: {
127
+ type: opts.type,
128
+ schema: opts.schema,
129
+ defaultData: opts.defaultData,
130
+ defaultSize,
131
+ component: Component
132
+ },
133
+ archetype: {
134
+ id: opts.type,
135
+ widget: opts.type,
136
+ components: [[require_hooks.Card, { preset: opts.size }]],
137
+ interactive: {
138
+ selectable: true,
139
+ draggable: true,
140
+ resizable: false,
141
+ selectionFrame: false
142
+ },
143
+ defaultSize
144
+ }
145
+ };
146
+ }
147
+ //#endregion
148
+ //#region src/react/geometry-card.tsx
149
+ /** Must match {@link CardPresetsResource} defaults. */
150
+ const DEFAULT_CARD_PRESET_SIZES = {
151
+ small: {
152
+ width: 155,
153
+ height: 155
154
+ },
155
+ medium: {
156
+ width: 329,
157
+ height: 155
158
+ },
159
+ large: {
160
+ width: 329,
161
+ height: 345
162
+ },
163
+ xl: {
164
+ width: 329,
165
+ height: 535
166
+ }
167
+ };
168
+ /**
169
+ * Pure-three rounded-rect extrude geometry — avoids a drei dependency.
170
+ * Rounded corners match the DOM CardFrame radius (21.67 px).
171
+ */
172
+ function makeRoundedCardGeometry(width, height, radius, depth) {
173
+ const shape = new three.Shape();
174
+ const r = Math.min(radius, Math.min(width, height) / 2);
175
+ const x = -width / 2;
176
+ const y = -height / 2;
177
+ shape.moveTo(x, y + r);
178
+ shape.lineTo(x, y + height - r);
179
+ shape.quadraticCurveTo(x, y + height, x + r, y + height);
180
+ shape.lineTo(x + width - r, y + height);
181
+ shape.quadraticCurveTo(x + width, y + height, x + width, y + height - r);
182
+ shape.lineTo(x + width, y + r);
183
+ shape.quadraticCurveTo(x + width, y, x + width - r, y);
184
+ shape.lineTo(x + r, y);
185
+ shape.quadraticCurveTo(x, y, x, y + r);
186
+ return new three.ExtrudeGeometry(shape, {
187
+ depth,
188
+ bevelEnabled: true,
189
+ bevelSegments: 3,
190
+ bevelSize: .6,
191
+ bevelThickness: .6
192
+ });
193
+ }
194
+ function CardBack({ width, height, color, roughness, metalness }) {
195
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("mesh", {
196
+ geometry: (0, react.useMemo)(() => makeRoundedCardGeometry(width, height, 21.67, 3), [width, height]),
197
+ position: [
198
+ 0,
199
+ 0,
200
+ -6
201
+ ],
202
+ receiveShadow: true,
203
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("meshStandardMaterial", {
204
+ color,
205
+ roughness,
206
+ metalness
207
+ })
208
+ });
209
+ }
210
+ /**
211
+ * Returns a paired R3F widget + archetype for a card-shaped 3D widget.
212
+ * Behaves like {@link createCardWidget} — fixed preset size, non-resizable,
213
+ * no engine-drawn selection frame, and lifts on drag (scale + z) — but
214
+ * renders a three.js scene instead of DOM content.
215
+ *
216
+ * Lighting: this helper adds no lights. Declare your own in the `geometry`
217
+ * component (typically a local `pointLight` scoped with `distance`).
218
+ */
219
+ function createGeometryCardWidget(opts) {
220
+ const defaultSize = DEFAULT_CARD_PRESET_SIZES[opts.size];
221
+ const Render = opts.geometry;
222
+ const backgroundConfig = opts.background ?? "card";
223
+ const resolvedBack = backgroundConfig === "transparent" ? null : backgroundConfig === "card" ? {
224
+ color: "#1C1C1E",
225
+ roughness: .55,
226
+ metalness: 0
227
+ } : {
228
+ color: backgroundConfig.color,
229
+ roughness: backgroundConfig.roughness ?? .55,
230
+ metalness: backgroundConfig.metalness ?? 0
231
+ };
232
+ const Component = ({ entityId, width, height }) => {
233
+ const data = useWidgetData(entityId);
234
+ const dragging = require_hooks.useTag(entityId, require_hooks.Dragging);
235
+ const groupRef = (0, react.useRef)(null);
236
+ (0, _react_three_fiber.useFrame)(() => {
237
+ const g = groupRef.current;
238
+ if (!g) return;
239
+ const targetScale = dragging ? 1.05 : 1;
240
+ const targetZ = dragging ? 8 : 0;
241
+ const s = g.scale.x;
242
+ g.scale.setScalar(s + (targetScale - s) * .2);
243
+ g.position.z += (targetZ - g.position.z) * .2;
244
+ });
245
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("group", {
246
+ ref: groupRef,
247
+ children: [resolvedBack && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardBack, {
248
+ width,
249
+ height,
250
+ color: resolvedBack.color,
251
+ roughness: resolvedBack.roughness,
252
+ metalness: resolvedBack.metalness
253
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Render, {
254
+ entityId,
255
+ data,
256
+ width,
257
+ height
258
+ })]
259
+ });
260
+ };
261
+ return {
262
+ widget: {
263
+ type: opts.type,
264
+ surface: "webgl",
265
+ schema: opts.schema,
266
+ defaultData: opts.defaultData,
267
+ defaultSize,
268
+ component: Component
269
+ },
270
+ archetype: {
271
+ id: opts.type,
272
+ widget: opts.type,
273
+ components: [[require_hooks.Card, { preset: opts.size }]],
274
+ interactive: {
275
+ selectable: true,
276
+ draggable: true,
277
+ resizable: false,
278
+ selectionFrame: false
279
+ },
280
+ defaultSize
281
+ }
282
+ };
283
+ }
284
+ //#endregion
285
+ //#region src/react/WidgetProvider.tsx
286
+ /**
287
+ * Bridges the engine's widget registry to React context so WidgetSlot /
288
+ * WebGLWidgetLayer can resolve components by type.
289
+ */
290
+ function WidgetProvider({ engine, children }) {
291
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_hooks.WidgetResolverProvider, {
292
+ value: (0, react.useCallback)((_entityId, widgetType) => {
293
+ const def = engine.getWidget(widgetType);
294
+ if (!def) return null;
295
+ if (require_WebGLWidgetLayer.isR3FWidget(def)) return {
296
+ surface: "webgl",
297
+ component: def.component
298
+ };
299
+ return {
300
+ surface: "dom",
301
+ component: def.component
302
+ };
303
+ }, [engine]),
304
+ children
305
+ });
306
+ }
307
+ //#endregion
308
+ //#region src/react/InfiniteCanvas.tsx
309
+ const InfiniteCanvas = react.default.forwardRef(function InfiniteCanvas({ engine, grid, selection, onSelectionChange, onCameraChange, onNavigationChange, className, style, children }, ref) {
310
+ const containerRef = (0, react.useRef)(null);
311
+ const onSelectionChangeRef = (0, react.useRef)(onSelectionChange);
312
+ const onCameraChangeRef = (0, react.useRef)(onCameraChange);
313
+ const onNavigationChangeRef = (0, react.useRef)(onNavigationChange);
314
+ (0, react.useEffect)(() => {
315
+ onSelectionChangeRef.current = onSelectionChange;
316
+ }, [onSelectionChange]);
317
+ (0, react.useEffect)(() => {
318
+ onCameraChangeRef.current = onCameraChange;
319
+ }, [onCameraChange]);
320
+ (0, react.useEffect)(() => {
321
+ onNavigationChangeRef.current = onNavigationChange;
322
+ }, [onNavigationChange]);
323
+ (0, react.useImperativeHandle)(ref, () => ({
324
+ panTo: (x, y) => {
325
+ engine.panTo(x, y);
326
+ engine.markDirty();
327
+ },
328
+ zoomTo: (zoom) => {
329
+ engine.zoomTo(zoom);
330
+ engine.markDirty();
331
+ },
332
+ zoomToFit: (padding) => {
333
+ engine.zoomToFit(void 0, padding);
334
+ engine.markDirty();
335
+ },
336
+ undo: () => {
337
+ engine.undo();
338
+ engine.markDirty();
339
+ },
340
+ redo: () => {
341
+ engine.redo();
342
+ engine.markDirty();
343
+ },
344
+ getEngine: () => engine
345
+ }), [engine]);
346
+ const webglCanvasRef = (0, react.useRef)(null);
347
+ const gridRendererRef = (0, react.useRef)(null);
348
+ const selectionRendererRef = (0, react.useRef)(null);
349
+ const cameraLayerRef = (0, react.useRef)(null);
350
+ const slotRefs = (0, react.useRef)(/* @__PURE__ */ new Map());
351
+ const [visibleEntities, setVisibleEntities] = (0, react.useState)([]);
352
+ const registerSlotRef = (0, react.useCallback)((entityId, el) => {
353
+ if (el) slotRefs.current.set(entityId, el);
354
+ else slotRefs.current.delete(entityId);
355
+ }, []);
356
+ (0, react.useLayoutEffect)(() => {
357
+ const container = containerRef.current;
358
+ const canvas = webglCanvasRef.current;
359
+ if (!container || !canvas) return;
360
+ const gridEnabled = grid !== false;
361
+ let gridInst = null;
362
+ if (gridEnabled) {
363
+ gridInst = new require_WebGLWidgetLayer.GridRenderer(canvas);
364
+ gridRendererRef.current = gridInst;
365
+ }
366
+ const selInst = new require_WebGLWidgetLayer.SelectionRenderer();
367
+ selectionRendererRef.current = selInst;
368
+ const updateSize = () => {
369
+ const rect = container.getBoundingClientRect();
370
+ const dpr = window.devicePixelRatio;
371
+ engine.setViewport(rect.width, rect.height, dpr);
372
+ canvas.style.width = `${rect.width}px`;
373
+ canvas.style.height = `${rect.height}px`;
374
+ if (gridInst) gridInst.setSize(rect.width, rect.height, dpr);
375
+ selInst.setSize(new three.Vector2(rect.width * dpr, rect.height * dpr), dpr);
376
+ };
377
+ updateSize();
378
+ const observer = new ResizeObserver(updateSize);
379
+ observer.observe(container);
380
+ return () => {
381
+ observer.disconnect();
382
+ if (gridInst) {
383
+ gridInst.dispose();
384
+ gridRendererRef.current = null;
385
+ }
386
+ selInst.dispose();
387
+ selectionRendererRef.current = null;
388
+ };
389
+ }, [engine, grid]);
390
+ (0, react.useEffect)(() => {
391
+ const gridR = gridRendererRef.current;
392
+ if (gridR && grid !== false) {
393
+ const isDark = document.documentElement.classList.contains("dark");
394
+ gridR.setConfig({
395
+ dotColor: isDark ? [
396
+ 1,
397
+ 1,
398
+ 1
399
+ ] : [
400
+ 0,
401
+ 0,
402
+ 0
403
+ ],
404
+ dotAlpha: isDark ? .12 : .18,
405
+ ...grid
406
+ });
407
+ }
408
+ const selR = selectionRendererRef.current;
409
+ if (selR && selection) selR.setConfig(selection);
410
+ engine.markDirty();
411
+ }, [
412
+ engine,
413
+ grid,
414
+ selection
415
+ ]);
416
+ (0, react.useEffect)(() => {
417
+ const container = containerRef.current;
418
+ if (!container) return;
419
+ const onWheel = (e) => {
420
+ e.preventDefault();
421
+ if (e.ctrlKey || e.metaKey) {
422
+ const rect = container.getBoundingClientRect();
423
+ engine.zoomAtPoint(e.clientX - rect.left, e.clientY - rect.top, -e.deltaY * .01);
424
+ } else engine.panBy(-e.deltaX, -e.deltaY);
425
+ };
426
+ container.addEventListener("wheel", onWheel, { passive: false });
427
+ return () => container.removeEventListener("wheel", onWheel);
428
+ }, [engine]);
429
+ (0, react.useEffect)(() => {
430
+ const container = containerRef.current;
431
+ if (!container) return;
432
+ let gesture = { type: "idle" };
433
+ let lastTapTime = 0;
434
+ let lastTapX = 0;
435
+ let lastTapY = 0;
436
+ const DOUBLE_TAP_MS = 300;
437
+ const DOUBLE_TAP_DIST = 30;
438
+ function isOnWidget(target) {
439
+ let el = target;
440
+ while (el && el !== container) {
441
+ if (el.hasAttribute("data-widget-slot")) return true;
442
+ el = el.parentElement;
443
+ }
444
+ return false;
445
+ }
446
+ function isInteractive(target) {
447
+ const el = target;
448
+ if (!el) return false;
449
+ const tag = el.tagName;
450
+ return tag === "INPUT" || tag === "TEXTAREA" || tag === "BUTTON" || tag === "SELECT" || el.isContentEditable || el.closest("button") !== null;
451
+ }
452
+ function getRect() {
453
+ return container?.getBoundingClientRect() ?? new DOMRect();
454
+ }
455
+ function touchDist(t1, t2) {
456
+ const dx = t1.clientX - t2.clientX;
457
+ const dy = t1.clientY - t2.clientY;
458
+ return Math.sqrt(dx * dx + dy * dy);
459
+ }
460
+ function touchCenter(t1, t2, rect) {
461
+ return {
462
+ x: (t1.clientX + t2.clientX) / 2 - rect.left,
463
+ y: (t1.clientY + t2.clientY) / 2 - rect.top
464
+ };
465
+ }
466
+ function cancelEngineGesture() {
467
+ if (gesture.type === "pending-entity" || gesture.type === "entity-dragging") engine.handlePointerUp();
468
+ }
469
+ const noMods = {
470
+ shift: false,
471
+ ctrl: false,
472
+ alt: false,
473
+ meta: false
474
+ };
475
+ function onTouchStart(e) {
476
+ const rect = getRect();
477
+ const touches = e.touches;
478
+ if (touches.length >= 2) {
479
+ e.preventDefault();
480
+ cancelEngineGesture();
481
+ const dist = touchDist(touches[0], touches[1]);
482
+ const center = touchCenter(touches[0], touches[1], rect);
483
+ gesture = {
484
+ type: "pinching",
485
+ lastDist: dist,
486
+ lastCx: center.x,
487
+ lastCy: center.y
488
+ };
489
+ return;
490
+ }
491
+ const touch = touches[0];
492
+ const x = touch.clientX - rect.left;
493
+ const y = touch.clientY - rect.top;
494
+ if (isInteractive(e.target)) return;
495
+ e.preventDefault();
496
+ const now = Date.now();
497
+ if (now - lastTapTime < DOUBLE_TAP_MS && Math.abs(x - lastTapX) < DOUBLE_TAP_DIST && Math.abs(y - lastTapY) < DOUBLE_TAP_DIST) {
498
+ lastTapTime = 0;
499
+ const directive = engine.handlePointerDown(x, y, 0, noMods);
500
+ try {
501
+ if (directive.action === "passthrough-track-drag") {
502
+ const selected = engine.getSelectedEntities();
503
+ if (selected.length === 1) engine.enterContainer(selected[0]);
504
+ } else {
505
+ const camera = engine.getCamera();
506
+ const target = camera.zoom < .9 ? 1 : camera.zoom < 1.8 ? 2 : 1;
507
+ engine.zoomAtPoint(x, y, (target - camera.zoom) / camera.zoom);
508
+ }
509
+ } finally {
510
+ engine.handlePointerUp();
511
+ engine.markDirty();
512
+ }
513
+ gesture = { type: "idle" };
514
+ return;
515
+ }
516
+ if (isOnWidget(e.target)) {
517
+ engine.handlePointerDown(x, y, 0, noMods);
518
+ gesture = {
519
+ type: "pending-entity",
520
+ x,
521
+ y,
522
+ time: now
523
+ };
524
+ } else gesture = {
525
+ type: "pending-pan",
526
+ x,
527
+ y,
528
+ time: now
529
+ };
530
+ }
531
+ function onTouchMove(e) {
532
+ e.preventDefault();
533
+ const rect = getRect();
534
+ const touches = e.touches;
535
+ if (gesture.type === "pinching" && touches.length >= 2) {
536
+ const dist = touchDist(touches[0], touches[1]);
537
+ const center = touchCenter(touches[0], touches[1], rect);
538
+ const scale = dist / gesture.lastDist;
539
+ engine.zoomAtPoint(center.x, center.y, scale - 1);
540
+ engine.panBy(center.x - gesture.lastCx, center.y - gesture.lastCy);
541
+ gesture.lastDist = dist;
542
+ gesture.lastCx = center.x;
543
+ gesture.lastCy = center.y;
544
+ return;
545
+ }
546
+ if (touches.length >= 2) {
547
+ cancelEngineGesture();
548
+ const dist = touchDist(touches[0], touches[1]);
549
+ const center = touchCenter(touches[0], touches[1], rect);
550
+ gesture = {
551
+ type: "pinching",
552
+ lastDist: dist,
553
+ lastCx: center.x,
554
+ lastCy: center.y
555
+ };
556
+ return;
557
+ }
558
+ if (touches.length < 1) return;
559
+ const touch = touches[0];
560
+ const x = touch.clientX - rect.left;
561
+ const y = touch.clientY - rect.top;
562
+ if (gesture.type === "pending-pan") {
563
+ if (Math.abs(x - gesture.x) > 8 || Math.abs(y - gesture.y) > 8) gesture = {
564
+ type: "panning",
565
+ lastX: x,
566
+ lastY: y
567
+ };
568
+ return;
569
+ }
570
+ if (gesture.type === "panning") {
571
+ engine.panBy(x - gesture.lastX, y - gesture.lastY);
572
+ gesture.lastX = x;
573
+ gesture.lastY = y;
574
+ return;
575
+ }
576
+ if (gesture.type === "pending-entity" || gesture.type === "entity-dragging") {
577
+ engine.handlePointerMove(x, y, noMods);
578
+ if (gesture.type === "pending-entity") {
579
+ if (Math.abs(x - gesture.x) > 8 || Math.abs(y - gesture.y) > 8) gesture = { type: "entity-dragging" };
580
+ }
581
+ }
582
+ }
583
+ function onTouchEnd(e) {
584
+ e.preventDefault();
585
+ const remaining = e.touches.length;
586
+ const rect = getRect();
587
+ if (gesture.type === "pinching") {
588
+ if (remaining === 1) {
589
+ const t = e.touches[0];
590
+ gesture = {
591
+ type: "panning",
592
+ lastX: t.clientX - rect.left,
593
+ lastY: t.clientY - rect.top
594
+ };
595
+ } else if (remaining === 0) gesture = { type: "idle" };
596
+ return;
597
+ }
598
+ if (remaining > 0) return;
599
+ if (gesture.type === "pending-pan") {
600
+ engine.handlePointerDown(gesture.x, gesture.y, 0, noMods);
601
+ engine.handlePointerUp();
602
+ engine.markDirty();
603
+ lastTapTime = Date.now();
604
+ lastTapX = gesture.x;
605
+ lastTapY = gesture.y;
606
+ }
607
+ if (gesture.type === "pending-entity") {
608
+ engine.handlePointerUp();
609
+ engine.markDirty();
610
+ lastTapTime = Date.now();
611
+ lastTapX = gesture.x;
612
+ lastTapY = gesture.y;
613
+ }
614
+ if (gesture.type === "entity-dragging") {
615
+ engine.handlePointerUp();
616
+ engine.markDirty();
617
+ }
618
+ gesture = { type: "idle" };
619
+ }
620
+ function onTouchCancel(_e) {
621
+ gesture = { type: "idle" };
622
+ engine.handlePointerCancel();
623
+ }
624
+ container.addEventListener("touchstart", onTouchStart, { passive: false });
625
+ container.addEventListener("touchmove", onTouchMove, { passive: false });
626
+ container.addEventListener("touchend", onTouchEnd, { passive: false });
627
+ container.addEventListener("touchcancel", onTouchCancel, { passive: true });
628
+ return () => {
629
+ container.removeEventListener("touchstart", onTouchStart);
630
+ container.removeEventListener("touchmove", onTouchMove);
631
+ container.removeEventListener("touchend", onTouchEnd);
632
+ container.removeEventListener("touchcancel", onTouchCancel);
633
+ };
634
+ }, [engine]);
635
+ const onCanvasPointerDown = (0, react.useCallback)((e) => {
636
+ if (e.target?.closest("button, input, textarea, select, [contenteditable]")) return;
637
+ const rect = containerRef.current?.getBoundingClientRect();
638
+ if (!rect) return;
639
+ const directive = engine.handlePointerDown(e.clientX - rect.left, e.clientY - rect.top, e.button, {
640
+ shift: e.shiftKey,
641
+ ctrl: e.ctrlKey,
642
+ alt: e.altKey,
643
+ meta: e.metaKey
644
+ });
645
+ if (directive.action === "capture-resize" || directive.action === "passthrough-track-drag") containerRef.current?.setPointerCapture(e.pointerId);
646
+ if (directive.action === "capture-resize") e.preventDefault();
647
+ }, [engine]);
648
+ const onCanvasPointerMove = (0, react.useCallback)((e) => {
649
+ const target = e.target;
650
+ if (target.closest?.("[data-widget-slot]") && target !== containerRef.current) return;
651
+ const rect = containerRef.current?.getBoundingClientRect();
652
+ if (!rect) return;
653
+ engine.handlePointerMove(e.clientX - rect.left, e.clientY - rect.top, {
654
+ shift: e.shiftKey,
655
+ ctrl: e.ctrlKey,
656
+ alt: e.altKey,
657
+ meta: e.metaKey
658
+ });
659
+ }, [engine]);
660
+ const onCanvasPointerUp = (0, react.useCallback)((e) => {
661
+ if (containerRef.current?.hasPointerCapture(e.pointerId)) containerRef.current.releasePointerCapture(e.pointerId);
662
+ engine.handlePointerUp();
663
+ }, [engine]);
664
+ (0, react.useEffect)(() => {
665
+ let rafId;
666
+ let running = true;
667
+ function loop() {
668
+ if (!running) return;
669
+ if (engine.flushIfDirty()) {
670
+ const camera = engine.getCamera();
671
+ const changes = engine.getFrameChanges();
672
+ if (cameraLayerRef.current) cameraLayerRef.current.style.transform = `scale(${camera.zoom}) translate(${-camera.x}px, ${-camera.y}px)`;
673
+ const cursor = engine.world.getResource(require_hooks.CursorResource).cursor;
674
+ if (containerRef.current && containerRef.current.style.cursor !== cursor) containerRef.current.style.cursor = cursor;
675
+ const profiler = engine.profiler;
676
+ const profilerOn = profiler.isEnabled();
677
+ let selectionFramesDrawn = 0;
678
+ let snapGuidesDrawn = 0;
679
+ let spacingIndicatorsDrawn = 0;
680
+ if (gridRendererRef.current) gridRendererRef.current.getWebGLRenderer().info.reset();
681
+ if (gridRendererRef.current) {
682
+ profiler.beginWebGL("grid");
683
+ gridRendererRef.current.render(camera.x, camera.y, camera.zoom);
684
+ profiler.endWebGL("grid");
685
+ }
686
+ if (selectionRendererRef.current && gridRendererRef.current) {
687
+ const selected = engine.getSelectedEntities();
688
+ const selBounds = [];
689
+ for (const id of selected) {
690
+ if (!engine.has(id, require_hooks.SelectionFrame)) continue;
691
+ const wb = engine.get(id, require_hooks.WorldBounds);
692
+ if (wb) selBounds.push({
693
+ x: wb.worldX,
694
+ y: wb.worldY,
695
+ width: wb.worldWidth,
696
+ height: wb.worldHeight
697
+ });
698
+ }
699
+ const hovId = engine.getHoveredEntity();
700
+ let hovBounds = null;
701
+ if (hovId !== null && engine.has(hovId, require_hooks.SelectionFrame)) {
702
+ const wb = engine.get(hovId, require_hooks.WorldBounds);
703
+ if (wb) hovBounds = {
704
+ x: wb.worldX,
705
+ y: wb.worldY,
706
+ width: wb.worldWidth,
707
+ height: wb.worldHeight
708
+ };
709
+ }
710
+ const snapGuides = engine.getSnapGuides();
711
+ const equalSpacing = engine.getEqualSpacing();
712
+ selectionFramesDrawn = selBounds.length + (hovBounds ? 1 : 0);
713
+ snapGuidesDrawn = snapGuides.length;
714
+ spacingIndicatorsDrawn = equalSpacing.length;
715
+ profiler.beginWebGL("selection");
716
+ selectionRendererRef.current.render(gridRendererRef.current.getWebGLRenderer(), camera.x, camera.y, camera.zoom, selBounds, hovBounds, snapGuides, equalSpacing);
717
+ profiler.endWebGL("selection");
718
+ }
719
+ if (profilerOn && gridRendererRef.current) {
720
+ const info = gridRendererRef.current.getWebGLRenderer().info;
721
+ profiler.recordWebGLStats({
722
+ drawCalls: info.render.calls,
723
+ triangles: info.render.triangles,
724
+ selectionFrames: selectionFramesDrawn,
725
+ snapGuides: snapGuidesDrawn,
726
+ spacingIndicators: spacingIndicatorsDrawn,
727
+ domPositionsUpdated: changes.positionsChanged.length
728
+ });
729
+ }
730
+ for (const entityId of changes.positionsChanged) {
731
+ const el = slotRefs.current.get(entityId);
732
+ if (!el) continue;
733
+ const wb = engine.get(entityId, require_hooks.WorldBounds);
734
+ if (!wb) continue;
735
+ el.style.transform = `translate(${wb.worldX}px, ${wb.worldY}px)`;
736
+ el.style.width = `${wb.worldWidth}px`;
737
+ el.style.height = `${wb.worldHeight}px`;
738
+ }
739
+ if (changes.entered.length > 0 || changes.exited.length > 0) setVisibleEntities(engine.getVisibleEntities().map((v) => v.entityId));
740
+ if (changes.selectionChanged && onSelectionChangeRef.current) onSelectionChangeRef.current(engine.getSelectedEntities());
741
+ if (changes.cameraChanged && onCameraChangeRef.current) onCameraChangeRef.current({
742
+ x: camera.x,
743
+ y: camera.y,
744
+ zoom: camera.zoom
745
+ });
746
+ if (changes.navigationChanged && onNavigationChangeRef.current) {
747
+ const navStack = engine.world.getResource(require_hooks.NavigationStackResource);
748
+ const depth = navStack.frames.length - 1;
749
+ const containerId = navStack.frames[navStack.frames.length - 1].containerId;
750
+ onNavigationChangeRef.current(depth, containerId);
751
+ }
752
+ }
753
+ rafId = requestAnimationFrame(loop);
754
+ }
755
+ engine.tick();
756
+ const visible = engine.getVisibleEntities();
757
+ setVisibleEntities(visible.map((v) => v.entityId));
758
+ const camera = engine.getCamera();
759
+ if (cameraLayerRef.current) cameraLayerRef.current.style.transform = `scale(${camera.zoom}) translate(${-camera.x}px, ${-camera.y}px)`;
760
+ if (gridRendererRef.current) gridRendererRef.current.render(camera.x, camera.y, camera.zoom);
761
+ for (const v of visible) {
762
+ const el = slotRefs.current.get(v.entityId);
763
+ if (!el) continue;
764
+ el.style.transform = `translate(${v.worldX}px, ${v.worldY}px)`;
765
+ el.style.width = `${v.worldWidth}px`;
766
+ el.style.height = `${v.worldHeight}px`;
767
+ }
768
+ rafId = requestAnimationFrame(loop);
769
+ return () => {
770
+ running = false;
771
+ cancelAnimationFrame(rafId);
772
+ };
773
+ }, [engine]);
774
+ (0, react.useLayoutEffect)(() => {
775
+ for (const entityId of visibleEntities) {
776
+ const el = slotRefs.current.get(entityId);
777
+ if (!el) continue;
778
+ const wb = engine.get(entityId, require_hooks.WorldBounds);
779
+ if (!wb) continue;
780
+ el.style.transform = `translate(${wb.worldX}px, ${wb.worldY}px)`;
781
+ el.style.width = `${wb.worldWidth}px`;
782
+ el.style.height = `${wb.worldHeight}px`;
783
+ }
784
+ }, [visibleEntities, engine]);
785
+ const { domEntities, webglEntities } = (0, react.useMemo)(() => {
786
+ const dom = [];
787
+ const webgl = [];
788
+ for (const id of visibleEntities) if (engine.get(id, require_hooks.Widget)?.surface === "webgl") webgl.push(id);
789
+ else dom.push(id);
790
+ return {
791
+ domEntities: dom,
792
+ webglEntities: webgl
793
+ };
794
+ }, [visibleEntities, engine]);
795
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_hooks.EngineProvider, {
796
+ value: engine,
797
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_hooks.ContainerRefProvider, {
798
+ value: containerRef,
799
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WidgetProvider, {
800
+ engine,
801
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
802
+ ref: containerRef,
803
+ className: `relative overflow-hidden ${className ?? ""}`,
804
+ style: {
805
+ ...style,
806
+ touchAction: "none",
807
+ backgroundColor: "var(--canvas-bg, #fafafa)"
808
+ },
809
+ onPointerDown: onCanvasPointerDown,
810
+ onPointerMove: onCanvasPointerMove,
811
+ onPointerUp: onCanvasPointerUp,
812
+ children: [
813
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("canvas", {
814
+ ref: webglCanvasRef,
815
+ className: "absolute inset-0 pointer-events-none"
816
+ }),
817
+ webglEntities.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WebGLWidgetBridge, {
818
+ engine,
819
+ entities: webglEntities
820
+ }),
821
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "absolute inset-0 pointer-events-none" }),
822
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
823
+ ref: cameraLayerRef,
824
+ className: "absolute left-0 top-0 origin-top-left will-change-transform",
825
+ children: [domEntities.map((entityId) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_WebGLWidgetLayer.WidgetSlot, {
826
+ entityId,
827
+ slotRef: registerSlotRef
828
+ }, entityId)), webglEntities.map((entityId) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_WebGLWidgetLayer.SelectionOverlaySlot, {
829
+ entityId,
830
+ slotRef: registerSlotRef
831
+ }, entityId))]
832
+ }),
833
+ children
834
+ ]
835
+ })
836
+ })
837
+ })
838
+ });
839
+ });
840
+ /** Bridge component — reads widget resolver from context and passes to WebGLWidgetLayer */
841
+ function WebGLWidgetBridge({ engine, entities }) {
842
+ const resolver = require_hooks.useWidgetResolver();
843
+ const resolve = (0, react.useCallback)((entityId) => {
844
+ if (!resolver) return null;
845
+ return resolver(entityId, engine.get(entityId, require_hooks.Widget)?.type ?? "");
846
+ }, [resolver, engine]);
847
+ if (!resolver) return null;
848
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_WebGLWidgetLayer.WebGLWidgetLayer, {
849
+ engine,
850
+ entities,
851
+ resolve
852
+ });
853
+ }
854
+ //#endregion
855
+ exports.Active = require_hooks.Active;
856
+ exports.BreakpointConfigResource = require_hooks.BreakpointConfigResource;
857
+ exports.CameraResource = require_hooks.CameraResource;
858
+ exports.Card = require_hooks.Card;
859
+ exports.CardFrame = CardFrame;
860
+ exports.CardPresetsResource = require_hooks.CardPresetsResource;
861
+ exports.Children = require_hooks.Children;
862
+ exports.CommandBuffer = require_WebGLWidgetLayer.CommandBuffer;
863
+ exports.Container = require_hooks.Container;
864
+ exports.CursorHint = require_hooks.CursorHint;
865
+ exports.CursorResource = require_hooks.CursorResource;
866
+ exports.DEFAULT_GRID_CONFIG = require_WebGLWidgetLayer.DEFAULT_GRID_CONFIG;
867
+ exports.DEFAULT_SELECTION_CONFIG = require_WebGLWidgetLayer.DEFAULT_SELECTION_CONFIG;
868
+ exports.Draggable = require_hooks.Draggable;
869
+ exports.Dragging = require_hooks.Dragging;
870
+ exports.HandleSet = require_hooks.HandleSet;
871
+ exports.Hitbox = require_hooks.Hitbox;
813
872
  exports.InfiniteCanvas = InfiniteCanvas;
873
+ exports.InteractionRole = require_hooks.InteractionRole;
874
+ exports.Locked = require_hooks.Locked;
875
+ exports.MoveCommand = require_WebGLWidgetLayer.MoveCommand;
876
+ exports.NavigationStackResource = require_hooks.NavigationStackResource;
877
+ exports.Parent = require_hooks.Parent;
878
+ exports.Resizable = require_hooks.Resizable;
879
+ exports.ResizeCommand = require_WebGLWidgetLayer.ResizeCommand;
880
+ exports.Selectable = require_hooks.Selectable;
881
+ exports.Selected = require_hooks.Selected;
882
+ exports.SelectionFrame = require_hooks.SelectionFrame;
883
+ exports.SetComponentCommand = require_WebGLWidgetLayer.SetComponentCommand;
884
+ exports.Transform2D = require_hooks.Transform2D;
885
+ exports.ViewportResource = require_hooks.ViewportResource;
886
+ exports.Visible = require_hooks.Visible;
887
+ exports.Widget = require_hooks.Widget;
888
+ exports.WidgetBreakpoint = require_hooks.WidgetBreakpoint;
889
+ exports.WidgetData = require_hooks.WidgetData;
814
890
  exports.WidgetProvider = WidgetProvider;
891
+ exports.WidgetResolverProvider = require_hooks.WidgetResolverProvider;
892
+ exports.WorldBounds = require_hooks.WorldBounds;
893
+ exports.ZIndex = require_hooks.ZIndex;
894
+ exports.ZoomConfigResource = require_hooks.ZoomConfigResource;
895
+ exports.clamp = require_WebGLWidgetLayer.clamp;
896
+ exports.createArchetypeRegistry = require_WebGLWidgetLayer.createArchetypeRegistry;
897
+ exports.createCardWidget = createCardWidget;
898
+ exports.createGeometryCardWidget = createGeometryCardWidget;
899
+ exports.createLayoutEngine = require_WebGLWidgetLayer.createLayoutEngine;
900
+ exports.createWidgetRegistry = require_WebGLWidgetLayer.createWidgetRegistry;
901
+ exports.intersectsAABB = require_WebGLWidgetLayer.intersectsAABB;
902
+ exports.isR3FWidget = require_WebGLWidgetLayer.isR3FWidget;
903
+ exports.pointInAABB = require_WebGLWidgetLayer.pointInAABB;
904
+ exports.screenToWorld = require_WebGLWidgetLayer.screenToWorld;
905
+ exports.useAllEntities = require_hooks.useAllEntities;
815
906
  exports.useBreakpoint = useBreakpoint;
907
+ exports.useCamera = require_hooks.useCamera;
816
908
  exports.useChildren = useChildren;
909
+ exports.useComponent = require_hooks.useComponent;
910
+ exports.useContainerRef = require_hooks.useContainerRef;
911
+ exports.useEntityComponents = require_hooks.useEntityComponents;
912
+ exports.useEntityTags = require_hooks.useEntityTags;
817
913
  exports.useIsSelected = useIsSelected;
914
+ exports.useLayoutEngine = require_hooks.useLayoutEngine;
915
+ exports.useQuery = require_hooks.useQuery;
916
+ exports.useRegisteredComponents = require_hooks.useRegisteredComponents;
917
+ exports.useRegisteredTags = require_hooks.useRegisteredTags;
918
+ exports.useResource = require_hooks.useResource;
919
+ exports.useTag = require_hooks.useTag;
920
+ exports.useTaggedEntities = require_hooks.useTaggedEntities;
818
921
  exports.useUpdateWidget = useUpdateWidget;
819
922
  exports.useWidgetData = useWidgetData;
820
- //# sourceMappingURL=index.cjs.map
923
+ exports.useWidgetResolver = require_hooks.useWidgetResolver;
924
+ exports.worldBoundsToAABB = require_WebGLWidgetLayer.worldBoundsToAABB;
925
+ exports.worldToScreen = require_WebGLWidgetLayer.worldToScreen;
926
+
821
927
  //# sourceMappingURL=index.cjs.map