@vibecook/ice 0.1.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 (148) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +76 -0
  3. package/dist/chunk-5S7GSXJG.js +6003 -0
  4. package/dist/chunk-5S7GSXJG.js.map +1 -0
  5. package/dist/chunk-BCJ47SX7.js +550 -0
  6. package/dist/chunk-BCJ47SX7.js.map +1 -0
  7. package/dist/chunk-FIAXPNNY.js +1446 -0
  8. package/dist/chunk-FIAXPNNY.js.map +1 -0
  9. package/dist/devtools.js +417 -0
  10. package/dist/devtools.js.map +1 -0
  11. package/dist/dom.js +41 -0
  12. package/dist/dom.js.map +1 -0
  13. package/dist/index.js +450 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/kernel.js +63 -0
  16. package/dist/kernel.js.map +1 -0
  17. package/dist/r3f.js +1101 -0
  18. package/dist/r3f.js.map +1 -0
  19. package/dist/react.js +440 -0
  20. package/dist/react.js.map +1 -0
  21. package/dist/types/packages/core/src/boot/hmr.d.ts +12 -0
  22. package/dist/types/packages/core/src/catalog/camera-derived.d.ts +144 -0
  23. package/dist/types/packages/core/src/catalog/gesture.d.ts +254 -0
  24. package/dist/types/packages/core/src/catalog/graph.d.ts +55 -0
  25. package/dist/types/packages/core/src/catalog/index.d.ts +32 -0
  26. package/dist/types/packages/core/src/catalog/pointer.d.ts +111 -0
  27. package/dist/types/packages/core/src/catalog/scene.d.ts +34 -0
  28. package/dist/types/packages/core/src/catalog/selection-presence.d.ts +53 -0
  29. package/dist/types/packages/core/src/catalog/settings-resources.d.ts +46 -0
  30. package/dist/types/packages/core/src/doc/autosave.d.ts +69 -0
  31. package/dist/types/packages/core/src/doc/bootstrap.d.ts +74 -0
  32. package/dist/types/packages/core/src/doc/broadcast-relay.d.ts +52 -0
  33. package/dist/types/packages/core/src/doc/channels.d.ts +49 -0
  34. package/dist/types/packages/core/src/doc/doc-commit-sink.d.ts +22 -0
  35. package/dist/types/packages/core/src/doc/doc-kit.d.ts +50 -0
  36. package/dist/types/packages/core/src/doc/envelope.d.ts +36 -0
  37. package/dist/types/packages/core/src/doc/migrate.d.ts +69 -0
  38. package/dist/types/packages/core/src/doc/version-gate.d.ts +49 -0
  39. package/dist/types/packages/core/src/engine/commit-sink.d.ts +61 -0
  40. package/dist/types/packages/core/src/engine/engine.d.ts +62 -0
  41. package/dist/types/packages/core/src/engine/frame-info.d.ts +16 -0
  42. package/dist/types/packages/core/src/engine/instantiate.d.ts +45 -0
  43. package/dist/types/packages/core/src/engine/pipeline.d.ts +17 -0
  44. package/dist/types/packages/core/src/engine/reflectors.d.ts +56 -0
  45. package/dist/types/packages/core/src/facade/create-canvas-engine.d.ts +120 -0
  46. package/dist/types/packages/core/src/guards/dev.d.ts +2 -0
  47. package/dist/types/packages/core/src/guards/guarded-tx.d.ts +51 -0
  48. package/dist/types/packages/core/src/guards/live-writer.d.ts +33 -0
  49. package/dist/types/packages/core/src/guards/resource-writer.d.ts +17 -0
  50. package/dist/types/packages/core/src/helpers/phase-set.d.ts +70 -0
  51. package/dist/types/packages/core/src/helpers/version-stamps.d.ts +55 -0
  52. package/dist/types/packages/core/src/index.d.ts +63 -0
  53. package/dist/types/packages/core/src/input/measure-queue.d.ts +30 -0
  54. package/dist/types/packages/core/src/input/queue.d.ts +60 -0
  55. package/dist/types/packages/core/src/interaction/install.d.ts +58 -0
  56. package/dist/types/packages/core/src/nav/nested-canvas.d.ts +62 -0
  57. package/dist/types/packages/core/src/ops/cascade.d.ts +18 -0
  58. package/dist/types/packages/core/src/ops/claims.d.ts +15 -0
  59. package/dist/types/packages/core/src/ops/gestures.d.ts +10 -0
  60. package/dist/types/packages/core/src/ops/point-pick.d.ts +42 -0
  61. package/dist/types/packages/core/src/ops/port-geometry.d.ts +17 -0
  62. package/dist/types/packages/core/src/ops/selection.d.ts +14 -0
  63. package/dist/types/packages/core/src/presence/index.d.ts +7 -0
  64. package/dist/types/packages/core/src/presence/presence-kit.d.ts +39 -0
  65. package/dist/types/packages/core/src/presence/publish.d.ts +14 -0
  66. package/dist/types/packages/core/src/presence/remote-cursors.d.ts +18 -0
  67. package/dist/types/packages/core/src/schema/meta.d.ts +43 -0
  68. package/dist/types/packages/core/src/schema/prefab.d.ts +69 -0
  69. package/dist/types/packages/core/src/settings/defaults.d.ts +56 -0
  70. package/dist/types/packages/core/src/systems/camera-sim.d.ts +19 -0
  71. package/dist/types/packages/core/src/systems/chrome.d.ts +48 -0
  72. package/dist/types/packages/core/src/systems/cleanup.d.ts +19 -0
  73. package/dist/types/packages/core/src/systems/l0-input.d.ts +31 -0
  74. package/dist/types/packages/core/src/systems/l1-pick.d.ts +44 -0
  75. package/dist/types/packages/core/src/systems/l1-wires.d.ts +30 -0
  76. package/dist/types/packages/core/src/systems/l2-arbitrate.d.ts +40 -0
  77. package/dist/types/packages/core/src/systems/l2-recognize.d.ts +45 -0
  78. package/dist/types/packages/core/src/systems/l3-behave.d.ts +24 -0
  79. package/dist/types/packages/core/src/systems/l3-claim.d.ts +26 -0
  80. package/dist/types/packages/core/src/systems/l3-connect.d.ts +57 -0
  81. package/dist/types/packages/core/src/systems/l3-draw.d.ts +21 -0
  82. package/dist/types/packages/core/src/systems/l3-drop.d.ts +21 -0
  83. package/dist/types/packages/core/src/systems/l3-marquee.d.ts +35 -0
  84. package/dist/types/packages/core/src/systems/l3-ports.d.ts +30 -0
  85. package/dist/types/packages/core/src/systems/l3-resize.d.ts +17 -0
  86. package/dist/types/packages/core/src/systems/l3-snap.d.ts +19 -0
  87. package/dist/types/packages/core/src/systems/l4-cursor.d.ts +24 -0
  88. package/dist/types/packages/core/src/systems/measure-ingest.d.ts +26 -0
  89. package/dist/types/packages/core/src/tools/define-tool.d.ts +79 -0
  90. package/dist/types/packages/core/src/widget/define-widget.d.ts +124 -0
  91. package/dist/types/packages/core/src/widget/equip.d.ts +14 -0
  92. package/dist/types/packages/core/src/widget/mount-store.d.ts +47 -0
  93. package/dist/types/packages/core/src/widget/props.d.ts +98 -0
  94. package/dist/types/packages/core/src/widget/spawn.d.ts +30 -0
  95. package/dist/types/packages/devtools/src/index.d.ts +8 -0
  96. package/dist/types/packages/devtools/src/panel.d.ts +48 -0
  97. package/dist/types/packages/dom/src/host.d.ts +24 -0
  98. package/dist/types/packages/dom/src/index.d.ts +19 -0
  99. package/dist/types/packages/dom/src/loop.d.ts +11 -0
  100. package/dist/types/packages/dom/src/measure-adapter.d.ts +31 -0
  101. package/dist/types/packages/dom/src/measure-wiring.d.ts +49 -0
  102. package/dist/types/packages/dom/src/planes.d.ts +33 -0
  103. package/dist/types/packages/dom/src/pointer-adapter.d.ts +48 -0
  104. package/dist/types/packages/dom/src/reflectors/chrome.d.ts +33 -0
  105. package/dist/types/packages/dom/src/reflectors/cursor.d.ts +21 -0
  106. package/dist/types/packages/dom/src/reflectors/dom-widgets.d.ts +54 -0
  107. package/dist/types/packages/dom/src/reflectors/graybox.d.ts +31 -0
  108. package/dist/types/packages/dom/src/reflectors/grid.d.ts +63 -0
  109. package/dist/types/packages/dom/src/reflectors/plane-transform.d.ts +38 -0
  110. package/dist/types/packages/dom/src/reflectors/remote-cursors.d.ts +20 -0
  111. package/dist/types/packages/dom/src/reflectors/wires.d.ts +88 -0
  112. package/dist/types/packages/ice/src/devtools.d.ts +1 -0
  113. package/dist/types/packages/ice/src/dom.d.ts +1 -0
  114. package/dist/types/packages/ice/src/index.d.ts +1 -0
  115. package/dist/types/packages/ice/src/kernel.d.ts +1 -0
  116. package/dist/types/packages/ice/src/r3f.d.ts +1 -0
  117. package/dist/types/packages/ice/src/react.d.ts +1 -0
  118. package/dist/types/packages/kernel/src/anchors.d.ts +18 -0
  119. package/dist/types/packages/kernel/src/bezier.d.ts +38 -0
  120. package/dist/types/packages/kernel/src/coords.d.ts +67 -0
  121. package/dist/types/packages/kernel/src/eviction.d.ts +23 -0
  122. package/dist/types/packages/kernel/src/index.d.ts +13 -0
  123. package/dist/types/packages/kernel/src/shapes.d.ts +22 -0
  124. package/dist/types/packages/kernel/src/snap.d.ts +44 -0
  125. package/dist/types/packages/kernel/src/spatial-index.d.ts +16 -0
  126. package/dist/types/packages/kernel/src/zoom-bands.d.ts +19 -0
  127. package/dist/types/packages/r3f/src/bridge.d.ts +68 -0
  128. package/dist/types/packages/r3f/src/composite-material.d.ts +17 -0
  129. package/dist/types/packages/r3f/src/compositor-pass.d.ts +83 -0
  130. package/dist/types/packages/r3f/src/dev-write-trap.d.ts +30 -0
  131. package/dist/types/packages/r3f/src/gl-root.d.ts +21 -0
  132. package/dist/types/packages/r3f/src/gl-router.d.ts +60 -0
  133. package/dist/types/packages/r3f/src/index.d.ts +16 -0
  134. package/dist/types/packages/r3f/src/island-state.d.ts +68 -0
  135. package/dist/types/packages/r3f/src/island.d.ts +13 -0
  136. package/dist/types/packages/r3f/src/pool.d.ts +56 -0
  137. package/dist/types/packages/r3f/src/resource-registry.d.ts +30 -0
  138. package/dist/types/packages/r3f/src/use-island-frame.d.ts +24 -0
  139. package/dist/types/packages/react/src/engine-context.d.ts +31 -0
  140. package/dist/types/packages/react/src/hooks.d.ts +40 -0
  141. package/dist/types/packages/react/src/index.d.ts +14 -0
  142. package/dist/types/packages/react/src/infinite-canvas.d.ts +71 -0
  143. package/dist/types/packages/react/src/keymap.d.ts +42 -0
  144. package/dist/types/packages/react/src/use-commit.d.ts +35 -0
  145. package/dist/types/packages/react/src/use-presence.d.ts +23 -0
  146. package/dist/types/packages/react/src/use-tool.d.ts +4 -0
  147. package/dist/types/packages/react/src/widget-root.d.ts +33 -0
  148. package/package.json +112 -0
package/dist/react.js ADDED
@@ -0,0 +1,440 @@
1
+ import {
2
+ attachPointerAdapter,
3
+ createCanvasHost,
4
+ createChromeReflector,
5
+ createCursorReflector,
6
+ createDomWidgetsReflector,
7
+ createGridReflector,
8
+ createPlaneTransformReflector,
9
+ createPlanes,
10
+ createRemoteCursorsReflector,
11
+ createWiresReflector,
12
+ startRafLoop,
13
+ wireMeasurement
14
+ } from "./chunk-FIAXPNNY.js";
15
+ import {
16
+ ActiveTool,
17
+ DurableUndoStatus,
18
+ Local,
19
+ Not,
20
+ Position,
21
+ PrefabId,
22
+ PresenceInfo,
23
+ PresencePeer,
24
+ Selected,
25
+ Viewport,
26
+ WidgetBreakpoint,
27
+ defineQuery,
28
+ devGuardsEnabled,
29
+ guardedTransaction,
30
+ selectedEntities,
31
+ tools,
32
+ widgets,
33
+ writeRuntimeResource
34
+ } from "./chunk-5S7GSXJG.js";
35
+ import "./chunk-BCJ47SX7.js";
36
+
37
+ // ../react/src/hooks.ts
38
+ import { createContext, useCallback, useContext, useMemo, useRef, useSyncExternalStore } from "react";
39
+ var WidgetHiddenContext = createContext(false);
40
+ var selectedQ = defineQuery([Selected]);
41
+ function shallowEq(a, b) {
42
+ if (Object.is(a, b)) return true;
43
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
44
+ const ka = Object.keys(a);
45
+ const kb = Object.keys(b);
46
+ if (ka.length !== kb.length) return false;
47
+ for (const k of ka) {
48
+ if (!Object.is(a[k], b[k])) return false;
49
+ }
50
+ return true;
51
+ }
52
+ function useWorldComponent(world, entity, component) {
53
+ const hidden = useContext(WidgetHiddenContext);
54
+ const last = useRef(void 0);
55
+ const subscribe = useCallback(
56
+ (onChange) => {
57
+ if (hidden) return () => {
58
+ };
59
+ return world.reactive.observeValue(entity, component, onChange);
60
+ },
61
+ [world, entity, component, hidden]
62
+ );
63
+ const getSnapshot = useCallback(() => {
64
+ if (hidden) return last.current;
65
+ const v = world.isAlive(entity) ? world.get(entity, component) : void 0;
66
+ if (!shallowEq(v, last.current)) last.current = v;
67
+ return last.current;
68
+ }, [world, entity, component, hidden]);
69
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
70
+ }
71
+ function useWidgetProps(world, entity, type, group = "props") {
72
+ const widget = widgets.get(type);
73
+ const g = widget?.groups.find((x) => x.name === group);
74
+ if (widget === void 0 || g === void 0) {
75
+ throw new Error(`ice: useWidgetProps \u2014 unknown widget type/group "${type}"/"${group}".`);
76
+ }
77
+ const raw = useWorldComponent(world, entity, g.component);
78
+ return useMemo(() => {
79
+ if (raw === void 0) return void 0;
80
+ const out = {};
81
+ for (const [name, spec] of Object.entries(g.fields)) {
82
+ const v = raw[name];
83
+ out[name] = spec.kind === "json" && typeof v === "string" ? JSON.parse(v) : v;
84
+ }
85
+ return out;
86
+ }, [raw, g]);
87
+ }
88
+ function useSelected(world, entity) {
89
+ const hidden = useContext(WidgetHiddenContext);
90
+ const last = useRef(false);
91
+ const subscribe = useCallback(
92
+ (onChange) => {
93
+ if (hidden) return () => {
94
+ };
95
+ return world.reactive.observeQuery(selectedQ, onChange);
96
+ },
97
+ [world, hidden]
98
+ );
99
+ const getSnapshot = useCallback(() => {
100
+ if (hidden) return last.current;
101
+ last.current = world.isAlive(entity) && world.hasTag(entity, Selected);
102
+ return last.current;
103
+ }, [world, entity, hidden]);
104
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
105
+ }
106
+ function useBreakpoint(world, entity) {
107
+ const bp = useWorldComponent(world, entity, WidgetBreakpoint);
108
+ return bp?.tier ?? "normal";
109
+ }
110
+
111
+ // ../react/src/widget-root.tsx
112
+ import { createElement } from "react";
113
+ import { createPortal } from "react-dom";
114
+ import { useSyncExternalStore as useSyncExternalStore2 } from "react";
115
+ function WidgetRoot({ world, store, hosts }) {
116
+ const entries = useSyncExternalStore2(store.subscribe, store.getSnapshot, store.getSnapshot);
117
+ const portals = [];
118
+ for (const entry of entries) {
119
+ if (!world.isAlive(entry.entity)) continue;
120
+ const type = world.get(entry.entity, PrefabId)?.id;
121
+ const widget = typeof type === "string" ? widgets.get(type) : void 0;
122
+ if (widget === void 0 || widget.surface !== "dom") continue;
123
+ const target = hosts.hostFor(entry.entity);
124
+ if (target === void 0) continue;
125
+ const View = widget.component;
126
+ if (View == null) continue;
127
+ portals.push(
128
+ createPortal(
129
+ createElement(
130
+ WidgetHiddenContext.Provider,
131
+ { value: entry.hidden },
132
+ createElement(View, { entity: entry.entity, world })
133
+ ),
134
+ target,
135
+ String(entry.entity)
136
+ )
137
+ );
138
+ }
139
+ return createElement("div", { "data-ice-widget-root": "" }, portals);
140
+ }
141
+
142
+ // ../react/src/engine-context.tsx
143
+ import { createContext as createContext2, useContext as useContext2 } from "react";
144
+ import { jsx } from "react/jsx-runtime";
145
+ var EngineContext = createContext2(null);
146
+ function EngineProvider({ engine, children }) {
147
+ return /* @__PURE__ */ jsx(EngineContext.Provider, { value: engine, children });
148
+ }
149
+ function useCanvasEngine() {
150
+ const engine = useContext2(EngineContext);
151
+ if (engine === null) {
152
+ throw new Error(
153
+ "ice: useCanvasEngine \u2014 no <EngineProvider>. Render widgets inside <InfiniteCanvas> (which provides it) or wrap your tree in <EngineProvider engine={...}>."
154
+ );
155
+ }
156
+ return engine;
157
+ }
158
+ function useOps() {
159
+ return useCanvasEngine().ops;
160
+ }
161
+ var warnedUseWorld = false;
162
+ function useWorld() {
163
+ const engine = useCanvasEngine();
164
+ if (devGuardsEnabled() && !warnedUseWorld) {
165
+ warnedUseWorld = true;
166
+ console.warn(
167
+ "ice: useWorld() is a READ/OBSERVE escape hatch \u2014 never write to the world directly. Use useOps()/useCommit() for mutation (design-005 \xA75)."
168
+ );
169
+ }
170
+ return engine.world;
171
+ }
172
+
173
+ // ../react/src/use-commit.ts
174
+ import { useCallback as useCallback2, useRef as useRef2, useSyncExternalStore as useSyncExternalStore3 } from "react";
175
+ function useCommit() {
176
+ const engine = useCanvasEngine();
177
+ return useCallback2(
178
+ (fn, opts) => {
179
+ const session = engine.docs.current();
180
+ if (session === void 0) {
181
+ throw new Error(
182
+ "ice: useCommit \u2014 no active document. Attach one with engine.docs.create()/open()/join() before committing widget edits."
183
+ );
184
+ }
185
+ guardedTransaction(session.store, engine.world, fn, opts);
186
+ },
187
+ [engine]
188
+ );
189
+ }
190
+ var NO_UNDO = { canUndo: false, canRedo: false };
191
+ function useUndoStatus() {
192
+ const engine = useCanvasEngine();
193
+ const last = useRef2(NO_UNDO);
194
+ const subscribe = useCallback2(
195
+ (onChange) => engine.world.reactive.observeResource(DurableUndoStatus, onChange),
196
+ [engine]
197
+ );
198
+ const getSnapshot = useCallback2(() => {
199
+ const status = engine.world.getResource(DurableUndoStatus);
200
+ const canUndo = status?.canUndo ?? false;
201
+ const canRedo = status?.canRedo ?? false;
202
+ if (last.current.canUndo !== canUndo || last.current.canRedo !== canRedo) {
203
+ last.current = { canUndo, canRedo };
204
+ }
205
+ return last.current;
206
+ }, [engine]);
207
+ return useSyncExternalStore3(subscribe, getSnapshot, getSnapshot);
208
+ }
209
+
210
+ // ../react/src/use-tool.ts
211
+ import { useCallback as useCallback3, useSyncExternalStore as useSyncExternalStore4 } from "react";
212
+ function useTool() {
213
+ const engine = useCanvasEngine();
214
+ const subscribe = useCallback3(
215
+ (onChange) => engine.world.reactive.observeResource(ActiveTool, onChange),
216
+ [engine]
217
+ );
218
+ const getSnapshot = useCallback3(() => engine.world.getResource(ActiveTool)?.id ?? "select", [engine]);
219
+ const active = useSyncExternalStore4(subscribe, getSnapshot, getSnapshot);
220
+ const setTool = useCallback3((id) => engine.ops.setTool(id), [engine]);
221
+ return [active, setTool];
222
+ }
223
+ function useToolState(id) {
224
+ const [active] = useTool();
225
+ return active === id;
226
+ }
227
+
228
+ // ../react/src/use-presence.ts
229
+ import { useCallback as useCallback4, useRef as useRef3, useSyncExternalStore as useSyncExternalStore5 } from "react";
230
+ var remotePeersQ = defineQuery([PresencePeer, Not(Local)]);
231
+ function usePresencePeers() {
232
+ const engine = useCanvasEngine();
233
+ const cache = useRef3({ key: "\0", value: [] });
234
+ const subscribe = useCallback4(
235
+ (onChange) => engine.world.reactive.observeQuery(remotePeersQ, onChange),
236
+ [engine]
237
+ );
238
+ const getSnapshot = useCallback4(() => {
239
+ const world = engine.world;
240
+ const ids = [];
241
+ world.query(remotePeersQ).each((b) => {
242
+ for (const r of b) ids.push(b.entity(r));
243
+ });
244
+ const key = ids.join(",");
245
+ if (key !== cache.current.key) {
246
+ cache.current = {
247
+ key,
248
+ value: ids.map((entity) => ({ entity, info: world.get(entity, PresenceInfo) }))
249
+ };
250
+ }
251
+ return cache.current.value;
252
+ }, [engine]);
253
+ return useSyncExternalStore5(subscribe, getSnapshot, getSnapshot);
254
+ }
255
+
256
+ // ../react/src/keymap.ts
257
+ var signature = (key, mod, shift) => `${key.toLowerCase()}|${mod ? 1 : 0}|${shift ? 1 : 0}`;
258
+ function isEditableTarget(target) {
259
+ if (target === null || !(target instanceof HTMLElement)) return false;
260
+ const tag = target.tagName;
261
+ return tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || target.isContentEditable;
262
+ }
263
+ function nudgeSelection(engine, dx, dy) {
264
+ const session = engine.docs.current();
265
+ if (session === void 0) return;
266
+ const selection = selectedEntities(engine.world).filter((e) => session.store.keyOf(e) !== void 0);
267
+ if (selection.length === 0) return;
268
+ guardedTransaction(session.store, engine.world, (tx) => {
269
+ for (const e of selection) {
270
+ const p = engine.world.get(e, Position);
271
+ if (p === void 0) continue;
272
+ tx.edit(e).set(Position, { x: p.x + dx, y: p.y + dy });
273
+ }
274
+ });
275
+ }
276
+ var ARROWS = [
277
+ ["ArrowLeft", -1, 0],
278
+ ["ArrowRight", 1, 0],
279
+ ["ArrowUp", 0, -1],
280
+ ["ArrowDown", 0, 1]
281
+ ];
282
+ function defaultEntries() {
283
+ const entries = [
284
+ { key: "Backspace", run: (e) => e.ops.deleteSelection() },
285
+ { key: "Delete", run: (e) => e.ops.deleteSelection() },
286
+ { key: "z", mod: true, run: (e) => e.docs.undo() },
287
+ { key: "z", mod: true, shift: true, run: (e) => e.docs.redo() },
288
+ { key: "d", mod: true, run: (e) => e.ops.duplicateSelection() },
289
+ { key: "a", mod: true, run: (e) => e.ops.selectAll() },
290
+ { key: "Escape", run: (e) => e.ops.cancelActiveGestures() }
291
+ ];
292
+ for (const [key, dx, dy] of ARROWS) {
293
+ entries.push({ key, run: (e) => nudgeSelection(e, dx, dy) });
294
+ entries.push({ key, shift: true, run: (e) => nudgeSelection(e, dx * 10, dy * 10) });
295
+ }
296
+ for (const tool of tools.all()) {
297
+ if (tool.shortcut !== void 0) {
298
+ const id = tool.id;
299
+ entries.push({ key: tool.shortcut, run: (e) => e.ops.setTool(id) });
300
+ }
301
+ }
302
+ return entries;
303
+ }
304
+ function resolveTarget(target) {
305
+ if (target !== void 0) return target;
306
+ return typeof window !== "undefined" ? window : void 0;
307
+ }
308
+ function attachKeymap(engine, target, overrides = []) {
309
+ const el = resolveTarget(target);
310
+ if (el === void 0) return () => {
311
+ };
312
+ const map = /* @__PURE__ */ new Map();
313
+ for (const entry of defaultEntries()) map.set(signature(entry.key, entry.mod, entry.shift), entry);
314
+ for (const entry of overrides) map.set(signature(entry.key, entry.mod, entry.shift), entry);
315
+ const onKeyDown = (event) => {
316
+ if (isEditableTarget(event.target)) return;
317
+ const mod = event.metaKey || event.ctrlKey;
318
+ const entry = map.get(signature(event.key, mod, event.shiftKey));
319
+ if (entry === void 0) return;
320
+ event.preventDefault();
321
+ entry.run(engine);
322
+ };
323
+ el.addEventListener("keydown", onKeyDown);
324
+ return () => el.removeEventListener("keydown", onKeyDown);
325
+ }
326
+
327
+ // ../react/src/infinite-canvas.tsx
328
+ import { useEffect, useRef as useRef4, useState } from "react";
329
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
330
+ function InfiniteCanvas({
331
+ engine,
332
+ measureQueue,
333
+ onReady,
334
+ grid: gridConfig,
335
+ glRoute,
336
+ className,
337
+ style,
338
+ children
339
+ }) {
340
+ const containerRef = useRef4(null);
341
+ const [hosts, setHosts] = useState(void 0);
342
+ const onReadyRef = useRef4(onReady);
343
+ onReadyRef.current = onReady;
344
+ const gridRef = useRef4(null);
345
+ const gridConfigRef = useRef4(gridConfig);
346
+ gridConfigRef.current = gridConfig;
347
+ const glRouteRef = useRef4(glRoute);
348
+ glRouteRef.current = glRoute;
349
+ useEffect(() => {
350
+ const container = containerRef.current;
351
+ if (container === null) return;
352
+ const { world, engine: core, stack, runtime } = engine;
353
+ const host = createCanvasHost(container);
354
+ const planes = createPlanes(host);
355
+ const planeArgs = { contentPlane: planes.content, liftedPlane: planes.lifted };
356
+ const domWidgets = createDomWidgetsReflector(planeArgs, world, runtime.store);
357
+ const remoteCursors = createRemoteCursorsReflector(host, world);
358
+ const grid = createGridReflector(host, gridConfigRef.current ?? {});
359
+ gridRef.current = grid;
360
+ const wires = createWiresReflector(host, world, { readPreview: () => stack.wirePreview });
361
+ const chrome = createChromeReflector(host, world, stack.marqueeBuffer);
362
+ const unregister = [
363
+ core.registerReflector(createPlaneTransformReflector(planeArgs)),
364
+ core.registerReflector(grid),
365
+ core.registerReflector(wires),
366
+ core.registerReflector(domWidgets),
367
+ core.registerReflector(chrome),
368
+ core.registerReflector(createCursorReflector(host, stack.readCursor)),
369
+ core.registerReflector(remoteCursors.reflector)
370
+ ];
371
+ const detachPointer = attachPointerAdapter(
372
+ host,
373
+ stack.queue,
374
+ glRouteRef.current !== void 0 ? { glRoute: (kind, x, y, e) => glRouteRef.current?.(kind, x, y, e) === true } : {}
375
+ );
376
+ const detachMeasure = measureQueue !== void 0 ? wireMeasurement(runtime.store, domWidgets, measureQueue) : void 0;
377
+ const detachKeymap = attachKeymap(engine);
378
+ const syncViewport = () => {
379
+ const rect = container.getBoundingClientRect();
380
+ const dpr = typeof window !== "undefined" ? window.devicePixelRatio : 1;
381
+ writeRuntimeResource(world, Viewport, { w: rect.width, h: rect.height, dpr });
382
+ };
383
+ syncViewport();
384
+ let resizeObserver;
385
+ if (typeof ResizeObserver !== "undefined") {
386
+ resizeObserver = new ResizeObserver(syncViewport);
387
+ resizeObserver.observe(container);
388
+ }
389
+ const stopLoop = startRafLoop(core);
390
+ setHosts(domWidgets);
391
+ onReadyRef.current?.({ engine, host, planes });
392
+ return () => {
393
+ stopLoop();
394
+ detachKeymap();
395
+ detachMeasure?.();
396
+ detachPointer();
397
+ resizeObserver?.disconnect();
398
+ for (const unreg of unregister) unreg();
399
+ remoteCursors.destroy();
400
+ grid.dispose();
401
+ gridRef.current = null;
402
+ wires.dispose();
403
+ chrome.dispose();
404
+ planes.dispose();
405
+ host.dispose();
406
+ setHosts(void 0);
407
+ };
408
+ }, [engine, measureQueue]);
409
+ useEffect(() => {
410
+ if (gridConfig !== void 0) gridRef.current?.configure(gridConfig);
411
+ }, [gridConfig]);
412
+ return /* @__PURE__ */ jsx2(EngineProvider, { engine, children: /* @__PURE__ */ jsxs("div", { ref: containerRef, className, style: { width: "100%", height: "100%", ...style }, "data-ice-canvas": "", children: [
413
+ hosts !== void 0 ? /* @__PURE__ */ jsx2(WidgetRoot, { world: engine.world, store: engine.runtime.store, hosts }) : null,
414
+ children
415
+ ] }) });
416
+ }
417
+
418
+ // ../react/src/index.ts
419
+ var REACT_VERSION = "0.0.0";
420
+ export {
421
+ EngineProvider,
422
+ InfiniteCanvas,
423
+ REACT_VERSION,
424
+ WidgetHiddenContext,
425
+ WidgetRoot,
426
+ attachKeymap,
427
+ useBreakpoint,
428
+ useCanvasEngine,
429
+ useCommit,
430
+ useOps,
431
+ usePresencePeers,
432
+ useSelected,
433
+ useTool,
434
+ useToolState,
435
+ useUndoStatus,
436
+ useWidgetProps,
437
+ useWorld,
438
+ useWorldComponent
439
+ };
440
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../react/src/hooks.ts","../../react/src/widget-root.tsx","../../react/src/engine-context.tsx","../../react/src/use-commit.ts","../../react/src/use-tool.ts","../../react/src/use-presence.ts","../../react/src/keymap.ts","../../react/src/infinite-canvas.tsx","../../react/src/index.ts"],"sourcesContent":["/**\n * React hooks over the engine's Tier-3 reactivity (design-005 §2 hooks;\n * design-004 §2 frozen-hidden rule).\n *\n * Implemented directly on `world.reactive.observeValue` + `useSyncExternalStore`\n * rather than strata's own react module: core is react-free by law, so\n * strata/react cannot be re-exported through it — and the adapter is ~20\n * lines. Value semantics are strata Tier-3: equality-suppressed, fired at\n * notify(), never during the tick.\n *\n * FROZEN-HIDDEN: a widget inside a hidden (culled-but-kept-mounted) host must\n * not re-render on doc edits — `useWidgetProps` reads {@link WidgetHiddenContext}\n * (provided per-portal by WidgetRoot) and suspends its subscription while\n * hidden, serving the last snapshot; on show it resubscribes and refreshes.\n */\nimport {\n Selected,\n WidgetBreakpoint,\n defineQuery,\n widgets,\n type Component,\n type Entity,\n type World,\n} from \"@ice/core\";\nimport { createContext, useCallback, useContext, useMemo, useRef, useSyncExternalStore } from \"react\";\n\n/** Per-portal hidden flag (WidgetRoot provides it; defaults to live). */\nexport const WidgetHiddenContext = createContext(false);\n\nconst selectedQ = defineQuery([Selected]);\n\n/** Shallow field equality — strata cells are flat field records. */\nfunction shallowEq(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true;\n if (typeof a !== \"object\" || typeof b !== \"object\" || a === null || b === null) return false;\n const ka = Object.keys(a);\n const kb = Object.keys(b);\n if (ka.length !== kb.length) return false;\n for (const k of ka) {\n if (!Object.is((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k])) return false;\n }\n return true;\n}\n\n/**\n * Tier-3 component value subscription (equality-suppressed). Snapshot\n * STABILITY is load-bearing: strata's `get()` materializes a fresh object per\n * read (SoA columns), and `useSyncExternalStore` treats a new reference as a\n * new snapshot — so reads go through a shallow-equality cache and only a real\n * field change yields a new reference.\n */\nexport function useWorldComponent<S>(world: World, entity: Entity, component: Component<S>): S | undefined {\n const hidden = useContext(WidgetHiddenContext);\n const last = useRef<S | undefined>(undefined);\n const subscribe = useCallback(\n (onChange: () => void) => {\n if (hidden) return () => {}; // frozen while hidden — no wakeups, no renders\n return world.reactive.observeValue(entity, component, onChange);\n },\n [world, entity, component, hidden],\n );\n const getSnapshot = useCallback(() => {\n if (hidden) return last.current; // stable snapshot while frozen\n const v = world.isAlive(entity) ? world.get(entity, component) : undefined;\n if (!shallowEq(v, last.current)) last.current = v;\n return last.current;\n }, [world, entity, component, hidden]);\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/**\n * Typed props for one conflict group of a widget (design-005 §2). Group\n * component values come back whole; `p.json` fields are parsed. Identity is\n * stable per underlying group value (memo on the raw reference).\n */\nexport function useWidgetProps<T extends Record<string, unknown>>(\n world: World,\n entity: Entity,\n type: string,\n group = \"props\",\n): T | undefined {\n const widget = widgets.get(type);\n const g = widget?.groups.find((x) => x.name === group);\n if (widget === undefined || g === undefined) {\n throw new Error(`ice: useWidgetProps — unknown widget type/group \"${type}\"/\"${group}\".`);\n }\n const raw = useWorldComponent(world, entity, g.component) as Record<string, unknown> | undefined;\n return useMemo(() => {\n if (raw === undefined) return undefined;\n const out: Record<string, unknown> = {};\n for (const [name, spec] of Object.entries(g.fields)) {\n const v = raw[name];\n out[name] = spec.kind === \"json\" && typeof v === \"string\" ? JSON.parse(v) : v;\n }\n return out as T;\n }, [raw, g]);\n}\n\n/**\n * Selection membership (Tier-1 wake on Selected churn; O(1) snapshot).\n * Frozen-hidden like every widget hook: a selection change must not re-render\n * 256 hidden trees (review finding — design-004 §2 applies to ALL hooks).\n */\nexport function useSelected(world: World, entity: Entity): boolean {\n const hidden = useContext(WidgetHiddenContext);\n const last = useRef(false);\n const subscribe = useCallback(\n (onChange: () => void) => {\n if (hidden) return () => {};\n return world.reactive.observeQuery(selectedQ, onChange);\n },\n [world, hidden],\n );\n const getSnapshot = useCallback(() => {\n if (hidden) return last.current;\n last.current = world.isAlive(entity) && world.hasTag(entity, Selected);\n return last.current;\n }, [world, entity, hidden]);\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/** LOD tier (design-004 §8); \"normal\" until the breakpoint system stamps one. */\nexport function useBreakpoint(world: World, entity: Entity): string {\n const bp = useWorldComponent(world, entity, WidgetBreakpoint);\n return (bp as { tier?: string } | undefined)?.tier ?? \"normal\";\n}\n","/**\n * WidgetRoot — portals from ONE app root (design-004 §2).\n *\n * Portal-list membership (mount/unmount/evict) is owned HERE, by React,\n * subscribed to the engine's mount store via `useSyncExternalStore`; the\n * imperative dom-widgets reflector owns only the host DIVs. Eviction is\n * decided engine-side (LRU derive) and merely consumed. Each mounted entry\n * portals its widget type's component (from the defineWidget registry) into\n * the host's content element; hidden entries stay mounted (React state\n * preserved — cull ≠ unmount) inside a `WidgetHiddenContext` so their prop\n * subscriptions freeze (design-004 §2).\n *\n * A host div may not exist yet on the very first snapshot after mount (the\n * host reflector runs in the same post-notify pass, ordered by reflector\n * registration) — entries without a host render nothing this pass and pick\n * up on the next notification.\n */\nimport { PrefabId, widgets, type Entity, type World, type WidgetMountStore } from \"@ice/core\";\nimport { createElement, type ComponentType, type ReactElement } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useSyncExternalStore } from \"react\";\nimport { WidgetHiddenContext } from \"./hooks\";\n\nexport interface WidgetHosts {\n /** The dom-widgets reflector's lookup (content element per entity). */\n hostFor(entity: Entity): HTMLElement | undefined;\n}\n\nexport interface WidgetRootProps {\n readonly world: World;\n readonly store: WidgetMountStore;\n readonly hosts: WidgetHosts;\n}\n\nexport interface WidgetComponentProps {\n readonly entity: Entity;\n readonly world: World;\n}\n\nexport function WidgetRoot({ world, store, hosts }: WidgetRootProps): ReactElement {\n const entries = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);\n\n const portals: ReactElement[] = [];\n for (const entry of entries) {\n if (!world.isAlive(entry.entity)) continue;\n const type = world.get(entry.entity, PrefabId)?.id;\n const widget = typeof type === \"string\" ? widgets.get(type) : undefined;\n if (widget === undefined || widget.surface !== \"dom\") continue;\n const target = hosts.hostFor(entry.entity);\n if (target === undefined) continue; // host lands next pass\n const View = widget.component as ComponentType<WidgetComponentProps>;\n if (View == null) continue;\n portals.push(\n createPortal(\n createElement(\n WidgetHiddenContext.Provider,\n { value: entry.hidden },\n createElement(View, { entity: entry.entity, world }),\n ),\n target,\n String(entry.entity),\n ),\n );\n }\n return createElement(\"div\", { \"data-ice-widget-root\": \"\" }, portals);\n}\n","/**\n * `<EngineProvider>` + engine access hooks (design-005 §5; the M6 field\n * amendment 2026-07-10 gap — grep \"useCommit\" in design-005).\n *\n * The whole React surface reaches the running canvas through ONE context\n * carrying the {@link CanvasEngine} facade (world + engine + stack + runtime +\n * ops + docs). Widgets never hand-roll store plumbing again: {@link useOps}\n * gives the engine-owned write paths, {@link useCommit} (its own module) the\n * sanctioned durable commit seam, and {@link useWorld} the read/observe escape\n * hatch. `<InfiniteCanvas>` provides this automatically; apps that mount\n * WidgetRoot themselves wrap it in `<EngineProvider>`.\n */\nimport { devGuardsEnabled, type CanvasEngine, type CanvasOps, type World } from \"@ice/core\";\nimport { createContext, useContext, type ReactElement, type ReactNode } from \"react\";\n\nconst EngineContext = createContext<CanvasEngine | null>(null);\n\nexport interface EngineProviderProps {\n readonly engine: CanvasEngine;\n readonly children?: ReactNode;\n}\n\n/** Publish the canvas engine to the React subtree (WidgetRoot + userland hooks). */\nexport function EngineProvider({ engine, children }: EngineProviderProps): ReactElement {\n return <EngineContext.Provider value={engine}>{children}</EngineContext.Provider>;\n}\n\n/** The canvas engine for this subtree; throws with guidance outside a provider. */\nexport function useCanvasEngine(): CanvasEngine {\n const engine = useContext(EngineContext);\n if (engine === null) {\n throw new Error(\n \"ice: useCanvasEngine — no <EngineProvider>. Render widgets inside <InfiniteCanvas> (which provides it) or wrap your tree in <EngineProvider engine={...}>.\",\n );\n }\n return engine;\n}\n\n/** The engine-owned write paths (design-005 §4): setTool, deleteSelection, etc. */\nexport function useOps(): CanvasOps {\n return useCanvasEngine().ops;\n}\n\nlet warnedUseWorld = false;\n\n/**\n * Escape hatch — the raw {@link World} for READS and Tier-3 OBSERVATION only.\n * Mutation goes through {@link useOps}/{@link useCommit} (a gesture-claimed,\n * one-tx-per-gesture durable write; direct world writes bypass sovereignty and\n * the guards). DEV-warns once on first use.\n */\nexport function useWorld(): World {\n const engine = useCanvasEngine();\n if (devGuardsEnabled() && !warnedUseWorld) {\n warnedUseWorld = true;\n console.warn(\n \"ice: useWorld() is a READ/OBSERVE escape hatch — never write to the world directly. Use useOps()/useCommit() for mutation (design-005 §5).\",\n );\n }\n return engine.world;\n}\n","/**\n * `useCommit` + `useUndoStatus` — the sanctioned widget durable-write path and\n * the undo/redo status subscription (design-005 §2 M6 field amendment,\n * 2026-07-10: \"widgets also need a SANCTIONED commit path\").\n *\n * A widget commits a prop edit through {@link useCommit}: it resolves the\n * CURRENT doc session (`engine.docs.current()`) and runs a\n * {@link guardedTransaction} against that session's store — one transaction per\n * call, eligibility-guarded, absolute writes only. The session is resolved at\n * CALL time (not hook time) so a widget rendered doc-less that gains a doc later\n * commits correctly without re-mounting.\n */\nimport { DurableUndoStatus, guardedTransaction, type GuardedTx, type GuardedTxOpts } from \"@ice/core\";\nimport { useCallback, useRef, useSyncExternalStore } from \"react\";\nimport { useCanvasEngine } from \"./engine-context\";\n\n/** A durable commit: run `fn` against the current doc session's store, one tx. */\nexport type Commit = (fn: (tx: GuardedTx) => void, opts?: GuardedTxOpts) => void;\n\n/**\n * The widget commit seam. The returned function throws with guidance when no\n * document is attached (commits need a durable store — call\n * `engine.docs.create()/open()/join()` first).\n */\nexport function useCommit(): Commit {\n const engine = useCanvasEngine();\n return useCallback(\n (fn, opts) => {\n const session = engine.docs.current();\n if (session === undefined) {\n throw new Error(\n \"ice: useCommit — no active document. Attach one with engine.docs.create()/open()/join() before committing widget edits.\",\n );\n }\n guardedTransaction(session.store, engine.world, fn, opts);\n },\n [engine],\n );\n}\n\nexport interface UndoStatus {\n readonly canUndo: boolean;\n readonly canRedo: boolean;\n}\n\nconst NO_UNDO: UndoStatus = { canUndo: false, canRedo: false };\n\n/**\n * Undo/redo availability for the current document (drives toolbar\n * disablement) — the design-005 §5 path: the `DurableUndoStatus` RESOURCE\n * (strata plan-undo U2, re-exported through @ice/core) via\n * `observeResource`. A resource subscription is WORLD-level, so it survives\n * document swaps — no remount needed, the earlier onHistoryChange-per-store\n * caveat is gone. Fires at notify(), equality-suppressed; snapshot identity\n * is stable while the flags are unchanged.\n */\nexport function useUndoStatus(): UndoStatus {\n const engine = useCanvasEngine();\n const last = useRef<UndoStatus>(NO_UNDO);\n const subscribe = useCallback(\n (onChange: () => void) => engine.world.reactive.observeResource(DurableUndoStatus, onChange),\n [engine],\n );\n const getSnapshot = useCallback(() => {\n const status = engine.world.getResource(DurableUndoStatus);\n const canUndo = status?.canUndo ?? false;\n const canRedo = status?.canRedo ?? false;\n if (last.current.canUndo !== canUndo || last.current.canRedo !== canRedo) {\n last.current = { canUndo, canRedo };\n }\n return last.current;\n }, [engine]);\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n","/**\n * `useTool` + `useToolState` — the active-tool subscription (design-005 §5).\n *\n * The active tool is the `ActiveTool` runtime resource (design-005 §4). Reads go\n * through strata's Tier-3 `observeResource` (fires only when the id actually\n * changes, at notify()); the setter is `ops.setTool`, which cancels active\n * gestures before the switch (the strata-example lesson, design-003 §8) — never\n * a raw resource write. The snapshot is a primitive string, so identity is\n * inherently stable.\n */\nimport { ActiveTool } from \"@ice/core\";\nimport { useCallback, useSyncExternalStore } from \"react\";\nimport { useCanvasEngine } from \"./engine-context\";\n\n/** `[activeToolId, setTool]`. `setTool` routes through `ops.setTool`. */\nexport function useTool(): [string, (id: string) => void] {\n const engine = useCanvasEngine();\n const subscribe = useCallback(\n (onChange: () => void) => engine.world.reactive.observeResource(ActiveTool, onChange),\n [engine],\n );\n const getSnapshot = useCallback(() => engine.world.getResource(ActiveTool)?.id ?? \"select\", [engine]);\n const active = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n const setTool = useCallback((id: string) => engine.ops.setTool(id), [engine]);\n return [active, setTool];\n}\n\n/** Sugar: is tool `id` the active one? (toolbar button pressed-state). */\nexport function useToolState(id: string): boolean {\n const [active] = useTool();\n return active === id;\n}\n","/**\n * `usePresencePeers` — the remote-collaborator roster (design-005 §5:\n * \"Not(Local) presence query\").\n *\n * Queries `PresencePeer` entities that are NOT `Local` (the local peer carries\n * `Local`, auto-applied by the ephemeral store and never transmitted) and pairs\n * each with its `PresenceInfo` (name/color). Wakes on Tier-1 query membership\n * churn (`observeQuery`) — peers joining/leaving. The snapshot is\n * MEMBERSHIP-KEYED: identity stays stable across unrelated re-renders, and info\n * is sampled when membership changes (steady-state presence info is set once at\n * join; a mid-session rename reflects on the next membership change).\n */\nimport { Local, Not, PresenceInfo, PresencePeer, defineQuery, type Entity } from \"@ice/core\";\nimport { useCallback, useRef, useSyncExternalStore } from \"react\";\nimport { useCanvasEngine } from \"./engine-context\";\n\nconst remotePeersQ = defineQuery([PresencePeer, Not(Local)]);\n\nexport interface PresencePeerView {\n readonly entity: Entity;\n /** The peer's `PresenceInfo` (strata \"string\" fields are nullable until set). */\n readonly info: { readonly name: string | null; readonly color: string | null } | undefined;\n}\n\n/** Remote presence peers (excludes the local peer); stable identity by membership. */\nexport function usePresencePeers(): readonly PresencePeerView[] {\n const engine = useCanvasEngine();\n const cache = useRef<{ key: string; value: readonly PresencePeerView[] }>({ key: \"\u0000\", value: [] });\n const subscribe = useCallback(\n (onChange: () => void) => engine.world.reactive.observeQuery(remotePeersQ, onChange),\n [engine],\n );\n const getSnapshot = useCallback(() => {\n const world = engine.world;\n const ids: Entity[] = [];\n world.query(remotePeersQ).each((b) => {\n for (const r of b) ids.push(b.entity(r));\n });\n const key = ids.join(\",\");\n if (key !== cache.current.key) {\n cache.current = {\n key,\n value: ids.map((entity) => ({ entity, info: world.get(entity, PresenceInfo) })),\n };\n }\n return cache.current.value;\n }, [engine]);\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n","/**\n * The default keymap (design-005 §4 \"Keymap\"; design-003 §2 — NO system-side\n * keyboard logic, every entry resolves to an `ops.*`/`docs.*` call).\n *\n * Locked defaults:\n * ⌫/Delete → ops.deleteSelection\n * ⌘Z / Ctrl-Z → docs.undo\n * ⇧⌘Z / ⇧Ctrl-Z → docs.redo\n * ⌘D → ops.duplicateSelection\n * ⌘A → ops.selectAll\n * Esc → ops.cancelActiveGestures\n * Arrows → nudge the selection ±1px (⇧ = ±10px) — ONE tx per press\n * tool shortcuts → ops.setTool (v/h/c + any registered tool's shortcut)\n *\n * Space-hold pan is ALREADY owned by the pointer adapter (design-003 §2) — it is\n * NOT rebound here. A keystroke is IGNORED when the event target is editable\n * (input/textarea/select/contenteditable) so typing into widget fields never\n * triggers a shortcut. `mod` = ⌘ on macOS, Ctrl elsewhere (metaKey || ctrlKey).\n *\n * Overrides replace a default by its key-signature `key|mod|shift`; a signature\n * with no default is added. A matched entry `preventDefault()`s (the target was\n * already filtered to non-editable, so no typing is swallowed).\n */\nimport { Position, guardedTransaction, selectedEntities, tools, type CanvasEngine } from \"@ice/core\";\n\nexport interface KeymapEntry {\n /** `event.key` to match (case-insensitive; e.g. \"z\", \"Backspace\", \"ArrowUp\"). */\n readonly key: string;\n /** Require ⌘/Ctrl (default false → must NOT be held). */\n readonly mod?: boolean;\n /** Require ⇧ (default false → must NOT be held). */\n readonly shift?: boolean;\n /** Resolve to an engine write path — no keyboard logic beyond dispatch. */\n run(engine: CanvasEngine): void;\n}\n\ntype KeyTarget = Pick<Window, \"addEventListener\" | \"removeEventListener\">;\n\nconst signature = (key: string, mod?: boolean, shift?: boolean): string =>\n `${key.toLowerCase()}|${mod ? 1 : 0}|${shift ? 1 : 0}`;\n\nfunction isEditableTarget(target: EventTarget | null): boolean {\n if (target === null || !(target instanceof HTMLElement)) return false;\n const tag = target.tagName;\n return tag === \"INPUT\" || tag === \"TEXTAREA\" || tag === \"SELECT\" || target.isContentEditable;\n}\n\n/** One nudge = one gesture-equivalent transaction (absolute Position writes). */\nfunction nudgeSelection(engine: CanvasEngine, dx: number, dy: number): void {\n const session = engine.docs.current();\n if (session === undefined) return;\n const selection = selectedEntities(engine.world).filter((e) => session.store.keyOf(e) !== undefined);\n if (selection.length === 0) return;\n guardedTransaction(session.store, engine.world, (tx) => {\n for (const e of selection) {\n const p = engine.world.get(e, Position);\n if (p === undefined) continue;\n tx.edit(e).set(Position, { x: p.x + dx, y: p.y + dy });\n }\n });\n}\n\nconst ARROWS: readonly [key: string, dx: number, dy: number][] = [\n [\"ArrowLeft\", -1, 0],\n [\"ArrowRight\", 1, 0],\n [\"ArrowUp\", 0, -1],\n [\"ArrowDown\", 0, 1],\n];\n\n/** The locked defaults + tool shortcuts (read from the registry at attach time). */\nfunction defaultEntries(): KeymapEntry[] {\n const entries: KeymapEntry[] = [\n { key: \"Backspace\", run: (e) => e.ops.deleteSelection() },\n { key: \"Delete\", run: (e) => e.ops.deleteSelection() },\n { key: \"z\", mod: true, run: (e) => e.docs.undo() },\n { key: \"z\", mod: true, shift: true, run: (e) => e.docs.redo() },\n { key: \"d\", mod: true, run: (e) => e.ops.duplicateSelection() },\n { key: \"a\", mod: true, run: (e) => e.ops.selectAll() },\n { key: \"Escape\", run: (e) => e.ops.cancelActiveGestures() },\n ];\n for (const [key, dx, dy] of ARROWS) {\n entries.push({ key, run: (e) => nudgeSelection(e, dx, dy) });\n entries.push({ key, shift: true, run: (e) => nudgeSelection(e, dx * 10, dy * 10) });\n }\n for (const tool of tools.all()) {\n if (tool.shortcut !== undefined) {\n const id = tool.id;\n entries.push({ key: tool.shortcut, run: (e) => e.ops.setTool(id) });\n }\n }\n return entries;\n}\n\nfunction resolveTarget(target?: KeyTarget): KeyTarget | undefined {\n if (target !== undefined) return target;\n return typeof window !== \"undefined\" ? window : undefined;\n}\n\n/**\n * Attach the default keymap (plus `overrides`) to `target` (default: `window`).\n * Returns a detach function. No-op (returns a no-op detach) when there is no\n * target — e.g. a headless environment with no `window`.\n */\nexport function attachKeymap(\n engine: CanvasEngine,\n target?: KeyTarget,\n overrides: readonly KeymapEntry[] = [],\n): () => void {\n const el = resolveTarget(target);\n if (el === undefined) return () => {};\n\n const map = new Map<string, KeymapEntry>();\n for (const entry of defaultEntries()) map.set(signature(entry.key, entry.mod, entry.shift), entry);\n for (const entry of overrides) map.set(signature(entry.key, entry.mod, entry.shift), entry);\n\n const onKeyDown = (event: KeyboardEvent): void => {\n if (isEditableTarget(event.target)) return;\n const mod = event.metaKey || event.ctrlKey;\n const entry = map.get(signature(event.key, mod, event.shiftKey));\n if (entry === undefined) return;\n event.preventDefault();\n entry.run(engine);\n };\n\n el.addEventListener(\"keydown\", onKeyDown as EventListener);\n return () => el.removeEventListener(\"keydown\", onKeyDown as EventListener);\n}\n","/**\n * `<InfiniteCanvas>` — the one-line canvas mount (design-005 §5): planes +\n * adapters + reflectors + portal root, wired in node-board's PROVEN boot order\n * (apps/nodeboard/src/app.tsx). The app supplies a constructed {@link\n * CanvasEngine} (via `createCanvasEngine`); this component owns only the DOM\n * host, the reflector registrations, the pointer/keymap adapters, the rAF loop,\n * and the viewport sync — everything that must live next to a real container.\n *\n * Boot order (registration order = reflector flush order, mirrored exactly):\n * host → planes → reflectors[ planeTransform · grid(P0) · wires(P0) ·\n * domWidgets(P1/P3) · chrome(P4) · cursor · remoteCursors(P5) ] →\n * pointer adapter → measurement (optional) → keymap → rAF loop → viewport RO.\n *\n * The dom-widgets reflector is BOTH a reflector and the host lookup WidgetRoot\n * portals into; it is created before mount and stored in state so WidgetRoot\n * renders once the hosts exist.\n *\n * Lifecycle: this component does NOT own the engine — it never calls\n * `engine.dispose()` (the engine outlives the mount; the app owns it). Unmount\n * detaches every adapter, unregisters every reflector, stops the loop, and\n * disposes the host.\n *\n * Not handled here (by design):\n * - GL / R3F: the `@ice/r3f` wall forbids `@ice/react` importing three, so a\n * GL layer (GLViews) mounts APP-SIDE. Use {@link onReady} to receive the host\n * + planes and mount it yourself (like apps/glboard).\n * - Devtools: the import wall forbids `@ice/react` importing `@ice/devtools`.\n * Wire the panel app-side against `engine.engine` (also via {@link onReady}).\n * - Measurement: auto-sized widgets need a `MeasureQueue` passed to BOTH\n * `createCanvasEngine({ measureQueue })` (ingest side) and this component's\n * `measureQueue` prop (ResizeObserver side). Absent ⇒ measurement is skipped.\n */\nimport { Viewport, writeRuntimeResource, type CanvasEngine, type MeasureQueue } from \"@ice/core\";\nimport {\n attachPointerAdapter,\n createCanvasHost,\n createChromeReflector,\n createCursorReflector,\n createDomWidgetsReflector,\n createGridReflector,\n createPlaneTransformReflector,\n createPlanes,\n createRemoteCursorsReflector,\n createWiresReflector,\n startRafLoop,\n wireMeasurement,\n type CanvasHost,\n type DomWidgetsReflector,\n type GLRoute,\n type GridConfig,\n type Planes,\n} from \"@ice/dom\";\nimport { useEffect, useRef, useState, type CSSProperties, type ReactElement, type ReactNode } from \"react\";\nimport { EngineProvider } from \"./engine-context\";\nimport { attachKeymap } from \"./keymap\";\nimport { WidgetRoot } from \"./widget-root\";\n\n/** Handed to {@link InfiniteCanvasProps.onReady} for app-side GL/devtools wiring. */\nexport interface InfiniteCanvasHandle {\n readonly engine: CanvasEngine;\n readonly host: CanvasHost;\n readonly planes: Planes;\n}\n\nexport interface InfiniteCanvasProps {\n /** A constructed engine (`createCanvasEngine(...)`); NOT disposed on unmount. */\n readonly engine: CanvasEngine;\n /**\n * The ResizeObserver side of widget measurement. Pass the SAME queue given to\n * `createCanvasEngine({ measureQueue })`. Absent ⇒ measurement skipped.\n */\n readonly measureQueue?: MeasureQueue;\n /** Called once after the host/reflectors/loop are live (app-side GL/devtools). */\n readonly onReady?: (handle: InfiniteCanvasHandle) => void;\n /**\n * Dot-grid tuning (theme dot color, spacing, fades). Applied live via the\n * grid reflector's `configure` — changing it never re-boots the canvas\n * (memoize in the caller to avoid redundant same-value redraws).\n */\n readonly grid?: Partial<GridConfig>;\n /**\n * GL pointer routing (event-time island pick — @ice/r3f's\n * createGLPointerRouter). Provide from the FIRST render (a stub delegating\n * to a ref is fine — the real router usually arrives in onReady); the prop\n * is read through a ref, so later identity changes take effect without\n * re-attaching the adapter.\n */\n readonly glRoute?: GLRoute;\n readonly className?: string;\n readonly style?: CSSProperties;\n /** Overlays inside the viewport (toolbars, HUD) — rendered under the EngineProvider. */\n readonly children?: ReactNode;\n}\n\nexport function InfiniteCanvas({\n engine,\n measureQueue,\n onReady,\n grid: gridConfig,\n glRoute,\n className,\n style,\n children,\n}: InfiniteCanvasProps): ReactElement {\n const containerRef = useRef<HTMLDivElement>(null);\n const [hosts, setHosts] = useState<DomWidgetsReflector | undefined>(undefined);\n // Keep onReady out of the effect deps (identity churn must not re-boot).\n const onReadyRef = useRef(onReady);\n onReadyRef.current = onReady;\n // The live grid handle (set by the mount effect); the grid-config effect\n // below re-tunes it without re-booting the canvas.\n const gridRef = useRef<ReturnType<typeof createGridReflector> | null>(null);\n const gridConfigRef = useRef(gridConfig);\n gridConfigRef.current = gridConfig;\n // glRoute reads through a ref: the adapter captures ONE function at attach,\n // and the app's real router typically arrives post-mount (onReady).\n const glRouteRef = useRef(glRoute);\n glRouteRef.current = glRoute;\n\n useEffect(() => {\n const container = containerRef.current;\n if (container === null) return;\n const { world, engine: core, stack, runtime } = engine;\n\n const host = createCanvasHost(container);\n const planes = createPlanes(host);\n const planeArgs = { contentPlane: planes.content, liftedPlane: planes.lifted };\n const domWidgets = createDomWidgetsReflector(planeArgs, world, runtime.store);\n const remoteCursors = createRemoteCursorsReflector(host, world);\n\n // Handles kept for teardown: unregistering only stops flushes — the DOM\n // these factories inserted (grid canvas, wires canvas, chrome plane) must\n // be disposed too, or a StrictMode remount stacks duplicates (the\n // double-grid field report, 2026-07-11).\n const grid = createGridReflector(host, gridConfigRef.current ?? {});\n gridRef.current = grid;\n const wires = createWiresReflector(host, world, { readPreview: () => stack.wirePreview });\n const chrome = createChromeReflector(host, world, stack.marqueeBuffer);\n\n // Registration order = flush order — node-board's proven sequence.\n const unregister = [\n core.registerReflector(createPlaneTransformReflector(planeArgs)),\n core.registerReflector(grid),\n core.registerReflector(wires),\n core.registerReflector(domWidgets),\n core.registerReflector(chrome),\n core.registerReflector(createCursorReflector(host, stack.readCursor)),\n core.registerReflector(remoteCursors.reflector),\n ];\n\n const detachPointer = attachPointerAdapter(\n host,\n stack.queue,\n glRouteRef.current !== undefined\n ? { glRoute: (kind, x, y, e) => glRouteRef.current?.(kind, x, y, e) === true }\n : {},\n );\n const detachMeasure =\n measureQueue !== undefined ? wireMeasurement(runtime.store, domWidgets, measureQueue) : undefined;\n const detachKeymap = attachKeymap(engine);\n\n const syncViewport = (): void => {\n const rect = container.getBoundingClientRect();\n const dpr = typeof window !== \"undefined\" ? window.devicePixelRatio : 1;\n writeRuntimeResource(world, Viewport, { w: rect.width, h: rect.height, dpr });\n };\n syncViewport();\n let resizeObserver: ResizeObserver | undefined;\n if (typeof ResizeObserver !== \"undefined\") {\n resizeObserver = new ResizeObserver(syncViewport);\n resizeObserver.observe(container);\n }\n\n const stopLoop = startRafLoop(core);\n setHosts(domWidgets);\n onReadyRef.current?.({ engine, host, planes });\n\n return () => {\n stopLoop();\n detachKeymap();\n detachMeasure?.();\n detachPointer();\n resizeObserver?.disconnect();\n for (const unreg of unregister) unreg();\n remoteCursors.destroy();\n grid.dispose();\n gridRef.current = null;\n wires.dispose();\n chrome.dispose();\n planes.dispose();\n host.dispose();\n setHosts(undefined);\n };\n }, [engine, measureQueue]);\n\n // Live grid re-tune — never re-boots the canvas (the mount effect above\n // deliberately omits `gridConfig` from its deps; initial config rides the\n // ref at creation).\n useEffect(() => {\n if (gridConfig !== undefined) gridRef.current?.configure(gridConfig);\n }, [gridConfig]);\n\n return (\n <EngineProvider engine={engine}>\n <div ref={containerRef} className={className} style={{ width: \"100%\", height: \"100%\", ...style }} data-ice-canvas=\"\">\n {hosts !== undefined ? (\n <WidgetRoot world={engine.world} store={engine.runtime.store} hosts={hosts} />\n ) : null}\n {children}\n </div>\n </EngineProvider>\n );\n}\n","/**\n * @ice/react — widget content layer: portals from one root + Tier-3 hooks.\n * Import wall: @ice/dom → @ice/core down only — never three/@react-three\n * (enforced). react/react-dom are peers.\n */\nexport const REACT_VERSION = \"0.0.0\";\n\nexport {\n WidgetHiddenContext,\n useBreakpoint,\n useSelected,\n useWidgetProps,\n useWorldComponent,\n} from \"./hooks\";\nexport { WidgetRoot, type WidgetComponentProps, type WidgetHosts, type WidgetRootProps } from \"./widget-root\";\n\n// M10 React facade (design-005 §5): engine context, commit seam, hooks, keymap,\n// and the <InfiniteCanvas> mount.\nexport {\n EngineProvider,\n useCanvasEngine,\n useOps,\n useWorld,\n type EngineProviderProps,\n} from \"./engine-context\";\nexport { useCommit, useUndoStatus, type Commit, type UndoStatus } from \"./use-commit\";\nexport { useTool, useToolState } from \"./use-tool\";\nexport { usePresencePeers, type PresencePeerView } from \"./use-presence\";\nexport { attachKeymap, type KeymapEntry } from \"./keymap\";\nexport {\n InfiniteCanvas,\n type InfiniteCanvasHandle,\n type InfiniteCanvasProps,\n} from \"./infinite-canvas\";\n"],"mappings":"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","names":["useSyncExternalStore","useSyncExternalStore","createContext","useContext","useCallback","useRef","useSyncExternalStore","useCallback","useRef","useSyncExternalStore","useCallback","useSyncExternalStore","useCallback","useSyncExternalStore","useCallback","useRef","useSyncExternalStore","useRef","useCallback","useSyncExternalStore","useRef","jsx","useRef"]}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * HMR-safe schema/prefab boot kit (M0 deliverable; the strata+Vite reference pattern).
3
+ *
4
+ * strata's define* registry is process-global: a re-executed schema module throws
5
+ * "already defined". Apps register ALL schema/prefabs through defineSchemaOnce from
6
+ * one module, and call hmrInvalidateOnSchemaChange(import.meta.hot) so any edit to
7
+ * that module forces a full reload instead of a broken hot-swap.
8
+ */
9
+ export declare function defineSchemaOnce<T>(key: string, build: () => T): T;
10
+ export declare function hmrInvalidateOnSchemaChange(hot: {
11
+ invalidate(): void;
12
+ } | undefined): void;