@jamesyong42/infinite-canvas 1.2.0 → 1.3.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 +65 -0
- package/dist/advanced.cjs +61 -24
- package/dist/advanced.cjs.map +1 -1
- package/dist/advanced.d.cts +180 -64
- package/dist/advanced.d.cts.map +1 -1
- package/dist/advanced.d.mts +180 -64
- package/dist/advanced.d.mts.map +1 -1
- package/dist/advanced.mjs +29 -12
- package/dist/advanced.mjs.map +1 -1
- package/dist/devtools.cjs +22 -22
- package/dist/devtools.cjs.map +1 -1
- package/dist/devtools.d.cts +2 -2
- package/dist/devtools.d.cts.map +1 -1
- package/dist/devtools.d.mts +2 -2
- package/dist/devtools.d.mts.map +1 -1
- package/dist/devtools.mjs +2 -2
- package/dist/devtools.mjs.map +1 -1
- package/dist/{hooks-BwY7rRHg.mjs → ecs-3kimUV5Z.mjs} +238 -74
- package/dist/ecs-3kimUV5Z.mjs.map +1 -0
- package/dist/{hooks-DHShH86C.cjs → ecs-B4QrqfvQ.cjs} +320 -108
- package/dist/ecs-B4QrqfvQ.cjs.map +1 -0
- package/dist/hooks-CtP02JNt.cjs +3762 -0
- package/dist/hooks-CtP02JNt.cjs.map +1 -0
- package/dist/hooks-gsQDDE56.mjs +3494 -0
- package/dist/hooks-gsQDDE56.mjs.map +1 -0
- package/dist/index-3GY7T8JM.d.mts +480 -0
- package/dist/index-3GY7T8JM.d.mts.map +1 -0
- package/dist/index-B7B1tRPl.d.cts +480 -0
- package/dist/index-B7B1tRPl.d.cts.map +1 -0
- package/dist/index-DSdbSQ_t.d.cts +1451 -0
- package/dist/index-DSdbSQ_t.d.cts.map +1 -0
- package/dist/index-Dj9odADH.d.mts +1451 -0
- package/dist/index-Dj9odADH.d.mts.map +1 -0
- package/dist/index.cjs +3865 -643
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +315 -138
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +315 -138
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3767 -571
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/SelectionRenderer-CR2PBQwx.d.cts +0 -105
- package/dist/SelectionRenderer-CR2PBQwx.d.cts.map +0 -1
- package/dist/SelectionRenderer-DlsBstAq.d.mts +0 -105
- package/dist/SelectionRenderer-DlsBstAq.d.mts.map +0 -1
- package/dist/WebGLWidgetLayer-BBMuwzHq.cjs +0 -3560
- package/dist/WebGLWidgetLayer-BBMuwzHq.cjs.map +0 -1
- package/dist/WebGLWidgetLayer-C3p1tnpm.mjs +0 -3375
- package/dist/WebGLWidgetLayer-C3p1tnpm.mjs.map +0 -1
- package/dist/engine-BfbvWXSk.d.mts +0 -982
- package/dist/engine-BfbvWXSk.d.mts.map +0 -1
- package/dist/engine-CCjuFMC-.d.cts +0 -982
- package/dist/engine-CCjuFMC-.d.cts.map +0 -1
- package/dist/hooks-BwY7rRHg.mjs.map +0 -1
- package/dist/hooks-DHShH86C.cjs.map +0 -1
package/dist/devtools.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devtools.cjs","names":["EngineProvider","useLayoutEngine","useAllEntities","useTaggedEntities","Selected","Widget","useComponent","useEntityComponents","useEntityTags","useRegisteredComponents","useRegisteredTags","WidgetData"],"sources":["../src/react/devtools/EcsDevtools.tsx"],"sourcesContent":["import type { ComponentType, EntityId, TagType } from '@jamesyong42/reactive-ecs';\nimport { useEffect, useMemo, useState } from 'react';\nimport { Selected, Widget, WidgetData } from '../../components.js';\nimport type { LayoutEngine } from '../../engine.js';\nimport { EngineProvider, useLayoutEngine } from '../context.js';\nimport {\n\tuseAllEntities,\n\tuseComponent,\n\tuseEntityComponents,\n\tuseEntityTags,\n\tuseRegisteredComponents,\n\tuseRegisteredTags,\n\tuseTaggedEntities,\n} from '../hooks.js';\n\ninterface EcsDevtoolsProps {\n\t/**\n\t * Engine to inspect. If omitted, reads from the nearest InfiniteCanvas context —\n\t * supply this prop when the panel is rendered outside the `<InfiniteCanvas>` subtree.\n\t */\n\tengine?: LayoutEngine;\n\tonClose?: () => void;\n}\n\n/**\n * Live ECS editor: spawn widgets, browse entities, edit components, toggle tags.\n * Ship in a dev mode or behind a feature flag — not intended for production users.\n */\nexport function EcsDevtools({ engine, onClose }: EcsDevtoolsProps) {\n\tif (engine) {\n\t\treturn (\n\t\t\t<EngineProvider value={engine}>\n\t\t\t\t<EcsDevtoolsInner onClose={onClose} />\n\t\t\t</EngineProvider>\n\t\t);\n\t}\n\treturn <EcsDevtoolsInner onClose={onClose} />;\n}\n\nfunction EcsDevtoolsInner({ onClose }: { onClose?: () => void }) {\n\tconst engine = useLayoutEngine();\n\tconst allEntities = useAllEntities();\n\tconst selectedIds = useTaggedEntities(Selected);\n\tconst widgets = useMemo(() => engine.getWidgets(), [engine]);\n\n\tconst [showAll, setShowAll] = useState(false);\n\tconst [spawnType, setSpawnType] = useState(widgets[0]?.type ?? '');\n\tconst [manualFocusId, setManualFocusId] = useState<EntityId | null>(null);\n\n\tconst focusId = selectedIds[0] ?? manualFocusId;\n\n\tconst entityList = useMemo(() => {\n\t\tif (showAll) return allEntities;\n\t\treturn allEntities.filter((id) => engine.has(id, Widget));\n\t}, [engine, allEntities, showAll]);\n\n\tconst handleSpawn = () => {\n\t\tif (!spawnType) return;\n\t\tconst id = engine.spawnAtCameraCenter(spawnType);\n\t\tengine.markDirty();\n\t\tsetManualFocusId(id);\n\t};\n\n\treturn (\n\t\t<div className=\"ic-ecs-root\">\n\t\t\t<StyleTag />\n\n\t\t\t<div className=\"ic-ecs-header\">\n\t\t\t\t<span className=\"ic-ecs-title\">ECS Editor</span>\n\t\t\t\t{onClose && (\n\t\t\t\t\t<button type=\"button\" className=\"ic-ecs-close\" onClick={onClose} title=\"Close\">\n\t\t\t\t\t\t×\n\t\t\t\t\t</button>\n\t\t\t\t)}\n\t\t\t</div>\n\n\t\t\t<div className=\"ic-ecs-section\">\n\t\t\t\t<div className=\"ic-ecs-label\">Spawn widget</div>\n\t\t\t\t<div className=\"ic-ecs-row\">\n\t\t\t\t\t<select\n\t\t\t\t\t\tclassName=\"ic-ecs-select\"\n\t\t\t\t\t\tvalue={spawnType}\n\t\t\t\t\t\tonChange={(e) => setSpawnType(e.target.value)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{widgets.map((w) => (\n\t\t\t\t\t\t\t<option key={w.type} value={w.type}>\n\t\t\t\t\t\t\t\t{w.type}\n\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</select>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"ic-ecs-btn ic-ecs-btn-primary\"\n\t\t\t\t\t\tonClick={handleSpawn}\n\t\t\t\t\t\tdisabled={!spawnType}\n\t\t\t\t\t>\n\t\t\t\t\t\t+ Spawn\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div className=\"ic-ecs-section\">\n\t\t\t\t<div className=\"ic-ecs-label-row\">\n\t\t\t\t\t<span className=\"ic-ecs-label\">\n\t\t\t\t\t\tEntities ({entityList.length}\n\t\t\t\t\t\t{showAll ? '' : ' widgets'})\n\t\t\t\t\t</span>\n\t\t\t\t\t<label className=\"ic-ecs-check\">\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\tchecked={showAll}\n\t\t\t\t\t\t\tonChange={(e) => setShowAll(e.target.checked)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\tshow all\n\t\t\t\t\t</label>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"ic-ecs-list\">\n\t\t\t\t\t{entityList.map((id) => (\n\t\t\t\t\t\t<EntityRow\n\t\t\t\t\t\t\tkey={id}\n\t\t\t\t\t\t\tentity={id}\n\t\t\t\t\t\t\tfocused={id === focusId}\n\t\t\t\t\t\t\tonClick={() => setManualFocusId(id)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t\t{entityList.length === 0 && <div className=\"ic-ecs-empty\">no entities</div>}\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t{focusId !== null && focusId !== undefined && engine.world.entityExists(focusId) && (\n\t\t\t\t<EntityInspector entity={focusId} />\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction EntityRow({\n\tentity,\n\tfocused,\n\tonClick,\n}: {\n\tentity: EntityId;\n\tfocused: boolean;\n\tonClick: () => void;\n}) {\n\tconst engine = useLayoutEngine();\n\tconst widget = useComponent(entity, Widget);\n\tconst label = widget?.type ?? 'entity';\n\n\treturn (\n\t\t<div className={`ic-ecs-entity-row ${focused ? 'is-focused' : ''}`}>\n\t\t\t<button type=\"button\" className=\"ic-ecs-entity-btn\" onClick={onClick}>\n\t\t\t\t<span className=\"ic-ecs-entity-id\">e{entity}</span>\n\t\t\t\t<span className=\"ic-ecs-entity-label\">{label}</span>\n\t\t\t</button>\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tclassName=\"ic-ecs-btn ic-ecs-btn-danger ic-ecs-btn-sm\"\n\t\t\t\tonClick={() => {\n\t\t\t\t\tengine.destroyEntity(entity);\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t}}\n\t\t\t\ttitle=\"Destroy entity\"\n\t\t\t>\n\t\t\t\t×\n\t\t\t</button>\n\t\t</div>\n\t);\n}\n\nfunction EntityInspector({ entity }: { entity: EntityId }) {\n\tconst engine = useLayoutEngine();\n\tconst components = useEntityComponents(entity);\n\tconst tags = useEntityTags(entity);\n\tconst registeredComponents = useRegisteredComponents();\n\tconst registeredTags = useRegisteredTags();\n\tconst widget = useComponent(entity, Widget);\n\n\tconst absentComponents = useMemo(() => {\n\t\tconst present = new Set(components.map((c) => c.name));\n\t\treturn registeredComponents.filter((c) => !present.has(c.name));\n\t}, [components, registeredComponents]);\n\n\tconst [componentToAdd, setComponentToAdd] = useState('');\n\tuseEffect(() => {\n\t\tsetComponentToAdd(absentComponents[0]?.name ?? '');\n\t}, [absentComponents]);\n\n\tconst handleAddComponent = () => {\n\t\tconst type = absentComponents.find((c) => c.name === componentToAdd);\n\t\tif (!type) return;\n\t\tengine.addComponent(entity, type);\n\t};\n\n\treturn (\n\t\t<div className=\"ic-ecs-section\">\n\t\t\t<div className=\"ic-ecs-inspect-head\">\n\t\t\t\t<span className=\"ic-ecs-label\">\n\t\t\t\t\tEntity <span className=\"ic-ecs-entity-id\">e{entity}</span>\n\t\t\t\t\t{widget?.type && <span className=\"ic-ecs-entity-label\"> · {widget.type}</span>}\n\t\t\t\t</span>\n\t\t\t</div>\n\n\t\t\t<div className=\"ic-ecs-sub-label\">Components</div>\n\t\t\t<div className=\"ic-ecs-components\">\n\t\t\t\t{components.map((type) => (\n\t\t\t\t\t<ComponentEditor key={type.name} entity={entity} type={type} />\n\t\t\t\t))}\n\t\t\t</div>\n\n\t\t\t{absentComponents.length > 0 && (\n\t\t\t\t<div className=\"ic-ecs-row\" style={{ marginTop: 6 }}>\n\t\t\t\t\t<select\n\t\t\t\t\t\tclassName=\"ic-ecs-select\"\n\t\t\t\t\t\tvalue={componentToAdd}\n\t\t\t\t\t\tonChange={(e) => setComponentToAdd(e.target.value)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{absentComponents.map((c) => (\n\t\t\t\t\t\t\t<option key={c.name} value={c.name}>\n\t\t\t\t\t\t\t\t{c.name}\n\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</select>\n\t\t\t\t\t<button type=\"button\" className=\"ic-ecs-btn\" onClick={handleAddComponent}>\n\t\t\t\t\t\t+ Add component\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t<div className=\"ic-ecs-sub-label\">Tags</div>\n\t\t\t<div className=\"ic-ecs-tags\">\n\t\t\t\t{registeredTags.map((type) => (\n\t\t\t\t\t<TagPill\n\t\t\t\t\t\tkey={type.name}\n\t\t\t\t\t\tentity={entity}\n\t\t\t\t\t\ttype={type}\n\t\t\t\t\t\tactive={tags.some((t) => t.name === type.name)}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nfunction ComponentEditor({ entity, type }: { entity: EntityId; type: ComponentType }) {\n\tconst engine = useLayoutEngine();\n\tconst value = useComponent(entity, type);\n\tconst [collapsed, setCollapsed] = useState(false);\n\n\tif (!value) return null;\n\n\tconst isWidgetData = type.name === 'WidgetData';\n\n\treturn (\n\t\t<div className=\"ic-ecs-component\">\n\t\t\t<div className=\"ic-ecs-component-head\">\n\t\t\t\t<button type=\"button\" className=\"ic-ecs-toggle\" onClick={() => setCollapsed((c) => !c)}>\n\t\t\t\t\t{collapsed ? '▶' : '▼'} {type.name}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"ic-ecs-btn ic-ecs-btn-danger ic-ecs-btn-sm\"\n\t\t\t\t\tonClick={() => engine.removeComponent(entity, type)}\n\t\t\t\t\ttitle=\"Remove component\"\n\t\t\t\t>\n\t\t\t\t\t×\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t{!collapsed && (\n\t\t\t\t<div className=\"ic-ecs-fields\">\n\t\t\t\t\t{isWidgetData ? (\n\t\t\t\t\t\t<WidgetDataEditor entity={entity} value={value as { data: Record<string, unknown> }} />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<GenericFieldsEditor entity={entity} type={type} value={value} />\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction GenericFieldsEditor<T>({\n\tentity,\n\ttype,\n\tvalue,\n}: {\n\tentity: EntityId;\n\ttype: ComponentType<T>;\n\tvalue: T;\n}) {\n\tconst engine = useLayoutEngine();\n\tconst defaults = type.defaults as Record<string, unknown>;\n\tconst val = value as Record<string, unknown>;\n\tconst keys = Object.keys(defaults);\n\n\treturn (\n\t\t<>\n\t\t\t{keys.map((key) => (\n\t\t\t\t<FieldRow\n\t\t\t\t\tkey={key}\n\t\t\t\t\tlabel={key}\n\t\t\t\t\tvalue={val[key]}\n\t\t\t\t\tonChange={(next) => {\n\t\t\t\t\t\tengine.set(entity, type, { [key]: next } as Partial<T>);\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</>\n\t);\n}\n\nfunction WidgetDataEditor({\n\tentity,\n\tvalue,\n}: {\n\tentity: EntityId;\n\tvalue: { data: Record<string, unknown> };\n}) {\n\tconst engine = useLayoutEngine();\n\tconst data = value.data ?? {};\n\tconst keys = Object.keys(data);\n\n\tif (keys.length === 0) {\n\t\treturn <div className=\"ic-ecs-empty\">(no fields)</div>;\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t{keys.map((key) => (\n\t\t\t\t<FieldRow\n\t\t\t\t\tkey={key}\n\t\t\t\t\tlabel={key}\n\t\t\t\t\tvalue={data[key]}\n\t\t\t\t\tonChange={(next) => {\n\t\t\t\t\t\tengine.set(entity, WidgetData, { data: { ...data, [key]: next } });\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</>\n\t);\n}\n\nfunction FieldRow({\n\tlabel,\n\tvalue,\n\tonChange,\n}: {\n\tlabel: string;\n\tvalue: unknown;\n\tonChange: (next: unknown) => void;\n}) {\n\treturn (\n\t\t<div className=\"ic-ecs-field\">\n\t\t\t<span className=\"ic-ecs-field-label\">{label}</span>\n\t\t\t<FieldInput value={value} onChange={onChange} />\n\t\t</div>\n\t);\n}\n\nfunction FieldInput({ value, onChange }: { value: unknown; onChange: (next: unknown) => void }) {\n\tif (typeof value === 'number') {\n\t\treturn (\n\t\t\t<input\n\t\t\t\ttype=\"number\"\n\t\t\t\tclassName=\"ic-ecs-input\"\n\t\t\t\tvalue={value}\n\t\t\t\tonChange={(e) => {\n\t\t\t\t\tconst n = Number.parseFloat(e.target.value);\n\t\t\t\t\tif (!Number.isNaN(n)) onChange(n);\n\t\t\t\t}}\n\t\t\t/>\n\t\t);\n\t}\n\tif (typeof value === 'boolean') {\n\t\treturn (\n\t\t\t<input\n\t\t\t\ttype=\"checkbox\"\n\t\t\t\tclassName=\"ic-ecs-checkbox\"\n\t\t\t\tchecked={value}\n\t\t\t\tonChange={(e) => onChange(e.target.checked)}\n\t\t\t/>\n\t\t);\n\t}\n\tif (typeof value === 'string') {\n\t\treturn (\n\t\t\t<input\n\t\t\t\ttype=\"text\"\n\t\t\t\tclassName=\"ic-ecs-input\"\n\t\t\t\tvalue={value}\n\t\t\t\tonChange={(e) => onChange(e.target.value)}\n\t\t\t/>\n\t\t);\n\t}\n\treturn <JsonInput value={value} onChange={onChange} />;\n}\n\nfunction JsonInput({ value, onChange }: { value: unknown; onChange: (next: unknown) => void }) {\n\tconst serialized = JSON.stringify(value);\n\tconst [text, setText] = useState(serialized);\n\tconst [error, setError] = useState(false);\n\n\tuseEffect(() => {\n\t\tsetText(JSON.stringify(value));\n\t\tsetError(false);\n\t}, [value]);\n\n\tconst commit = () => {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(text);\n\t\t\tsetError(false);\n\t\t\tonChange(parsed);\n\t\t} catch {\n\t\t\tsetError(true);\n\t\t}\n\t};\n\n\treturn (\n\t\t<input\n\t\t\ttype=\"text\"\n\t\t\tclassName={`ic-ecs-input ic-ecs-input-json ${error ? 'is-error' : ''}`}\n\t\t\tvalue={text}\n\t\t\tonChange={(e) => setText(e.target.value)}\n\t\t\tonBlur={commit}\n\t\t\tonKeyDown={(e) => {\n\t\t\t\tif (e.key === 'Enter') commit();\n\t\t\t}}\n\t\t/>\n\t);\n}\n\nfunction TagPill({ entity, type, active }: { entity: EntityId; type: TagType; active: boolean }) {\n\tconst engine = useLayoutEngine();\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclassName={`ic-ecs-tag ${active ? 'is-active' : ''}`}\n\t\t\tonClick={() => {\n\t\t\t\tif (active) engine.removeTag(entity, type);\n\t\t\t\telse engine.addTag(entity, type);\n\t\t\t}}\n\t\t>\n\t\t\t{type.name}\n\t\t</button>\n\t);\n}\n\n// Scoped styles, inlined once on mount. Dark-mode-aware via prefers-color-scheme\n// and a parent `.dark` class (matches the playground's toggle convention).\nconst STYLE_ID = 'ic-ecs-devtools-style';\nconst CSS = `\n.ic-ecs-root {\n\t--ic-ecs-bg: rgba(255, 255, 255, 0.96);\n\t--ic-ecs-bg-elev: #f7f7f7;\n\t--ic-ecs-fg: #1a1a1a;\n\t--ic-ecs-fg-muted: #6b7280;\n\t--ic-ecs-fg-faint: #9ca3af;\n\t--ic-ecs-border: #e5e7eb;\n\t--ic-ecs-accent: #0d99ff;\n\t--ic-ecs-accent-fg: #ffffff;\n\t--ic-ecs-danger: #dc2626;\n\t--ic-ecs-focus-bg: rgba(13, 153, 255, 0.12);\n\tposition: absolute;\n\ttop: 4rem;\n\tright: 1rem;\n\tz-index: 50;\n\twidth: 360px;\n\tmax-height: calc(100vh - 6rem);\n\toverflow-y: auto;\n\tbackground: var(--ic-ecs-bg);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 8px;\n\tbox-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);\n\tbackdrop-filter: blur(6px);\n\tfont-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n\tfont-size: 11px;\n\tline-height: 1.4;\n}\n.dark .ic-ecs-root,\n:root[data-theme=\"dark\"] .ic-ecs-root {\n\t--ic-ecs-bg: rgba(23, 23, 23, 0.96);\n\t--ic-ecs-bg-elev: #1f1f1f;\n\t--ic-ecs-fg: #e5e5e5;\n\t--ic-ecs-fg-muted: #a1a1aa;\n\t--ic-ecs-fg-faint: #525252;\n\t--ic-ecs-border: #2a2a2a;\n\t--ic-ecs-focus-bg: rgba(13, 153, 255, 0.18);\n}\n.ic-ecs-header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--ic-ecs-border);\n}\n.ic-ecs-title {\n\tfont-weight: 600;\n\tfont-size: 12px;\n}\n.ic-ecs-close {\n\tbackground: transparent;\n\tborder: 0;\n\tcolor: var(--ic-ecs-fg-muted);\n\tcursor: pointer;\n\tfont-size: 16px;\n\tline-height: 1;\n\tpadding: 0 4px;\n}\n.ic-ecs-close:hover { color: var(--ic-ecs-fg); }\n.ic-ecs-section {\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--ic-ecs-border);\n}\n.ic-ecs-section:last-child { border-bottom: 0; }\n.ic-ecs-label {\n\tfont-size: 10px;\n\tfont-weight: 600;\n\tletter-spacing: 0.05em;\n\ttext-transform: uppercase;\n\tcolor: var(--ic-ecs-fg-muted);\n}\n.ic-ecs-label-row {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tmargin-bottom: 4px;\n}\n.ic-ecs-sub-label {\n\tfont-size: 9px;\n\tfont-weight: 600;\n\tletter-spacing: 0.05em;\n\ttext-transform: uppercase;\n\tcolor: var(--ic-ecs-fg-faint);\n\tmargin: 8px 0 4px;\n}\n.ic-ecs-row {\n\tdisplay: flex;\n\tgap: 6px;\n\talign-items: center;\n\tmargin-top: 4px;\n}\n.ic-ecs-select {\n\tflex: 1 1 auto;\n\tmin-width: 0;\n\tbackground: var(--ic-ecs-bg-elev);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tpadding: 4px 6px;\n\tfont: inherit;\n}\n.ic-ecs-input {\n\tflex: 1 1 auto;\n\tmin-width: 0;\n\tbackground: var(--ic-ecs-bg-elev);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tpadding: 2px 6px;\n\tfont: inherit;\n}\n.ic-ecs-input:focus { outline: 1px solid var(--ic-ecs-accent); outline-offset: -1px; }\n.ic-ecs-input-json.is-error { border-color: var(--ic-ecs-danger); }\n.ic-ecs-checkbox {\n\taccent-color: var(--ic-ecs-accent);\n}\n.ic-ecs-btn {\n\tbackground: var(--ic-ecs-bg-elev);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tpadding: 3px 8px;\n\tfont: inherit;\n\tcursor: pointer;\n\twhite-space: nowrap;\n}\n.ic-ecs-btn:hover { background: var(--ic-ecs-border); }\n.ic-ecs-btn:disabled { opacity: 0.5; cursor: not-allowed; }\n.ic-ecs-btn-primary {\n\tbackground: var(--ic-ecs-accent);\n\tcolor: var(--ic-ecs-accent-fg);\n\tborder-color: var(--ic-ecs-accent);\n}\n.ic-ecs-btn-primary:hover { filter: brightness(1.08); background: var(--ic-ecs-accent); }\n.ic-ecs-btn-danger { color: var(--ic-ecs-danger); }\n.ic-ecs-btn-sm { padding: 0 6px; font-size: 11px; }\n.ic-ecs-check {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n\tfont-size: 10px;\n\tcolor: var(--ic-ecs-fg-muted);\n\tcursor: pointer;\n}\n.ic-ecs-list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tmax-height: 200px;\n\toverflow-y: auto;\n\tmargin-top: 4px;\n}\n.ic-ecs-empty {\n\tcolor: var(--ic-ecs-fg-faint);\n\tfont-style: italic;\n\tpadding: 4px 0;\n}\n.ic-ecs-entity-row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\tpadding: 2px 4px;\n\tborder-radius: 4px;\n}\n.ic-ecs-entity-row.is-focused { background: var(--ic-ecs-focus-bg); }\n.ic-ecs-entity-btn {\n\tflex: 1 1 auto;\n\tdisplay: flex;\n\tgap: 8px;\n\talign-items: center;\n\tbackground: transparent;\n\tborder: 0;\n\tcolor: inherit;\n\tcursor: pointer;\n\ttext-align: left;\n\tpadding: 2px 0;\n\tfont: inherit;\n\tmin-width: 0;\n}\n.ic-ecs-entity-id {\n\tcolor: var(--ic-ecs-fg-muted);\n\tfont-variant-numeric: tabular-nums;\n}\n.ic-ecs-entity-label {\n\tcolor: var(--ic-ecs-fg);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n.ic-ecs-inspect-head {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tmargin-bottom: 4px;\n}\n.ic-ecs-components {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n.ic-ecs-component {\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tbackground: var(--ic-ecs-bg-elev);\n}\n.ic-ecs-component-head {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 2px 6px;\n}\n.ic-ecs-toggle {\n\tbackground: transparent;\n\tborder: 0;\n\tcolor: inherit;\n\tcursor: pointer;\n\tfont: inherit;\n\tfont-weight: 600;\n\tpadding: 2px 0;\n}\n.ic-ecs-fields {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 3px;\n\tpadding: 4px 6px 6px;\n\tborder-top: 1px dashed var(--ic-ecs-border);\n}\n.ic-ecs-field {\n\tdisplay: grid;\n\tgrid-template-columns: 70px 1fr;\n\talign-items: center;\n\tgap: 6px;\n}\n.ic-ecs-field-label {\n\tcolor: var(--ic-ecs-fg-muted);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n.ic-ecs-tags {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 4px;\n}\n.ic-ecs-tag {\n\tbackground: transparent;\n\tcolor: var(--ic-ecs-fg-faint);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 999px;\n\tpadding: 2px 8px;\n\tfont: inherit;\n\tcursor: pointer;\n}\n.ic-ecs-tag:hover { color: var(--ic-ecs-fg); }\n.ic-ecs-tag.is-active {\n\tbackground: var(--ic-ecs-accent);\n\tcolor: var(--ic-ecs-accent-fg);\n\tborder-color: var(--ic-ecs-accent);\n}\n`;\n\nfunction StyleTag() {\n\tuseEffect(() => {\n\t\tif (typeof document === 'undefined') return;\n\t\tif (document.getElementById(STYLE_ID)) return;\n\t\tconst el = document.createElement('style');\n\t\tel.id = STYLE_ID;\n\t\tel.textContent = CSS;\n\t\tdocument.head.appendChild(el);\n\t}, []);\n\treturn null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"devtools.cjs","names":["EngineProvider","useLayoutEngine","useAllEntities","useTaggedEntities","Selected","Widget","useComponent","useEntityComponents","useEntityTags","useRegisteredComponents","useRegisteredTags","WidgetData"],"sources":["../src/devtools/EcsDevtools.tsx"],"sourcesContent":["import type { ComponentType, EntityId, TagType } from '@jamesyong42/reactive-ecs';\nimport { useEffect, useMemo, useState } from 'react';\nimport { Selected, Widget, WidgetData } from '../ecs/components.js';\nimport type { LayoutEngine } from '../ecs/engine/index.js';\nimport { EngineProvider, useLayoutEngine } from '../react/context/engine-context.js';\nimport {\n\tuseAllEntities,\n\tuseComponent,\n\tuseEntityComponents,\n\tuseEntityTags,\n\tuseRegisteredComponents,\n\tuseRegisteredTags,\n\tuseTaggedEntities,\n} from '../react/hooks/ecs.js';\n\ninterface EcsDevtoolsProps {\n\t/**\n\t * Engine to inspect. If omitted, reads from the nearest InfiniteCanvas context —\n\t * supply this prop when the panel is rendered outside the `<InfiniteCanvas>` subtree.\n\t */\n\tengine?: LayoutEngine;\n\tonClose?: () => void;\n}\n\n/**\n * Live ECS editor: spawn widgets, browse entities, edit components, toggle tags.\n * Ship in a dev mode or behind a feature flag — not intended for production users.\n */\nexport function EcsDevtools({ engine, onClose }: EcsDevtoolsProps) {\n\tif (engine) {\n\t\treturn (\n\t\t\t<EngineProvider value={engine}>\n\t\t\t\t<EcsDevtoolsInner onClose={onClose} />\n\t\t\t</EngineProvider>\n\t\t);\n\t}\n\treturn <EcsDevtoolsInner onClose={onClose} />;\n}\n\nfunction EcsDevtoolsInner({ onClose }: { onClose?: () => void }) {\n\tconst engine = useLayoutEngine();\n\tconst allEntities = useAllEntities();\n\tconst selectedIds = useTaggedEntities(Selected);\n\tconst widgets = useMemo(() => engine.getWidgets(), [engine]);\n\n\tconst [showAll, setShowAll] = useState(false);\n\tconst [spawnType, setSpawnType] = useState(widgets[0]?.type ?? '');\n\tconst [manualFocusId, setManualFocusId] = useState<EntityId | null>(null);\n\n\tconst focusId = selectedIds[0] ?? manualFocusId;\n\n\tconst entityList = useMemo(() => {\n\t\tif (showAll) return allEntities;\n\t\treturn allEntities.filter((id) => engine.has(id, Widget));\n\t}, [engine, allEntities, showAll]);\n\n\tconst handleSpawn = () => {\n\t\tif (!spawnType) return;\n\t\tconst id = engine.spawnAtCameraCenter(spawnType);\n\t\tengine.markDirty();\n\t\tsetManualFocusId(id);\n\t};\n\n\treturn (\n\t\t<div className=\"ic-ecs-root\">\n\t\t\t<StyleTag />\n\n\t\t\t<div className=\"ic-ecs-header\">\n\t\t\t\t<span className=\"ic-ecs-title\">ECS Editor</span>\n\t\t\t\t{onClose && (\n\t\t\t\t\t<button type=\"button\" className=\"ic-ecs-close\" onClick={onClose} title=\"Close\">\n\t\t\t\t\t\t×\n\t\t\t\t\t</button>\n\t\t\t\t)}\n\t\t\t</div>\n\n\t\t\t<div className=\"ic-ecs-section\">\n\t\t\t\t<div className=\"ic-ecs-label\">Spawn widget</div>\n\t\t\t\t<div className=\"ic-ecs-row\">\n\t\t\t\t\t<select\n\t\t\t\t\t\tclassName=\"ic-ecs-select\"\n\t\t\t\t\t\tvalue={spawnType}\n\t\t\t\t\t\tonChange={(e) => setSpawnType(e.target.value)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{widgets.map((w) => (\n\t\t\t\t\t\t\t<option key={w.type} value={w.type}>\n\t\t\t\t\t\t\t\t{w.type}\n\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</select>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"ic-ecs-btn ic-ecs-btn-primary\"\n\t\t\t\t\t\tonClick={handleSpawn}\n\t\t\t\t\t\tdisabled={!spawnType}\n\t\t\t\t\t>\n\t\t\t\t\t\t+ Spawn\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div className=\"ic-ecs-section\">\n\t\t\t\t<div className=\"ic-ecs-label-row\">\n\t\t\t\t\t<span className=\"ic-ecs-label\">\n\t\t\t\t\t\tEntities ({entityList.length}\n\t\t\t\t\t\t{showAll ? '' : ' widgets'})\n\t\t\t\t\t</span>\n\t\t\t\t\t<label className=\"ic-ecs-check\">\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\tchecked={showAll}\n\t\t\t\t\t\t\tonChange={(e) => setShowAll(e.target.checked)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\tshow all\n\t\t\t\t\t</label>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"ic-ecs-list\">\n\t\t\t\t\t{entityList.map((id) => (\n\t\t\t\t\t\t<EntityRow\n\t\t\t\t\t\t\tkey={id}\n\t\t\t\t\t\t\tentity={id}\n\t\t\t\t\t\t\tfocused={id === focusId}\n\t\t\t\t\t\t\tonClick={() => setManualFocusId(id)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t\t{entityList.length === 0 && <div className=\"ic-ecs-empty\">no entities</div>}\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t{focusId !== null && focusId !== undefined && engine.world.entityExists(focusId) && (\n\t\t\t\t<EntityInspector entity={focusId} />\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction EntityRow({\n\tentity,\n\tfocused,\n\tonClick,\n}: {\n\tentity: EntityId;\n\tfocused: boolean;\n\tonClick: () => void;\n}) {\n\tconst engine = useLayoutEngine();\n\tconst widget = useComponent(entity, Widget);\n\tconst label = widget?.type ?? 'entity';\n\n\treturn (\n\t\t<div className={`ic-ecs-entity-row ${focused ? 'is-focused' : ''}`}>\n\t\t\t<button type=\"button\" className=\"ic-ecs-entity-btn\" onClick={onClick}>\n\t\t\t\t<span className=\"ic-ecs-entity-id\">e{entity}</span>\n\t\t\t\t<span className=\"ic-ecs-entity-label\">{label}</span>\n\t\t\t</button>\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tclassName=\"ic-ecs-btn ic-ecs-btn-danger ic-ecs-btn-sm\"\n\t\t\t\tonClick={() => {\n\t\t\t\t\tengine.destroyEntity(entity);\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t}}\n\t\t\t\ttitle=\"Destroy entity\"\n\t\t\t>\n\t\t\t\t×\n\t\t\t</button>\n\t\t</div>\n\t);\n}\n\nfunction EntityInspector({ entity }: { entity: EntityId }) {\n\tconst engine = useLayoutEngine();\n\tconst components = useEntityComponents(entity);\n\tconst tags = useEntityTags(entity);\n\tconst registeredComponents = useRegisteredComponents();\n\tconst registeredTags = useRegisteredTags();\n\tconst widget = useComponent(entity, Widget);\n\n\tconst absentComponents = useMemo(() => {\n\t\tconst present = new Set(components.map((c) => c.name));\n\t\treturn registeredComponents.filter((c) => !present.has(c.name));\n\t}, [components, registeredComponents]);\n\n\tconst [componentToAdd, setComponentToAdd] = useState('');\n\tuseEffect(() => {\n\t\tsetComponentToAdd(absentComponents[0]?.name ?? '');\n\t}, [absentComponents]);\n\n\tconst handleAddComponent = () => {\n\t\tconst type = absentComponents.find((c) => c.name === componentToAdd);\n\t\tif (!type) return;\n\t\tengine.addComponent(entity, type);\n\t};\n\n\treturn (\n\t\t<div className=\"ic-ecs-section\">\n\t\t\t<div className=\"ic-ecs-inspect-head\">\n\t\t\t\t<span className=\"ic-ecs-label\">\n\t\t\t\t\tEntity <span className=\"ic-ecs-entity-id\">e{entity}</span>\n\t\t\t\t\t{widget?.type && <span className=\"ic-ecs-entity-label\"> · {widget.type}</span>}\n\t\t\t\t</span>\n\t\t\t</div>\n\n\t\t\t<div className=\"ic-ecs-sub-label\">Components</div>\n\t\t\t<div className=\"ic-ecs-components\">\n\t\t\t\t{components.map((type) => (\n\t\t\t\t\t<ComponentEditor key={type.name} entity={entity} type={type} />\n\t\t\t\t))}\n\t\t\t</div>\n\n\t\t\t{absentComponents.length > 0 && (\n\t\t\t\t<div className=\"ic-ecs-row\" style={{ marginTop: 6 }}>\n\t\t\t\t\t<select\n\t\t\t\t\t\tclassName=\"ic-ecs-select\"\n\t\t\t\t\t\tvalue={componentToAdd}\n\t\t\t\t\t\tonChange={(e) => setComponentToAdd(e.target.value)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{absentComponents.map((c) => (\n\t\t\t\t\t\t\t<option key={c.name} value={c.name}>\n\t\t\t\t\t\t\t\t{c.name}\n\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</select>\n\t\t\t\t\t<button type=\"button\" className=\"ic-ecs-btn\" onClick={handleAddComponent}>\n\t\t\t\t\t\t+ Add component\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t<div className=\"ic-ecs-sub-label\">Tags</div>\n\t\t\t<div className=\"ic-ecs-tags\">\n\t\t\t\t{registeredTags.map((type) => (\n\t\t\t\t\t<TagPill\n\t\t\t\t\t\tkey={type.name}\n\t\t\t\t\t\tentity={entity}\n\t\t\t\t\t\ttype={type}\n\t\t\t\t\t\tactive={tags.some((t) => t.name === type.name)}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nfunction ComponentEditor({ entity, type }: { entity: EntityId; type: ComponentType }) {\n\tconst engine = useLayoutEngine();\n\tconst value = useComponent(entity, type);\n\tconst [collapsed, setCollapsed] = useState(false);\n\n\tif (!value) return null;\n\n\tconst isWidgetData = type.name === 'WidgetData';\n\n\treturn (\n\t\t<div className=\"ic-ecs-component\">\n\t\t\t<div className=\"ic-ecs-component-head\">\n\t\t\t\t<button type=\"button\" className=\"ic-ecs-toggle\" onClick={() => setCollapsed((c) => !c)}>\n\t\t\t\t\t{collapsed ? '▶' : '▼'} {type.name}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"ic-ecs-btn ic-ecs-btn-danger ic-ecs-btn-sm\"\n\t\t\t\t\tonClick={() => engine.removeComponent(entity, type)}\n\t\t\t\t\ttitle=\"Remove component\"\n\t\t\t\t>\n\t\t\t\t\t×\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t{!collapsed && (\n\t\t\t\t<div className=\"ic-ecs-fields\">\n\t\t\t\t\t{isWidgetData ? (\n\t\t\t\t\t\t<WidgetDataEditor entity={entity} value={value as { data: Record<string, unknown> }} />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<GenericFieldsEditor entity={entity} type={type} value={value} />\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction GenericFieldsEditor<T>({\n\tentity,\n\ttype,\n\tvalue,\n}: {\n\tentity: EntityId;\n\ttype: ComponentType<T>;\n\tvalue: T;\n}) {\n\tconst engine = useLayoutEngine();\n\tconst defaults = type.defaults as Record<string, unknown>;\n\tconst val = value as Record<string, unknown>;\n\tconst keys = Object.keys(defaults);\n\n\treturn (\n\t\t<>\n\t\t\t{keys.map((key) => (\n\t\t\t\t<FieldRow\n\t\t\t\t\tkey={key}\n\t\t\t\t\tlabel={key}\n\t\t\t\t\tvalue={val[key]}\n\t\t\t\t\tonChange={(next) => {\n\t\t\t\t\t\tengine.set(entity, type, { [key]: next } as Partial<T>);\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</>\n\t);\n}\n\nfunction WidgetDataEditor({\n\tentity,\n\tvalue,\n}: {\n\tentity: EntityId;\n\tvalue: { data: Record<string, unknown> };\n}) {\n\tconst engine = useLayoutEngine();\n\tconst data = value.data ?? {};\n\tconst keys = Object.keys(data);\n\n\tif (keys.length === 0) {\n\t\treturn <div className=\"ic-ecs-empty\">(no fields)</div>;\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t{keys.map((key) => (\n\t\t\t\t<FieldRow\n\t\t\t\t\tkey={key}\n\t\t\t\t\tlabel={key}\n\t\t\t\t\tvalue={data[key]}\n\t\t\t\t\tonChange={(next) => {\n\t\t\t\t\t\tengine.set(entity, WidgetData, { data: { ...data, [key]: next } });\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</>\n\t);\n}\n\nfunction FieldRow({\n\tlabel,\n\tvalue,\n\tonChange,\n}: {\n\tlabel: string;\n\tvalue: unknown;\n\tonChange: (next: unknown) => void;\n}) {\n\treturn (\n\t\t<div className=\"ic-ecs-field\">\n\t\t\t<span className=\"ic-ecs-field-label\">{label}</span>\n\t\t\t<FieldInput value={value} onChange={onChange} />\n\t\t</div>\n\t);\n}\n\nfunction FieldInput({ value, onChange }: { value: unknown; onChange: (next: unknown) => void }) {\n\tif (typeof value === 'number') {\n\t\treturn (\n\t\t\t<input\n\t\t\t\ttype=\"number\"\n\t\t\t\tclassName=\"ic-ecs-input\"\n\t\t\t\tvalue={value}\n\t\t\t\tonChange={(e) => {\n\t\t\t\t\tconst n = Number.parseFloat(e.target.value);\n\t\t\t\t\tif (!Number.isNaN(n)) onChange(n);\n\t\t\t\t}}\n\t\t\t/>\n\t\t);\n\t}\n\tif (typeof value === 'boolean') {\n\t\treturn (\n\t\t\t<input\n\t\t\t\ttype=\"checkbox\"\n\t\t\t\tclassName=\"ic-ecs-checkbox\"\n\t\t\t\tchecked={value}\n\t\t\t\tonChange={(e) => onChange(e.target.checked)}\n\t\t\t/>\n\t\t);\n\t}\n\tif (typeof value === 'string') {\n\t\treturn (\n\t\t\t<input\n\t\t\t\ttype=\"text\"\n\t\t\t\tclassName=\"ic-ecs-input\"\n\t\t\t\tvalue={value}\n\t\t\t\tonChange={(e) => onChange(e.target.value)}\n\t\t\t/>\n\t\t);\n\t}\n\treturn <JsonInput value={value} onChange={onChange} />;\n}\n\nfunction JsonInput({ value, onChange }: { value: unknown; onChange: (next: unknown) => void }) {\n\tconst serialized = JSON.stringify(value);\n\tconst [text, setText] = useState(serialized);\n\tconst [error, setError] = useState(false);\n\n\tuseEffect(() => {\n\t\tsetText(JSON.stringify(value));\n\t\tsetError(false);\n\t}, [value]);\n\n\tconst commit = () => {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(text);\n\t\t\tsetError(false);\n\t\t\tonChange(parsed);\n\t\t} catch {\n\t\t\tsetError(true);\n\t\t}\n\t};\n\n\treturn (\n\t\t<input\n\t\t\ttype=\"text\"\n\t\t\tclassName={`ic-ecs-input ic-ecs-input-json ${error ? 'is-error' : ''}`}\n\t\t\tvalue={text}\n\t\t\tonChange={(e) => setText(e.target.value)}\n\t\t\tonBlur={commit}\n\t\t\tonKeyDown={(e) => {\n\t\t\t\tif (e.key === 'Enter') commit();\n\t\t\t}}\n\t\t/>\n\t);\n}\n\nfunction TagPill({ entity, type, active }: { entity: EntityId; type: TagType; active: boolean }) {\n\tconst engine = useLayoutEngine();\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclassName={`ic-ecs-tag ${active ? 'is-active' : ''}`}\n\t\t\tonClick={() => {\n\t\t\t\tif (active) engine.removeTag(entity, type);\n\t\t\t\telse engine.addTag(entity, type);\n\t\t\t}}\n\t\t>\n\t\t\t{type.name}\n\t\t</button>\n\t);\n}\n\n// Scoped styles, inlined once on mount. Dark-mode-aware via prefers-color-scheme\n// and a parent `.dark` class (matches the playground's toggle convention).\nconst STYLE_ID = 'ic-ecs-devtools-style';\nconst CSS = `\n.ic-ecs-root {\n\t--ic-ecs-bg: rgba(255, 255, 255, 0.96);\n\t--ic-ecs-bg-elev: #f7f7f7;\n\t--ic-ecs-fg: #1a1a1a;\n\t--ic-ecs-fg-muted: #6b7280;\n\t--ic-ecs-fg-faint: #9ca3af;\n\t--ic-ecs-border: #e5e7eb;\n\t--ic-ecs-accent: #0d99ff;\n\t--ic-ecs-accent-fg: #ffffff;\n\t--ic-ecs-danger: #dc2626;\n\t--ic-ecs-focus-bg: rgba(13, 153, 255, 0.12);\n\tposition: absolute;\n\ttop: 4rem;\n\tright: 1rem;\n\tz-index: 50;\n\twidth: 360px;\n\tmax-height: calc(100vh - 6rem);\n\toverflow-y: auto;\n\tbackground: var(--ic-ecs-bg);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 8px;\n\tbox-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);\n\tbackdrop-filter: blur(6px);\n\tfont-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n\tfont-size: 11px;\n\tline-height: 1.4;\n}\n.dark .ic-ecs-root,\n:root[data-theme=\"dark\"] .ic-ecs-root {\n\t--ic-ecs-bg: rgba(23, 23, 23, 0.96);\n\t--ic-ecs-bg-elev: #1f1f1f;\n\t--ic-ecs-fg: #e5e5e5;\n\t--ic-ecs-fg-muted: #a1a1aa;\n\t--ic-ecs-fg-faint: #525252;\n\t--ic-ecs-border: #2a2a2a;\n\t--ic-ecs-focus-bg: rgba(13, 153, 255, 0.18);\n}\n.ic-ecs-header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--ic-ecs-border);\n}\n.ic-ecs-title {\n\tfont-weight: 600;\n\tfont-size: 12px;\n}\n.ic-ecs-close {\n\tbackground: transparent;\n\tborder: 0;\n\tcolor: var(--ic-ecs-fg-muted);\n\tcursor: pointer;\n\tfont-size: 16px;\n\tline-height: 1;\n\tpadding: 0 4px;\n}\n.ic-ecs-close:hover { color: var(--ic-ecs-fg); }\n.ic-ecs-section {\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--ic-ecs-border);\n}\n.ic-ecs-section:last-child { border-bottom: 0; }\n.ic-ecs-label {\n\tfont-size: 10px;\n\tfont-weight: 600;\n\tletter-spacing: 0.05em;\n\ttext-transform: uppercase;\n\tcolor: var(--ic-ecs-fg-muted);\n}\n.ic-ecs-label-row {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tmargin-bottom: 4px;\n}\n.ic-ecs-sub-label {\n\tfont-size: 9px;\n\tfont-weight: 600;\n\tletter-spacing: 0.05em;\n\ttext-transform: uppercase;\n\tcolor: var(--ic-ecs-fg-faint);\n\tmargin: 8px 0 4px;\n}\n.ic-ecs-row {\n\tdisplay: flex;\n\tgap: 6px;\n\talign-items: center;\n\tmargin-top: 4px;\n}\n.ic-ecs-select {\n\tflex: 1 1 auto;\n\tmin-width: 0;\n\tbackground: var(--ic-ecs-bg-elev);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tpadding: 4px 6px;\n\tfont: inherit;\n}\n.ic-ecs-input {\n\tflex: 1 1 auto;\n\tmin-width: 0;\n\tbackground: var(--ic-ecs-bg-elev);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tpadding: 2px 6px;\n\tfont: inherit;\n}\n.ic-ecs-input:focus { outline: 1px solid var(--ic-ecs-accent); outline-offset: -1px; }\n.ic-ecs-input-json.is-error { border-color: var(--ic-ecs-danger); }\n.ic-ecs-checkbox {\n\taccent-color: var(--ic-ecs-accent);\n}\n.ic-ecs-btn {\n\tbackground: var(--ic-ecs-bg-elev);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tpadding: 3px 8px;\n\tfont: inherit;\n\tcursor: pointer;\n\twhite-space: nowrap;\n}\n.ic-ecs-btn:hover { background: var(--ic-ecs-border); }\n.ic-ecs-btn:disabled { opacity: 0.5; cursor: not-allowed; }\n.ic-ecs-btn-primary {\n\tbackground: var(--ic-ecs-accent);\n\tcolor: var(--ic-ecs-accent-fg);\n\tborder-color: var(--ic-ecs-accent);\n}\n.ic-ecs-btn-primary:hover { filter: brightness(1.08); background: var(--ic-ecs-accent); }\n.ic-ecs-btn-danger { color: var(--ic-ecs-danger); }\n.ic-ecs-btn-sm { padding: 0 6px; font-size: 11px; }\n.ic-ecs-check {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n\tfont-size: 10px;\n\tcolor: var(--ic-ecs-fg-muted);\n\tcursor: pointer;\n}\n.ic-ecs-list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tmax-height: 200px;\n\toverflow-y: auto;\n\tmargin-top: 4px;\n}\n.ic-ecs-empty {\n\tcolor: var(--ic-ecs-fg-faint);\n\tfont-style: italic;\n\tpadding: 4px 0;\n}\n.ic-ecs-entity-row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\tpadding: 2px 4px;\n\tborder-radius: 4px;\n}\n.ic-ecs-entity-row.is-focused { background: var(--ic-ecs-focus-bg); }\n.ic-ecs-entity-btn {\n\tflex: 1 1 auto;\n\tdisplay: flex;\n\tgap: 8px;\n\talign-items: center;\n\tbackground: transparent;\n\tborder: 0;\n\tcolor: inherit;\n\tcursor: pointer;\n\ttext-align: left;\n\tpadding: 2px 0;\n\tfont: inherit;\n\tmin-width: 0;\n}\n.ic-ecs-entity-id {\n\tcolor: var(--ic-ecs-fg-muted);\n\tfont-variant-numeric: tabular-nums;\n}\n.ic-ecs-entity-label {\n\tcolor: var(--ic-ecs-fg);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n.ic-ecs-inspect-head {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tmargin-bottom: 4px;\n}\n.ic-ecs-components {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n.ic-ecs-component {\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tbackground: var(--ic-ecs-bg-elev);\n}\n.ic-ecs-component-head {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 2px 6px;\n}\n.ic-ecs-toggle {\n\tbackground: transparent;\n\tborder: 0;\n\tcolor: inherit;\n\tcursor: pointer;\n\tfont: inherit;\n\tfont-weight: 600;\n\tpadding: 2px 0;\n}\n.ic-ecs-fields {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 3px;\n\tpadding: 4px 6px 6px;\n\tborder-top: 1px dashed var(--ic-ecs-border);\n}\n.ic-ecs-field {\n\tdisplay: grid;\n\tgrid-template-columns: 70px 1fr;\n\talign-items: center;\n\tgap: 6px;\n}\n.ic-ecs-field-label {\n\tcolor: var(--ic-ecs-fg-muted);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n.ic-ecs-tags {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 4px;\n}\n.ic-ecs-tag {\n\tbackground: transparent;\n\tcolor: var(--ic-ecs-fg-faint);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 999px;\n\tpadding: 2px 8px;\n\tfont: inherit;\n\tcursor: pointer;\n}\n.ic-ecs-tag:hover { color: var(--ic-ecs-fg); }\n.ic-ecs-tag.is-active {\n\tbackground: var(--ic-ecs-accent);\n\tcolor: var(--ic-ecs-accent-fg);\n\tborder-color: var(--ic-ecs-accent);\n}\n`;\n\nfunction StyleTag() {\n\tuseEffect(() => {\n\t\tif (typeof document === 'undefined') return;\n\t\tif (document.getElementById(STYLE_ID)) return;\n\t\tconst el = document.createElement('style');\n\t\tel.id = STYLE_ID;\n\t\tel.textContent = CSS;\n\t\tdocument.head.appendChild(el);\n\t}, []);\n\treturn null;\n}\n"],"mappings":"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"}
|
package/dist/devtools.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { r as LayoutEngine } from "./index-DSdbSQ_t.cjs";
|
|
2
2
|
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/devtools/EcsDevtools.d.ts
|
|
5
5
|
interface EcsDevtoolsProps {
|
|
6
6
|
/**
|
|
7
7
|
* Engine to inspect. If omitted, reads from the nearest InfiniteCanvas context —
|
package/dist/devtools.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devtools.d.cts","names":[],"sources":["../src/
|
|
1
|
+
{"version":3,"file":"devtools.d.cts","names":[],"sources":["../src/devtools/EcsDevtools.tsx"],"mappings":";;;;UAeU,gBAAA;;;AAZiD;;EAiB1D,MAAA,GAAS,YAAA;EACT,OAAA;AAAA;;;;;iBAOe,WAAA,CAAA;EAAc,MAAA;EAAQ;AAAA,GAAW,gBAAA,GAAgB,oBAAA,CAAA,GAAA,CAAA,OAAA"}
|
package/dist/devtools.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { r as LayoutEngine } from "./index-Dj9odADH.mjs";
|
|
2
2
|
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/devtools/EcsDevtools.d.ts
|
|
5
5
|
interface EcsDevtoolsProps {
|
|
6
6
|
/**
|
|
7
7
|
* Engine to inspect. If omitted, reads from the nearest InfiniteCanvas context —
|
package/dist/devtools.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devtools.d.mts","names":[],"sources":["../src/
|
|
1
|
+
{"version":3,"file":"devtools.d.mts","names":[],"sources":["../src/devtools/EcsDevtools.tsx"],"mappings":";;;;UAeU,gBAAA;;;AAZiD;;EAiB1D,MAAA,GAAS,YAAA;EACT,OAAA;AAAA;;;;;iBAOe,WAAA,CAAA;EAAc,MAAA;EAAQ;AAAA,GAAW,gBAAA,GAAgB,oBAAA,CAAA,GAAA,CAAA,OAAA"}
|
package/dist/devtools.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { G as
|
|
1
|
+
import { G as Selected, Q as Widget, a as useEntityTags, c as useRegisteredTags, d as useTaggedEntities, et as WidgetData, f as EngineProvider, i as useEntityComponents, p as useLayoutEngine, r as useComponent, s as useRegisteredComponents, t as useAllEntities } from "./ecs-3kimUV5Z.mjs";
|
|
2
2
|
import { useEffect, useMemo, useState } from "react";
|
|
3
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/devtools/EcsDevtools.tsx
|
|
5
5
|
/**
|
|
6
6
|
* Live ECS editor: spawn widgets, browse entities, edit components, toggle tags.
|
|
7
7
|
* Ship in a dev mode or behind a feature flag — not intended for production users.
|
package/dist/devtools.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devtools.mjs","names":[],"sources":["../src/react/devtools/EcsDevtools.tsx"],"sourcesContent":["import type { ComponentType, EntityId, TagType } from '@jamesyong42/reactive-ecs';\nimport { useEffect, useMemo, useState } from 'react';\nimport { Selected, Widget, WidgetData } from '../../components.js';\nimport type { LayoutEngine } from '../../engine.js';\nimport { EngineProvider, useLayoutEngine } from '../context.js';\nimport {\n\tuseAllEntities,\n\tuseComponent,\n\tuseEntityComponents,\n\tuseEntityTags,\n\tuseRegisteredComponents,\n\tuseRegisteredTags,\n\tuseTaggedEntities,\n} from '../hooks.js';\n\ninterface EcsDevtoolsProps {\n\t/**\n\t * Engine to inspect. If omitted, reads from the nearest InfiniteCanvas context —\n\t * supply this prop when the panel is rendered outside the `<InfiniteCanvas>` subtree.\n\t */\n\tengine?: LayoutEngine;\n\tonClose?: () => void;\n}\n\n/**\n * Live ECS editor: spawn widgets, browse entities, edit components, toggle tags.\n * Ship in a dev mode or behind a feature flag — not intended for production users.\n */\nexport function EcsDevtools({ engine, onClose }: EcsDevtoolsProps) {\n\tif (engine) {\n\t\treturn (\n\t\t\t<EngineProvider value={engine}>\n\t\t\t\t<EcsDevtoolsInner onClose={onClose} />\n\t\t\t</EngineProvider>\n\t\t);\n\t}\n\treturn <EcsDevtoolsInner onClose={onClose} />;\n}\n\nfunction EcsDevtoolsInner({ onClose }: { onClose?: () => void }) {\n\tconst engine = useLayoutEngine();\n\tconst allEntities = useAllEntities();\n\tconst selectedIds = useTaggedEntities(Selected);\n\tconst widgets = useMemo(() => engine.getWidgets(), [engine]);\n\n\tconst [showAll, setShowAll] = useState(false);\n\tconst [spawnType, setSpawnType] = useState(widgets[0]?.type ?? '');\n\tconst [manualFocusId, setManualFocusId] = useState<EntityId | null>(null);\n\n\tconst focusId = selectedIds[0] ?? manualFocusId;\n\n\tconst entityList = useMemo(() => {\n\t\tif (showAll) return allEntities;\n\t\treturn allEntities.filter((id) => engine.has(id, Widget));\n\t}, [engine, allEntities, showAll]);\n\n\tconst handleSpawn = () => {\n\t\tif (!spawnType) return;\n\t\tconst id = engine.spawnAtCameraCenter(spawnType);\n\t\tengine.markDirty();\n\t\tsetManualFocusId(id);\n\t};\n\n\treturn (\n\t\t<div className=\"ic-ecs-root\">\n\t\t\t<StyleTag />\n\n\t\t\t<div className=\"ic-ecs-header\">\n\t\t\t\t<span className=\"ic-ecs-title\">ECS Editor</span>\n\t\t\t\t{onClose && (\n\t\t\t\t\t<button type=\"button\" className=\"ic-ecs-close\" onClick={onClose} title=\"Close\">\n\t\t\t\t\t\t×\n\t\t\t\t\t</button>\n\t\t\t\t)}\n\t\t\t</div>\n\n\t\t\t<div className=\"ic-ecs-section\">\n\t\t\t\t<div className=\"ic-ecs-label\">Spawn widget</div>\n\t\t\t\t<div className=\"ic-ecs-row\">\n\t\t\t\t\t<select\n\t\t\t\t\t\tclassName=\"ic-ecs-select\"\n\t\t\t\t\t\tvalue={spawnType}\n\t\t\t\t\t\tonChange={(e) => setSpawnType(e.target.value)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{widgets.map((w) => (\n\t\t\t\t\t\t\t<option key={w.type} value={w.type}>\n\t\t\t\t\t\t\t\t{w.type}\n\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</select>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"ic-ecs-btn ic-ecs-btn-primary\"\n\t\t\t\t\t\tonClick={handleSpawn}\n\t\t\t\t\t\tdisabled={!spawnType}\n\t\t\t\t\t>\n\t\t\t\t\t\t+ Spawn\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div className=\"ic-ecs-section\">\n\t\t\t\t<div className=\"ic-ecs-label-row\">\n\t\t\t\t\t<span className=\"ic-ecs-label\">\n\t\t\t\t\t\tEntities ({entityList.length}\n\t\t\t\t\t\t{showAll ? '' : ' widgets'})\n\t\t\t\t\t</span>\n\t\t\t\t\t<label className=\"ic-ecs-check\">\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\tchecked={showAll}\n\t\t\t\t\t\t\tonChange={(e) => setShowAll(e.target.checked)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\tshow all\n\t\t\t\t\t</label>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"ic-ecs-list\">\n\t\t\t\t\t{entityList.map((id) => (\n\t\t\t\t\t\t<EntityRow\n\t\t\t\t\t\t\tkey={id}\n\t\t\t\t\t\t\tentity={id}\n\t\t\t\t\t\t\tfocused={id === focusId}\n\t\t\t\t\t\t\tonClick={() => setManualFocusId(id)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t\t{entityList.length === 0 && <div className=\"ic-ecs-empty\">no entities</div>}\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t{focusId !== null && focusId !== undefined && engine.world.entityExists(focusId) && (\n\t\t\t\t<EntityInspector entity={focusId} />\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction EntityRow({\n\tentity,\n\tfocused,\n\tonClick,\n}: {\n\tentity: EntityId;\n\tfocused: boolean;\n\tonClick: () => void;\n}) {\n\tconst engine = useLayoutEngine();\n\tconst widget = useComponent(entity, Widget);\n\tconst label = widget?.type ?? 'entity';\n\n\treturn (\n\t\t<div className={`ic-ecs-entity-row ${focused ? 'is-focused' : ''}`}>\n\t\t\t<button type=\"button\" className=\"ic-ecs-entity-btn\" onClick={onClick}>\n\t\t\t\t<span className=\"ic-ecs-entity-id\">e{entity}</span>\n\t\t\t\t<span className=\"ic-ecs-entity-label\">{label}</span>\n\t\t\t</button>\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tclassName=\"ic-ecs-btn ic-ecs-btn-danger ic-ecs-btn-sm\"\n\t\t\t\tonClick={() => {\n\t\t\t\t\tengine.destroyEntity(entity);\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t}}\n\t\t\t\ttitle=\"Destroy entity\"\n\t\t\t>\n\t\t\t\t×\n\t\t\t</button>\n\t\t</div>\n\t);\n}\n\nfunction EntityInspector({ entity }: { entity: EntityId }) {\n\tconst engine = useLayoutEngine();\n\tconst components = useEntityComponents(entity);\n\tconst tags = useEntityTags(entity);\n\tconst registeredComponents = useRegisteredComponents();\n\tconst registeredTags = useRegisteredTags();\n\tconst widget = useComponent(entity, Widget);\n\n\tconst absentComponents = useMemo(() => {\n\t\tconst present = new Set(components.map((c) => c.name));\n\t\treturn registeredComponents.filter((c) => !present.has(c.name));\n\t}, [components, registeredComponents]);\n\n\tconst [componentToAdd, setComponentToAdd] = useState('');\n\tuseEffect(() => {\n\t\tsetComponentToAdd(absentComponents[0]?.name ?? '');\n\t}, [absentComponents]);\n\n\tconst handleAddComponent = () => {\n\t\tconst type = absentComponents.find((c) => c.name === componentToAdd);\n\t\tif (!type) return;\n\t\tengine.addComponent(entity, type);\n\t};\n\n\treturn (\n\t\t<div className=\"ic-ecs-section\">\n\t\t\t<div className=\"ic-ecs-inspect-head\">\n\t\t\t\t<span className=\"ic-ecs-label\">\n\t\t\t\t\tEntity <span className=\"ic-ecs-entity-id\">e{entity}</span>\n\t\t\t\t\t{widget?.type && <span className=\"ic-ecs-entity-label\"> · {widget.type}</span>}\n\t\t\t\t</span>\n\t\t\t</div>\n\n\t\t\t<div className=\"ic-ecs-sub-label\">Components</div>\n\t\t\t<div className=\"ic-ecs-components\">\n\t\t\t\t{components.map((type) => (\n\t\t\t\t\t<ComponentEditor key={type.name} entity={entity} type={type} />\n\t\t\t\t))}\n\t\t\t</div>\n\n\t\t\t{absentComponents.length > 0 && (\n\t\t\t\t<div className=\"ic-ecs-row\" style={{ marginTop: 6 }}>\n\t\t\t\t\t<select\n\t\t\t\t\t\tclassName=\"ic-ecs-select\"\n\t\t\t\t\t\tvalue={componentToAdd}\n\t\t\t\t\t\tonChange={(e) => setComponentToAdd(e.target.value)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{absentComponents.map((c) => (\n\t\t\t\t\t\t\t<option key={c.name} value={c.name}>\n\t\t\t\t\t\t\t\t{c.name}\n\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</select>\n\t\t\t\t\t<button type=\"button\" className=\"ic-ecs-btn\" onClick={handleAddComponent}>\n\t\t\t\t\t\t+ Add component\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t<div className=\"ic-ecs-sub-label\">Tags</div>\n\t\t\t<div className=\"ic-ecs-tags\">\n\t\t\t\t{registeredTags.map((type) => (\n\t\t\t\t\t<TagPill\n\t\t\t\t\t\tkey={type.name}\n\t\t\t\t\t\tentity={entity}\n\t\t\t\t\t\ttype={type}\n\t\t\t\t\t\tactive={tags.some((t) => t.name === type.name)}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nfunction ComponentEditor({ entity, type }: { entity: EntityId; type: ComponentType }) {\n\tconst engine = useLayoutEngine();\n\tconst value = useComponent(entity, type);\n\tconst [collapsed, setCollapsed] = useState(false);\n\n\tif (!value) return null;\n\n\tconst isWidgetData = type.name === 'WidgetData';\n\n\treturn (\n\t\t<div className=\"ic-ecs-component\">\n\t\t\t<div className=\"ic-ecs-component-head\">\n\t\t\t\t<button type=\"button\" className=\"ic-ecs-toggle\" onClick={() => setCollapsed((c) => !c)}>\n\t\t\t\t\t{collapsed ? '▶' : '▼'} {type.name}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"ic-ecs-btn ic-ecs-btn-danger ic-ecs-btn-sm\"\n\t\t\t\t\tonClick={() => engine.removeComponent(entity, type)}\n\t\t\t\t\ttitle=\"Remove component\"\n\t\t\t\t>\n\t\t\t\t\t×\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t{!collapsed && (\n\t\t\t\t<div className=\"ic-ecs-fields\">\n\t\t\t\t\t{isWidgetData ? (\n\t\t\t\t\t\t<WidgetDataEditor entity={entity} value={value as { data: Record<string, unknown> }} />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<GenericFieldsEditor entity={entity} type={type} value={value} />\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction GenericFieldsEditor<T>({\n\tentity,\n\ttype,\n\tvalue,\n}: {\n\tentity: EntityId;\n\ttype: ComponentType<T>;\n\tvalue: T;\n}) {\n\tconst engine = useLayoutEngine();\n\tconst defaults = type.defaults as Record<string, unknown>;\n\tconst val = value as Record<string, unknown>;\n\tconst keys = Object.keys(defaults);\n\n\treturn (\n\t\t<>\n\t\t\t{keys.map((key) => (\n\t\t\t\t<FieldRow\n\t\t\t\t\tkey={key}\n\t\t\t\t\tlabel={key}\n\t\t\t\t\tvalue={val[key]}\n\t\t\t\t\tonChange={(next) => {\n\t\t\t\t\t\tengine.set(entity, type, { [key]: next } as Partial<T>);\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</>\n\t);\n}\n\nfunction WidgetDataEditor({\n\tentity,\n\tvalue,\n}: {\n\tentity: EntityId;\n\tvalue: { data: Record<string, unknown> };\n}) {\n\tconst engine = useLayoutEngine();\n\tconst data = value.data ?? {};\n\tconst keys = Object.keys(data);\n\n\tif (keys.length === 0) {\n\t\treturn <div className=\"ic-ecs-empty\">(no fields)</div>;\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t{keys.map((key) => (\n\t\t\t\t<FieldRow\n\t\t\t\t\tkey={key}\n\t\t\t\t\tlabel={key}\n\t\t\t\t\tvalue={data[key]}\n\t\t\t\t\tonChange={(next) => {\n\t\t\t\t\t\tengine.set(entity, WidgetData, { data: { ...data, [key]: next } });\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</>\n\t);\n}\n\nfunction FieldRow({\n\tlabel,\n\tvalue,\n\tonChange,\n}: {\n\tlabel: string;\n\tvalue: unknown;\n\tonChange: (next: unknown) => void;\n}) {\n\treturn (\n\t\t<div className=\"ic-ecs-field\">\n\t\t\t<span className=\"ic-ecs-field-label\">{label}</span>\n\t\t\t<FieldInput value={value} onChange={onChange} />\n\t\t</div>\n\t);\n}\n\nfunction FieldInput({ value, onChange }: { value: unknown; onChange: (next: unknown) => void }) {\n\tif (typeof value === 'number') {\n\t\treturn (\n\t\t\t<input\n\t\t\t\ttype=\"number\"\n\t\t\t\tclassName=\"ic-ecs-input\"\n\t\t\t\tvalue={value}\n\t\t\t\tonChange={(e) => {\n\t\t\t\t\tconst n = Number.parseFloat(e.target.value);\n\t\t\t\t\tif (!Number.isNaN(n)) onChange(n);\n\t\t\t\t}}\n\t\t\t/>\n\t\t);\n\t}\n\tif (typeof value === 'boolean') {\n\t\treturn (\n\t\t\t<input\n\t\t\t\ttype=\"checkbox\"\n\t\t\t\tclassName=\"ic-ecs-checkbox\"\n\t\t\t\tchecked={value}\n\t\t\t\tonChange={(e) => onChange(e.target.checked)}\n\t\t\t/>\n\t\t);\n\t}\n\tif (typeof value === 'string') {\n\t\treturn (\n\t\t\t<input\n\t\t\t\ttype=\"text\"\n\t\t\t\tclassName=\"ic-ecs-input\"\n\t\t\t\tvalue={value}\n\t\t\t\tonChange={(e) => onChange(e.target.value)}\n\t\t\t/>\n\t\t);\n\t}\n\treturn <JsonInput value={value} onChange={onChange} />;\n}\n\nfunction JsonInput({ value, onChange }: { value: unknown; onChange: (next: unknown) => void }) {\n\tconst serialized = JSON.stringify(value);\n\tconst [text, setText] = useState(serialized);\n\tconst [error, setError] = useState(false);\n\n\tuseEffect(() => {\n\t\tsetText(JSON.stringify(value));\n\t\tsetError(false);\n\t}, [value]);\n\n\tconst commit = () => {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(text);\n\t\t\tsetError(false);\n\t\t\tonChange(parsed);\n\t\t} catch {\n\t\t\tsetError(true);\n\t\t}\n\t};\n\n\treturn (\n\t\t<input\n\t\t\ttype=\"text\"\n\t\t\tclassName={`ic-ecs-input ic-ecs-input-json ${error ? 'is-error' : ''}`}\n\t\t\tvalue={text}\n\t\t\tonChange={(e) => setText(e.target.value)}\n\t\t\tonBlur={commit}\n\t\t\tonKeyDown={(e) => {\n\t\t\t\tif (e.key === 'Enter') commit();\n\t\t\t}}\n\t\t/>\n\t);\n}\n\nfunction TagPill({ entity, type, active }: { entity: EntityId; type: TagType; active: boolean }) {\n\tconst engine = useLayoutEngine();\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclassName={`ic-ecs-tag ${active ? 'is-active' : ''}`}\n\t\t\tonClick={() => {\n\t\t\t\tif (active) engine.removeTag(entity, type);\n\t\t\t\telse engine.addTag(entity, type);\n\t\t\t}}\n\t\t>\n\t\t\t{type.name}\n\t\t</button>\n\t);\n}\n\n// Scoped styles, inlined once on mount. Dark-mode-aware via prefers-color-scheme\n// and a parent `.dark` class (matches the playground's toggle convention).\nconst STYLE_ID = 'ic-ecs-devtools-style';\nconst CSS = `\n.ic-ecs-root {\n\t--ic-ecs-bg: rgba(255, 255, 255, 0.96);\n\t--ic-ecs-bg-elev: #f7f7f7;\n\t--ic-ecs-fg: #1a1a1a;\n\t--ic-ecs-fg-muted: #6b7280;\n\t--ic-ecs-fg-faint: #9ca3af;\n\t--ic-ecs-border: #e5e7eb;\n\t--ic-ecs-accent: #0d99ff;\n\t--ic-ecs-accent-fg: #ffffff;\n\t--ic-ecs-danger: #dc2626;\n\t--ic-ecs-focus-bg: rgba(13, 153, 255, 0.12);\n\tposition: absolute;\n\ttop: 4rem;\n\tright: 1rem;\n\tz-index: 50;\n\twidth: 360px;\n\tmax-height: calc(100vh - 6rem);\n\toverflow-y: auto;\n\tbackground: var(--ic-ecs-bg);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 8px;\n\tbox-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);\n\tbackdrop-filter: blur(6px);\n\tfont-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n\tfont-size: 11px;\n\tline-height: 1.4;\n}\n.dark .ic-ecs-root,\n:root[data-theme=\"dark\"] .ic-ecs-root {\n\t--ic-ecs-bg: rgba(23, 23, 23, 0.96);\n\t--ic-ecs-bg-elev: #1f1f1f;\n\t--ic-ecs-fg: #e5e5e5;\n\t--ic-ecs-fg-muted: #a1a1aa;\n\t--ic-ecs-fg-faint: #525252;\n\t--ic-ecs-border: #2a2a2a;\n\t--ic-ecs-focus-bg: rgba(13, 153, 255, 0.18);\n}\n.ic-ecs-header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--ic-ecs-border);\n}\n.ic-ecs-title {\n\tfont-weight: 600;\n\tfont-size: 12px;\n}\n.ic-ecs-close {\n\tbackground: transparent;\n\tborder: 0;\n\tcolor: var(--ic-ecs-fg-muted);\n\tcursor: pointer;\n\tfont-size: 16px;\n\tline-height: 1;\n\tpadding: 0 4px;\n}\n.ic-ecs-close:hover { color: var(--ic-ecs-fg); }\n.ic-ecs-section {\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--ic-ecs-border);\n}\n.ic-ecs-section:last-child { border-bottom: 0; }\n.ic-ecs-label {\n\tfont-size: 10px;\n\tfont-weight: 600;\n\tletter-spacing: 0.05em;\n\ttext-transform: uppercase;\n\tcolor: var(--ic-ecs-fg-muted);\n}\n.ic-ecs-label-row {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tmargin-bottom: 4px;\n}\n.ic-ecs-sub-label {\n\tfont-size: 9px;\n\tfont-weight: 600;\n\tletter-spacing: 0.05em;\n\ttext-transform: uppercase;\n\tcolor: var(--ic-ecs-fg-faint);\n\tmargin: 8px 0 4px;\n}\n.ic-ecs-row {\n\tdisplay: flex;\n\tgap: 6px;\n\talign-items: center;\n\tmargin-top: 4px;\n}\n.ic-ecs-select {\n\tflex: 1 1 auto;\n\tmin-width: 0;\n\tbackground: var(--ic-ecs-bg-elev);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tpadding: 4px 6px;\n\tfont: inherit;\n}\n.ic-ecs-input {\n\tflex: 1 1 auto;\n\tmin-width: 0;\n\tbackground: var(--ic-ecs-bg-elev);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tpadding: 2px 6px;\n\tfont: inherit;\n}\n.ic-ecs-input:focus { outline: 1px solid var(--ic-ecs-accent); outline-offset: -1px; }\n.ic-ecs-input-json.is-error { border-color: var(--ic-ecs-danger); }\n.ic-ecs-checkbox {\n\taccent-color: var(--ic-ecs-accent);\n}\n.ic-ecs-btn {\n\tbackground: var(--ic-ecs-bg-elev);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tpadding: 3px 8px;\n\tfont: inherit;\n\tcursor: pointer;\n\twhite-space: nowrap;\n}\n.ic-ecs-btn:hover { background: var(--ic-ecs-border); }\n.ic-ecs-btn:disabled { opacity: 0.5; cursor: not-allowed; }\n.ic-ecs-btn-primary {\n\tbackground: var(--ic-ecs-accent);\n\tcolor: var(--ic-ecs-accent-fg);\n\tborder-color: var(--ic-ecs-accent);\n}\n.ic-ecs-btn-primary:hover { filter: brightness(1.08); background: var(--ic-ecs-accent); }\n.ic-ecs-btn-danger { color: var(--ic-ecs-danger); }\n.ic-ecs-btn-sm { padding: 0 6px; font-size: 11px; }\n.ic-ecs-check {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n\tfont-size: 10px;\n\tcolor: var(--ic-ecs-fg-muted);\n\tcursor: pointer;\n}\n.ic-ecs-list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tmax-height: 200px;\n\toverflow-y: auto;\n\tmargin-top: 4px;\n}\n.ic-ecs-empty {\n\tcolor: var(--ic-ecs-fg-faint);\n\tfont-style: italic;\n\tpadding: 4px 0;\n}\n.ic-ecs-entity-row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\tpadding: 2px 4px;\n\tborder-radius: 4px;\n}\n.ic-ecs-entity-row.is-focused { background: var(--ic-ecs-focus-bg); }\n.ic-ecs-entity-btn {\n\tflex: 1 1 auto;\n\tdisplay: flex;\n\tgap: 8px;\n\talign-items: center;\n\tbackground: transparent;\n\tborder: 0;\n\tcolor: inherit;\n\tcursor: pointer;\n\ttext-align: left;\n\tpadding: 2px 0;\n\tfont: inherit;\n\tmin-width: 0;\n}\n.ic-ecs-entity-id {\n\tcolor: var(--ic-ecs-fg-muted);\n\tfont-variant-numeric: tabular-nums;\n}\n.ic-ecs-entity-label {\n\tcolor: var(--ic-ecs-fg);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n.ic-ecs-inspect-head {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tmargin-bottom: 4px;\n}\n.ic-ecs-components {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n.ic-ecs-component {\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tbackground: var(--ic-ecs-bg-elev);\n}\n.ic-ecs-component-head {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 2px 6px;\n}\n.ic-ecs-toggle {\n\tbackground: transparent;\n\tborder: 0;\n\tcolor: inherit;\n\tcursor: pointer;\n\tfont: inherit;\n\tfont-weight: 600;\n\tpadding: 2px 0;\n}\n.ic-ecs-fields {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 3px;\n\tpadding: 4px 6px 6px;\n\tborder-top: 1px dashed var(--ic-ecs-border);\n}\n.ic-ecs-field {\n\tdisplay: grid;\n\tgrid-template-columns: 70px 1fr;\n\talign-items: center;\n\tgap: 6px;\n}\n.ic-ecs-field-label {\n\tcolor: var(--ic-ecs-fg-muted);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n.ic-ecs-tags {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 4px;\n}\n.ic-ecs-tag {\n\tbackground: transparent;\n\tcolor: var(--ic-ecs-fg-faint);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 999px;\n\tpadding: 2px 8px;\n\tfont: inherit;\n\tcursor: pointer;\n}\n.ic-ecs-tag:hover { color: var(--ic-ecs-fg); }\n.ic-ecs-tag.is-active {\n\tbackground: var(--ic-ecs-accent);\n\tcolor: var(--ic-ecs-accent-fg);\n\tborder-color: var(--ic-ecs-accent);\n}\n`;\n\nfunction StyleTag() {\n\tuseEffect(() => {\n\t\tif (typeof document === 'undefined') return;\n\t\tif (document.getElementById(STYLE_ID)) return;\n\t\tconst el = document.createElement('style');\n\t\tel.id = STYLE_ID;\n\t\tel.textContent = CSS;\n\t\tdocument.head.appendChild(el);\n\t}, []);\n\treturn null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"devtools.mjs","names":[],"sources":["../src/devtools/EcsDevtools.tsx"],"sourcesContent":["import type { ComponentType, EntityId, TagType } from '@jamesyong42/reactive-ecs';\nimport { useEffect, useMemo, useState } from 'react';\nimport { Selected, Widget, WidgetData } from '../ecs/components.js';\nimport type { LayoutEngine } from '../ecs/engine/index.js';\nimport { EngineProvider, useLayoutEngine } from '../react/context/engine-context.js';\nimport {\n\tuseAllEntities,\n\tuseComponent,\n\tuseEntityComponents,\n\tuseEntityTags,\n\tuseRegisteredComponents,\n\tuseRegisteredTags,\n\tuseTaggedEntities,\n} from '../react/hooks/ecs.js';\n\ninterface EcsDevtoolsProps {\n\t/**\n\t * Engine to inspect. If omitted, reads from the nearest InfiniteCanvas context —\n\t * supply this prop when the panel is rendered outside the `<InfiniteCanvas>` subtree.\n\t */\n\tengine?: LayoutEngine;\n\tonClose?: () => void;\n}\n\n/**\n * Live ECS editor: spawn widgets, browse entities, edit components, toggle tags.\n * Ship in a dev mode or behind a feature flag — not intended for production users.\n */\nexport function EcsDevtools({ engine, onClose }: EcsDevtoolsProps) {\n\tif (engine) {\n\t\treturn (\n\t\t\t<EngineProvider value={engine}>\n\t\t\t\t<EcsDevtoolsInner onClose={onClose} />\n\t\t\t</EngineProvider>\n\t\t);\n\t}\n\treturn <EcsDevtoolsInner onClose={onClose} />;\n}\n\nfunction EcsDevtoolsInner({ onClose }: { onClose?: () => void }) {\n\tconst engine = useLayoutEngine();\n\tconst allEntities = useAllEntities();\n\tconst selectedIds = useTaggedEntities(Selected);\n\tconst widgets = useMemo(() => engine.getWidgets(), [engine]);\n\n\tconst [showAll, setShowAll] = useState(false);\n\tconst [spawnType, setSpawnType] = useState(widgets[0]?.type ?? '');\n\tconst [manualFocusId, setManualFocusId] = useState<EntityId | null>(null);\n\n\tconst focusId = selectedIds[0] ?? manualFocusId;\n\n\tconst entityList = useMemo(() => {\n\t\tif (showAll) return allEntities;\n\t\treturn allEntities.filter((id) => engine.has(id, Widget));\n\t}, [engine, allEntities, showAll]);\n\n\tconst handleSpawn = () => {\n\t\tif (!spawnType) return;\n\t\tconst id = engine.spawnAtCameraCenter(spawnType);\n\t\tengine.markDirty();\n\t\tsetManualFocusId(id);\n\t};\n\n\treturn (\n\t\t<div className=\"ic-ecs-root\">\n\t\t\t<StyleTag />\n\n\t\t\t<div className=\"ic-ecs-header\">\n\t\t\t\t<span className=\"ic-ecs-title\">ECS Editor</span>\n\t\t\t\t{onClose && (\n\t\t\t\t\t<button type=\"button\" className=\"ic-ecs-close\" onClick={onClose} title=\"Close\">\n\t\t\t\t\t\t×\n\t\t\t\t\t</button>\n\t\t\t\t)}\n\t\t\t</div>\n\n\t\t\t<div className=\"ic-ecs-section\">\n\t\t\t\t<div className=\"ic-ecs-label\">Spawn widget</div>\n\t\t\t\t<div className=\"ic-ecs-row\">\n\t\t\t\t\t<select\n\t\t\t\t\t\tclassName=\"ic-ecs-select\"\n\t\t\t\t\t\tvalue={spawnType}\n\t\t\t\t\t\tonChange={(e) => setSpawnType(e.target.value)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{widgets.map((w) => (\n\t\t\t\t\t\t\t<option key={w.type} value={w.type}>\n\t\t\t\t\t\t\t\t{w.type}\n\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</select>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"ic-ecs-btn ic-ecs-btn-primary\"\n\t\t\t\t\t\tonClick={handleSpawn}\n\t\t\t\t\t\tdisabled={!spawnType}\n\t\t\t\t\t>\n\t\t\t\t\t\t+ Spawn\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div className=\"ic-ecs-section\">\n\t\t\t\t<div className=\"ic-ecs-label-row\">\n\t\t\t\t\t<span className=\"ic-ecs-label\">\n\t\t\t\t\t\tEntities ({entityList.length}\n\t\t\t\t\t\t{showAll ? '' : ' widgets'})\n\t\t\t\t\t</span>\n\t\t\t\t\t<label className=\"ic-ecs-check\">\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\tchecked={showAll}\n\t\t\t\t\t\t\tonChange={(e) => setShowAll(e.target.checked)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\tshow all\n\t\t\t\t\t</label>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"ic-ecs-list\">\n\t\t\t\t\t{entityList.map((id) => (\n\t\t\t\t\t\t<EntityRow\n\t\t\t\t\t\t\tkey={id}\n\t\t\t\t\t\t\tentity={id}\n\t\t\t\t\t\t\tfocused={id === focusId}\n\t\t\t\t\t\t\tonClick={() => setManualFocusId(id)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t\t{entityList.length === 0 && <div className=\"ic-ecs-empty\">no entities</div>}\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t{focusId !== null && focusId !== undefined && engine.world.entityExists(focusId) && (\n\t\t\t\t<EntityInspector entity={focusId} />\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction EntityRow({\n\tentity,\n\tfocused,\n\tonClick,\n}: {\n\tentity: EntityId;\n\tfocused: boolean;\n\tonClick: () => void;\n}) {\n\tconst engine = useLayoutEngine();\n\tconst widget = useComponent(entity, Widget);\n\tconst label = widget?.type ?? 'entity';\n\n\treturn (\n\t\t<div className={`ic-ecs-entity-row ${focused ? 'is-focused' : ''}`}>\n\t\t\t<button type=\"button\" className=\"ic-ecs-entity-btn\" onClick={onClick}>\n\t\t\t\t<span className=\"ic-ecs-entity-id\">e{entity}</span>\n\t\t\t\t<span className=\"ic-ecs-entity-label\">{label}</span>\n\t\t\t</button>\n\t\t\t<button\n\t\t\t\ttype=\"button\"\n\t\t\t\tclassName=\"ic-ecs-btn ic-ecs-btn-danger ic-ecs-btn-sm\"\n\t\t\t\tonClick={() => {\n\t\t\t\t\tengine.destroyEntity(entity);\n\t\t\t\t\tengine.markDirty();\n\t\t\t\t}}\n\t\t\t\ttitle=\"Destroy entity\"\n\t\t\t>\n\t\t\t\t×\n\t\t\t</button>\n\t\t</div>\n\t);\n}\n\nfunction EntityInspector({ entity }: { entity: EntityId }) {\n\tconst engine = useLayoutEngine();\n\tconst components = useEntityComponents(entity);\n\tconst tags = useEntityTags(entity);\n\tconst registeredComponents = useRegisteredComponents();\n\tconst registeredTags = useRegisteredTags();\n\tconst widget = useComponent(entity, Widget);\n\n\tconst absentComponents = useMemo(() => {\n\t\tconst present = new Set(components.map((c) => c.name));\n\t\treturn registeredComponents.filter((c) => !present.has(c.name));\n\t}, [components, registeredComponents]);\n\n\tconst [componentToAdd, setComponentToAdd] = useState('');\n\tuseEffect(() => {\n\t\tsetComponentToAdd(absentComponents[0]?.name ?? '');\n\t}, [absentComponents]);\n\n\tconst handleAddComponent = () => {\n\t\tconst type = absentComponents.find((c) => c.name === componentToAdd);\n\t\tif (!type) return;\n\t\tengine.addComponent(entity, type);\n\t};\n\n\treturn (\n\t\t<div className=\"ic-ecs-section\">\n\t\t\t<div className=\"ic-ecs-inspect-head\">\n\t\t\t\t<span className=\"ic-ecs-label\">\n\t\t\t\t\tEntity <span className=\"ic-ecs-entity-id\">e{entity}</span>\n\t\t\t\t\t{widget?.type && <span className=\"ic-ecs-entity-label\"> · {widget.type}</span>}\n\t\t\t\t</span>\n\t\t\t</div>\n\n\t\t\t<div className=\"ic-ecs-sub-label\">Components</div>\n\t\t\t<div className=\"ic-ecs-components\">\n\t\t\t\t{components.map((type) => (\n\t\t\t\t\t<ComponentEditor key={type.name} entity={entity} type={type} />\n\t\t\t\t))}\n\t\t\t</div>\n\n\t\t\t{absentComponents.length > 0 && (\n\t\t\t\t<div className=\"ic-ecs-row\" style={{ marginTop: 6 }}>\n\t\t\t\t\t<select\n\t\t\t\t\t\tclassName=\"ic-ecs-select\"\n\t\t\t\t\t\tvalue={componentToAdd}\n\t\t\t\t\t\tonChange={(e) => setComponentToAdd(e.target.value)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{absentComponents.map((c) => (\n\t\t\t\t\t\t\t<option key={c.name} value={c.name}>\n\t\t\t\t\t\t\t\t{c.name}\n\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</select>\n\t\t\t\t\t<button type=\"button\" className=\"ic-ecs-btn\" onClick={handleAddComponent}>\n\t\t\t\t\t\t+ Add component\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t<div className=\"ic-ecs-sub-label\">Tags</div>\n\t\t\t<div className=\"ic-ecs-tags\">\n\t\t\t\t{registeredTags.map((type) => (\n\t\t\t\t\t<TagPill\n\t\t\t\t\t\tkey={type.name}\n\t\t\t\t\t\tentity={entity}\n\t\t\t\t\t\ttype={type}\n\t\t\t\t\t\tactive={tags.some((t) => t.name === type.name)}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\nfunction ComponentEditor({ entity, type }: { entity: EntityId; type: ComponentType }) {\n\tconst engine = useLayoutEngine();\n\tconst value = useComponent(entity, type);\n\tconst [collapsed, setCollapsed] = useState(false);\n\n\tif (!value) return null;\n\n\tconst isWidgetData = type.name === 'WidgetData';\n\n\treturn (\n\t\t<div className=\"ic-ecs-component\">\n\t\t\t<div className=\"ic-ecs-component-head\">\n\t\t\t\t<button type=\"button\" className=\"ic-ecs-toggle\" onClick={() => setCollapsed((c) => !c)}>\n\t\t\t\t\t{collapsed ? '▶' : '▼'} {type.name}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"ic-ecs-btn ic-ecs-btn-danger ic-ecs-btn-sm\"\n\t\t\t\t\tonClick={() => engine.removeComponent(entity, type)}\n\t\t\t\t\ttitle=\"Remove component\"\n\t\t\t\t>\n\t\t\t\t\t×\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t{!collapsed && (\n\t\t\t\t<div className=\"ic-ecs-fields\">\n\t\t\t\t\t{isWidgetData ? (\n\t\t\t\t\t\t<WidgetDataEditor entity={entity} value={value as { data: Record<string, unknown> }} />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<GenericFieldsEditor entity={entity} type={type} value={value} />\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\nfunction GenericFieldsEditor<T>({\n\tentity,\n\ttype,\n\tvalue,\n}: {\n\tentity: EntityId;\n\ttype: ComponentType<T>;\n\tvalue: T;\n}) {\n\tconst engine = useLayoutEngine();\n\tconst defaults = type.defaults as Record<string, unknown>;\n\tconst val = value as Record<string, unknown>;\n\tconst keys = Object.keys(defaults);\n\n\treturn (\n\t\t<>\n\t\t\t{keys.map((key) => (\n\t\t\t\t<FieldRow\n\t\t\t\t\tkey={key}\n\t\t\t\t\tlabel={key}\n\t\t\t\t\tvalue={val[key]}\n\t\t\t\t\tonChange={(next) => {\n\t\t\t\t\t\tengine.set(entity, type, { [key]: next } as Partial<T>);\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</>\n\t);\n}\n\nfunction WidgetDataEditor({\n\tentity,\n\tvalue,\n}: {\n\tentity: EntityId;\n\tvalue: { data: Record<string, unknown> };\n}) {\n\tconst engine = useLayoutEngine();\n\tconst data = value.data ?? {};\n\tconst keys = Object.keys(data);\n\n\tif (keys.length === 0) {\n\t\treturn <div className=\"ic-ecs-empty\">(no fields)</div>;\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t{keys.map((key) => (\n\t\t\t\t<FieldRow\n\t\t\t\t\tkey={key}\n\t\t\t\t\tlabel={key}\n\t\t\t\t\tvalue={data[key]}\n\t\t\t\t\tonChange={(next) => {\n\t\t\t\t\t\tengine.set(entity, WidgetData, { data: { ...data, [key]: next } });\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</>\n\t);\n}\n\nfunction FieldRow({\n\tlabel,\n\tvalue,\n\tonChange,\n}: {\n\tlabel: string;\n\tvalue: unknown;\n\tonChange: (next: unknown) => void;\n}) {\n\treturn (\n\t\t<div className=\"ic-ecs-field\">\n\t\t\t<span className=\"ic-ecs-field-label\">{label}</span>\n\t\t\t<FieldInput value={value} onChange={onChange} />\n\t\t</div>\n\t);\n}\n\nfunction FieldInput({ value, onChange }: { value: unknown; onChange: (next: unknown) => void }) {\n\tif (typeof value === 'number') {\n\t\treturn (\n\t\t\t<input\n\t\t\t\ttype=\"number\"\n\t\t\t\tclassName=\"ic-ecs-input\"\n\t\t\t\tvalue={value}\n\t\t\t\tonChange={(e) => {\n\t\t\t\t\tconst n = Number.parseFloat(e.target.value);\n\t\t\t\t\tif (!Number.isNaN(n)) onChange(n);\n\t\t\t\t}}\n\t\t\t/>\n\t\t);\n\t}\n\tif (typeof value === 'boolean') {\n\t\treturn (\n\t\t\t<input\n\t\t\t\ttype=\"checkbox\"\n\t\t\t\tclassName=\"ic-ecs-checkbox\"\n\t\t\t\tchecked={value}\n\t\t\t\tonChange={(e) => onChange(e.target.checked)}\n\t\t\t/>\n\t\t);\n\t}\n\tif (typeof value === 'string') {\n\t\treturn (\n\t\t\t<input\n\t\t\t\ttype=\"text\"\n\t\t\t\tclassName=\"ic-ecs-input\"\n\t\t\t\tvalue={value}\n\t\t\t\tonChange={(e) => onChange(e.target.value)}\n\t\t\t/>\n\t\t);\n\t}\n\treturn <JsonInput value={value} onChange={onChange} />;\n}\n\nfunction JsonInput({ value, onChange }: { value: unknown; onChange: (next: unknown) => void }) {\n\tconst serialized = JSON.stringify(value);\n\tconst [text, setText] = useState(serialized);\n\tconst [error, setError] = useState(false);\n\n\tuseEffect(() => {\n\t\tsetText(JSON.stringify(value));\n\t\tsetError(false);\n\t}, [value]);\n\n\tconst commit = () => {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(text);\n\t\t\tsetError(false);\n\t\t\tonChange(parsed);\n\t\t} catch {\n\t\t\tsetError(true);\n\t\t}\n\t};\n\n\treturn (\n\t\t<input\n\t\t\ttype=\"text\"\n\t\t\tclassName={`ic-ecs-input ic-ecs-input-json ${error ? 'is-error' : ''}`}\n\t\t\tvalue={text}\n\t\t\tonChange={(e) => setText(e.target.value)}\n\t\t\tonBlur={commit}\n\t\t\tonKeyDown={(e) => {\n\t\t\t\tif (e.key === 'Enter') commit();\n\t\t\t}}\n\t\t/>\n\t);\n}\n\nfunction TagPill({ entity, type, active }: { entity: EntityId; type: TagType; active: boolean }) {\n\tconst engine = useLayoutEngine();\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclassName={`ic-ecs-tag ${active ? 'is-active' : ''}`}\n\t\t\tonClick={() => {\n\t\t\t\tif (active) engine.removeTag(entity, type);\n\t\t\t\telse engine.addTag(entity, type);\n\t\t\t}}\n\t\t>\n\t\t\t{type.name}\n\t\t</button>\n\t);\n}\n\n// Scoped styles, inlined once on mount. Dark-mode-aware via prefers-color-scheme\n// and a parent `.dark` class (matches the playground's toggle convention).\nconst STYLE_ID = 'ic-ecs-devtools-style';\nconst CSS = `\n.ic-ecs-root {\n\t--ic-ecs-bg: rgba(255, 255, 255, 0.96);\n\t--ic-ecs-bg-elev: #f7f7f7;\n\t--ic-ecs-fg: #1a1a1a;\n\t--ic-ecs-fg-muted: #6b7280;\n\t--ic-ecs-fg-faint: #9ca3af;\n\t--ic-ecs-border: #e5e7eb;\n\t--ic-ecs-accent: #0d99ff;\n\t--ic-ecs-accent-fg: #ffffff;\n\t--ic-ecs-danger: #dc2626;\n\t--ic-ecs-focus-bg: rgba(13, 153, 255, 0.12);\n\tposition: absolute;\n\ttop: 4rem;\n\tright: 1rem;\n\tz-index: 50;\n\twidth: 360px;\n\tmax-height: calc(100vh - 6rem);\n\toverflow-y: auto;\n\tbackground: var(--ic-ecs-bg);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 8px;\n\tbox-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);\n\tbackdrop-filter: blur(6px);\n\tfont-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n\tfont-size: 11px;\n\tline-height: 1.4;\n}\n.dark .ic-ecs-root,\n:root[data-theme=\"dark\"] .ic-ecs-root {\n\t--ic-ecs-bg: rgba(23, 23, 23, 0.96);\n\t--ic-ecs-bg-elev: #1f1f1f;\n\t--ic-ecs-fg: #e5e5e5;\n\t--ic-ecs-fg-muted: #a1a1aa;\n\t--ic-ecs-fg-faint: #525252;\n\t--ic-ecs-border: #2a2a2a;\n\t--ic-ecs-focus-bg: rgba(13, 153, 255, 0.18);\n}\n.ic-ecs-header {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--ic-ecs-border);\n}\n.ic-ecs-title {\n\tfont-weight: 600;\n\tfont-size: 12px;\n}\n.ic-ecs-close {\n\tbackground: transparent;\n\tborder: 0;\n\tcolor: var(--ic-ecs-fg-muted);\n\tcursor: pointer;\n\tfont-size: 16px;\n\tline-height: 1;\n\tpadding: 0 4px;\n}\n.ic-ecs-close:hover { color: var(--ic-ecs-fg); }\n.ic-ecs-section {\n\tpadding: 8px 12px;\n\tborder-bottom: 1px solid var(--ic-ecs-border);\n}\n.ic-ecs-section:last-child { border-bottom: 0; }\n.ic-ecs-label {\n\tfont-size: 10px;\n\tfont-weight: 600;\n\tletter-spacing: 0.05em;\n\ttext-transform: uppercase;\n\tcolor: var(--ic-ecs-fg-muted);\n}\n.ic-ecs-label-row {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tmargin-bottom: 4px;\n}\n.ic-ecs-sub-label {\n\tfont-size: 9px;\n\tfont-weight: 600;\n\tletter-spacing: 0.05em;\n\ttext-transform: uppercase;\n\tcolor: var(--ic-ecs-fg-faint);\n\tmargin: 8px 0 4px;\n}\n.ic-ecs-row {\n\tdisplay: flex;\n\tgap: 6px;\n\talign-items: center;\n\tmargin-top: 4px;\n}\n.ic-ecs-select {\n\tflex: 1 1 auto;\n\tmin-width: 0;\n\tbackground: var(--ic-ecs-bg-elev);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tpadding: 4px 6px;\n\tfont: inherit;\n}\n.ic-ecs-input {\n\tflex: 1 1 auto;\n\tmin-width: 0;\n\tbackground: var(--ic-ecs-bg-elev);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tpadding: 2px 6px;\n\tfont: inherit;\n}\n.ic-ecs-input:focus { outline: 1px solid var(--ic-ecs-accent); outline-offset: -1px; }\n.ic-ecs-input-json.is-error { border-color: var(--ic-ecs-danger); }\n.ic-ecs-checkbox {\n\taccent-color: var(--ic-ecs-accent);\n}\n.ic-ecs-btn {\n\tbackground: var(--ic-ecs-bg-elev);\n\tcolor: var(--ic-ecs-fg);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tpadding: 3px 8px;\n\tfont: inherit;\n\tcursor: pointer;\n\twhite-space: nowrap;\n}\n.ic-ecs-btn:hover { background: var(--ic-ecs-border); }\n.ic-ecs-btn:disabled { opacity: 0.5; cursor: not-allowed; }\n.ic-ecs-btn-primary {\n\tbackground: var(--ic-ecs-accent);\n\tcolor: var(--ic-ecs-accent-fg);\n\tborder-color: var(--ic-ecs-accent);\n}\n.ic-ecs-btn-primary:hover { filter: brightness(1.08); background: var(--ic-ecs-accent); }\n.ic-ecs-btn-danger { color: var(--ic-ecs-danger); }\n.ic-ecs-btn-sm { padding: 0 6px; font-size: 11px; }\n.ic-ecs-check {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n\tfont-size: 10px;\n\tcolor: var(--ic-ecs-fg-muted);\n\tcursor: pointer;\n}\n.ic-ecs-list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tmax-height: 200px;\n\toverflow-y: auto;\n\tmargin-top: 4px;\n}\n.ic-ecs-empty {\n\tcolor: var(--ic-ecs-fg-faint);\n\tfont-style: italic;\n\tpadding: 4px 0;\n}\n.ic-ecs-entity-row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 4px;\n\tpadding: 2px 4px;\n\tborder-radius: 4px;\n}\n.ic-ecs-entity-row.is-focused { background: var(--ic-ecs-focus-bg); }\n.ic-ecs-entity-btn {\n\tflex: 1 1 auto;\n\tdisplay: flex;\n\tgap: 8px;\n\talign-items: center;\n\tbackground: transparent;\n\tborder: 0;\n\tcolor: inherit;\n\tcursor: pointer;\n\ttext-align: left;\n\tpadding: 2px 0;\n\tfont: inherit;\n\tmin-width: 0;\n}\n.ic-ecs-entity-id {\n\tcolor: var(--ic-ecs-fg-muted);\n\tfont-variant-numeric: tabular-nums;\n}\n.ic-ecs-entity-label {\n\tcolor: var(--ic-ecs-fg);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n.ic-ecs-inspect-head {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tmargin-bottom: 4px;\n}\n.ic-ecs-components {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n.ic-ecs-component {\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 4px;\n\tbackground: var(--ic-ecs-bg-elev);\n}\n.ic-ecs-component-head {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 2px 6px;\n}\n.ic-ecs-toggle {\n\tbackground: transparent;\n\tborder: 0;\n\tcolor: inherit;\n\tcursor: pointer;\n\tfont: inherit;\n\tfont-weight: 600;\n\tpadding: 2px 0;\n}\n.ic-ecs-fields {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 3px;\n\tpadding: 4px 6px 6px;\n\tborder-top: 1px dashed var(--ic-ecs-border);\n}\n.ic-ecs-field {\n\tdisplay: grid;\n\tgrid-template-columns: 70px 1fr;\n\talign-items: center;\n\tgap: 6px;\n}\n.ic-ecs-field-label {\n\tcolor: var(--ic-ecs-fg-muted);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n.ic-ecs-tags {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 4px;\n}\n.ic-ecs-tag {\n\tbackground: transparent;\n\tcolor: var(--ic-ecs-fg-faint);\n\tborder: 1px solid var(--ic-ecs-border);\n\tborder-radius: 999px;\n\tpadding: 2px 8px;\n\tfont: inherit;\n\tcursor: pointer;\n}\n.ic-ecs-tag:hover { color: var(--ic-ecs-fg); }\n.ic-ecs-tag.is-active {\n\tbackground: var(--ic-ecs-accent);\n\tcolor: var(--ic-ecs-accent-fg);\n\tborder-color: var(--ic-ecs-accent);\n}\n`;\n\nfunction StyleTag() {\n\tuseEffect(() => {\n\t\tif (typeof document === 'undefined') return;\n\t\tif (document.getElementById(STYLE_ID)) return;\n\t\tconst el = document.createElement('style');\n\t\tel.id = STYLE_ID;\n\t\tel.textContent = CSS;\n\t\tdocument.head.appendChild(el);\n\t}, []);\n\treturn null;\n}\n"],"mappings":"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"}
|