@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.
- package/README.md +170 -9
- package/dist/SelectionRenderer-CR2PBQwx.d.cts +105 -0
- package/dist/SelectionRenderer-CR2PBQwx.d.cts.map +1 -0
- package/dist/SelectionRenderer-DlsBstAq.d.mts +105 -0
- package/dist/SelectionRenderer-DlsBstAq.d.mts.map +1 -0
- package/dist/WebGLWidgetLayer-BBMuwzHq.cjs +3560 -0
- package/dist/WebGLWidgetLayer-BBMuwzHq.cjs.map +1 -0
- package/dist/WebGLWidgetLayer-C3p1tnpm.mjs +3375 -0
- package/dist/WebGLWidgetLayer-C3p1tnpm.mjs.map +1 -0
- package/dist/advanced.cjs +110 -165
- package/dist/advanced.cjs.map +1 -1
- package/dist/advanced.d.cts +58 -40
- package/dist/advanced.d.cts.map +1 -0
- package/dist/advanced.d.mts +99 -0
- package/dist/advanced.d.mts.map +1 -0
- package/dist/advanced.mjs +105 -0
- package/dist/advanced.mjs.map +1 -0
- package/dist/devtools.cjs +654 -0
- package/dist/devtools.cjs.map +1 -0
- package/dist/devtools.d.cts +23 -0
- package/dist/devtools.d.cts.map +1 -0
- package/dist/devtools.d.mts +23 -0
- package/dist/devtools.d.mts.map +1 -0
- package/dist/devtools.mjs +652 -0
- package/dist/devtools.mjs.map +1 -0
- package/dist/engine-BfbvWXSk.d.mts +982 -0
- package/dist/engine-BfbvWXSk.d.mts.map +1 -0
- package/dist/engine-CCjuFMC-.d.cts +982 -0
- package/dist/engine-CCjuFMC-.d.cts.map +1 -0
- package/dist/hooks-BwY7rRHg.mjs +425 -0
- package/dist/hooks-BwY7rRHg.mjs.map +1 -0
- package/dist/hooks-DHShH86C.cjs +707 -0
- package/dist/hooks-DHShH86C.cjs.map +1 -0
- package/dist/index.cjs +909 -803
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +199 -67
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +258 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +855 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +47 -15
- package/dist/SelectionRenderer-CeWSNZT8.d.cts +0 -891
- package/dist/SelectionRenderer-CeWSNZT8.d.ts +0 -891
- package/dist/advanced.d.ts +0 -81
- package/dist/advanced.js +0 -124
- package/dist/advanced.js.map +0 -1
- package/dist/chunk-VSHXWTJH.cjs +0 -3228
- package/dist/chunk-VSHXWTJH.cjs.map +0 -1
- package/dist/chunk-Z6JQQOWL.js +0 -3142
- package/dist/chunk-Z6JQQOWL.js.map +0 -1
- package/dist/index.d.ts +0 -126
- package/dist/index.js +0 -602
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine-CCjuFMC-.d.cts","names":[],"sources":["../src/archetype.ts","../src/commands.ts","../src/components.ts","../src/profiler.ts","../src/schema.ts","../src/react/registry.ts","../src/resources.ts","../src/snap.ts","../src/math.ts","../src/spatial.ts","../src/engine.ts"],"mappings":"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"}
|
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
import { defineComponent, defineResource, defineTag } from "@jamesyong42/reactive-ecs";
|
|
2
|
+
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
|
3
|
+
//#region src/components.ts
|
|
4
|
+
/** Position, size, and rotation of an entity in local coordinates (world units). */
|
|
5
|
+
const Transform2D = defineComponent("Transform2D", {
|
|
6
|
+
x: 0,
|
|
7
|
+
y: 0,
|
|
8
|
+
width: 100,
|
|
9
|
+
height: 100,
|
|
10
|
+
rotation: 0
|
|
11
|
+
});
|
|
12
|
+
/** Computed world-space bounding box. Read-only -- updated by the transform propagation system. */
|
|
13
|
+
const WorldBounds = defineComponent("WorldBounds", {
|
|
14
|
+
worldX: 0,
|
|
15
|
+
worldY: 0,
|
|
16
|
+
worldWidth: 0,
|
|
17
|
+
worldHeight: 0
|
|
18
|
+
});
|
|
19
|
+
/** Rendering and hit-test ordering. Higher values render on top. */
|
|
20
|
+
const ZIndex = defineComponent("ZIndex", { value: 0 });
|
|
21
|
+
/** Parent entity reference. Used for nested containers and handle sync. */
|
|
22
|
+
const Parent = defineComponent("Parent", { id: 0 });
|
|
23
|
+
/** Child entity IDs. Used for nested containers and handle sync. */
|
|
24
|
+
const Children = defineComponent("Children", { ids: [] });
|
|
25
|
+
/** Marks an entity as a renderable widget with a type identifier and rendering surface. */
|
|
26
|
+
const Widget = defineComponent("Widget", {
|
|
27
|
+
surface: "dom",
|
|
28
|
+
type: ""
|
|
29
|
+
});
|
|
30
|
+
/** Arbitrary application data attached to a widget entity. Access via useWidgetData(). */
|
|
31
|
+
const WidgetData = defineComponent("WidgetData", { data: {} });
|
|
32
|
+
/** Computed responsive breakpoint based on screen-space size. Read-only. */
|
|
33
|
+
const WidgetBreakpoint = defineComponent("WidgetBreakpoint", {
|
|
34
|
+
current: "normal",
|
|
35
|
+
screenWidth: 0,
|
|
36
|
+
screenHeight: 0
|
|
37
|
+
});
|
|
38
|
+
/**
|
|
39
|
+
* Marks an entity as an iOS-style card with a fixed preset size.
|
|
40
|
+
* The `cardSystem` reconciles `Transform2D.width/height` from the preset
|
|
41
|
+
* each tick, so cards cannot be resized freely — change `preset` instead.
|
|
42
|
+
*/
|
|
43
|
+
const Card = defineComponent("Card", { preset: "small" });
|
|
44
|
+
/** Marks an entity as an enterable container (double-click/double-tap to enter). */
|
|
45
|
+
const Container = defineComponent("Container", { enterable: true });
|
|
46
|
+
/**
|
|
47
|
+
* Rectangular interactable region anchored relative to the parent entity's WorldBounds.
|
|
48
|
+
* Anchor values are in 0..1 space: 0 = parent min edge, 1 = parent max edge.
|
|
49
|
+
* Widget bodies do NOT need Hitbox — their WorldBounds is already their hit area.
|
|
50
|
+
* Hitbox is only for sub-entities (handles, ports) whose position is parent-relative.
|
|
51
|
+
*/
|
|
52
|
+
const Hitbox = defineComponent("Hitbox", {
|
|
53
|
+
anchorX: 0,
|
|
54
|
+
anchorY: 0,
|
|
55
|
+
width: 0,
|
|
56
|
+
height: 0
|
|
57
|
+
});
|
|
58
|
+
/**
|
|
59
|
+
* Declares what happens when this entity is hit, plus its hit-test priority.
|
|
60
|
+
* Canonical layers: 0=canvas, 5=widget body, 10=edge handles, 15=corner handles, 20=reserved.
|
|
61
|
+
*/
|
|
62
|
+
const InteractionRole = defineComponent("InteractionRole", {
|
|
63
|
+
layer: 0,
|
|
64
|
+
role: { type: "canvas" }
|
|
65
|
+
});
|
|
66
|
+
/**
|
|
67
|
+
* Component on the parent entity listing the EntityIds of its spawned handle children.
|
|
68
|
+
* Enables O(1) cascade destroy without a reverse-index scan of Parent components.
|
|
69
|
+
*/
|
|
70
|
+
const HandleSet = defineComponent("HandleSet", { ids: [] });
|
|
71
|
+
/** Declares the cursor this entity requests when hovered and when active. */
|
|
72
|
+
const CursorHint = defineComponent("CursorHint", {
|
|
73
|
+
hover: "default",
|
|
74
|
+
active: "default"
|
|
75
|
+
});
|
|
76
|
+
/** Marks an entity as selectable by click or marquee. */
|
|
77
|
+
const Selectable = defineTag("Selectable");
|
|
78
|
+
/** Marks an entity as draggable via pointer interaction. */
|
|
79
|
+
const Draggable = defineTag("Draggable");
|
|
80
|
+
/** Marks an entity as resizable via edge/corner handles. */
|
|
81
|
+
const Resizable = defineTag("Resizable");
|
|
82
|
+
/** Prevents an entity from being moved or resized. */
|
|
83
|
+
const Locked = defineTag("Locked");
|
|
84
|
+
/** Indicates the entity is currently selected. */
|
|
85
|
+
const Selected = defineTag("Selected");
|
|
86
|
+
/**
|
|
87
|
+
* Indicates the entity is currently being dragged by the user.
|
|
88
|
+
* Added after the drag dead-zone is crossed; removed on pointer up/cancel.
|
|
89
|
+
* Renderers read this to apply transient drag affordances (e.g. scale/shadow lift).
|
|
90
|
+
*/
|
|
91
|
+
const Dragging = defineTag("Dragging");
|
|
92
|
+
/**
|
|
93
|
+
* Entities with this tag get the engine-drawn selection + hover outline frame.
|
|
94
|
+
* Granted automatically to Selectable entities unless explicitly disabled via
|
|
95
|
+
* `Archetype.interactive.selectionFrame: false`. Widgets that render their own
|
|
96
|
+
* selected/hover chrome (e.g. iOS-style cards) opt out.
|
|
97
|
+
*/
|
|
98
|
+
const SelectionFrame = defineTag("SelectionFrame");
|
|
99
|
+
/** Indicates the entity is currently being interacted with (drag, resize). */
|
|
100
|
+
const Active = defineTag("Active");
|
|
101
|
+
/** Indicates the entity is within the visible viewport. Set by the cull system. */
|
|
102
|
+
const Visible = defineTag("Visible");
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/resources.ts
|
|
105
|
+
/**
|
|
106
|
+
* Output sink for the cursor system. Written by cursorSystem each tick;
|
|
107
|
+
* read by the RAF loop to apply style.cursor on the root container div.
|
|
108
|
+
*/
|
|
109
|
+
const CursorResource = defineResource("Cursor", { cursor: "default" });
|
|
110
|
+
/** Camera state: world-space position (x, y) and zoom level. Updated by pan/zoom gestures. */
|
|
111
|
+
const CameraResource = defineResource("Camera", {
|
|
112
|
+
x: 0,
|
|
113
|
+
y: 0,
|
|
114
|
+
zoom: 1
|
|
115
|
+
});
|
|
116
|
+
/** Viewport dimensions in CSS pixels and device pixel ratio. Updated on resize. */
|
|
117
|
+
const ViewportResource = defineResource("Viewport", {
|
|
118
|
+
width: 0,
|
|
119
|
+
height: 0,
|
|
120
|
+
dpr: 1
|
|
121
|
+
});
|
|
122
|
+
/** Minimum and maximum zoom levels. */
|
|
123
|
+
const ZoomConfigResource = defineResource("ZoomConfig", {
|
|
124
|
+
min: .1,
|
|
125
|
+
max: 5
|
|
126
|
+
});
|
|
127
|
+
/** Screen-space pixel thresholds for responsive breakpoints (micro/compact/normal/expanded/detailed). */
|
|
128
|
+
const BreakpointConfigResource = defineResource("BreakpointConfig", {
|
|
129
|
+
micro: 40,
|
|
130
|
+
compact: 120,
|
|
131
|
+
normal: 500,
|
|
132
|
+
expanded: 1200
|
|
133
|
+
});
|
|
134
|
+
/** Navigation stack for hierarchical container traversal. */
|
|
135
|
+
const NavigationStackResource = defineResource("NavigationStack", {
|
|
136
|
+
frames: [{
|
|
137
|
+
containerId: null,
|
|
138
|
+
camera: {
|
|
139
|
+
x: 0,
|
|
140
|
+
y: 0,
|
|
141
|
+
zoom: 1
|
|
142
|
+
}
|
|
143
|
+
}],
|
|
144
|
+
changed: false
|
|
145
|
+
});
|
|
146
|
+
/**
|
|
147
|
+
* iOS-style card preset size map. Lookup happens by `Card.preset`; the
|
|
148
|
+
* `cardSystem` stamps `Transform2D.width/height` from the resolved size.
|
|
149
|
+
*
|
|
150
|
+
* Defaults mirror iOS widget conventions — 155×155 tile + 19px gap.
|
|
151
|
+
* Override at `createLayoutEngine({ cardPresets })` for tablet-scale or
|
|
152
|
+
* custom design systems.
|
|
153
|
+
*/
|
|
154
|
+
const CardPresetsResource = defineResource("CardPresets", {
|
|
155
|
+
presets: {
|
|
156
|
+
small: {
|
|
157
|
+
width: 155,
|
|
158
|
+
height: 155
|
|
159
|
+
},
|
|
160
|
+
medium: {
|
|
161
|
+
width: 329,
|
|
162
|
+
height: 155
|
|
163
|
+
},
|
|
164
|
+
large: {
|
|
165
|
+
width: 329,
|
|
166
|
+
height: 345
|
|
167
|
+
},
|
|
168
|
+
xl: {
|
|
169
|
+
width: 329,
|
|
170
|
+
height: 535
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
/** Gap between adjacent tiles (future tile-snap system reads this). */
|
|
174
|
+
gap: 19
|
|
175
|
+
});
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region src/react/context.ts
|
|
178
|
+
const EngineContext = createContext(null);
|
|
179
|
+
const EngineProvider = EngineContext.Provider;
|
|
180
|
+
const ContainerRefContext = createContext(null);
|
|
181
|
+
const ContainerRefProvider = ContainerRefContext.Provider;
|
|
182
|
+
function useContainerRef() {
|
|
183
|
+
return useContext(ContainerRefContext);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Returns the LayoutEngine instance from the nearest InfiniteCanvas context.
|
|
187
|
+
* Throws if used outside an InfiniteCanvas provider.
|
|
188
|
+
*/
|
|
189
|
+
function useLayoutEngine() {
|
|
190
|
+
const engine = useContext(EngineContext);
|
|
191
|
+
if (!engine) throw new Error("useLayoutEngine must be used within an <InfiniteCanvas>");
|
|
192
|
+
return engine;
|
|
193
|
+
}
|
|
194
|
+
const WidgetResolverContext = createContext(null);
|
|
195
|
+
const WidgetResolverProvider = WidgetResolverContext.Provider;
|
|
196
|
+
function useWidgetResolver() {
|
|
197
|
+
return useContext(WidgetResolverContext);
|
|
198
|
+
}
|
|
199
|
+
//#endregion
|
|
200
|
+
//#region src/react/hooks.ts
|
|
201
|
+
function shallowEqual(a, b) {
|
|
202
|
+
const keysA = Object.keys(a);
|
|
203
|
+
const keysB = Object.keys(b);
|
|
204
|
+
if (keysA.length !== keysB.length) return false;
|
|
205
|
+
for (const key of keysA) if (a[key] !== b[key]) return false;
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Reactively reads an ECS component from an entity.
|
|
210
|
+
* Returns undefined if the entity doesn't have the component. Re-renders when the component changes.
|
|
211
|
+
*/
|
|
212
|
+
function useComponent(entity, type) {
|
|
213
|
+
const engine = useLayoutEngine();
|
|
214
|
+
const [value, setValue] = useState(() => engine.get(entity, type));
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
const current = engine.get(entity, type);
|
|
217
|
+
setValue(current === void 0 ? void 0 : { ...current });
|
|
218
|
+
return engine.world.onComponentChanged(type, (_id, _prev, next) => {
|
|
219
|
+
setValue(next === void 0 ? void 0 : { ...next });
|
|
220
|
+
}, entity);
|
|
221
|
+
}, [
|
|
222
|
+
engine,
|
|
223
|
+
entity,
|
|
224
|
+
type
|
|
225
|
+
]);
|
|
226
|
+
return value;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Reactively checks whether an entity has a tag.
|
|
230
|
+
* Re-renders when the tag is added or removed.
|
|
231
|
+
*/
|
|
232
|
+
function useTag(entity, type) {
|
|
233
|
+
const engine = useLayoutEngine();
|
|
234
|
+
const [has, setHas] = useState(() => engine.world.hasTag(entity, type));
|
|
235
|
+
useEffect(() => {
|
|
236
|
+
setHas(engine.world.hasTag(entity, type));
|
|
237
|
+
const unsub1 = engine.world.onTagAdded(type, () => setHas(true), entity);
|
|
238
|
+
const unsub2 = engine.world.onTagRemoved(type, () => setHas(false), entity);
|
|
239
|
+
return () => {
|
|
240
|
+
unsub1();
|
|
241
|
+
unsub2();
|
|
242
|
+
};
|
|
243
|
+
}, [
|
|
244
|
+
engine,
|
|
245
|
+
entity,
|
|
246
|
+
type
|
|
247
|
+
]);
|
|
248
|
+
return has;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Reactively reads an ECS resource (singleton data).
|
|
252
|
+
* Re-renders when any field of the resource changes (shallow comparison).
|
|
253
|
+
*/
|
|
254
|
+
function useResource(type) {
|
|
255
|
+
const engine = useLayoutEngine();
|
|
256
|
+
const [value, setValue] = useState(() => ({ ...engine.world.getResource(type) }));
|
|
257
|
+
const prevRef = useRef(void 0);
|
|
258
|
+
useEffect(() => {
|
|
259
|
+
const current = engine.world.getResource(type);
|
|
260
|
+
if (current !== void 0) {
|
|
261
|
+
prevRef.current = current;
|
|
262
|
+
setValue({ ...current });
|
|
263
|
+
}
|
|
264
|
+
return engine.onFrame(() => {
|
|
265
|
+
const current = engine.world.getResource(type);
|
|
266
|
+
if (prevRef.current === void 0 || !shallowEqual(current, prevRef.current)) {
|
|
267
|
+
prevRef.current = current;
|
|
268
|
+
setValue({ ...current });
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
}, [engine, type]);
|
|
272
|
+
return value;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Returns entity IDs matching all specified component/tag types.
|
|
276
|
+
* Re-renders when the result set changes.
|
|
277
|
+
*/
|
|
278
|
+
function useQuery(...types) {
|
|
279
|
+
const engine = useLayoutEngine();
|
|
280
|
+
const typesRef = useRef(types);
|
|
281
|
+
typesRef.current = types;
|
|
282
|
+
const typesKey = types.map((t) => t.name).join("\0");
|
|
283
|
+
const [result, setResult] = useState(() => engine.world.query(...types));
|
|
284
|
+
useEffect(() => {
|
|
285
|
+
setResult(engine.world.query(...typesRef.current));
|
|
286
|
+
return engine.onFrame(() => {
|
|
287
|
+
const next = engine.world.query(...typesRef.current);
|
|
288
|
+
setResult((prev) => {
|
|
289
|
+
if (prev.length !== next.length) return next;
|
|
290
|
+
for (let i = 0; i < prev.length; i++) if (prev[i] !== next[i]) return next;
|
|
291
|
+
return prev;
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
}, [engine, typesKey]);
|
|
295
|
+
return result;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Returns all entity IDs that have the specified tag.
|
|
299
|
+
* Re-renders when entities are tagged or untagged.
|
|
300
|
+
*/
|
|
301
|
+
function useTaggedEntities(type) {
|
|
302
|
+
const engine = useLayoutEngine();
|
|
303
|
+
const [result, setResult] = useState(() => engine.world.queryTagged(type));
|
|
304
|
+
useEffect(() => {
|
|
305
|
+
setResult([...engine.world.queryTagged(type)]);
|
|
306
|
+
const update = () => setResult([...engine.world.queryTagged(type)]);
|
|
307
|
+
const unsub1 = engine.world.onTagAdded(type, update);
|
|
308
|
+
const unsub2 = engine.world.onTagRemoved(type, update);
|
|
309
|
+
return () => {
|
|
310
|
+
unsub1();
|
|
311
|
+
unsub2();
|
|
312
|
+
};
|
|
313
|
+
}, [engine, type]);
|
|
314
|
+
return result;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Returns the current camera state {x, y, zoom}.
|
|
318
|
+
* Shorthand for useResource(CameraResource).
|
|
319
|
+
*/
|
|
320
|
+
function useCamera() {
|
|
321
|
+
const cam = useResource(CameraResource);
|
|
322
|
+
return {
|
|
323
|
+
x: cam?.x ?? 0,
|
|
324
|
+
y: cam?.y ?? 0,
|
|
325
|
+
zoom: cam?.zoom ?? 1
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
function sameIdList(a, b) {
|
|
329
|
+
if (a.length !== b.length) return false;
|
|
330
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
function sameTypeList(a, b) {
|
|
334
|
+
if (a.length !== b.length) return false;
|
|
335
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Reactively returns the IDs of every live entity in the world.
|
|
340
|
+
* Updates on entity create and destroy.
|
|
341
|
+
*/
|
|
342
|
+
function useAllEntities() {
|
|
343
|
+
const engine = useLayoutEngine();
|
|
344
|
+
const [entities, setEntities] = useState(() => engine.world.getAllEntities());
|
|
345
|
+
useEffect(() => {
|
|
346
|
+
const refresh = () => {
|
|
347
|
+
const next = engine.world.getAllEntities();
|
|
348
|
+
setEntities((prev) => sameIdList(prev, next) ? prev : next);
|
|
349
|
+
};
|
|
350
|
+
refresh();
|
|
351
|
+
const unsub1 = engine.world.onEntityCreated(refresh);
|
|
352
|
+
const unsub2 = engine.world.onEntityDestroyed(refresh);
|
|
353
|
+
return () => {
|
|
354
|
+
unsub1();
|
|
355
|
+
unsub2();
|
|
356
|
+
};
|
|
357
|
+
}, [engine]);
|
|
358
|
+
return entities;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Reactively returns the ComponentTypes currently attached to an entity.
|
|
362
|
+
* Polls per frame (engine only ticks when dirty), but never re-renders unless the set changes.
|
|
363
|
+
*/
|
|
364
|
+
function useEntityComponents(entity) {
|
|
365
|
+
const engine = useLayoutEngine();
|
|
366
|
+
const [types, setTypes] = useState(() => engine.world.getComponentsOf(entity));
|
|
367
|
+
useEffect(() => {
|
|
368
|
+
setTypes(engine.world.getComponentsOf(entity));
|
|
369
|
+
return engine.onFrame(() => {
|
|
370
|
+
const next = engine.world.getComponentsOf(entity);
|
|
371
|
+
setTypes((prev) => sameTypeList(prev, next) ? prev : next);
|
|
372
|
+
});
|
|
373
|
+
}, [engine, entity]);
|
|
374
|
+
return types;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Reactively returns the TagTypes currently attached to an entity.
|
|
378
|
+
*/
|
|
379
|
+
function useEntityTags(entity) {
|
|
380
|
+
const engine = useLayoutEngine();
|
|
381
|
+
const [types, setTypes] = useState(() => engine.world.getTagsOf(entity));
|
|
382
|
+
useEffect(() => {
|
|
383
|
+
setTypes(engine.world.getTagsOf(entity));
|
|
384
|
+
return engine.onFrame(() => {
|
|
385
|
+
const next = engine.world.getTagsOf(entity);
|
|
386
|
+
setTypes((prev) => sameTypeList(prev, next) ? prev : next);
|
|
387
|
+
});
|
|
388
|
+
}, [engine, entity]);
|
|
389
|
+
return types;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Reactively returns every ComponentType the world has observed.
|
|
393
|
+
* Grows over time as new component types are first used.
|
|
394
|
+
*/
|
|
395
|
+
function useRegisteredComponents() {
|
|
396
|
+
const engine = useLayoutEngine();
|
|
397
|
+
const [types, setTypes] = useState(() => engine.world.getRegisteredComponents());
|
|
398
|
+
useEffect(() => {
|
|
399
|
+
setTypes(engine.world.getRegisteredComponents());
|
|
400
|
+
return engine.onFrame(() => {
|
|
401
|
+
const next = engine.world.getRegisteredComponents();
|
|
402
|
+
setTypes((prev) => sameTypeList(prev, next) ? prev : next);
|
|
403
|
+
});
|
|
404
|
+
}, [engine]);
|
|
405
|
+
return types;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Reactively returns every TagType the world has observed.
|
|
409
|
+
*/
|
|
410
|
+
function useRegisteredTags() {
|
|
411
|
+
const engine = useLayoutEngine();
|
|
412
|
+
const [types, setTypes] = useState(() => engine.world.getRegisteredTags());
|
|
413
|
+
useEffect(() => {
|
|
414
|
+
setTypes(engine.world.getRegisteredTags());
|
|
415
|
+
return engine.onFrame(() => {
|
|
416
|
+
const next = engine.world.getRegisteredTags();
|
|
417
|
+
setTypes((prev) => sameTypeList(prev, next) ? prev : next);
|
|
418
|
+
});
|
|
419
|
+
}, [engine]);
|
|
420
|
+
return types;
|
|
421
|
+
}
|
|
422
|
+
//#endregion
|
|
423
|
+
export { Draggable as A, SelectionFrame as B, ViewportResource as C, Children as D, Card as E, Locked as F, WidgetData as G, Visible as H, Parent as I, WorldBounds as K, Resizable as L, HandleSet as M, Hitbox as N, Container as O, InteractionRole as P, Selectable as R, NavigationStackResource as S, Active as T, Widget as U, Transform2D as V, WidgetBreakpoint as W, useWidgetResolver as _, useEntityTags as a, CardPresetsResource as b, useRegisteredTags as c, useTaggedEntities as d, ContainerRefProvider as f, useLayoutEngine as g, useContainerRef as h, useEntityComponents as i, Dragging as j, CursorHint as k, useResource as l, WidgetResolverProvider as m, useCamera as n, useQuery as o, EngineProvider as p, ZIndex as q, useComponent as r, useRegisteredComponents as s, useAllEntities as t, useTag as u, BreakpointConfigResource as v, ZoomConfigResource as w, CursorResource as x, CameraResource as y, Selected as z };
|
|
424
|
+
|
|
425
|
+
//# sourceMappingURL=hooks-BwY7rRHg.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks-BwY7rRHg.mjs","names":[],"sources":["../src/components.ts","../src/resources.ts","../src/react/context.ts","../src/react/hooks.ts"],"sourcesContent":["import type { EntityId } from '@jamesyong42/reactive-ecs';\nimport { defineComponent, defineTag } from '@jamesyong42/reactive-ecs';\n\n// === Spatial ===\n\n/** Position, size, and rotation of an entity in local coordinates (world units). */\nexport const Transform2D = defineComponent('Transform2D', {\n\tx: 0,\n\ty: 0,\n\twidth: 100,\n\theight: 100,\n\trotation: 0,\n});\n\n/** Computed world-space bounding box. Read-only -- updated by the transform propagation system. */\nexport const WorldBounds = defineComponent('WorldBounds', {\n\tworldX: 0,\n\tworldY: 0,\n\tworldWidth: 0,\n\tworldHeight: 0,\n});\n\n/** Rendering and hit-test ordering. Higher values render on top. */\nexport const ZIndex = defineComponent('ZIndex', { value: 0 });\n\n// === Hierarchy ===\n\n/** Parent entity reference. Used for nested containers and handle sync. */\nexport const Parent = defineComponent('Parent', { id: 0 as EntityId });\n\n/** Child entity IDs. Used for nested containers and handle sync. */\nexport const Children = defineComponent('Children', { ids: [] as EntityId[] });\n\n// === Widget ===\n\n/** Marks an entity as a renderable widget with a type identifier and rendering surface. */\nexport const Widget = defineComponent('Widget', {\n\tsurface: 'dom' as 'dom' | 'webgl' | 'webview',\n\ttype: '' as string,\n});\n\n/** Arbitrary application data attached to a widget entity. Access via useWidgetData(). */\nexport const WidgetData = defineComponent('WidgetData', {\n\tdata: {} as Record<string, unknown>,\n});\n\n/** Computed responsive breakpoint based on screen-space size. Read-only. */\nexport const WidgetBreakpoint = defineComponent('WidgetBreakpoint', {\n\tcurrent: 'normal' as 'micro' | 'compact' | 'normal' | 'expanded' | 'detailed',\n\tscreenWidth: 0,\n\tscreenHeight: 0,\n});\n\n// === Card ===\n\n/** iOS-style card size presets. Actual dimensions live in CardPresetsResource. */\nexport type CardPreset = 'small' | 'medium' | 'large' | 'xl';\n\n/**\n * Marks an entity as an iOS-style card with a fixed preset size.\n * The `cardSystem` reconciles `Transform2D.width/height` from the preset\n * each tick, so cards cannot be resized freely — change `preset` instead.\n */\nexport const Card = defineComponent('Card', {\n\tpreset: 'small' as CardPreset,\n});\n\n// === Container ===\n\n/** Marks an entity as an enterable container (double-click/double-tap to enter). */\nexport const Container = defineComponent('Container', { enterable: true });\n\n// === Interaction ===\n\n/** Resize handle positions — 4 edges + 4 corners. */\nexport type ResizeHandlePos = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw';\n\n/**\n * Rectangular interactable region anchored relative to the parent entity's WorldBounds.\n * Anchor values are in 0..1 space: 0 = parent min edge, 1 = parent max edge.\n * Widget bodies do NOT need Hitbox — their WorldBounds is already their hit area.\n * Hitbox is only for sub-entities (handles, ports) whose position is parent-relative.\n */\nexport const Hitbox = defineComponent('Hitbox', {\n\tanchorX: 0,\n\tanchorY: 0,\n\twidth: 0,\n\theight: 0,\n});\n\n/** Discriminated union of interaction roles an entity can fulfil. */\nexport type InteractionRoleType =\n\t| { type: 'drag' }\n\t| { type: 'select' }\n\t| { type: 'resize'; handle: ResizeHandlePos }\n\t| { type: 'rotate' }\n\t| { type: 'connect' }\n\t| { type: 'canvas' };\n\nexport type InteractionRoleData = {\n\t/** Hit-test priority — higher wins when multiple entities contain the point. */\n\tlayer: number;\n\t/** Discriminated role + role-specific data. */\n\trole: InteractionRoleType;\n};\n\n/**\n * Declares what happens when this entity is hit, plus its hit-test priority.\n * Canonical layers: 0=canvas, 5=widget body, 10=edge handles, 15=corner handles, 20=reserved.\n */\nexport const InteractionRole = defineComponent<InteractionRoleData>('InteractionRole', {\n\tlayer: 0,\n\trole: { type: 'canvas' },\n});\n\n/** Data shape for the HandleSet component. */\nexport type HandleSetData = {\n\tids: EntityId[];\n};\n\n/**\n * Component on the parent entity listing the EntityIds of its spawned handle children.\n * Enables O(1) cascade destroy without a reverse-index scan of Parent components.\n */\nexport const HandleSet = defineComponent<HandleSetData>('HandleSet', {\n\tids: [] as EntityId[],\n});\n\n/** CSS cursor values the canvas may request. */\nexport type CSSCursor =\n\t| 'default'\n\t| 'grab'\n\t| 'grabbing'\n\t| 'crosshair'\n\t| 'n-resize'\n\t| 's-resize'\n\t| 'e-resize'\n\t| 'w-resize'\n\t| 'ne-resize'\n\t| 'nw-resize'\n\t| 'se-resize'\n\t| 'sw-resize';\n\nexport type CursorHintData = {\n\t/** Cursor when this entity is hovered in idle state. */\n\thover: CSSCursor;\n\t/** Cursor while this entity is being dragged/resized. */\n\tactive: CSSCursor;\n};\n\n/** Declares the cursor this entity requests when hovered and when active. */\nexport const CursorHint = defineComponent<CursorHintData>('CursorHint', {\n\thover: 'default',\n\tactive: 'default',\n});\n\n// === Tags ===\n\n/** Marks an entity as selectable by click or marquee. */\nexport const Selectable = defineTag('Selectable');\n/** Marks an entity as draggable via pointer interaction. */\nexport const Draggable = defineTag('Draggable');\n/** Marks an entity as resizable via edge/corner handles. */\nexport const Resizable = defineTag('Resizable');\n/** Prevents an entity from being moved or resized. */\nexport const Locked = defineTag('Locked');\n/** Indicates the entity is currently selected. */\nexport const Selected = defineTag('Selected');\n/**\n * Indicates the entity is currently being dragged by the user.\n * Added after the drag dead-zone is crossed; removed on pointer up/cancel.\n * Renderers read this to apply transient drag affordances (e.g. scale/shadow lift).\n */\nexport const Dragging = defineTag('Dragging');\n/**\n * Entities with this tag get the engine-drawn selection + hover outline frame.\n * Granted automatically to Selectable entities unless explicitly disabled via\n * `Archetype.interactive.selectionFrame: false`. Widgets that render their own\n * selected/hover chrome (e.g. iOS-style cards) opt out.\n */\nexport const SelectionFrame = defineTag('SelectionFrame');\n/** Indicates the entity is currently being interacted with (drag, resize). */\nexport const Active = defineTag('Active');\n/** Indicates the entity is within the visible viewport. Set by the cull system. */\nexport const Visible = defineTag('Visible');\n","import type { EntityId } from '@jamesyong42/reactive-ecs';\nimport { defineResource } from '@jamesyong42/reactive-ecs';\nimport type { CardPreset, CSSCursor } from './components.js';\n\n/** A single frame in the navigation stack, capturing the container and camera state. */\nexport interface NavigationFrame {\n\tcontainerId: EntityId | null;\n\tcamera: { x: number; y: number; zoom: number };\n}\n\n/** Data shape for the CursorResource. */\nexport type CursorResourceData = {\n\tcursor: CSSCursor;\n};\n\n/**\n * Output sink for the cursor system. Written by cursorSystem each tick;\n * read by the RAF loop to apply style.cursor on the root container div.\n */\nexport const CursorResource = defineResource<CursorResourceData>('Cursor', {\n\tcursor: 'default',\n});\n\n/** Camera state: world-space position (x, y) and zoom level. Updated by pan/zoom gestures. */\nexport const CameraResource = defineResource('Camera', {\n\tx: 0,\n\ty: 0,\n\tzoom: 1,\n});\n\n/** Viewport dimensions in CSS pixels and device pixel ratio. Updated on resize. */\nexport const ViewportResource = defineResource('Viewport', {\n\twidth: 0,\n\theight: 0,\n\tdpr: 1,\n});\n\n/** Minimum and maximum zoom levels. */\nexport const ZoomConfigResource = defineResource('ZoomConfig', {\n\tmin: 0.1,\n\tmax: 5.0,\n});\n\n/** Screen-space pixel thresholds for responsive breakpoints (micro/compact/normal/expanded/detailed). */\nexport const BreakpointConfigResource = defineResource('BreakpointConfig', {\n\tmicro: 40,\n\tcompact: 120,\n\tnormal: 500,\n\texpanded: 1200,\n});\n\n/** Navigation stack for hierarchical container traversal. */\nexport const NavigationStackResource = defineResource('NavigationStack', {\n\tframes: [{ containerId: null, camera: { x: 0, y: 0, zoom: 1 } }] as NavigationFrame[],\n\tchanged: false,\n});\n\n/** Responsive breakpoint name derived from a widget's screen-space size. */\nexport type Breakpoint = 'micro' | 'compact' | 'normal' | 'expanded' | 'detailed';\n\n/**\n * iOS-style card preset size map. Lookup happens by `Card.preset`; the\n * `cardSystem` stamps `Transform2D.width/height` from the resolved size.\n *\n * Defaults mirror iOS widget conventions — 155×155 tile + 19px gap.\n * Override at `createLayoutEngine({ cardPresets })` for tablet-scale or\n * custom design systems.\n */\nexport const CardPresetsResource = defineResource('CardPresets', {\n\tpresets: {\n\t\tsmall: { width: 155, height: 155 },\n\t\tmedium: { width: 329, height: 155 },\n\t\tlarge: { width: 329, height: 345 },\n\t\txl: { width: 329, height: 535 },\n\t} as Record<CardPreset, { width: number; height: number }>,\n\t/** Gap between adjacent tiles (future tile-snap system reads this). */\n\tgap: 19,\n});\n","import type { EntityId } from '@jamesyong42/reactive-ecs';\nimport { createContext, useContext } from 'react';\nimport type { LayoutEngine } from '../engine.js';\nimport type { DomWidgetProps, R3FWidgetProps, WidgetSurface } from './registry.js';\n\n// === Engine Context ===\n\nconst EngineContext = createContext<LayoutEngine | null>(null);\n\nexport const EngineProvider = EngineContext.Provider;\n\n// === Container Ref Context ===\n// Shared so WidgetSlot can compute container-relative pointer coordinates.\n\nconst ContainerRefContext = createContext<React.RefObject<HTMLDivElement | null> | null>(null);\n\nexport const ContainerRefProvider = ContainerRefContext.Provider;\n\nexport function useContainerRef(): React.RefObject<HTMLDivElement | null> | null {\n\treturn useContext(ContainerRefContext);\n}\n\n/**\n * Returns the LayoutEngine instance from the nearest InfiniteCanvas context.\n * Throws if used outside an InfiniteCanvas provider.\n */\nexport function useLayoutEngine(): LayoutEngine {\n\tconst engine = useContext(EngineContext);\n\tif (!engine) {\n\t\tthrow new Error('useLayoutEngine must be used within an <InfiniteCanvas>');\n\t}\n\treturn engine;\n}\n\n// === Widget Resolver Context ===\n\nexport type { WidgetSurface };\n\n/**\n * Discriminated resolution of a widget by type. The surface determines which\n * layer renders the component and with what prop shape.\n */\nexport type ResolvedWidget =\n\t| { surface: 'dom'; component: React.ComponentType<DomWidgetProps> }\n\t| { surface: 'webgl'; component: React.ComponentType<R3FWidgetProps> };\n\nexport type WidgetResolver = (entityId: EntityId, widgetType: string) => ResolvedWidget | null;\n\nconst WidgetResolverContext = createContext<WidgetResolver | null>(null);\n\nexport const WidgetResolverProvider = WidgetResolverContext.Provider;\n\nexport function useWidgetResolver(): WidgetResolver | null {\n\treturn useContext(WidgetResolverContext);\n}\n","import type { ComponentType, EntityId, ResourceType, TagType } from '@jamesyong42/reactive-ecs';\nimport { useEffect, useRef, useState } from 'react';\nimport { CameraResource } from '../resources.js';\nimport { useLayoutEngine } from './context.js';\n\nfunction shallowEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean {\n\tconst keysA = Object.keys(a);\n\tconst keysB = Object.keys(b);\n\tif (keysA.length !== keysB.length) return false;\n\tfor (const key of keysA) {\n\t\tif (a[key] !== b[key]) return false;\n\t}\n\treturn true;\n}\n\n/**\n * Reactively reads an ECS component from an entity.\n * Returns undefined if the entity doesn't have the component. Re-renders when the component changes.\n */\nexport function useComponent<T>(entity: EntityId, type: ComponentType<T>): T | undefined {\n\tconst engine = useLayoutEngine();\n\tconst [value, setValue] = useState<T | undefined>(() => engine.get(entity, type));\n\n\tuseEffect(() => {\n\t\tconst current = engine.get(entity, type);\n\t\tsetValue(current === undefined ? undefined : { ...current });\n\n\t\tconst unsub = engine.world.onComponentChanged(\n\t\t\ttype,\n\t\t\t(_id, _prev, next) => {\n\t\t\t\tsetValue(next === undefined ? undefined : { ...next });\n\t\t\t},\n\t\t\tentity,\n\t\t);\n\n\t\treturn unsub;\n\t}, [engine, entity, type]);\n\n\treturn value;\n}\n\n/**\n * Reactively checks whether an entity has a tag.\n * Re-renders when the tag is added or removed.\n */\nexport function useTag(entity: EntityId, type: TagType): boolean {\n\tconst engine = useLayoutEngine();\n\tconst [has, setHas] = useState(() => engine.world.hasTag(entity, type));\n\n\tuseEffect(() => {\n\t\tsetHas(engine.world.hasTag(entity, type));\n\n\t\tconst unsub1 = engine.world.onTagAdded(type, () => setHas(true), entity);\n\t\tconst unsub2 = engine.world.onTagRemoved(type, () => setHas(false), entity);\n\n\t\treturn () => {\n\t\t\tunsub1();\n\t\t\tunsub2();\n\t\t};\n\t}, [engine, entity, type]);\n\n\treturn has;\n}\n\n/**\n * Reactively reads an ECS resource (singleton data).\n * Re-renders when any field of the resource changes (shallow comparison).\n */\nexport function useResource<T>(type: ResourceType<T>): T {\n\tconst engine = useLayoutEngine();\n\tconst [value, setValue] = useState<T>(() => ({ ...engine.world.getResource(type) }));\n\tconst prevRef = useRef<T | undefined>(undefined);\n\n\tuseEffect(() => {\n\t\t// Immediately sync to current value on (re-)subscription\n\t\tconst current = engine.world.getResource(type);\n\t\tif (current !== undefined) {\n\t\t\tprevRef.current = current;\n\t\t\tsetValue({ ...current });\n\t\t}\n\n\t\tconst unsub = engine.onFrame(() => {\n\t\t\tconst current = engine.world.getResource(type);\n\t\t\tif (\n\t\t\t\tprevRef.current === undefined ||\n\t\t\t\t!shallowEqual(\n\t\t\t\t\tcurrent as unknown as Record<string, unknown>,\n\t\t\t\t\tprevRef.current as unknown as Record<string, unknown>,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tprevRef.current = current;\n\t\t\t\tsetValue({ ...current });\n\t\t\t}\n\t\t});\n\t\treturn unsub;\n\t}, [engine, type]);\n\n\treturn value;\n}\n\n/**\n * Returns entity IDs matching all specified component/tag types.\n * Re-renders when the result set changes.\n */\nexport function useQuery(...types: (ComponentType | TagType)[]): EntityId[] {\n\tconst engine = useLayoutEngine();\n\tconst typesRef = useRef(types);\n\ttypesRef.current = types;\n\tconst typesKey = types.map((t) => t.name).join('\\0');\n\n\tconst [result, setResult] = useState<EntityId[]>(() => engine.world.query(...types));\n\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: typesKey is a stable proxy for the types array\n\tuseEffect(() => {\n\t\t// Immediately sync on (re-)subscription\n\t\tsetResult(engine.world.query(...typesRef.current));\n\n\t\tconst unsub = engine.onFrame(() => {\n\t\t\tconst next = engine.world.query(...typesRef.current);\n\t\t\tsetResult((prev) => {\n\t\t\t\tif (prev.length !== next.length) return next;\n\t\t\t\tfor (let i = 0; i < prev.length; i++) {\n\t\t\t\t\tif (prev[i] !== next[i]) return next;\n\t\t\t\t}\n\t\t\t\treturn prev;\n\t\t\t});\n\t\t});\n\t\treturn unsub;\n\t}, [engine, typesKey]);\n\n\treturn result;\n}\n\n/**\n * Returns all entity IDs that have the specified tag.\n * Re-renders when entities are tagged or untagged.\n */\nexport function useTaggedEntities(type: TagType): EntityId[] {\n\tconst engine = useLayoutEngine();\n\tconst [result, setResult] = useState<EntityId[]>(() => engine.world.queryTagged(type));\n\n\tuseEffect(() => {\n\t\tsetResult([...engine.world.queryTagged(type)]);\n\n\t\tconst update = () => setResult([...engine.world.queryTagged(type)]);\n\t\tconst unsub1 = engine.world.onTagAdded(type, update);\n\t\tconst unsub2 = engine.world.onTagRemoved(type, update);\n\t\treturn () => {\n\t\t\tunsub1();\n\t\t\tunsub2();\n\t\t};\n\t}, [engine, type]);\n\n\treturn result;\n}\n\n/**\n * Returns the current camera state {x, y, zoom}.\n * Shorthand for useResource(CameraResource).\n */\nexport function useCamera(): { x: number; y: number; zoom: number } {\n\tconst cam = useResource(CameraResource);\n\treturn { x: cam?.x ?? 0, y: cam?.y ?? 0, zoom: cam?.zoom ?? 1 };\n}\n\nfunction sameIdList(a: readonly number[], b: readonly number[]): boolean {\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n\treturn true;\n}\n\nfunction sameTypeList<T extends { name: string }>(a: readonly T[], b: readonly T[]): boolean {\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n\treturn true;\n}\n\n/**\n * Reactively returns the IDs of every live entity in the world.\n * Updates on entity create and destroy.\n */\nexport function useAllEntities(): EntityId[] {\n\tconst engine = useLayoutEngine();\n\tconst [entities, setEntities] = useState<EntityId[]>(() => engine.world.getAllEntities());\n\n\tuseEffect(() => {\n\t\tconst refresh = () => {\n\t\t\tconst next = engine.world.getAllEntities();\n\t\t\tsetEntities((prev) => (sameIdList(prev, next) ? prev : next));\n\t\t};\n\t\trefresh();\n\t\tconst unsub1 = engine.world.onEntityCreated(refresh);\n\t\tconst unsub2 = engine.world.onEntityDestroyed(refresh);\n\t\treturn () => {\n\t\t\tunsub1();\n\t\t\tunsub2();\n\t\t};\n\t}, [engine]);\n\n\treturn entities;\n}\n\n/**\n * Reactively returns the ComponentTypes currently attached to an entity.\n * Polls per frame (engine only ticks when dirty), but never re-renders unless the set changes.\n */\nexport function useEntityComponents(entity: EntityId): ComponentType[] {\n\tconst engine = useLayoutEngine();\n\tconst [types, setTypes] = useState<ComponentType[]>(() => engine.world.getComponentsOf(entity));\n\n\tuseEffect(() => {\n\t\tsetTypes(engine.world.getComponentsOf(entity));\n\t\tconst unsub = engine.onFrame(() => {\n\t\t\tconst next = engine.world.getComponentsOf(entity);\n\t\t\tsetTypes((prev) => (sameTypeList(prev, next) ? prev : next));\n\t\t});\n\t\treturn unsub;\n\t}, [engine, entity]);\n\n\treturn types;\n}\n\n/**\n * Reactively returns the TagTypes currently attached to an entity.\n */\nexport function useEntityTags(entity: EntityId): TagType[] {\n\tconst engine = useLayoutEngine();\n\tconst [types, setTypes] = useState<TagType[]>(() => engine.world.getTagsOf(entity));\n\n\tuseEffect(() => {\n\t\tsetTypes(engine.world.getTagsOf(entity));\n\t\tconst unsub = engine.onFrame(() => {\n\t\t\tconst next = engine.world.getTagsOf(entity);\n\t\t\tsetTypes((prev) => (sameTypeList(prev, next) ? prev : next));\n\t\t});\n\t\treturn unsub;\n\t}, [engine, entity]);\n\n\treturn types;\n}\n\n/**\n * Reactively returns every ComponentType the world has observed.\n * Grows over time as new component types are first used.\n */\nexport function useRegisteredComponents(): ComponentType[] {\n\tconst engine = useLayoutEngine();\n\tconst [types, setTypes] = useState<ComponentType[]>(() => engine.world.getRegisteredComponents());\n\n\tuseEffect(() => {\n\t\tsetTypes(engine.world.getRegisteredComponents());\n\t\tconst unsub = engine.onFrame(() => {\n\t\t\tconst next = engine.world.getRegisteredComponents();\n\t\t\tsetTypes((prev) => (sameTypeList(prev, next) ? prev : next));\n\t\t});\n\t\treturn unsub;\n\t}, [engine]);\n\n\treturn types;\n}\n\n/**\n * Reactively returns every TagType the world has observed.\n */\nexport function useRegisteredTags(): TagType[] {\n\tconst engine = useLayoutEngine();\n\tconst [types, setTypes] = useState<TagType[]>(() => engine.world.getRegisteredTags());\n\n\tuseEffect(() => {\n\t\tsetTypes(engine.world.getRegisteredTags());\n\t\tconst unsub = engine.onFrame(() => {\n\t\t\tconst next = engine.world.getRegisteredTags();\n\t\t\tsetTypes((prev) => (sameTypeList(prev, next) ? prev : next));\n\t\t});\n\t\treturn unsub;\n\t}, [engine]);\n\n\treturn types;\n}\n"],"mappings":"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"}
|