@jamesyong42/infinite-canvas 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +170 -9
  2. package/dist/SelectionRenderer-CR2PBQwx.d.cts +105 -0
  3. package/dist/SelectionRenderer-CR2PBQwx.d.cts.map +1 -0
  4. package/dist/SelectionRenderer-DlsBstAq.d.mts +105 -0
  5. package/dist/SelectionRenderer-DlsBstAq.d.mts.map +1 -0
  6. package/dist/WebGLWidgetLayer-BBMuwzHq.cjs +3560 -0
  7. package/dist/WebGLWidgetLayer-BBMuwzHq.cjs.map +1 -0
  8. package/dist/WebGLWidgetLayer-C3p1tnpm.mjs +3375 -0
  9. package/dist/WebGLWidgetLayer-C3p1tnpm.mjs.map +1 -0
  10. package/dist/advanced.cjs +110 -165
  11. package/dist/advanced.cjs.map +1 -1
  12. package/dist/advanced.d.cts +58 -40
  13. package/dist/advanced.d.cts.map +1 -0
  14. package/dist/advanced.d.mts +99 -0
  15. package/dist/advanced.d.mts.map +1 -0
  16. package/dist/advanced.mjs +105 -0
  17. package/dist/advanced.mjs.map +1 -0
  18. package/dist/devtools.cjs +654 -0
  19. package/dist/devtools.cjs.map +1 -0
  20. package/dist/devtools.d.cts +23 -0
  21. package/dist/devtools.d.cts.map +1 -0
  22. package/dist/devtools.d.mts +23 -0
  23. package/dist/devtools.d.mts.map +1 -0
  24. package/dist/devtools.mjs +652 -0
  25. package/dist/devtools.mjs.map +1 -0
  26. package/dist/engine-BfbvWXSk.d.mts +982 -0
  27. package/dist/engine-BfbvWXSk.d.mts.map +1 -0
  28. package/dist/engine-CCjuFMC-.d.cts +982 -0
  29. package/dist/engine-CCjuFMC-.d.cts.map +1 -0
  30. package/dist/hooks-BwY7rRHg.mjs +425 -0
  31. package/dist/hooks-BwY7rRHg.mjs.map +1 -0
  32. package/dist/hooks-DHShH86C.cjs +707 -0
  33. package/dist/hooks-DHShH86C.cjs.map +1 -0
  34. package/dist/index.cjs +909 -803
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +199 -67
  37. package/dist/index.d.cts.map +1 -0
  38. package/dist/index.d.mts +258 -0
  39. package/dist/index.d.mts.map +1 -0
  40. package/dist/index.mjs +855 -0
  41. package/dist/index.mjs.map +1 -0
  42. package/package.json +47 -15
  43. package/dist/SelectionRenderer-CeWSNZT8.d.cts +0 -891
  44. package/dist/SelectionRenderer-CeWSNZT8.d.ts +0 -891
  45. package/dist/advanced.d.ts +0 -81
  46. package/dist/advanced.js +0 -124
  47. package/dist/advanced.js.map +0 -1
  48. package/dist/chunk-VSHXWTJH.cjs +0 -3228
  49. package/dist/chunk-VSHXWTJH.cjs.map +0 -1
  50. package/dist/chunk-Z6JQQOWL.js +0 -3142
  51. package/dist/chunk-Z6JQQOWL.js.map +0 -1
  52. package/dist/index.d.ts +0 -126
  53. package/dist/index.js +0 -602
  54. package/dist/index.js.map +0 -1
@@ -0,0 +1,654 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ require("./WebGLWidgetLayer-BBMuwzHq.cjs");
3
+ const require_hooks = require("./hooks-DHShH86C.cjs");
4
+ let react = require("react");
5
+ let react_jsx_runtime = require("react/jsx-runtime");
6
+ //#region src/react/devtools/EcsDevtools.tsx
7
+ /**
8
+ * Live ECS editor: spawn widgets, browse entities, edit components, toggle tags.
9
+ * Ship in a dev mode or behind a feature flag — not intended for production users.
10
+ */
11
+ function EcsDevtools({ engine, onClose }) {
12
+ if (engine) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_hooks.EngineProvider, {
13
+ value: engine,
14
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EcsDevtoolsInner, { onClose })
15
+ });
16
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EcsDevtoolsInner, { onClose });
17
+ }
18
+ function EcsDevtoolsInner({ onClose }) {
19
+ const engine = require_hooks.useLayoutEngine();
20
+ const allEntities = require_hooks.useAllEntities();
21
+ const selectedIds = require_hooks.useTaggedEntities(require_hooks.Selected);
22
+ const widgets = (0, react.useMemo)(() => engine.getWidgets(), [engine]);
23
+ const [showAll, setShowAll] = (0, react.useState)(false);
24
+ const [spawnType, setSpawnType] = (0, react.useState)(widgets[0]?.type ?? "");
25
+ const [manualFocusId, setManualFocusId] = (0, react.useState)(null);
26
+ const focusId = selectedIds[0] ?? manualFocusId;
27
+ const entityList = (0, react.useMemo)(() => {
28
+ if (showAll) return allEntities;
29
+ return allEntities.filter((id) => engine.has(id, require_hooks.Widget));
30
+ }, [
31
+ engine,
32
+ allEntities,
33
+ showAll
34
+ ]);
35
+ const handleSpawn = () => {
36
+ if (!spawnType) return;
37
+ const id = engine.spawnAtCameraCenter(spawnType);
38
+ engine.markDirty();
39
+ setManualFocusId(id);
40
+ };
41
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
42
+ className: "ic-ecs-root",
43
+ children: [
44
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StyleTag, {}),
45
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
46
+ className: "ic-ecs-header",
47
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
48
+ className: "ic-ecs-title",
49
+ children: "ECS Editor"
50
+ }), onClose && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
51
+ type: "button",
52
+ className: "ic-ecs-close",
53
+ onClick: onClose,
54
+ title: "Close",
55
+ children: "×"
56
+ })]
57
+ }),
58
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
59
+ className: "ic-ecs-section",
60
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
61
+ className: "ic-ecs-label",
62
+ children: "Spawn widget"
63
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
64
+ className: "ic-ecs-row",
65
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
66
+ className: "ic-ecs-select",
67
+ value: spawnType,
68
+ onChange: (e) => setSpawnType(e.target.value),
69
+ children: widgets.map((w) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
70
+ value: w.type,
71
+ children: w.type
72
+ }, w.type))
73
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
74
+ type: "button",
75
+ className: "ic-ecs-btn ic-ecs-btn-primary",
76
+ onClick: handleSpawn,
77
+ disabled: !spawnType,
78
+ children: "+ Spawn"
79
+ })]
80
+ })]
81
+ }),
82
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
83
+ className: "ic-ecs-section",
84
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
85
+ className: "ic-ecs-label-row",
86
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
87
+ className: "ic-ecs-label",
88
+ children: [
89
+ "Entities (",
90
+ entityList.length,
91
+ showAll ? "" : " widgets",
92
+ ")"
93
+ ]
94
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
95
+ className: "ic-ecs-check",
96
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
97
+ type: "checkbox",
98
+ checked: showAll,
99
+ onChange: (e) => setShowAll(e.target.checked)
100
+ }), "show all"]
101
+ })]
102
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
103
+ className: "ic-ecs-list",
104
+ children: [entityList.map((id) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntityRow, {
105
+ entity: id,
106
+ focused: id === focusId,
107
+ onClick: () => setManualFocusId(id)
108
+ }, id)), entityList.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
109
+ className: "ic-ecs-empty",
110
+ children: "no entities"
111
+ })]
112
+ })]
113
+ }),
114
+ focusId !== null && focusId !== void 0 && engine.world.entityExists(focusId) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntityInspector, { entity: focusId })
115
+ ]
116
+ });
117
+ }
118
+ function EntityRow({ entity, focused, onClick }) {
119
+ const engine = require_hooks.useLayoutEngine();
120
+ const label = require_hooks.useComponent(entity, require_hooks.Widget)?.type ?? "entity";
121
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
122
+ className: `ic-ecs-entity-row ${focused ? "is-focused" : ""}`,
123
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
124
+ type: "button",
125
+ className: "ic-ecs-entity-btn",
126
+ onClick,
127
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
128
+ className: "ic-ecs-entity-id",
129
+ children: ["e", entity]
130
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
131
+ className: "ic-ecs-entity-label",
132
+ children: label
133
+ })]
134
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
135
+ type: "button",
136
+ className: "ic-ecs-btn ic-ecs-btn-danger ic-ecs-btn-sm",
137
+ onClick: () => {
138
+ engine.destroyEntity(entity);
139
+ engine.markDirty();
140
+ },
141
+ title: "Destroy entity",
142
+ children: "×"
143
+ })]
144
+ });
145
+ }
146
+ function EntityInspector({ entity }) {
147
+ const engine = require_hooks.useLayoutEngine();
148
+ const components = require_hooks.useEntityComponents(entity);
149
+ const tags = require_hooks.useEntityTags(entity);
150
+ const registeredComponents = require_hooks.useRegisteredComponents();
151
+ const registeredTags = require_hooks.useRegisteredTags();
152
+ const widget = require_hooks.useComponent(entity, require_hooks.Widget);
153
+ const absentComponents = (0, react.useMemo)(() => {
154
+ const present = new Set(components.map((c) => c.name));
155
+ return registeredComponents.filter((c) => !present.has(c.name));
156
+ }, [components, registeredComponents]);
157
+ const [componentToAdd, setComponentToAdd] = (0, react.useState)("");
158
+ (0, react.useEffect)(() => {
159
+ setComponentToAdd(absentComponents[0]?.name ?? "");
160
+ }, [absentComponents]);
161
+ const handleAddComponent = () => {
162
+ const type = absentComponents.find((c) => c.name === componentToAdd);
163
+ if (!type) return;
164
+ engine.addComponent(entity, type);
165
+ };
166
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
167
+ className: "ic-ecs-section",
168
+ children: [
169
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
170
+ className: "ic-ecs-inspect-head",
171
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
172
+ className: "ic-ecs-label",
173
+ children: [
174
+ "Entity ",
175
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
176
+ className: "ic-ecs-entity-id",
177
+ children: ["e", entity]
178
+ }),
179
+ widget?.type && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
180
+ className: "ic-ecs-entity-label",
181
+ children: [" · ", widget.type]
182
+ })
183
+ ]
184
+ })
185
+ }),
186
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
187
+ className: "ic-ecs-sub-label",
188
+ children: "Components"
189
+ }),
190
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
191
+ className: "ic-ecs-components",
192
+ children: components.map((type) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ComponentEditor, {
193
+ entity,
194
+ type
195
+ }, type.name))
196
+ }),
197
+ absentComponents.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
198
+ className: "ic-ecs-row",
199
+ style: { marginTop: 6 },
200
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
201
+ className: "ic-ecs-select",
202
+ value: componentToAdd,
203
+ onChange: (e) => setComponentToAdd(e.target.value),
204
+ children: absentComponents.map((c) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
205
+ value: c.name,
206
+ children: c.name
207
+ }, c.name))
208
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
209
+ type: "button",
210
+ className: "ic-ecs-btn",
211
+ onClick: handleAddComponent,
212
+ children: "+ Add component"
213
+ })]
214
+ }),
215
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
216
+ className: "ic-ecs-sub-label",
217
+ children: "Tags"
218
+ }),
219
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
220
+ className: "ic-ecs-tags",
221
+ children: registeredTags.map((type) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TagPill, {
222
+ entity,
223
+ type,
224
+ active: tags.some((t) => t.name === type.name)
225
+ }, type.name))
226
+ })
227
+ ]
228
+ });
229
+ }
230
+ function ComponentEditor({ entity, type }) {
231
+ const engine = require_hooks.useLayoutEngine();
232
+ const value = require_hooks.useComponent(entity, type);
233
+ const [collapsed, setCollapsed] = (0, react.useState)(false);
234
+ if (!value) return null;
235
+ const isWidgetData = type.name === "WidgetData";
236
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
237
+ className: "ic-ecs-component",
238
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
239
+ className: "ic-ecs-component-head",
240
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
241
+ type: "button",
242
+ className: "ic-ecs-toggle",
243
+ onClick: () => setCollapsed((c) => !c),
244
+ children: [
245
+ collapsed ? "▶" : "▼",
246
+ " ",
247
+ type.name
248
+ ]
249
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
250
+ type: "button",
251
+ className: "ic-ecs-btn ic-ecs-btn-danger ic-ecs-btn-sm",
252
+ onClick: () => engine.removeComponent(entity, type),
253
+ title: "Remove component",
254
+ children: "×"
255
+ })]
256
+ }), !collapsed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
257
+ className: "ic-ecs-fields",
258
+ children: isWidgetData ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WidgetDataEditor, {
259
+ entity,
260
+ value
261
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GenericFieldsEditor, {
262
+ entity,
263
+ type,
264
+ value
265
+ })
266
+ })]
267
+ });
268
+ }
269
+ function GenericFieldsEditor({ entity, type, value }) {
270
+ const engine = require_hooks.useLayoutEngine();
271
+ const defaults = type.defaults;
272
+ const val = value;
273
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: Object.keys(defaults).map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldRow, {
274
+ label: key,
275
+ value: val[key],
276
+ onChange: (next) => {
277
+ engine.set(entity, type, { [key]: next });
278
+ }
279
+ }, key)) });
280
+ }
281
+ function WidgetDataEditor({ entity, value }) {
282
+ const engine = require_hooks.useLayoutEngine();
283
+ const data = value.data ?? {};
284
+ const keys = Object.keys(data);
285
+ if (keys.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
286
+ className: "ic-ecs-empty",
287
+ children: "(no fields)"
288
+ });
289
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: keys.map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldRow, {
290
+ label: key,
291
+ value: data[key],
292
+ onChange: (next) => {
293
+ engine.set(entity, require_hooks.WidgetData, { data: {
294
+ ...data,
295
+ [key]: next
296
+ } });
297
+ }
298
+ }, key)) });
299
+ }
300
+ function FieldRow({ label, value, onChange }) {
301
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
302
+ className: "ic-ecs-field",
303
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
304
+ className: "ic-ecs-field-label",
305
+ children: label
306
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldInput, {
307
+ value,
308
+ onChange
309
+ })]
310
+ });
311
+ }
312
+ function FieldInput({ value, onChange }) {
313
+ if (typeof value === "number") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
314
+ type: "number",
315
+ className: "ic-ecs-input",
316
+ value,
317
+ onChange: (e) => {
318
+ const n = Number.parseFloat(e.target.value);
319
+ if (!Number.isNaN(n)) onChange(n);
320
+ }
321
+ });
322
+ if (typeof value === "boolean") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
323
+ type: "checkbox",
324
+ className: "ic-ecs-checkbox",
325
+ checked: value,
326
+ onChange: (e) => onChange(e.target.checked)
327
+ });
328
+ if (typeof value === "string") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
329
+ type: "text",
330
+ className: "ic-ecs-input",
331
+ value,
332
+ onChange: (e) => onChange(e.target.value)
333
+ });
334
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(JsonInput, {
335
+ value,
336
+ onChange
337
+ });
338
+ }
339
+ function JsonInput({ value, onChange }) {
340
+ const [text, setText] = (0, react.useState)(JSON.stringify(value));
341
+ const [error, setError] = (0, react.useState)(false);
342
+ (0, react.useEffect)(() => {
343
+ setText(JSON.stringify(value));
344
+ setError(false);
345
+ }, [value]);
346
+ const commit = () => {
347
+ try {
348
+ const parsed = JSON.parse(text);
349
+ setError(false);
350
+ onChange(parsed);
351
+ } catch {
352
+ setError(true);
353
+ }
354
+ };
355
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
356
+ type: "text",
357
+ className: `ic-ecs-input ic-ecs-input-json ${error ? "is-error" : ""}`,
358
+ value: text,
359
+ onChange: (e) => setText(e.target.value),
360
+ onBlur: commit,
361
+ onKeyDown: (e) => {
362
+ if (e.key === "Enter") commit();
363
+ }
364
+ });
365
+ }
366
+ function TagPill({ entity, type, active }) {
367
+ const engine = require_hooks.useLayoutEngine();
368
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
369
+ type: "button",
370
+ className: `ic-ecs-tag ${active ? "is-active" : ""}`,
371
+ onClick: () => {
372
+ if (active) engine.removeTag(entity, type);
373
+ else engine.addTag(entity, type);
374
+ },
375
+ children: type.name
376
+ });
377
+ }
378
+ const STYLE_ID = "ic-ecs-devtools-style";
379
+ const CSS = `
380
+ .ic-ecs-root {
381
+ --ic-ecs-bg: rgba(255, 255, 255, 0.96);
382
+ --ic-ecs-bg-elev: #f7f7f7;
383
+ --ic-ecs-fg: #1a1a1a;
384
+ --ic-ecs-fg-muted: #6b7280;
385
+ --ic-ecs-fg-faint: #9ca3af;
386
+ --ic-ecs-border: #e5e7eb;
387
+ --ic-ecs-accent: #0d99ff;
388
+ --ic-ecs-accent-fg: #ffffff;
389
+ --ic-ecs-danger: #dc2626;
390
+ --ic-ecs-focus-bg: rgba(13, 153, 255, 0.12);
391
+ position: absolute;
392
+ top: 4rem;
393
+ right: 1rem;
394
+ z-index: 50;
395
+ width: 360px;
396
+ max-height: calc(100vh - 6rem);
397
+ overflow-y: auto;
398
+ background: var(--ic-ecs-bg);
399
+ color: var(--ic-ecs-fg);
400
+ border: 1px solid var(--ic-ecs-border);
401
+ border-radius: 8px;
402
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
403
+ backdrop-filter: blur(6px);
404
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
405
+ font-size: 11px;
406
+ line-height: 1.4;
407
+ }
408
+ .dark .ic-ecs-root,
409
+ :root[data-theme="dark"] .ic-ecs-root {
410
+ --ic-ecs-bg: rgba(23, 23, 23, 0.96);
411
+ --ic-ecs-bg-elev: #1f1f1f;
412
+ --ic-ecs-fg: #e5e5e5;
413
+ --ic-ecs-fg-muted: #a1a1aa;
414
+ --ic-ecs-fg-faint: #525252;
415
+ --ic-ecs-border: #2a2a2a;
416
+ --ic-ecs-focus-bg: rgba(13, 153, 255, 0.18);
417
+ }
418
+ .ic-ecs-header {
419
+ display: flex;
420
+ align-items: center;
421
+ justify-content: space-between;
422
+ padding: 8px 12px;
423
+ border-bottom: 1px solid var(--ic-ecs-border);
424
+ }
425
+ .ic-ecs-title {
426
+ font-weight: 600;
427
+ font-size: 12px;
428
+ }
429
+ .ic-ecs-close {
430
+ background: transparent;
431
+ border: 0;
432
+ color: var(--ic-ecs-fg-muted);
433
+ cursor: pointer;
434
+ font-size: 16px;
435
+ line-height: 1;
436
+ padding: 0 4px;
437
+ }
438
+ .ic-ecs-close:hover { color: var(--ic-ecs-fg); }
439
+ .ic-ecs-section {
440
+ padding: 8px 12px;
441
+ border-bottom: 1px solid var(--ic-ecs-border);
442
+ }
443
+ .ic-ecs-section:last-child { border-bottom: 0; }
444
+ .ic-ecs-label {
445
+ font-size: 10px;
446
+ font-weight: 600;
447
+ letter-spacing: 0.05em;
448
+ text-transform: uppercase;
449
+ color: var(--ic-ecs-fg-muted);
450
+ }
451
+ .ic-ecs-label-row {
452
+ display: flex;
453
+ align-items: center;
454
+ justify-content: space-between;
455
+ margin-bottom: 4px;
456
+ }
457
+ .ic-ecs-sub-label {
458
+ font-size: 9px;
459
+ font-weight: 600;
460
+ letter-spacing: 0.05em;
461
+ text-transform: uppercase;
462
+ color: var(--ic-ecs-fg-faint);
463
+ margin: 8px 0 4px;
464
+ }
465
+ .ic-ecs-row {
466
+ display: flex;
467
+ gap: 6px;
468
+ align-items: center;
469
+ margin-top: 4px;
470
+ }
471
+ .ic-ecs-select {
472
+ flex: 1 1 auto;
473
+ min-width: 0;
474
+ background: var(--ic-ecs-bg-elev);
475
+ color: var(--ic-ecs-fg);
476
+ border: 1px solid var(--ic-ecs-border);
477
+ border-radius: 4px;
478
+ padding: 4px 6px;
479
+ font: inherit;
480
+ }
481
+ .ic-ecs-input {
482
+ flex: 1 1 auto;
483
+ min-width: 0;
484
+ background: var(--ic-ecs-bg-elev);
485
+ color: var(--ic-ecs-fg);
486
+ border: 1px solid var(--ic-ecs-border);
487
+ border-radius: 4px;
488
+ padding: 2px 6px;
489
+ font: inherit;
490
+ }
491
+ .ic-ecs-input:focus { outline: 1px solid var(--ic-ecs-accent); outline-offset: -1px; }
492
+ .ic-ecs-input-json.is-error { border-color: var(--ic-ecs-danger); }
493
+ .ic-ecs-checkbox {
494
+ accent-color: var(--ic-ecs-accent);
495
+ }
496
+ .ic-ecs-btn {
497
+ background: var(--ic-ecs-bg-elev);
498
+ color: var(--ic-ecs-fg);
499
+ border: 1px solid var(--ic-ecs-border);
500
+ border-radius: 4px;
501
+ padding: 3px 8px;
502
+ font: inherit;
503
+ cursor: pointer;
504
+ white-space: nowrap;
505
+ }
506
+ .ic-ecs-btn:hover { background: var(--ic-ecs-border); }
507
+ .ic-ecs-btn:disabled { opacity: 0.5; cursor: not-allowed; }
508
+ .ic-ecs-btn-primary {
509
+ background: var(--ic-ecs-accent);
510
+ color: var(--ic-ecs-accent-fg);
511
+ border-color: var(--ic-ecs-accent);
512
+ }
513
+ .ic-ecs-btn-primary:hover { filter: brightness(1.08); background: var(--ic-ecs-accent); }
514
+ .ic-ecs-btn-danger { color: var(--ic-ecs-danger); }
515
+ .ic-ecs-btn-sm { padding: 0 6px; font-size: 11px; }
516
+ .ic-ecs-check {
517
+ display: inline-flex;
518
+ align-items: center;
519
+ gap: 4px;
520
+ font-size: 10px;
521
+ color: var(--ic-ecs-fg-muted);
522
+ cursor: pointer;
523
+ }
524
+ .ic-ecs-list {
525
+ display: flex;
526
+ flex-direction: column;
527
+ gap: 2px;
528
+ max-height: 200px;
529
+ overflow-y: auto;
530
+ margin-top: 4px;
531
+ }
532
+ .ic-ecs-empty {
533
+ color: var(--ic-ecs-fg-faint);
534
+ font-style: italic;
535
+ padding: 4px 0;
536
+ }
537
+ .ic-ecs-entity-row {
538
+ display: flex;
539
+ align-items: center;
540
+ gap: 4px;
541
+ padding: 2px 4px;
542
+ border-radius: 4px;
543
+ }
544
+ .ic-ecs-entity-row.is-focused { background: var(--ic-ecs-focus-bg); }
545
+ .ic-ecs-entity-btn {
546
+ flex: 1 1 auto;
547
+ display: flex;
548
+ gap: 8px;
549
+ align-items: center;
550
+ background: transparent;
551
+ border: 0;
552
+ color: inherit;
553
+ cursor: pointer;
554
+ text-align: left;
555
+ padding: 2px 0;
556
+ font: inherit;
557
+ min-width: 0;
558
+ }
559
+ .ic-ecs-entity-id {
560
+ color: var(--ic-ecs-fg-muted);
561
+ font-variant-numeric: tabular-nums;
562
+ }
563
+ .ic-ecs-entity-label {
564
+ color: var(--ic-ecs-fg);
565
+ overflow: hidden;
566
+ text-overflow: ellipsis;
567
+ white-space: nowrap;
568
+ }
569
+ .ic-ecs-inspect-head {
570
+ display: flex;
571
+ align-items: center;
572
+ justify-content: space-between;
573
+ margin-bottom: 4px;
574
+ }
575
+ .ic-ecs-components {
576
+ display: flex;
577
+ flex-direction: column;
578
+ gap: 2px;
579
+ }
580
+ .ic-ecs-component {
581
+ border: 1px solid var(--ic-ecs-border);
582
+ border-radius: 4px;
583
+ background: var(--ic-ecs-bg-elev);
584
+ }
585
+ .ic-ecs-component-head {
586
+ display: flex;
587
+ align-items: center;
588
+ justify-content: space-between;
589
+ padding: 2px 6px;
590
+ }
591
+ .ic-ecs-toggle {
592
+ background: transparent;
593
+ border: 0;
594
+ color: inherit;
595
+ cursor: pointer;
596
+ font: inherit;
597
+ font-weight: 600;
598
+ padding: 2px 0;
599
+ }
600
+ .ic-ecs-fields {
601
+ display: flex;
602
+ flex-direction: column;
603
+ gap: 3px;
604
+ padding: 4px 6px 6px;
605
+ border-top: 1px dashed var(--ic-ecs-border);
606
+ }
607
+ .ic-ecs-field {
608
+ display: grid;
609
+ grid-template-columns: 70px 1fr;
610
+ align-items: center;
611
+ gap: 6px;
612
+ }
613
+ .ic-ecs-field-label {
614
+ color: var(--ic-ecs-fg-muted);
615
+ overflow: hidden;
616
+ text-overflow: ellipsis;
617
+ white-space: nowrap;
618
+ }
619
+ .ic-ecs-tags {
620
+ display: flex;
621
+ flex-wrap: wrap;
622
+ gap: 4px;
623
+ }
624
+ .ic-ecs-tag {
625
+ background: transparent;
626
+ color: var(--ic-ecs-fg-faint);
627
+ border: 1px solid var(--ic-ecs-border);
628
+ border-radius: 999px;
629
+ padding: 2px 8px;
630
+ font: inherit;
631
+ cursor: pointer;
632
+ }
633
+ .ic-ecs-tag:hover { color: var(--ic-ecs-fg); }
634
+ .ic-ecs-tag.is-active {
635
+ background: var(--ic-ecs-accent);
636
+ color: var(--ic-ecs-accent-fg);
637
+ border-color: var(--ic-ecs-accent);
638
+ }
639
+ `;
640
+ function StyleTag() {
641
+ (0, react.useEffect)(() => {
642
+ if (typeof document === "undefined") return;
643
+ if (document.getElementById(STYLE_ID)) return;
644
+ const el = document.createElement("style");
645
+ el.id = STYLE_ID;
646
+ el.textContent = CSS;
647
+ document.head.appendChild(el);
648
+ }, []);
649
+ return null;
650
+ }
651
+ //#endregion
652
+ exports.EcsDevtools = EcsDevtools;
653
+
654
+ //# sourceMappingURL=devtools.cjs.map