@stuly/anode 0.1.0 → 0.1.2
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 +26 -9
- package/dist/core/context.d.ts +124 -1
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/context.js +118 -2
- package/dist/core/context.js.map +1 -1
- package/dist/core/elements.d.ts +67 -4
- package/dist/core/elements.d.ts.map +1 -1
- package/dist/core/elements.js +67 -4
- package/dist/core/elements.js.map +1 -1
- package/dist/core/history.d.ts +25 -0
- package/dist/core/history.d.ts.map +1 -1
- package/dist/core/history.js +12 -0
- package/dist/core/history.js.map +1 -1
- package/dist/core/layout.d.ts +28 -0
- package/dist/core/layout.d.ts.map +1 -1
- package/dist/core/layout.js +28 -0
- package/dist/core/layout.js.map +1 -1
- package/package.json +17 -3
package/dist/core/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","names":[],"sources":["../../src/core/context.ts"],"sourcesContent":["import { Entity, Link, LinkKind, Socket, SocketKind, Vec2, Group } from './elements';\nimport { QuadTree, Rect } from './layout';\nimport { HistoryManager, type HistoryAction, type Command } from './history';\n\nexport type EntityCallback<T> = (entity: Entity<T>) => void;\nexport type LinkCallback = (link: Link) => void;\nexport type SocketCallback = (socket: Socket) => void;\nexport type EntityMoveCallback<T> = (entity: Entity<T>, pos: Vec2) => void;\nexport type GroupCallback = (group: Group) => void;\nexport type SocketValueCallback = (socket: Socket, value: any) => void;\nexport type CallbackHandle = number;\n\nexport class Context<T = any> {\n private eid: number = 0;\n private lid: number = 0;\n private sid: number = 0;\n private gid: number = 0;\n\n private freeEids: number[] = [];\n private freeLids: number[] = [];\n private freeSids: number[] = [];\n private freeGids: number[] = [];\n\n private callbackIds: number = 0;\n private freeCallbackIds: number[] = [];\n\n private entityCreateCallbacks: Map<number, EntityCallback<T>> = new Map();\n private entityDropCallbacks: Map<number, EntityCallback<T>> = new Map();\n private entityMoveCallbacks: Map<number, EntityMoveCallback<T>> = new Map();\n private socketMoveCallbacks: Map<number, SocketCallback> = new Map();\n private socketValueCallbacks: Map<number, SocketValueCallback> = new Map();\n\n private linkCreateCallbacks: Map<number, LinkCallback> = new Map();\n private linkDropCallbacks: Map<number, LinkCallback> = new Map();\n private linkUpdateCallbacks: Map<number, LinkCallback> = new Map();\n\n private socketCreateCallbacks: Map<number, SocketCallback> = new Map();\n private socketDropCallbacks: Map<number, SocketCallback> = new Map();\n\n private groupCreateCallbacks: Map<number, GroupCallback> = new Map();\n private groupDropCallbacks: Map<number, GroupCallback> = new Map();\n private bulkChangeCallbacks: Map<number, () => void> = new Map();\n\n entities: Map<number, Entity<T>> = new Map();\n links: Map<number, Link> = new Map();\n sockets: Map<number, Socket> = new Map();\n groups: Map<number, Group> = new Map();\n\n quadTree: QuadTree<number> = new QuadTree(new Rect(-100000, -100000, 200000, 200000));\n history: HistoryManager = new HistoryManager();\n private isApplyingHistory: boolean = false;\n private currentBatch: HistoryAction[] | null = null;\n private currentUndoBatch: HistoryAction[] | null = null;\n private isBatchingQuadTree: boolean = false;\n\n private getNextEid() {\n return this.freeEids.pop() ?? this.eid++;\n }\n private getNextLid() {\n return this.freeLids.pop() ?? this.lid++;\n }\n private getNextSid() {\n return this.freeSids.pop() ?? this.sid++;\n }\n private getNextGid() {\n return this.freeGids.pop() ?? this.gid++;\n }\n private getNextCallbackHandle(): CallbackHandle {\n return this.freeCallbackIds.pop() ?? this.callbackIds++;\n }\n\n private setupEntity(entity: Entity<T>) {\n entity.onMove((pos) => {\n this.updateQuadTree();\n for (const cb of this.entityMoveCallbacks.values()) {\n try {\n cb(entity, this.getWorldPosition(entity.id));\n } catch (err) {\n console.error(err);\n }\n }\n });\n }\n\n notifyBulkChange() {\n for (const cb of this.bulkChangeCallbacks.values()) {\n try {\n cb();\n } catch (err) {\n console.error(err);\n }\n }\n }\n\n registerBulkChangeListener(cb: () => void): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.bulkChangeCallbacks.set(handle, cb);\n return handle;\n }\n\n setSocketValue(socketId: number, value: any) {\n const socket = this.sockets.get(socketId);\n if (!socket) return;\n\n socket.value = value;\n\n // Notify listeners for this specific socket\n for (const cb of this.socketValueCallbacks.values()) {\n cb(socket, value);\n }\n\n // If it's an OUTPUT, propagate to all linked INPUTs\n if (socket.kind === SocketKind.OUTPUT) {\n for (const link of this.links.values()) {\n if (link.from === socketId) {\n this.setSocketValue(link.to, value);\n }\n }\n }\n }\n\n registerSocketValueListener(cb: SocketValueCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.socketValueCallbacks.set(handle, cb);\n return handle;\n }\n\n record(\n doActions: HistoryAction | HistoryAction[],\n undoActions: HistoryAction | HistoryAction[],\n label?: string\n ) {\n if (this.isApplyingHistory) return;\n\n // If we are in a batch, we don't record individual actions to history\n // We let the batch() method handle the combined history entry\n if (this.currentBatch) {\n return;\n }\n\n const das = Array.isArray(doActions) ? doActions : [doActions];\n const uas = Array.isArray(undoActions) ? undoActions : [undoActions];\n\n this.history.push({\n do: das,\n undo: uas,\n label: label ?? 'Action',\n timestamp: Date.now()\n });\n }\n\n batch(fn: () => void, label?: string) {\n if (this.currentBatch) {\n fn();\n return;\n }\n\n const oldApplying = this.isApplyingHistory;\n const oldBatchingQT = this.isBatchingQuadTree;\n const beforeState = this.toJSON();\n\n try {\n this.isApplyingHistory = true;\n this.isBatchingQuadTree = true;\n fn();\n\n this.isBatchingQuadTree = oldBatchingQT;\n this.updateQuadTree();\n\n const afterState = this.toJSON();\n\n this.history.push({\n do: [{ type: 'FROM_JSON', data: afterState }],\n undo: [{ type: 'FROM_JSON', data: beforeState }],\n label: label ?? 'Batch Action',\n timestamp: Date.now()\n });\n } finally {\n this.isApplyingHistory = oldApplying;\n this.isBatchingQuadTree = oldBatchingQT;\n }\n }\n undo() {\n const cmd = this.history.undoStack.pop();\n if (!cmd) return;\n this.isApplyingHistory = true;\n this.isBatchingQuadTree = true;\n try {\n for (let i = cmd.undo.length - 1; i >= 0; i--) {\n this.applyAction(cmd.undo[i]!);\n }\n this.isBatchingQuadTree = false;\n this.updateQuadTree();\n this.notifyBulkChange();\n this.history.redoStack.push(cmd);\n } finally {\n this.isApplyingHistory = false;\n this.isBatchingQuadTree = false;\n }\n }\n\n redo() {\n const cmd = this.history.redoStack.pop();\n if (!cmd) return;\n this.isApplyingHistory = true;\n this.isBatchingQuadTree = true;\n try {\n for (const action of cmd.do) {\n this.applyAction(action);\n }\n this.isBatchingQuadTree = false;\n this.updateQuadTree();\n this.notifyBulkChange();\n this.history.undoStack.push(cmd);\n } finally {\n this.isApplyingHistory = false;\n this.isBatchingQuadTree = false;\n }\n }\n\n private applyAction(action: HistoryAction) {\n switch (action.type) {\n case 'FROM_JSON': {\n this.fromJSON(action.data);\n break;\n }\n case 'MOVE_ENTITY': {\n const entity = this.entities.get(action.id);\n if (entity) {\n entity.position.set(action.to.x, action.to.y);\n for (const cb of this.entityMoveCallbacks.values())\n cb(entity, this.getWorldPosition(entity.id));\n this.updateQuadTree();\n }\n break;\n }\n case 'MOVE_GROUP': {\n const group = this.groups.get(action.id);\n if (group) {\n const dx = action.to.x - action.from.x;\n const dy = action.to.y - action.from.y;\n const oldApplying = this.isApplyingHistory;\n this.isApplyingHistory = true;\n try {\n this.moveGroup(group, dx, dy);\n } finally {\n this.isApplyingHistory = oldApplying;\n }\n }\n break;\n }\n case 'CREATE_ENTITY': {\n const entity = new Entity(action.id, action.inner);\n entity.position.set(action.position.x, action.position.y);\n this.entities.set(entity.id, entity);\n this.eid = Math.max(this.eid, entity.id + 1);\n\n this.setupEntity(entity);\n\n if (action.parentId !== null) {\n this.addToGroup(action.parentId, entity.id);\n }\n for (const cb of this.entityCreateCallbacks.values()) cb(entity);\n this.updateQuadTree();\n break;\n }\n case 'DROP_ENTITY': {\n const entity = this.entities.get(action.id);\n if (entity) {\n const oldApplying = this.isApplyingHistory;\n this.isApplyingHistory = true;\n try {\n this.dropEntity(entity);\n } finally {\n this.isApplyingHistory = oldApplying;\n }\n }\n break;\n }\n case 'CREATE_LINK': {\n const from = this.sockets.get(action.from);\n const to = this.sockets.get(action.to);\n if (from && to) {\n const link = new Link(action.id, from.id, to.id, action.kind, action.inner);\n this.links.set(link.id, link);\n this.lid = Math.max(this.lid, link.id + 1);\n for (const cb of this.linkCreateCallbacks.values()) cb(link);\n }\n break;\n }\n case 'DROP_LINK': {\n const link = this.links.get(action.id);\n if (link) {\n const oldApplying = this.isApplyingHistory;\n this.isApplyingHistory = true;\n try {\n this.dropLink(link);\n } finally {\n this.isApplyingHistory = oldApplying;\n }\n }\n break;\n }\n case 'UPDATE_LINK': {\n const link = this.links.get(action.id);\n if (link) {\n link.from = action.from.new;\n link.to = action.to.new;\n if (action.waypoints) {\n link.waypoints = action.waypoints.new.map((p) => new Vec2(p.x, p.y));\n }\n for (const cb of this.linkUpdateCallbacks.values()) cb(link);\n }\n break;\n }\n case 'ADD_TO_GROUP': {\n this.addToGroup(action.groupId, action.entityId);\n break;\n }\n case 'REMOVE_FROM_GROUP': {\n this.removeFromGroup(action.groupId, action.entityId);\n break;\n }\n case 'CREATE_SOCKET': {\n const entity = this.entities.get(action.entityId);\n if (entity) {\n const socket = new Socket(action.id, entity.id, action.kind, action.name);\n socket.offset.set(action.offset.x, action.offset.y);\n this.sockets.set(socket.id, socket);\n entity.sockets.set(socket.id, socket);\n this.sid = Math.max(this.sid, socket.id + 1);\n for (const cb of this.socketCreateCallbacks.values()) cb(socket);\n }\n break;\n }\n case 'DROP_SOCKET': {\n const socket = this.sockets.get(action.id);\n if (socket) {\n const oldApplying = this.isApplyingHistory;\n this.isApplyingHistory = true;\n try {\n this.dropSocket(socket);\n } finally {\n this.isApplyingHistory = oldApplying;\n }\n }\n break;\n }\n }\n }\n\n registerEntityCreateListener(cb: EntityCallback<T>): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.entityCreateCallbacks.set(handle, cb);\n return handle;\n }\n\n registerEntityDropListener(cb: EntityCallback<T>): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.entityDropCallbacks.set(handle, cb);\n return handle;\n }\n\n registerEntityMoveListener(cb: EntityMoveCallback<T>): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.entityMoveCallbacks.set(handle, cb);\n return handle;\n }\n\n registerSocketMoveListener(cb: SocketCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.socketMoveCallbacks.set(handle, cb);\n return handle;\n }\n\n notifySocketMove(socket: Socket) {\n for (const cb of this.socketMoveCallbacks.values()) {\n try {\n cb(socket);\n } catch (err) {\n console.error(err);\n }\n }\n }\n\n registerLinkCreateListener(cb: LinkCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.linkCreateCallbacks.set(handle, cb);\n return handle;\n }\n\n registerLinkDropListener(cb: LinkCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.linkDropCallbacks.set(handle, cb);\n return handle;\n }\n\n registerLinkUpdateListener(cb: LinkCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.linkUpdateCallbacks.set(handle, cb);\n return handle;\n }\n\n registerSocketCreateListener(cb: SocketCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.socketCreateCallbacks.set(handle, cb);\n return handle;\n }\n\n registerSocketDropListener(cb: SocketCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.socketDropCallbacks.set(handle, cb);\n return handle;\n }\n\n registerGroupCreateListener(cb: GroupCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.groupCreateCallbacks.set(handle, cb);\n return handle;\n }\n\n registerGroupDropListener(cb: GroupCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.groupDropCallbacks.set(handle, cb);\n return handle;\n }\n\n unregisterListener(handle: CallbackHandle) {\n const deleted =\n this.linkCreateCallbacks.delete(handle) ||\n this.linkDropCallbacks.delete(handle) ||\n this.linkUpdateCallbacks.delete(handle) ||\n this.entityCreateCallbacks.delete(handle) ||\n this.entityDropCallbacks.delete(handle) ||\n this.entityMoveCallbacks.delete(handle) ||\n this.socketCreateCallbacks.delete(handle) ||\n this.socketDropCallbacks.delete(handle) ||\n this.socketMoveCallbacks.delete(handle) ||\n this.groupCreateCallbacks.delete(handle) ||\n this.groupDropCallbacks.delete(handle) ||\n this.bulkChangeCallbacks.delete(handle);\n\n if (deleted) {\n this.freeCallbackIds.push(handle);\n return true;\n }\n return false;\n }\n\n newGroup(name: string = '') {\n const group = new Group(this.getNextGid(), name);\n this.groups.set(group.id, group);\n for (const cb of this.groupCreateCallbacks.values()) {\n try {\n cb(group);\n } catch (err) {\n console.error(err);\n }\n }\n return group;\n }\n\n dropGroup(group: Group) {\n if (this.groups.delete(group.id)) {\n if (group.parentId !== null) {\n this.removeGroupFromGroup(group.parentId, group.id);\n }\n // Detach all entities\n for (const eid of group.entities) {\n const entity = this.entities.get(eid);\n if (entity) entity.parentId = null;\n }\n // Detach all nested groups\n for (const gid of group.groups) {\n const childGroup = this.groups.get(gid);\n if (childGroup) childGroup.parentId = null;\n }\n\n this.freeGids.push(group.id);\n for (const cb of this.groupDropCallbacks.values()) {\n try {\n cb(group);\n } catch (err) {\n console.error(err);\n }\n }\n this.updateQuadTree();\n }\n }\n\n getWorldPosition(entityId: number): Vec2 {\n const entity = this.entities.get(entityId);\n if (!entity) return new Vec2();\n\n const pos = entity.position.clone();\n let currentParentId = entity.parentId;\n\n while (currentParentId !== null) {\n const parent = this.groups.get(currentParentId);\n if (!parent) break;\n pos.x += parent.position.x;\n pos.y += parent.position.y;\n currentParentId = parent.parentId;\n }\n\n return pos;\n }\n\n getGroupWorldPosition(groupId: number): Vec2 {\n const group = this.groups.get(groupId);\n if (!group) return new Vec2();\n\n const pos = group.position.clone();\n let currentParentId = group.parentId;\n\n while (currentParentId !== null) {\n const parent = this.groups.get(currentParentId);\n if (!parent) break;\n pos.x += parent.position.x;\n pos.y += parent.position.y;\n currentParentId = parent.parentId;\n }\n\n return pos;\n }\n\n moveGroup(group: Group, dx: number, dy: number) {\n const oldBatching = this.isBatchingQuadTree;\n this.isBatchingQuadTree = true;\n\n group.position.x += dx;\n group.position.y += dy;\n\n // Notify about moves for all nested entities recursively\n const notifyRecursive = (g: Group) => {\n for (const eid of g.entities) {\n const entity = this.entities.get(eid);\n if (entity) {\n for (const cb of this.entityMoveCallbacks.values()) {\n cb(entity, this.getWorldPosition(eid));\n }\n }\n }\n for (const gid of g.groups) {\n const childGroup = this.groups.get(gid);\n if (childGroup) notifyRecursive(childGroup);\n }\n };\n\n try {\n notifyRecursive(group);\n } finally {\n this.isBatchingQuadTree = oldBatching;\n this.updateQuadTree();\n }\n }\n\n addToGroup(groupId: number, entityId: number) {\n const group = this.groups.get(groupId);\n const entity = this.entities.get(entityId);\n if (group && entity) {\n // If already in a group, remove it\n if (entity.parentId !== null) {\n this.removeFromGroup(entity.parentId, entityId);\n }\n group.add(entityId);\n entity.parentId = groupId;\n this.updateQuadTree();\n }\n }\n\n removeFromGroup(groupId: number, entityId: number) {\n const group = this.groups.get(groupId);\n const entity = this.entities.get(entityId);\n if (group && entity) {\n group.remove(entityId);\n entity.parentId = null;\n this.updateQuadTree();\n }\n }\n\n addGroupToGroup(parentGroupId: number, childGroupId: number) {\n const parent = this.groups.get(parentGroupId);\n const child = this.groups.get(childGroupId);\n if (parent && child && parentGroupId !== childGroupId) {\n if (child.parentId !== null) {\n this.removeGroupFromGroup(child.parentId, childGroupId);\n }\n parent.addGroup(childGroupId);\n child.parentId = parentGroupId;\n this.updateQuadTree();\n }\n }\n\n removeGroupFromGroup(parentGroupId: number, childGroupId: number) {\n const parent = this.groups.get(parentGroupId);\n const child = this.groups.get(childGroupId);\n if (parent && child) {\n parent.removeGroup(childGroupId);\n child.parentId = null;\n this.updateQuadTree();\n }\n }\n\n updateQuadTree() {\n if (this.isBatchingQuadTree) return;\n\n this.quadTree.clear();\n for (const entity of this.entities.values()) {\n const entityWorldPos = this.getWorldPosition(entity.id);\n // Index entity top-left\n this.quadTree.insert(entityWorldPos, entity.id);\n\n // Index every socket world position\n for (const socket of entity.sockets.values()) {\n this.quadTree.insert(\n new Vec2(entityWorldPos.x + socket.offset.x, entityWorldPos.y + socket.offset.y),\n entity.id\n );\n }\n }\n }\n\n newEntity(inner: T, forcedId?: number) {\n const id = forcedId ?? this.getNextEid();\n const ett = new Entity(id, inner);\n this.entities.set(ett.id, ett);\n if (forcedId !== undefined) {\n this.eid = Math.max(this.eid, forcedId + 1);\n }\n\n this.setupEntity(ett);\n\n if (!this.isApplyingHistory) {\n this.record(\n {\n type: 'CREATE_ENTITY',\n id: ett.id,\n inner: ett.inner,\n position: { ...ett.position },\n parentId: ett.parentId\n },\n {\n type: 'DROP_ENTITY',\n id: ett.id,\n inner: ett.inner,\n position: { ...ett.position },\n parentId: ett.parentId\n },\n 'Create Entity'\n );\n }\n\n for (const cb of this.entityCreateCallbacks.values()) {\n try {\n cb(ett);\n } catch (err) {\n console.error(err);\n }\n }\n this.updateQuadTree();\n return ett;\n }\n\n dropEntity(entity: Entity<T>) {\n if (this.entities.has(entity.id)) {\n this.batch(() => {\n // Record entity drop itself\n this.record(\n {\n type: 'DROP_ENTITY',\n id: entity.id,\n inner: entity.inner,\n position: { ...entity.position },\n parentId: entity.parentId\n },\n {\n type: 'CREATE_ENTITY',\n id: entity.id,\n inner: entity.inner,\n position: { ...entity.position },\n parentId: entity.parentId\n },\n 'Drop Entity'\n );\n\n if (entity.parentId !== null) {\n this.removeFromGroup(entity.parentId, entity.id);\n }\n\n this.entities.delete(entity.id);\n\n // Drop all sockets of this entity\n for (const socket of entity.sockets.values()) {\n this.dropSocket(socket);\n }\n\n this.freeEids.push(entity.id);\n for (const cb of this.entityDropCallbacks.values()) {\n try {\n cb(entity);\n } catch (err) {\n console.error(err);\n }\n }\n this.updateQuadTree();\n }, 'Drop Entity');\n }\n }\n\n newSocket(entity: Entity<T>, kind: SocketKind, name: string = '', forcedId?: number) {\n const id = forcedId ?? this.getNextSid();\n const socket = new Socket(id, entity.id, kind, name);\n this.sockets.set(socket.id, socket);\n entity.sockets.set(socket.id, socket);\n if (forcedId !== undefined) {\n this.sid = Math.max(this.sid, forcedId + 1);\n }\n\n if (!this.isApplyingHistory) {\n this.record(\n {\n type: 'CREATE_SOCKET',\n id: socket.id,\n entityId: entity.id,\n kind,\n name,\n offset: { ...socket.offset }\n },\n {\n type: 'DROP_SOCKET',\n id: socket.id,\n entityId: entity.id,\n kind,\n name,\n offset: { ...socket.offset }\n },\n 'Create Socket'\n );\n }\n\n for (const cb of this.socketCreateCallbacks.values()) {\n try {\n cb(socket);\n } catch (err) {\n console.error(err);\n }\n }\n return socket;\n }\n\n dropSocket(socket: Socket) {\n if (this.sockets.delete(socket.id)) {\n if (!this.isApplyingHistory) {\n this.record(\n {\n type: 'DROP_SOCKET',\n id: socket.id,\n entityId: socket.entityId,\n kind: socket.kind,\n name: socket.name,\n offset: { ...socket.offset }\n },\n {\n type: 'CREATE_SOCKET',\n id: socket.id,\n entityId: socket.entityId,\n kind: socket.kind,\n name: socket.name,\n offset: { ...socket.offset }\n },\n 'Drop Socket'\n );\n }\n const entity = this.entities.get(socket.entityId);\n if (entity) {\n entity.sockets.delete(socket.id);\n }\n\n // Drop all links connected to this socket\n for (const link of this.links.values()) {\n if (link.from === socket.id || link.to === socket.id) {\n this.dropLink(link);\n }\n }\n\n this.freeSids.push(socket.id);\n for (const cb of this.socketDropCallbacks.values()) {\n try {\n cb(socket);\n } catch (err) {\n console.error(err);\n }\n }\n }\n }\n\n newLink(\n from: Socket,\n to: Socket,\n kind: LinkKind = LinkKind.BEZIER,\n forcedId?: number,\n inner: any = {}\n ) {\n if (!this.canLink(from, to)) {\n return null;\n }\n const id = forcedId ?? this.getNextLid();\n const link = new Link(id, from.id, to.id, kind, inner);\n this.links.set(link.id, link);\n if (forcedId !== undefined) {\n this.lid = Math.max(this.lid, forcedId + 1);\n }\n\n if (!this.isApplyingHistory) {\n this.record(\n {\n type: 'CREATE_LINK',\n id: link.id,\n from: link.from,\n to: link.to,\n kind: link.kind,\n inner: link.inner\n },\n {\n type: 'DROP_LINK',\n id: link.id,\n from: link.from,\n to: link.to,\n kind: link.kind,\n inner: link.inner\n },\n 'Create Link'\n );\n }\n\n // Immediate propagation: If the source has a value, push it to the target\n if (from.value !== null) {\n this.setSocketValue(to.id, from.value);\n }\n\n for (const cb of this.linkCreateCallbacks.values()) {\n try {\n cb(link);\n } catch (err) {\n console.error(err);\n }\n }\n return link;\n }\n\n updateLink(link: Link, fromId?: number, toId?: number) {\n const oldFrom = link.from;\n const oldTo = link.to;\n const newFrom = fromId ?? oldFrom;\n const newTo = toId ?? oldTo;\n\n if (oldFrom === newFrom && oldTo === newTo) return;\n\n const fromSocket = this.sockets.get(newFrom);\n const toSocket = this.sockets.get(newTo);\n\n if (!fromSocket || !toSocket || !this.canLink(fromSocket, toSocket)) {\n return;\n }\n\n const oldWaypoints = link.waypoints.map((p) => ({ x: p.x, y: p.y }));\n\n if (!this.isApplyingHistory) {\n this.record(\n {\n type: 'UPDATE_LINK',\n id: link.id,\n from: { old: oldFrom, new: newFrom },\n to: { old: oldTo, new: newTo },\n waypoints: { old: oldWaypoints, new: oldWaypoints }\n },\n {\n type: 'UPDATE_LINK',\n id: link.id,\n from: { old: newFrom, new: oldFrom },\n to: { old: newTo, new: oldTo },\n waypoints: { old: oldWaypoints, new: oldWaypoints }\n },\n 'Update Link'\n );\n }\n\n link.from = newFrom;\n link.to = newTo;\n\n for (const cb of this.linkUpdateCallbacks.values()) {\n try {\n cb(link);\n } catch (err) {\n console.error(err);\n }\n }\n }\n\n setLinkWaypoints(link: Link, waypoints: Vec2[]) {\n const oldWaypoints = link.waypoints.map((p) => ({ x: p.x, y: p.y }));\n const newWaypoints = waypoints.map((p) => ({ x: p.x, y: p.y }));\n\n if (!this.isApplyingHistory) {\n this.record(\n {\n type: 'UPDATE_LINK',\n id: link.id,\n from: { old: link.from, new: link.from },\n to: { old: link.to, new: link.to },\n waypoints: { old: oldWaypoints, new: newWaypoints }\n },\n {\n type: 'UPDATE_LINK',\n id: link.id,\n from: { old: link.from, new: link.from },\n to: { old: link.to, new: link.to },\n waypoints: { old: newWaypoints, new: oldWaypoints }\n },\n 'Update Link Routing'\n );\n }\n\n link.waypoints = waypoints.map((p) => p.clone());\n\n for (const cb of this.linkUpdateCallbacks.values()) {\n try {\n cb(link);\n } catch (err) {\n console.error(err);\n }\n }\n }\n\n canLink(from: Socket, to: Socket) {\n if (from.id === to.id) return false;\n if (from.entityId === to.entityId) return false;\n if (from.kind === to.kind) return false;\n // Don't allow multiple links between same sockets\n for (const link of this.links.values()) {\n if (\n (link.from === from.id && link.to === to.id) ||\n (link.from === to.id && link.to === from.id)\n ) {\n return false;\n }\n }\n\n if (this.detectCycle(from, to)) {\n return false;\n }\n\n return true;\n }\n\n detectCycle(from: Socket, to: Socket): boolean {\n const visited = new Set<number>();\n const stack = [to.entityId];\n\n while (stack.length > 0) {\n const currentEntityId = stack.pop()!;\n if (currentEntityId === from.entityId) return true;\n if (visited.has(currentEntityId)) continue;\n visited.add(currentEntityId);\n\n // Find all outgoing links from this entity\n const entity = this.entities.get(currentEntityId);\n if (!entity) continue;\n\n for (const socket of entity.sockets.values()) {\n if (socket.kind === SocketKind.OUTPUT) {\n for (const link of this.links.values()) {\n if (link.from === socket.id) {\n const targetSocket = this.sockets.get(link.to);\n if (targetSocket) {\n stack.push(targetSocket.entityId);\n }\n }\n }\n }\n }\n }\n\n return false;\n }\n\n dropLink(link: Link) {\n if (this.links.delete(link.id)) {\n if (!this.isApplyingHistory) {\n this.record(\n {\n type: 'DROP_LINK',\n id: link.id,\n from: link.from,\n to: link.to,\n kind: link.kind,\n inner: link.inner\n },\n {\n type: 'CREATE_LINK',\n id: link.id,\n from: link.from,\n to: link.to,\n kind: link.kind,\n inner: link.inner\n },\n 'Drop Link'\n );\n }\n this.freeLids.push(link.id);\n for (const cb of this.linkDropCallbacks.values()) {\n try {\n cb(link);\n } catch (err) {\n console.error(err);\n }\n }\n }\n }\n\n toJSON() {\n return {\n entities: Array.from(this.entities.values()).map((e) => ({\n id: e.id,\n position: { x: e.position.x, y: e.position.y },\n inner: e.inner,\n parentId: e.parentId,\n sockets: Array.from(e.sockets.values()).map((s) => ({\n id: s.id,\n kind: s.kind,\n name: s.name,\n offset: { x: s.offset.x, y: s.offset.y }\n }))\n })),\n links: Array.from(this.links.values()).map((l) => ({\n id: l.id,\n from: l.from,\n to: l.to,\n kind: l.kind,\n waypoints: l.waypoints.map((p) => ({ x: p.x, y: p.y })),\n inner: l.inner\n })),\n groups: Array.from(this.groups.values()).map((g) => ({\n id: g.id,\n name: g.name,\n entities: Array.from(g.entities),\n groups: Array.from(g.groups),\n position: { x: g.position.x, y: g.position.y },\n parentId: g.parentId\n }))\n };\n }\n\n fromJSON(data: any) {\n this.entities.clear();\n this.links.clear();\n this.sockets.clear();\n this.groups.clear();\n this.eid = 0;\n this.lid = 0;\n this.sid = 0;\n this.gid = 0;\n this.freeEids = [];\n this.freeLids = [];\n this.freeSids = [];\n this.freeGids = [];\n\n for (const eData of data.entities) {\n const entity = new Entity(eData.id, eData.inner);\n entity.position.set(eData.position.x, eData.position.y);\n entity.parentId = eData.parentId;\n this.entities.set(entity.id, entity);\n this.eid = Math.max(this.eid, entity.id + 1);\n\n this.setupEntity(entity);\n\n for (const sData of eData.sockets) {\n const socket = new Socket(sData.id, entity.id, sData.kind, sData.name);\n socket.offset.set(sData.offset.x, sData.offset.y);\n this.sockets.set(socket.id, socket);\n entity.sockets.set(socket.id, socket);\n this.sid = Math.max(this.sid, socket.id + 1);\n }\n }\n\n for (const lData of data.links) {\n const link = new Link(lData.id, lData.from, lData.to, lData.kind, lData.inner);\n if (lData.waypoints) {\n link.waypoints = lData.waypoints.map((p: any) => new Vec2(p.x, p.y));\n }\n this.links.set(link.id, link);\n this.lid = Math.max(this.lid, link.id + 1);\n }\n\n if (data.groups) {\n for (const gData of data.groups) {\n const group = new Group(gData.id, gData.name);\n group.position.set(gData.position.x, gData.position.y);\n group.parentId = gData.parentId;\n for (const eid of gData.entities) {\n group.add(eid);\n }\n if (gData.groups) {\n for (const gid of gData.groups) {\n group.addGroup(gid);\n }\n }\n this.groups.set(group.id, group);\n this.gid = Math.max(this.gid, group.id + 1);\n }\n }\n this.updateQuadTree();\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"context.js","names":[],"sources":["../../src/core/context.ts"],"sourcesContent":["import { Entity, Link, LinkKind, Socket, SocketKind, Vec2, Group } from './elements';\nimport { QuadTree, Rect } from './layout';\nimport { HistoryManager, type HistoryAction, type Command } from './history';\n\n/** Callback triggered when an entity is created or dropped */\nexport type EntityCallback<T> = (entity: Entity<T>) => void;\n/** Callback triggered when a link is created, dropped, or updated */\nexport type LinkCallback = (link: Link) => void;\n/** Callback triggered when a socket is created, dropped, or moved */\nexport type SocketCallback = (socket: Socket) => void;\n/** Callback triggered when an entity moves, providing its new world position */\nexport type EntityMoveCallback<T> = (entity: Entity<T>, pos: Vec2) => void;\n/** Callback triggered when a group is created or dropped */\nexport type GroupCallback = (group: Group) => void;\n/** Callback triggered when a socket value is updated */\nexport type SocketValueCallback = (socket: Socket, value: any) => void;\n/** A unique handle used to unregister a listener */\nexport type CallbackHandle = number;\n\n/**\n * The central engine for Anode.\n *\n * Context manages the lifecycle of entities, sockets, links, and groups.\n * It handles reactive data propagation, spatial indexing (QuadTree),\n * and transactional history (undo/redo).\n *\n * @template T The type of the custom data associated with entities.\n */\nexport class Context<T = any> {\n private eid: number = 0;\n private lid: number = 0;\n private sid: number = 0;\n private gid: number = 0;\n\n private freeEids: number[] = [];\n private freeLids: number[] = [];\n private freeSids: number[] = [];\n private freeGids: number[] = [];\n\n private callbackIds: number = 0;\n private freeCallbackIds: number[] = [];\n\n private entityCreateCallbacks: Map<number, EntityCallback<T>> = new Map();\n private entityDropCallbacks: Map<number, EntityCallback<T>> = new Map();\n private entityMoveCallbacks: Map<number, EntityMoveCallback<T>> = new Map();\n private socketMoveCallbacks: Map<number, SocketCallback> = new Map();\n private socketValueCallbacks: Map<number, SocketValueCallback> = new Map();\n\n private linkCreateCallbacks: Map<number, LinkCallback> = new Map();\n private linkDropCallbacks: Map<number, LinkCallback> = new Map();\n private linkUpdateCallbacks: Map<number, LinkCallback> = new Map();\n\n private socketCreateCallbacks: Map<number, SocketCallback> = new Map();\n private socketDropCallbacks: Map<number, SocketCallback> = new Map();\n\n private groupCreateCallbacks: Map<number, GroupCallback> = new Map();\n private groupDropCallbacks: Map<number, GroupCallback> = new Map();\n private bulkChangeCallbacks: Map<number, () => void> = new Map();\n\n /** Map of all entities indexed by their unique ID */\n entities: Map<number, Entity<T>> = new Map();\n /** Map of all links indexed by their unique ID */\n links: Map<number, Link> = new Map();\n /** Map of all sockets indexed by their unique ID */\n sockets: Map<number, Socket> = new Map();\n /** Map of all groups indexed by their unique ID */\n groups: Map<number, Group> = new Map();\n\n /** Spatial index for efficient querying and culling */\n quadTree: QuadTree<number> = new QuadTree(new Rect(-100000, -100000, 200000, 200000));\n /** Manager for undo/redo history */\n history: HistoryManager = new HistoryManager();\n\n private isApplyingHistory: boolean = false;\n private currentBatch: HistoryAction[] | null = null;\n private isBatchingQuadTree: boolean = false;\n\n private getNextEid() {\n return this.freeEids.pop() ?? this.eid++;\n }\n private getNextLid() {\n return this.freeLids.pop() ?? this.lid++;\n }\n private getNextSid() {\n return this.freeSids.pop() ?? this.sid++;\n }\n private getNextGid() {\n return this.freeGids.pop() ?? this.gid++;\n }\n private getNextCallbackHandle(): CallbackHandle {\n return this.freeCallbackIds.pop() ?? this.callbackIds++;\n }\n\n private setupEntity(entity: Entity<T>) {\n entity.onMove((_pos) => {\n this.updateQuadTree();\n for (const cb of this.entityMoveCallbacks.values()) {\n try {\n cb(entity, this.getWorldPosition(entity.id));\n } catch (err) {\n console.error(err);\n }\n }\n });\n }\n\n /** Triggers all bulk change listeners. Usually called after undo/redo or batch operations. */\n notifyBulkChange() {\n for (const cb of this.bulkChangeCallbacks.values()) {\n try {\n cb();\n } catch (err) {\n console.error(err);\n }\n }\n }\n\n /**\n * Registers a callback that is triggered when multiple changes occur at once.\n * Useful for syncing UI state that doesn't need to respond to every individual mutation.\n */\n registerBulkChangeListener(cb: () => void): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.bulkChangeCallbacks.set(handle, cb);\n return handle;\n }\n\n /**\n * Sets the value of a specific socket and triggers reactive propagation.\n *\n * **Side Effects:**\n * 1. Updates the `socket.value`.\n * 2. Triggers `SocketValueListener` for the socket.\n * 3. If the socket is an `OUTPUT`, pushes the value to all linked `INPUT` sockets recursively.\n *\n * @param socketId The unique ID of the socket.\n * @param value The new value to assign.\n */\n setSocketValue(socketId: number, value: any) {\n const socket = this.sockets.get(socketId);\n if (!socket) return;\n\n socket.value = value;\n\n for (const cb of this.socketValueCallbacks.values()) {\n cb(socket, value);\n }\n\n if (socket.kind === SocketKind.OUTPUT) {\n for (const link of this.links.values()) {\n if (link.from === socketId) {\n this.setSocketValue(link.to, value);\n }\n }\n }\n }\n\n /** Registers a listener for socket value changes. */\n registerSocketValueListener(cb: SocketValueCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.socketValueCallbacks.set(handle, cb);\n return handle;\n }\n\n /**\n * Records a custom set of actions to the history stack.\n * Internally used by all mutation methods.\n */\n record(\n doActions: HistoryAction | HistoryAction[],\n undoActions: HistoryAction | HistoryAction[],\n label?: string\n ) {\n if (this.isApplyingHistory) return;\n if (this.currentBatch) return;\n\n const das = Array.isArray(doActions) ? doActions : [doActions];\n const uas = Array.isArray(undoActions) ? undoActions : [undoActions];\n\n this.history.push({\n do: das,\n undo: uas,\n label: label ?? 'Action',\n timestamp: Date.now()\n });\n }\n\n /**\n * Executes a function as a single atomic transaction in the history stack.\n *\n * During the batch:\n * 1. Individual operations do not record separate history entries.\n * 2. QuadTree updates are suspended until the end of the batch.\n * 3. A single snapshot-based history entry is created for the entire operation.\n *\n * @param fn The function containing multiple mutations.\n * @param label A human-readable label for the history entry (e.g., \"Layout Graph\").\n */\n batch(fn: () => void, label?: string) {\n if (this.currentBatch) {\n fn();\n return;\n }\n\n const oldApplying = this.isApplyingHistory;\n const oldBatchingQT = this.isBatchingQuadTree;\n const beforeState = this.toJSON();\n\n try {\n this.isApplyingHistory = true;\n this.isBatchingQuadTree = true;\n fn();\n\n this.isBatchingQuadTree = oldBatchingQT;\n this.updateQuadTree();\n\n const afterState = this.toJSON();\n\n this.history.push({\n do: [{ type: 'FROM_JSON', data: afterState }],\n undo: [{ type: 'FROM_JSON', data: beforeState }],\n label: label ?? 'Batch Action',\n timestamp: Date.now()\n });\n } finally {\n this.isApplyingHistory = oldApplying;\n this.isBatchingQuadTree = oldBatchingQT;\n }\n }\n\n /** Reverts the last recorded transaction. */\n undo() {\n const cmd = this.history.undoStack.pop();\n if (!cmd) return;\n this.isApplyingHistory = true;\n this.isBatchingQuadTree = true;\n try {\n for (let i = cmd.undo.length - 1; i >= 0; i--) {\n this.applyAction(cmd.undo[i]!);\n }\n this.isBatchingQuadTree = false;\n this.updateQuadTree();\n this.notifyBulkChange();\n this.history.redoStack.push(cmd);\n } finally {\n this.isApplyingHistory = false;\n this.isBatchingQuadTree = false;\n }\n }\n\n /** Re-applies the last undone transaction. */\n redo() {\n const cmd = this.history.redoStack.pop();\n if (!cmd) return;\n this.isApplyingHistory = true;\n this.isBatchingQuadTree = true;\n try {\n for (const action of cmd.do) {\n this.applyAction(action);\n }\n this.isBatchingQuadTree = false;\n this.updateQuadTree();\n this.notifyBulkChange();\n this.history.undoStack.push(cmd);\n } finally {\n this.isApplyingHistory = false;\n this.isBatchingQuadTree = false;\n }\n }\n\n private applyAction(action: HistoryAction) {\n switch (action.type) {\n case 'FROM_JSON': {\n this.fromJSON(action.data);\n break;\n }\n case 'MOVE_ENTITY': {\n const entity = this.entities.get(action.id);\n if (entity) {\n entity.position.set(action.to.x, action.to.y);\n for (const cb of this.entityMoveCallbacks.values())\n cb(entity, this.getWorldPosition(entity.id));\n this.updateQuadTree();\n }\n break;\n }\n case 'MOVE_GROUP': {\n const group = this.groups.get(action.id);\n if (group) {\n const dx = action.to.x - action.from.x;\n const dy = action.to.y - action.from.y;\n const oldApplying = this.isApplyingHistory;\n this.isApplyingHistory = true;\n try {\n this.moveGroup(group, dx, dy);\n } finally {\n this.isApplyingHistory = oldApplying;\n }\n }\n break;\n }\n case 'CREATE_ENTITY': {\n const entity = new Entity(action.id, action.inner);\n entity.position.set(action.position.x, action.position.y);\n this.entities.set(entity.id, entity);\n this.eid = Math.max(this.eid, entity.id + 1);\n\n this.setupEntity(entity);\n\n if (action.parentId !== null) {\n this.addToGroup(action.parentId, entity.id);\n }\n for (const cb of this.entityCreateCallbacks.values()) cb(entity);\n this.updateQuadTree();\n break;\n }\n case 'DROP_ENTITY': {\n const entity = this.entities.get(action.id);\n if (entity) {\n const oldApplying = this.isApplyingHistory;\n this.isApplyingHistory = true;\n try {\n this.dropEntity(entity);\n } finally {\n this.isApplyingHistory = oldApplying;\n }\n }\n break;\n }\n case 'CREATE_LINK': {\n const from = this.sockets.get(action.from);\n const to = this.sockets.get(action.to);\n if (from && to) {\n const link = new Link(action.id, from.id, to.id, action.kind, action.inner);\n this.links.set(link.id, link);\n this.lid = Math.max(this.lid, link.id + 1);\n for (const cb of this.linkCreateCallbacks.values()) cb(link);\n }\n break;\n }\n case 'DROP_LINK': {\n const link = this.links.get(action.id);\n if (link) {\n const oldApplying = this.isApplyingHistory;\n this.isApplyingHistory = true;\n try {\n this.dropLink(link);\n } finally {\n this.isApplyingHistory = oldApplying;\n }\n }\n break;\n }\n case 'UPDATE_LINK': {\n const link = this.links.get(action.id);\n if (link) {\n link.from = action.from.new;\n link.to = action.to.new;\n if (action.waypoints) {\n link.waypoints = action.waypoints.new.map((p) => new Vec2(p.x, p.y));\n }\n for (const cb of this.linkUpdateCallbacks.values()) cb(link);\n }\n break;\n }\n case 'ADD_TO_GROUP': {\n this.addToGroup(action.groupId, action.entityId);\n break;\n }\n case 'REMOVE_FROM_GROUP': {\n this.removeFromGroup(action.groupId, action.entityId);\n break;\n }\n case 'CREATE_SOCKET': {\n const entity = this.entities.get(action.entityId);\n if (entity) {\n const socket = new Socket(action.id, entity.id, action.kind, action.name);\n socket.offset.set(action.offset.x, action.offset.y);\n this.sockets.set(socket.id, socket);\n entity.sockets.set(socket.id, socket);\n this.sid = Math.max(this.sid, socket.id + 1);\n for (const cb of this.socketCreateCallbacks.values()) cb(socket);\n }\n break;\n }\n case 'DROP_SOCKET': {\n const socket = this.sockets.get(action.id);\n if (socket) {\n const oldApplying = this.isApplyingHistory;\n this.isApplyingHistory = true;\n try {\n this.dropSocket(socket);\n } finally {\n this.isApplyingHistory = oldApplying;\n }\n }\n break;\n }\n }\n }\n\n /** Registers a listener for entity creation. */\n registerEntityCreateListener(cb: EntityCallback<T>): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.entityCreateCallbacks.set(handle, cb);\n return handle;\n }\n\n /** Registers a listener for entity deletion. */\n registerEntityDropListener(cb: EntityCallback<T>): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.entityDropCallbacks.set(handle, cb);\n return handle;\n }\n\n /** Registers a listener for entity movements (absolute position). */\n registerEntityMoveListener(cb: EntityMoveCallback<T>): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.entityMoveCallbacks.set(handle, cb);\n return handle;\n }\n\n /** Registers a listener for socket movements (relative offset changes). */\n registerSocketMoveListener(cb: SocketCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.socketMoveCallbacks.set(handle, cb);\n return handle;\n }\n\n /** Triggers all socket move listeners. */\n notifySocketMove(socket: Socket) {\n for (const cb of this.socketMoveCallbacks.values()) {\n try {\n cb(socket);\n } catch (err) {\n console.error(err);\n }\n }\n }\n\n /** Registers a listener for link creation. */\n registerLinkCreateListener(cb: LinkCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.linkCreateCallbacks.set(handle, cb);\n return handle;\n }\n\n /** Registers a listener for link deletion. */\n registerLinkDropListener(cb: LinkCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.linkDropCallbacks.set(handle, cb);\n return handle;\n }\n\n /** Registers a listener for link updates (reconnections, waypoints). */\n registerLinkUpdateListener(cb: LinkCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.linkUpdateCallbacks.set(handle, cb);\n return handle;\n }\n\n /** Registers a listener for socket creation. */\n registerSocketCreateListener(cb: SocketCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.socketCreateCallbacks.set(handle, cb);\n return handle;\n }\n\n /** Registers a listener for socket deletion. */\n registerSocketDropListener(cb: SocketCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.socketDropCallbacks.set(handle, cb);\n return handle;\n }\n\n /** Registers a listener for group creation. */\n registerGroupCreateListener(cb: GroupCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.groupCreateCallbacks.set(handle, cb);\n return handle;\n }\n\n /** Registers a listener for group deletion. */\n registerGroupDropListener(cb: GroupCallback): CallbackHandle {\n const handle = this.getNextCallbackHandle();\n this.groupDropCallbacks.set(handle, cb);\n return handle;\n }\n\n /**\n * Unregisters a listener using the handle returned by the registration method.\n * @returns true if the listener was successfully removed.\n */\n unregisterListener(handle: CallbackHandle) {\n const deleted =\n this.linkCreateCallbacks.delete(handle) ||\n this.linkDropCallbacks.delete(handle) ||\n this.linkUpdateCallbacks.delete(handle) ||\n this.entityCreateCallbacks.delete(handle) ||\n this.entityDropCallbacks.delete(handle) ||\n this.entityMoveCallbacks.delete(handle) ||\n this.socketCreateCallbacks.delete(handle) ||\n this.socketDropCallbacks.delete(handle) ||\n this.socketMoveCallbacks.delete(handle) ||\n this.groupCreateCallbacks.delete(handle) ||\n this.groupDropCallbacks.delete(handle) ||\n this.bulkChangeCallbacks.delete(handle);\n\n if (deleted) {\n this.freeCallbackIds.push(handle);\n return true;\n }\n return false;\n }\n\n /** Creates and returns a new group. */\n newGroup(name: string = '') {\n const group = new Group(this.getNextGid(), name);\n this.groups.set(group.id, group);\n for (const cb of this.groupCreateCallbacks.values()) {\n try {\n cb(group);\n } catch (err) {\n console.error(err);\n }\n }\n return group;\n }\n\n /**\n * Drops a group.\n *\n * **Side Effects:**\n * 1. Detaches all child entities and groups (they remain in the context).\n * 2. Removes the group from its parent group if applicable.\n * 3. Triggers `GroupDropListener`.\n */\n dropGroup(group: Group) {\n if (this.groups.delete(group.id)) {\n if (group.parentId !== null) {\n this.removeGroupFromGroup(group.parentId, group.id);\n }\n for (const eid of group.entities) {\n const entity = this.entities.get(eid);\n if (entity) entity.parentId = null;\n }\n for (const gid of group.groups) {\n const childGroup = this.groups.get(gid);\n if (childGroup) childGroup.parentId = null;\n }\n\n this.freeGids.push(group.id);\n for (const cb of this.groupDropCallbacks.values()) {\n try {\n cb(group);\n } catch (err) {\n console.error(err);\n }\n }\n this.updateQuadTree();\n }\n }\n\n /** Calculates the absolute world position of an entity by traversing its parent group hierarchy. */\n getWorldPosition(entityId: number): Vec2 {\n const entity = this.entities.get(entityId);\n if (!entity) return new Vec2();\n\n const pos = entity.position.clone();\n let currentParentId = entity.parentId;\n\n while (currentParentId !== null) {\n const parent = this.groups.get(currentParentId);\n if (!parent) break;\n pos.x += parent.position.x;\n pos.y += parent.position.y;\n currentParentId = parent.parentId;\n }\n\n return pos;\n }\n\n /** Calculates the absolute world position of a group by traversing its parent group hierarchy. */\n getGroupWorldPosition(groupId: number): Vec2 {\n const group = this.groups.get(groupId);\n if (!group) return new Vec2();\n\n const pos = group.position.clone();\n let currentParentId = group.parentId;\n\n while (currentParentId !== null) {\n const parent = this.groups.get(currentParentId);\n if (!parent) break;\n pos.x += parent.position.x;\n pos.y += parent.position.y;\n currentParentId = parent.parentId;\n }\n\n return pos;\n }\n\n /**\n * Moves a group and triggers move notifications for all nested entities recursively.\n * This handles the complex coordinate system updates during group drags.\n */\n moveGroup(group: Group, dx: number, dy: number) {\n const oldBatching = this.isBatchingQuadTree;\n this.isBatchingQuadTree = true;\n\n group.position.x += dx;\n group.position.y += dy;\n\n const notifyRecursive = (g: Group) => {\n for (const eid of g.entities) {\n const entity = this.entities.get(eid);\n if (entity) {\n for (const cb of this.entityMoveCallbacks.values()) {\n cb(entity, this.getWorldPosition(eid));\n }\n }\n }\n for (const gid of g.groups) {\n const childGroup = this.groups.get(gid);\n if (childGroup) notifyRecursive(childGroup);\n }\n };\n\n try {\n notifyRecursive(group);\n } finally {\n this.isBatchingQuadTree = oldBatching;\n this.updateQuadTree();\n }\n }\n\n /** Adds an entity to a group. Automatically removes it from its previous group if necessary. */\n addToGroup(groupId: number, entityId: number) {\n const group = this.groups.get(groupId);\n const entity = this.entities.get(entityId);\n if (group && entity) {\n if (entity.parentId !== null) {\n this.removeFromGroup(entity.parentId, entityId);\n }\n group.add(entityId);\n entity.parentId = groupId;\n this.updateQuadTree();\n }\n }\n\n /** Removes an entity from its parent group. */\n removeFromGroup(groupId: number, entityId: number) {\n const group = this.groups.get(groupId);\n const entity = this.entities.get(entityId);\n if (group && entity) {\n group.remove(entityId);\n entity.parentId = null;\n this.updateQuadTree();\n }\n }\n\n /** Adds a group to a parent group, creating a nested hierarchy. */\n addGroupToGroup(parentGroupId: number, childGroupId: number) {\n const parent = this.groups.get(parentGroupId);\n const child = this.groups.get(childGroupId);\n if (parent && child && parentGroupId !== childGroupId) {\n if (child.parentId !== null) {\n this.removeGroupFromGroup(child.parentId, childGroupId);\n }\n parent.addGroup(childGroupId);\n child.parentId = parentGroupId;\n this.updateQuadTree();\n }\n }\n\n /** Removes a group from its parent group. */\n removeGroupFromGroup(parentGroupId: number, childGroupId: number) {\n const parent = this.groups.get(parentGroupId);\n const child = this.groups.get(childGroupId);\n if (parent && child) {\n parent.removeGroup(childGroupId);\n child.parentId = null;\n this.updateQuadTree();\n }\n }\n\n /**\n * Rebuilds the QuadTree spatial index.\n * Suspended if `isBatchingQuadTree` is true.\n */\n updateQuadTree() {\n if (this.isBatchingQuadTree) return;\n\n this.quadTree.clear();\n for (const entity of this.entities.values()) {\n const entityWorldPos = this.getWorldPosition(entity.id);\n this.quadTree.insert(entityWorldPos, entity.id);\n\n for (const socket of entity.sockets.values()) {\n this.quadTree.insert(\n new Vec2(entityWorldPos.x + socket.offset.x, entityWorldPos.y + socket.offset.y),\n entity.id\n );\n }\n }\n }\n\n /**\n * Creates a new entity.\n * @param inner Custom data associated with the entity.\n * @param forcedId Optional forced ID (useful for synchronization/deserialization).\n */\n newEntity(inner: T, forcedId?: number) {\n const id = forcedId ?? this.getNextEid();\n const ett = new Entity(id, inner);\n this.entities.set(ett.id, ett);\n if (forcedId !== undefined) {\n this.eid = Math.max(this.eid, forcedId + 1);\n }\n\n this.setupEntity(ett);\n\n if (!this.isApplyingHistory) {\n this.record(\n {\n type: 'CREATE_ENTITY',\n id: ett.id,\n inner: ett.inner,\n position: { ...ett.position },\n parentId: ett.parentId\n },\n {\n type: 'DROP_ENTITY',\n id: ett.id,\n inner: ett.inner,\n position: { ...ett.position },\n parentId: ett.parentId\n },\n 'Create Entity'\n );\n }\n\n for (const cb of this.entityCreateCallbacks.values()) {\n try {\n cb(ett);\n } catch (err) {\n console.error(err);\n }\n }\n this.updateQuadTree();\n return ett;\n }\n\n /**\n * Drops an entity and all its associated sockets and links.\n * This is performed as a batched operation to ensure consistent history.\n */\n dropEntity(entity: Entity<T>) {\n if (this.entities.has(entity.id)) {\n this.batch(() => {\n this.record(\n {\n type: 'DROP_ENTITY',\n id: entity.id,\n inner: entity.inner,\n position: { ...entity.position },\n parentId: entity.parentId\n },\n {\n type: 'CREATE_ENTITY',\n id: entity.id,\n inner: entity.inner,\n position: { ...entity.position },\n parentId: entity.parentId\n },\n 'Drop Entity'\n );\n\n if (entity.parentId !== null) {\n this.removeFromGroup(entity.parentId, entity.id);\n }\n\n this.entities.delete(entity.id);\n\n for (const socket of entity.sockets.values()) {\n this.dropSocket(socket);\n }\n\n this.freeEids.push(entity.id);\n for (const cb of this.entityDropCallbacks.values()) {\n try {\n cb(entity);\n } catch (err) {\n console.error(err);\n }\n }\n this.updateQuadTree();\n }, 'Drop Entity');\n }\n }\n\n /** Adds a new socket to an entity. */\n newSocket(entity: Entity<T>, kind: SocketKind, name: string = '', forcedId?: number) {\n const id = forcedId ?? this.getNextSid();\n const socket = new Socket(id, entity.id, kind, name);\n this.sockets.set(socket.id, socket);\n entity.sockets.set(socket.id, socket);\n if (forcedId !== undefined) {\n this.sid = Math.max(this.sid, forcedId + 1);\n }\n\n if (!this.isApplyingHistory) {\n this.record(\n {\n type: 'CREATE_SOCKET',\n id: socket.id,\n entityId: entity.id,\n kind,\n name,\n offset: { ...socket.offset }\n },\n {\n type: 'DROP_SOCKET',\n id: socket.id,\n entityId: entity.id,\n kind,\n name,\n offset: { ...socket.offset }\n },\n 'Create Socket'\n );\n }\n\n for (const cb of this.socketCreateCallbacks.values()) {\n try {\n cb(socket);\n } catch (err) {\n console.error(err);\n }\n }\n return socket;\n }\n\n /** Drops a socket and all links connected to it. */\n dropSocket(socket: Socket) {\n if (this.sockets.delete(socket.id)) {\n if (!this.isApplyingHistory) {\n this.record(\n {\n type: 'DROP_SOCKET',\n id: socket.id,\n entityId: socket.entityId,\n kind: socket.kind,\n name: socket.name,\n offset: { ...socket.offset }\n },\n {\n type: 'CREATE_SOCKET',\n id: socket.id,\n entityId: socket.entityId,\n kind: socket.kind,\n name: socket.name,\n offset: { ...socket.offset }\n },\n 'Drop Socket'\n );\n }\n const entity = this.entities.get(socket.entityId);\n if (entity) {\n entity.sockets.delete(socket.id);\n }\n\n for (const link of this.links.values()) {\n if (link.from === socket.id || link.to === socket.id) {\n this.dropLink(link);\n }\n }\n\n this.freeSids.push(socket.id);\n for (const cb of this.socketDropCallbacks.values()) {\n try {\n cb(socket);\n } catch (err) {\n console.error(err);\n }\n }\n }\n }\n\n /**\n * Creates a new link between two sockets.\n * Fails if the connection is invalid (e.g., creating a cycle, connecting same entity, etc.).\n */\n newLink(\n from: Socket,\n to: Socket,\n kind: LinkKind = LinkKind.BEZIER,\n forcedId?: number,\n inner: any = {}\n ) {\n if (!this.canLink(from, to)) {\n return null;\n }\n const id = forcedId ?? this.getNextLid();\n const link = new Link(id, from.id, to.id, kind, inner);\n this.links.set(link.id, link);\n if (forcedId !== undefined) {\n this.lid = Math.max(this.lid, forcedId + 1);\n }\n\n if (!this.isApplyingHistory) {\n this.record(\n {\n type: 'CREATE_LINK',\n id: link.id,\n from: link.from,\n to: link.to,\n kind: link.kind,\n inner: link.inner\n },\n {\n type: 'DROP_LINK',\n id: link.id,\n from: link.from,\n to: link.to,\n kind: link.kind,\n inner: link.inner\n },\n 'Create Link'\n );\n }\n\n if (from.value !== null) {\n this.setSocketValue(to.id, from.value);\n }\n\n for (const cb of this.linkCreateCallbacks.values()) {\n try {\n cb(link);\n } catch (err) {\n console.error(err);\n }\n }\n return link;\n }\n\n /** Updates an existing link's source or target. */\n updateLink(link: Link, fromId?: number, toId?: number) {\n const oldFrom = link.from;\n const oldTo = link.to;\n const newFrom = fromId ?? oldFrom;\n const newTo = toId ?? oldTo;\n\n if (oldFrom === newFrom && oldTo === newTo) return;\n\n const fromSocket = this.sockets.get(newFrom);\n const toSocket = this.sockets.get(newTo);\n\n if (!fromSocket || !toSocket || !this.canLink(fromSocket, toSocket)) {\n return;\n }\n\n const oldWaypoints = link.waypoints.map((p) => ({ x: p.x, y: p.y }));\n\n if (!this.isApplyingHistory) {\n this.record(\n {\n type: 'UPDATE_LINK',\n id: link.id,\n from: { old: oldFrom, new: newFrom },\n to: { old: oldTo, new: newTo },\n waypoints: { old: oldWaypoints, new: oldWaypoints }\n },\n {\n type: 'UPDATE_LINK',\n id: link.id,\n from: { old: newFrom, new: oldFrom },\n to: { old: newTo, new: oldTo },\n waypoints: { old: oldWaypoints, new: oldWaypoints }\n },\n 'Update Link'\n );\n }\n\n link.from = newFrom;\n link.to = newTo;\n\n for (const cb of this.linkUpdateCallbacks.values()) {\n try {\n cb(link);\n } catch (err) {\n console.error(err);\n }\n }\n }\n\n /** Sets custom routing waypoints for a link. */\n setLinkWaypoints(link: Link, waypoints: Vec2[]) {\n const oldWaypoints = link.waypoints.map((p) => ({ x: p.x, y: p.y }));\n const newWaypoints = waypoints.map((p) => ({ x: p.x, y: p.y }));\n\n if (!this.isApplyingHistory) {\n this.record(\n {\n type: 'UPDATE_LINK',\n id: link.id,\n from: { old: link.from, new: link.from },\n to: { old: link.to, new: link.to },\n waypoints: { old: oldWaypoints, new: newWaypoints }\n },\n {\n type: 'UPDATE_LINK',\n id: link.id,\n from: { old: link.from, new: link.from },\n to: { old: link.to, new: link.to },\n waypoints: { old: newWaypoints, new: oldWaypoints }\n },\n 'Update Link Routing'\n );\n }\n\n link.waypoints = waypoints.map((p) => p.clone());\n\n for (const cb of this.linkUpdateCallbacks.values()) {\n try {\n cb(link);\n } catch (err) {\n console.error(err);\n }\n }\n }\n\n /**\n * Validation logic for connections.\n * Prevents self-loops, same-entity links, identical kind connections,\n * duplicate links, and cycles.\n */\n canLink(from: Socket, to: Socket) {\n if (from.id === to.id) return false;\n if (from.entityId === to.entityId) return false;\n if (from.kind === to.kind) return false;\n for (const link of this.links.values()) {\n if (\n (link.from === from.id && link.to === to.id) ||\n (link.from === to.id && link.to === from.id)\n ) {\n return false;\n }\n }\n\n if (this.detectCycle(from, to)) {\n return false;\n }\n\n return true;\n }\n\n /** Performs a cycle detection search in the graph. */\n detectCycle(from: Socket, to: Socket): boolean {\n const visited = new Set<number>();\n const stack = [to.entityId];\n\n while (stack.length > 0) {\n const currentEntityId = stack.pop()!;\n if (currentEntityId === from.entityId) return true;\n if (visited.has(currentEntityId)) continue;\n visited.add(currentEntityId);\n\n const entity = this.entities.get(currentEntityId);\n if (!entity) continue;\n\n for (const socket of entity.sockets.values()) {\n if (socket.kind === SocketKind.OUTPUT) {\n for (const link of this.links.values()) {\n if (link.from === socket.id) {\n const targetSocket = this.sockets.get(link.to);\n if (targetSocket) {\n stack.push(targetSocket.entityId);\n }\n }\n }\n }\n }\n }\n\n return false;\n }\n\n /** Deletes a link from the context. */\n dropLink(link: Link) {\n if (this.links.delete(link.id)) {\n if (!this.isApplyingHistory) {\n this.record(\n {\n type: 'DROP_LINK',\n id: link.id,\n from: link.from,\n to: link.to,\n kind: link.kind,\n inner: link.inner\n },\n {\n type: 'CREATE_LINK',\n id: link.id,\n from: link.from,\n to: link.to,\n kind: link.kind,\n inner: link.inner\n },\n 'Drop Link'\n );\n }\n this.freeLids.push(link.id);\n for (const cb of this.linkDropCallbacks.values()) {\n try {\n cb(link);\n } catch (err) {\n console.error(err);\n }\n }\n }\n }\n\n /** Serializes the entire context state into a JSON-compatible object. */\n toJSON() {\n return {\n entities: Array.from(this.entities.values()).map((e) => ({\n id: e.id,\n position: { x: e.position.x, y: e.position.y },\n inner: e.inner,\n parentId: e.parentId,\n sockets: Array.from(e.sockets.values()).map((s) => ({\n id: s.id,\n kind: s.kind,\n name: s.name,\n offset: { x: s.offset.x, y: s.offset.y }\n }))\n })),\n links: Array.from(this.links.values()).map((l) => ({\n id: l.id,\n from: l.from,\n to: l.to,\n kind: l.kind,\n waypoints: l.waypoints.map((p) => ({ x: p.x, y: p.y })),\n inner: l.inner\n })),\n groups: Array.from(this.groups.values()).map((g) => ({\n id: g.id,\n name: g.name,\n entities: Array.from(g.entities),\n groups: Array.from(g.groups),\n position: { x: g.position.x, y: g.position.y },\n parentId: g.parentId\n }))\n };\n }\n\n /**\n * Restores the context state from a serialized JSON object.\n * **Note:** This clears the current state completely.\n */\n fromJSON(data: any) {\n this.entities.clear();\n this.links.clear();\n this.sockets.clear();\n this.groups.clear();\n this.eid = 0;\n this.lid = 0;\n this.sid = 0;\n this.gid = 0;\n this.freeEids = [];\n this.freeLids = [];\n this.freeSids = [];\n this.freeGids = [];\n\n for (const eData of data.entities) {\n const entity = new Entity(eData.id, eData.inner);\n entity.position.set(eData.position.x, eData.position.y);\n entity.parentId = eData.parentId;\n this.entities.set(entity.id, entity);\n this.eid = Math.max(this.eid, entity.id + 1);\n\n this.setupEntity(entity);\n\n for (const sData of eData.sockets) {\n const socket = new Socket(sData.id, entity.id, sData.kind, sData.name);\n socket.offset.set(sData.offset.x, sData.offset.y);\n this.sockets.set(socket.id, socket);\n entity.sockets.set(socket.id, socket);\n this.sid = Math.max(this.sid, socket.id + 1);\n }\n }\n\n for (const lData of data.links) {\n const link = new Link(lData.id, lData.from, lData.to, lData.kind, lData.inner);\n if (lData.waypoints) {\n link.waypoints = lData.waypoints.map((p: any) => new Vec2(p.x, p.y));\n }\n this.links.set(link.id, link);\n this.lid = Math.max(this.lid, link.id + 1);\n }\n\n if (data.groups) {\n for (const gData of data.groups) {\n const group = new Group(gData.id, gData.name);\n group.position.set(gData.position.x, gData.position.y);\n group.parentId = gData.parentId;\n for (const eid of gData.entities) {\n group.add(eid);\n }\n if (gData.groups) {\n for (const gid of gData.groups) {\n group.addGroup(gid);\n }\n }\n this.groups.set(group.id, group);\n this.gid = Math.max(this.gid, group.id + 1);\n }\n }\n this.updateQuadTree();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AA4BA,IAAa,UAAb,MAA8B;CAC5B,AAAQ,MAAc;CACtB,AAAQ,MAAc;CACtB,AAAQ,MAAc;CACtB,AAAQ,MAAc;CAEtB,AAAQ,WAAqB,EAAE;CAC/B,AAAQ,WAAqB,EAAE;CAC/B,AAAQ,WAAqB,EAAE;CAC/B,AAAQ,WAAqB,EAAE;CAE/B,AAAQ,cAAsB;CAC9B,AAAQ,kBAA4B,EAAE;CAEtC,AAAQ,wCAAwD,IAAI,KAAK;CACzE,AAAQ,sCAAsD,IAAI,KAAK;CACvE,AAAQ,sCAA0D,IAAI,KAAK;CAC3E,AAAQ,sCAAmD,IAAI,KAAK;CACpE,AAAQ,uCAAyD,IAAI,KAAK;CAE1E,AAAQ,sCAAiD,IAAI,KAAK;CAClE,AAAQ,oCAA+C,IAAI,KAAK;CAChE,AAAQ,sCAAiD,IAAI,KAAK;CAElE,AAAQ,wCAAqD,IAAI,KAAK;CACtE,AAAQ,sCAAmD,IAAI,KAAK;CAEpE,AAAQ,uCAAmD,IAAI,KAAK;CACpE,AAAQ,qCAAiD,IAAI,KAAK;CAClE,AAAQ,sCAA+C,IAAI,KAAK;;CAGhE,2BAAmC,IAAI,KAAK;;CAE5C,wBAA2B,IAAI,KAAK;;CAEpC,0BAA+B,IAAI,KAAK;;CAExC,yBAA6B,IAAI,KAAK;;CAGtC,WAA6B,IAAI,SAAS,IAAI,KAAK,MAAS,MAAS,KAAQ,IAAO,CAAC;;CAErF,UAA0B,IAAI,gBAAgB;CAE9C,AAAQ,oBAA6B;CACrC,AAAQ,eAAuC;CAC/C,AAAQ,qBAA8B;CAEtC,AAAQ,aAAa;AACnB,SAAO,KAAK,SAAS,KAAK,IAAI,KAAK;;CAErC,AAAQ,aAAa;AACnB,SAAO,KAAK,SAAS,KAAK,IAAI,KAAK;;CAErC,AAAQ,aAAa;AACnB,SAAO,KAAK,SAAS,KAAK,IAAI,KAAK;;CAErC,AAAQ,aAAa;AACnB,SAAO,KAAK,SAAS,KAAK,IAAI,KAAK;;CAErC,AAAQ,wBAAwC;AAC9C,SAAO,KAAK,gBAAgB,KAAK,IAAI,KAAK;;CAG5C,AAAQ,YAAY,QAAmB;AACrC,SAAO,QAAQ,SAAS;AACtB,QAAK,gBAAgB;AACrB,QAAK,MAAM,MAAM,KAAK,oBAAoB,QAAQ,CAChD,KAAI;AACF,OAAG,QAAQ,KAAK,iBAAiB,OAAO,GAAG,CAAC;YACrC,KAAK;AACZ,YAAQ,MAAM,IAAI;;IAGtB;;;CAIJ,mBAAmB;AACjB,OAAK,MAAM,MAAM,KAAK,oBAAoB,QAAQ,CAChD,KAAI;AACF,OAAI;WACG,KAAK;AACZ,WAAQ,MAAM,IAAI;;;;;;;CASxB,2BAA2B,IAAgC;EACzD,MAAM,SAAS,KAAK,uBAAuB;AAC3C,OAAK,oBAAoB,IAAI,QAAQ,GAAG;AACxC,SAAO;;;;;;;;;;;;;CAcT,eAAe,UAAkB,OAAY;EAC3C,MAAM,SAAS,KAAK,QAAQ,IAAI,SAAS;AACzC,MAAI,CAAC,OAAQ;AAEb,SAAO,QAAQ;AAEf,OAAK,MAAM,MAAM,KAAK,qBAAqB,QAAQ,CACjD,IAAG,QAAQ,MAAM;AAGnB,MAAI,OAAO,SAAS,WAAW,QAC7B;QAAK,MAAM,QAAQ,KAAK,MAAM,QAAQ,CACpC,KAAI,KAAK,SAAS,SAChB,MAAK,eAAe,KAAK,IAAI,MAAM;;;;CAO3C,4BAA4B,IAAyC;EACnE,MAAM,SAAS,KAAK,uBAAuB;AAC3C,OAAK,qBAAqB,IAAI,QAAQ,GAAG;AACzC,SAAO;;;;;;CAOT,OACE,WACA,aACA,OACA;AACA,MAAI,KAAK,kBAAmB;AAC5B,MAAI,KAAK,aAAc;EAEvB,MAAM,MAAM,MAAM,QAAQ,UAAU,GAAG,YAAY,CAAC,UAAU;EAC9D,MAAM,MAAM,MAAM,QAAQ,YAAY,GAAG,cAAc,CAAC,YAAY;AAEpE,OAAK,QAAQ,KAAK;GAChB,IAAI;GACJ,MAAM;GACN,OAAO,SAAS;GAChB,WAAW,KAAK,KAAK;GACtB,CAAC;;;;;;;;;;;;;CAcJ,MAAM,IAAgB,OAAgB;AACpC,MAAI,KAAK,cAAc;AACrB,OAAI;AACJ;;EAGF,MAAM,cAAc,KAAK;EACzB,MAAM,gBAAgB,KAAK;EAC3B,MAAM,cAAc,KAAK,QAAQ;AAEjC,MAAI;AACF,QAAK,oBAAoB;AACzB,QAAK,qBAAqB;AAC1B,OAAI;AAEJ,QAAK,qBAAqB;AAC1B,QAAK,gBAAgB;GAErB,MAAM,aAAa,KAAK,QAAQ;AAEhC,QAAK,QAAQ,KAAK;IAChB,IAAI,CAAC;KAAE,MAAM;KAAa,MAAM;KAAY,CAAC;IAC7C,MAAM,CAAC;KAAE,MAAM;KAAa,MAAM;KAAa,CAAC;IAChD,OAAO,SAAS;IAChB,WAAW,KAAK,KAAK;IACtB,CAAC;YACM;AACR,QAAK,oBAAoB;AACzB,QAAK,qBAAqB;;;;CAK9B,OAAO;EACL,MAAM,MAAM,KAAK,QAAQ,UAAU,KAAK;AACxC,MAAI,CAAC,IAAK;AACV,OAAK,oBAAoB;AACzB,OAAK,qBAAqB;AAC1B,MAAI;AACF,QAAK,IAAI,IAAI,IAAI,KAAK,SAAS,GAAG,KAAK,GAAG,IACxC,MAAK,YAAY,IAAI,KAAK,GAAI;AAEhC,QAAK,qBAAqB;AAC1B,QAAK,gBAAgB;AACrB,QAAK,kBAAkB;AACvB,QAAK,QAAQ,UAAU,KAAK,IAAI;YACxB;AACR,QAAK,oBAAoB;AACzB,QAAK,qBAAqB;;;;CAK9B,OAAO;EACL,MAAM,MAAM,KAAK,QAAQ,UAAU,KAAK;AACxC,MAAI,CAAC,IAAK;AACV,OAAK,oBAAoB;AACzB,OAAK,qBAAqB;AAC1B,MAAI;AACF,QAAK,MAAM,UAAU,IAAI,GACvB,MAAK,YAAY,OAAO;AAE1B,QAAK,qBAAqB;AAC1B,QAAK,gBAAgB;AACrB,QAAK,kBAAkB;AACvB,QAAK,QAAQ,UAAU,KAAK,IAAI;YACxB;AACR,QAAK,oBAAoB;AACzB,QAAK,qBAAqB;;;CAI9B,AAAQ,YAAY,QAAuB;AACzC,UAAQ,OAAO,MAAf;GACE,KAAK;AACH,SAAK,SAAS,OAAO,KAAK;AAC1B;GAEF,KAAK,eAAe;IAClB,MAAM,SAAS,KAAK,SAAS,IAAI,OAAO,GAAG;AAC3C,QAAI,QAAQ;AACV,YAAO,SAAS,IAAI,OAAO,GAAG,GAAG,OAAO,GAAG,EAAE;AAC7C,UAAK,MAAM,MAAM,KAAK,oBAAoB,QAAQ,CAChD,IAAG,QAAQ,KAAK,iBAAiB,OAAO,GAAG,CAAC;AAC9C,UAAK,gBAAgB;;AAEvB;;GAEF,KAAK,cAAc;IACjB,MAAM,QAAQ,KAAK,OAAO,IAAI,OAAO,GAAG;AACxC,QAAI,OAAO;KACT,MAAM,KAAK,OAAO,GAAG,IAAI,OAAO,KAAK;KACrC,MAAM,KAAK,OAAO,GAAG,IAAI,OAAO,KAAK;KACrC,MAAM,cAAc,KAAK;AACzB,UAAK,oBAAoB;AACzB,SAAI;AACF,WAAK,UAAU,OAAO,IAAI,GAAG;eACrB;AACR,WAAK,oBAAoB;;;AAG7B;;GAEF,KAAK,iBAAiB;IACpB,MAAM,SAAS,IAAI,OAAO,OAAO,IAAI,OAAO,MAAM;AAClD,WAAO,SAAS,IAAI,OAAO,SAAS,GAAG,OAAO,SAAS,EAAE;AACzD,SAAK,SAAS,IAAI,OAAO,IAAI,OAAO;AACpC,SAAK,MAAM,KAAK,IAAI,KAAK,KAAK,OAAO,KAAK,EAAE;AAE5C,SAAK,YAAY,OAAO;AAExB,QAAI,OAAO,aAAa,KACtB,MAAK,WAAW,OAAO,UAAU,OAAO,GAAG;AAE7C,SAAK,MAAM,MAAM,KAAK,sBAAsB,QAAQ,CAAE,IAAG,OAAO;AAChE,SAAK,gBAAgB;AACrB;;GAEF,KAAK,eAAe;IAClB,MAAM,SAAS,KAAK,SAAS,IAAI,OAAO,GAAG;AAC3C,QAAI,QAAQ;KACV,MAAM,cAAc,KAAK;AACzB,UAAK,oBAAoB;AACzB,SAAI;AACF,WAAK,WAAW,OAAO;eACf;AACR,WAAK,oBAAoB;;;AAG7B;;GAEF,KAAK,eAAe;IAClB,MAAM,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK;IAC1C,MAAM,KAAK,KAAK,QAAQ,IAAI,OAAO,GAAG;AACtC,QAAI,QAAQ,IAAI;KACd,MAAM,OAAO,IAAI,KAAK,OAAO,IAAI,KAAK,IAAI,GAAG,IAAI,OAAO,MAAM,OAAO,MAAM;AAC3E,UAAK,MAAM,IAAI,KAAK,IAAI,KAAK;AAC7B,UAAK,MAAM,KAAK,IAAI,KAAK,KAAK,KAAK,KAAK,EAAE;AAC1C,UAAK,MAAM,MAAM,KAAK,oBAAoB,QAAQ,CAAE,IAAG,KAAK;;AAE9D;;GAEF,KAAK,aAAa;IAChB,MAAM,OAAO,KAAK,MAAM,IAAI,OAAO,GAAG;AACtC,QAAI,MAAM;KACR,MAAM,cAAc,KAAK;AACzB,UAAK,oBAAoB;AACzB,SAAI;AACF,WAAK,SAAS,KAAK;eACX;AACR,WAAK,oBAAoB;;;AAG7B;;GAEF,KAAK,eAAe;IAClB,MAAM,OAAO,KAAK,MAAM,IAAI,OAAO,GAAG;AACtC,QAAI,MAAM;AACR,UAAK,OAAO,OAAO,KAAK;AACxB,UAAK,KAAK,OAAO,GAAG;AACpB,SAAI,OAAO,UACT,MAAK,YAAY,OAAO,UAAU,IAAI,KAAK,MAAM,IAAI,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC;AAEtE,UAAK,MAAM,MAAM,KAAK,oBAAoB,QAAQ,CAAE,IAAG,KAAK;;AAE9D;;GAEF,KAAK;AACH,SAAK,WAAW,OAAO,SAAS,OAAO,SAAS;AAChD;GAEF,KAAK;AACH,SAAK,gBAAgB,OAAO,SAAS,OAAO,SAAS;AACrD;GAEF,KAAK,iBAAiB;IACpB,MAAM,SAAS,KAAK,SAAS,IAAI,OAAO,SAAS;AACjD,QAAI,QAAQ;KACV,MAAM,SAAS,IAAI,OAAO,OAAO,IAAI,OAAO,IAAI,OAAO,MAAM,OAAO,KAAK;AACzE,YAAO,OAAO,IAAI,OAAO,OAAO,GAAG,OAAO,OAAO,EAAE;AACnD,UAAK,QAAQ,IAAI,OAAO,IAAI,OAAO;AACnC,YAAO,QAAQ,IAAI,OAAO,IAAI,OAAO;AACrC,UAAK,MAAM,KAAK,IAAI,KAAK,KAAK,OAAO,KAAK,EAAE;AAC5C,UAAK,MAAM,MAAM,KAAK,sBAAsB,QAAQ,CAAE,IAAG,OAAO;;AAElE;;GAEF,KAAK,eAAe;IAClB,MAAM,SAAS,KAAK,QAAQ,IAAI,OAAO,GAAG;AAC1C,QAAI,QAAQ;KACV,MAAM,cAAc,KAAK;AACzB,UAAK,oBAAoB;AACzB,SAAI;AACF,WAAK,WAAW,OAAO;eACf;AACR,WAAK,oBAAoB;;;AAG7B;;;;;CAMN,6BAA6B,IAAuC;EAClE,MAAM,SAAS,KAAK,uBAAuB;AAC3C,OAAK,sBAAsB,IAAI,QAAQ,GAAG;AAC1C,SAAO;;;CAIT,2BAA2B,IAAuC;EAChE,MAAM,SAAS,KAAK,uBAAuB;AAC3C,OAAK,oBAAoB,IAAI,QAAQ,GAAG;AACxC,SAAO;;;CAIT,2BAA2B,IAA2C;EACpE,MAAM,SAAS,KAAK,uBAAuB;AAC3C,OAAK,oBAAoB,IAAI,QAAQ,GAAG;AACxC,SAAO;;;CAIT,2BAA2B,IAAoC;EAC7D,MAAM,SAAS,KAAK,uBAAuB;AAC3C,OAAK,oBAAoB,IAAI,QAAQ,GAAG;AACxC,SAAO;;;CAIT,iBAAiB,QAAgB;AAC/B,OAAK,MAAM,MAAM,KAAK,oBAAoB,QAAQ,CAChD,KAAI;AACF,MAAG,OAAO;WACH,KAAK;AACZ,WAAQ,MAAM,IAAI;;;;CAMxB,2BAA2B,IAAkC;EAC3D,MAAM,SAAS,KAAK,uBAAuB;AAC3C,OAAK,oBAAoB,IAAI,QAAQ,GAAG;AACxC,SAAO;;;CAIT,yBAAyB,IAAkC;EACzD,MAAM,SAAS,KAAK,uBAAuB;AAC3C,OAAK,kBAAkB,IAAI,QAAQ,GAAG;AACtC,SAAO;;;CAIT,2BAA2B,IAAkC;EAC3D,MAAM,SAAS,KAAK,uBAAuB;AAC3C,OAAK,oBAAoB,IAAI,QAAQ,GAAG;AACxC,SAAO;;;CAIT,6BAA6B,IAAoC;EAC/D,MAAM,SAAS,KAAK,uBAAuB;AAC3C,OAAK,sBAAsB,IAAI,QAAQ,GAAG;AAC1C,SAAO;;;CAIT,2BAA2B,IAAoC;EAC7D,MAAM,SAAS,KAAK,uBAAuB;AAC3C,OAAK,oBAAoB,IAAI,QAAQ,GAAG;AACxC,SAAO;;;CAIT,4BAA4B,IAAmC;EAC7D,MAAM,SAAS,KAAK,uBAAuB;AAC3C,OAAK,qBAAqB,IAAI,QAAQ,GAAG;AACzC,SAAO;;;CAIT,0BAA0B,IAAmC;EAC3D,MAAM,SAAS,KAAK,uBAAuB;AAC3C,OAAK,mBAAmB,IAAI,QAAQ,GAAG;AACvC,SAAO;;;;;;CAOT,mBAAmB,QAAwB;AAezC,MAbE,KAAK,oBAAoB,OAAO,OAAO,IACvC,KAAK,kBAAkB,OAAO,OAAO,IACrC,KAAK,oBAAoB,OAAO,OAAO,IACvC,KAAK,sBAAsB,OAAO,OAAO,IACzC,KAAK,oBAAoB,OAAO,OAAO,IACvC,KAAK,oBAAoB,OAAO,OAAO,IACvC,KAAK,sBAAsB,OAAO,OAAO,IACzC,KAAK,oBAAoB,OAAO,OAAO,IACvC,KAAK,oBAAoB,OAAO,OAAO,IACvC,KAAK,qBAAqB,OAAO,OAAO,IACxC,KAAK,mBAAmB,OAAO,OAAO,IACtC,KAAK,oBAAoB,OAAO,OAAO,EAE5B;AACX,QAAK,gBAAgB,KAAK,OAAO;AACjC,UAAO;;AAET,SAAO;;;CAIT,SAAS,OAAe,IAAI;EAC1B,MAAM,QAAQ,IAAI,MAAM,KAAK,YAAY,EAAE,KAAK;AAChD,OAAK,OAAO,IAAI,MAAM,IAAI,MAAM;AAChC,OAAK,MAAM,MAAM,KAAK,qBAAqB,QAAQ,CACjD,KAAI;AACF,MAAG,MAAM;WACF,KAAK;AACZ,WAAQ,MAAM,IAAI;;AAGtB,SAAO;;;;;;;;;;CAWT,UAAU,OAAc;AACtB,MAAI,KAAK,OAAO,OAAO,MAAM,GAAG,EAAE;AAChC,OAAI,MAAM,aAAa,KACrB,MAAK,qBAAqB,MAAM,UAAU,MAAM,GAAG;AAErD,QAAK,MAAM,OAAO,MAAM,UAAU;IAChC,MAAM,SAAS,KAAK,SAAS,IAAI,IAAI;AACrC,QAAI,OAAQ,QAAO,WAAW;;AAEhC,QAAK,MAAM,OAAO,MAAM,QAAQ;IAC9B,MAAM,aAAa,KAAK,OAAO,IAAI,IAAI;AACvC,QAAI,WAAY,YAAW,WAAW;;AAGxC,QAAK,SAAS,KAAK,MAAM,GAAG;AAC5B,QAAK,MAAM,MAAM,KAAK,mBAAmB,QAAQ,CAC/C,KAAI;AACF,OAAG,MAAM;YACF,KAAK;AACZ,YAAQ,MAAM,IAAI;;AAGtB,QAAK,gBAAgB;;;;CAKzB,iBAAiB,UAAwB;EACvC,MAAM,SAAS,KAAK,SAAS,IAAI,SAAS;AAC1C,MAAI,CAAC,OAAQ,QAAO,IAAI,MAAM;EAE9B,MAAM,MAAM,OAAO,SAAS,OAAO;EACnC,IAAI,kBAAkB,OAAO;AAE7B,SAAO,oBAAoB,MAAM;GAC/B,MAAM,SAAS,KAAK,OAAO,IAAI,gBAAgB;AAC/C,OAAI,CAAC,OAAQ;AACb,OAAI,KAAK,OAAO,SAAS;AACzB,OAAI,KAAK,OAAO,SAAS;AACzB,qBAAkB,OAAO;;AAG3B,SAAO;;;CAIT,sBAAsB,SAAuB;EAC3C,MAAM,QAAQ,KAAK,OAAO,IAAI,QAAQ;AACtC,MAAI,CAAC,MAAO,QAAO,IAAI,MAAM;EAE7B,MAAM,MAAM,MAAM,SAAS,OAAO;EAClC,IAAI,kBAAkB,MAAM;AAE5B,SAAO,oBAAoB,MAAM;GAC/B,MAAM,SAAS,KAAK,OAAO,IAAI,gBAAgB;AAC/C,OAAI,CAAC,OAAQ;AACb,OAAI,KAAK,OAAO,SAAS;AACzB,OAAI,KAAK,OAAO,SAAS;AACzB,qBAAkB,OAAO;;AAG3B,SAAO;;;;;;CAOT,UAAU,OAAc,IAAY,IAAY;EAC9C,MAAM,cAAc,KAAK;AACzB,OAAK,qBAAqB;AAE1B,QAAM,SAAS,KAAK;AACpB,QAAM,SAAS,KAAK;EAEpB,MAAM,mBAAmB,MAAa;AACpC,QAAK,MAAM,OAAO,EAAE,UAAU;IAC5B,MAAM,SAAS,KAAK,SAAS,IAAI,IAAI;AACrC,QAAI,OACF,MAAK,MAAM,MAAM,KAAK,oBAAoB,QAAQ,CAChD,IAAG,QAAQ,KAAK,iBAAiB,IAAI,CAAC;;AAI5C,QAAK,MAAM,OAAO,EAAE,QAAQ;IAC1B,MAAM,aAAa,KAAK,OAAO,IAAI,IAAI;AACvC,QAAI,WAAY,iBAAgB,WAAW;;;AAI/C,MAAI;AACF,mBAAgB,MAAM;YACd;AACR,QAAK,qBAAqB;AAC1B,QAAK,gBAAgB;;;;CAKzB,WAAW,SAAiB,UAAkB;EAC5C,MAAM,QAAQ,KAAK,OAAO,IAAI,QAAQ;EACtC,MAAM,SAAS,KAAK,SAAS,IAAI,SAAS;AAC1C,MAAI,SAAS,QAAQ;AACnB,OAAI,OAAO,aAAa,KACtB,MAAK,gBAAgB,OAAO,UAAU,SAAS;AAEjD,SAAM,IAAI,SAAS;AACnB,UAAO,WAAW;AAClB,QAAK,gBAAgB;;;;CAKzB,gBAAgB,SAAiB,UAAkB;EACjD,MAAM,QAAQ,KAAK,OAAO,IAAI,QAAQ;EACtC,MAAM,SAAS,KAAK,SAAS,IAAI,SAAS;AAC1C,MAAI,SAAS,QAAQ;AACnB,SAAM,OAAO,SAAS;AACtB,UAAO,WAAW;AAClB,QAAK,gBAAgB;;;;CAKzB,gBAAgB,eAAuB,cAAsB;EAC3D,MAAM,SAAS,KAAK,OAAO,IAAI,cAAc;EAC7C,MAAM,QAAQ,KAAK,OAAO,IAAI,aAAa;AAC3C,MAAI,UAAU,SAAS,kBAAkB,cAAc;AACrD,OAAI,MAAM,aAAa,KACrB,MAAK,qBAAqB,MAAM,UAAU,aAAa;AAEzD,UAAO,SAAS,aAAa;AAC7B,SAAM,WAAW;AACjB,QAAK,gBAAgB;;;;CAKzB,qBAAqB,eAAuB,cAAsB;EAChE,MAAM,SAAS,KAAK,OAAO,IAAI,cAAc;EAC7C,MAAM,QAAQ,KAAK,OAAO,IAAI,aAAa;AAC3C,MAAI,UAAU,OAAO;AACnB,UAAO,YAAY,aAAa;AAChC,SAAM,WAAW;AACjB,QAAK,gBAAgB;;;;;;;CAQzB,iBAAiB;AACf,MAAI,KAAK,mBAAoB;AAE7B,OAAK,SAAS,OAAO;AACrB,OAAK,MAAM,UAAU,KAAK,SAAS,QAAQ,EAAE;GAC3C,MAAM,iBAAiB,KAAK,iBAAiB,OAAO,GAAG;AACvD,QAAK,SAAS,OAAO,gBAAgB,OAAO,GAAG;AAE/C,QAAK,MAAM,UAAU,OAAO,QAAQ,QAAQ,CAC1C,MAAK,SAAS,OACZ,IAAI,KAAK,eAAe,IAAI,OAAO,OAAO,GAAG,eAAe,IAAI,OAAO,OAAO,EAAE,EAChF,OAAO,GACR;;;;;;;;CAUP,UAAU,OAAU,UAAmB;EAErC,MAAM,MAAM,IAAI,OADL,YAAY,KAAK,YAAY,EACb,MAAM;AACjC,OAAK,SAAS,IAAI,IAAI,IAAI,IAAI;AAC9B,MAAI,aAAa,OACf,MAAK,MAAM,KAAK,IAAI,KAAK,KAAK,WAAW,EAAE;AAG7C,OAAK,YAAY,IAAI;AAErB,MAAI,CAAC,KAAK,kBACR,MAAK,OACH;GACE,MAAM;GACN,IAAI,IAAI;GACR,OAAO,IAAI;GACX,UAAU,EAAE,GAAG,IAAI,UAAU;GAC7B,UAAU,IAAI;GACf,EACD;GACE,MAAM;GACN,IAAI,IAAI;GACR,OAAO,IAAI;GACX,UAAU,EAAE,GAAG,IAAI,UAAU;GAC7B,UAAU,IAAI;GACf,EACD,gBACD;AAGH,OAAK,MAAM,MAAM,KAAK,sBAAsB,QAAQ,CAClD,KAAI;AACF,MAAG,IAAI;WACA,KAAK;AACZ,WAAQ,MAAM,IAAI;;AAGtB,OAAK,gBAAgB;AACrB,SAAO;;;;;;CAOT,WAAW,QAAmB;AAC5B,MAAI,KAAK,SAAS,IAAI,OAAO,GAAG,CAC9B,MAAK,YAAY;AACf,QAAK,OACH;IACE,MAAM;IACN,IAAI,OAAO;IACX,OAAO,OAAO;IACd,UAAU,EAAE,GAAG,OAAO,UAAU;IAChC,UAAU,OAAO;IAClB,EACD;IACE,MAAM;IACN,IAAI,OAAO;IACX,OAAO,OAAO;IACd,UAAU,EAAE,GAAG,OAAO,UAAU;IAChC,UAAU,OAAO;IAClB,EACD,cACD;AAED,OAAI,OAAO,aAAa,KACtB,MAAK,gBAAgB,OAAO,UAAU,OAAO,GAAG;AAGlD,QAAK,SAAS,OAAO,OAAO,GAAG;AAE/B,QAAK,MAAM,UAAU,OAAO,QAAQ,QAAQ,CAC1C,MAAK,WAAW,OAAO;AAGzB,QAAK,SAAS,KAAK,OAAO,GAAG;AAC7B,QAAK,MAAM,MAAM,KAAK,oBAAoB,QAAQ,CAChD,KAAI;AACF,OAAG,OAAO;YACH,KAAK;AACZ,YAAQ,MAAM,IAAI;;AAGtB,QAAK,gBAAgB;KACpB,cAAc;;;CAKrB,UAAU,QAAmB,MAAkB,OAAe,IAAI,UAAmB;EAEnF,MAAM,SAAS,IAAI,OADR,YAAY,KAAK,YAAY,EACV,OAAO,IAAI,MAAM,KAAK;AACpD,OAAK,QAAQ,IAAI,OAAO,IAAI,OAAO;AACnC,SAAO,QAAQ,IAAI,OAAO,IAAI,OAAO;AACrC,MAAI,aAAa,OACf,MAAK,MAAM,KAAK,IAAI,KAAK,KAAK,WAAW,EAAE;AAG7C,MAAI,CAAC,KAAK,kBACR,MAAK,OACH;GACE,MAAM;GACN,IAAI,OAAO;GACX,UAAU,OAAO;GACjB;GACA;GACA,QAAQ,EAAE,GAAG,OAAO,QAAQ;GAC7B,EACD;GACE,MAAM;GACN,IAAI,OAAO;GACX,UAAU,OAAO;GACjB;GACA;GACA,QAAQ,EAAE,GAAG,OAAO,QAAQ;GAC7B,EACD,gBACD;AAGH,OAAK,MAAM,MAAM,KAAK,sBAAsB,QAAQ,CAClD,KAAI;AACF,MAAG,OAAO;WACH,KAAK;AACZ,WAAQ,MAAM,IAAI;;AAGtB,SAAO;;;CAIT,WAAW,QAAgB;AACzB,MAAI,KAAK,QAAQ,OAAO,OAAO,GAAG,EAAE;AAClC,OAAI,CAAC,KAAK,kBACR,MAAK,OACH;IACE,MAAM;IACN,IAAI,OAAO;IACX,UAAU,OAAO;IACjB,MAAM,OAAO;IACb,MAAM,OAAO;IACb,QAAQ,EAAE,GAAG,OAAO,QAAQ;IAC7B,EACD;IACE,MAAM;IACN,IAAI,OAAO;IACX,UAAU,OAAO;IACjB,MAAM,OAAO;IACb,MAAM,OAAO;IACb,QAAQ,EAAE,GAAG,OAAO,QAAQ;IAC7B,EACD,cACD;GAEH,MAAM,SAAS,KAAK,SAAS,IAAI,OAAO,SAAS;AACjD,OAAI,OACF,QAAO,QAAQ,OAAO,OAAO,GAAG;AAGlC,QAAK,MAAM,QAAQ,KAAK,MAAM,QAAQ,CACpC,KAAI,KAAK,SAAS,OAAO,MAAM,KAAK,OAAO,OAAO,GAChD,MAAK,SAAS,KAAK;AAIvB,QAAK,SAAS,KAAK,OAAO,GAAG;AAC7B,QAAK,MAAM,MAAM,KAAK,oBAAoB,QAAQ,CAChD,KAAI;AACF,OAAG,OAAO;YACH,KAAK;AACZ,YAAQ,MAAM,IAAI;;;;;;;;CAU1B,QACE,MACA,IACA,OAAiB,SAAS,QAC1B,UACA,QAAa,EAAE,EACf;AACA,MAAI,CAAC,KAAK,QAAQ,MAAM,GAAG,CACzB,QAAO;EAGT,MAAM,OAAO,IAAI,KADN,YAAY,KAAK,YAAY,EACd,KAAK,IAAI,GAAG,IAAI,MAAM,MAAM;AACtD,OAAK,MAAM,IAAI,KAAK,IAAI,KAAK;AAC7B,MAAI,aAAa,OACf,MAAK,MAAM,KAAK,IAAI,KAAK,KAAK,WAAW,EAAE;AAG7C,MAAI,CAAC,KAAK,kBACR,MAAK,OACH;GACE,MAAM;GACN,IAAI,KAAK;GACT,MAAM,KAAK;GACX,IAAI,KAAK;GACT,MAAM,KAAK;GACX,OAAO,KAAK;GACb,EACD;GACE,MAAM;GACN,IAAI,KAAK;GACT,MAAM,KAAK;GACX,IAAI,KAAK;GACT,MAAM,KAAK;GACX,OAAO,KAAK;GACb,EACD,cACD;AAGH,MAAI,KAAK,UAAU,KACjB,MAAK,eAAe,GAAG,IAAI,KAAK,MAAM;AAGxC,OAAK,MAAM,MAAM,KAAK,oBAAoB,QAAQ,CAChD,KAAI;AACF,MAAG,KAAK;WACD,KAAK;AACZ,WAAQ,MAAM,IAAI;;AAGtB,SAAO;;;CAIT,WAAW,MAAY,QAAiB,MAAe;EACrD,MAAM,UAAU,KAAK;EACrB,MAAM,QAAQ,KAAK;EACnB,MAAM,UAAU,UAAU;EAC1B,MAAM,QAAQ,QAAQ;AAEtB,MAAI,YAAY,WAAW,UAAU,MAAO;EAE5C,MAAM,aAAa,KAAK,QAAQ,IAAI,QAAQ;EAC5C,MAAM,WAAW,KAAK,QAAQ,IAAI,MAAM;AAExC,MAAI,CAAC,cAAc,CAAC,YAAY,CAAC,KAAK,QAAQ,YAAY,SAAS,CACjE;EAGF,MAAM,eAAe,KAAK,UAAU,KAAK,OAAO;GAAE,GAAG,EAAE;GAAG,GAAG,EAAE;GAAG,EAAE;AAEpE,MAAI,CAAC,KAAK,kBACR,MAAK,OACH;GACE,MAAM;GACN,IAAI,KAAK;GACT,MAAM;IAAE,KAAK;IAAS,KAAK;IAAS;GACpC,IAAI;IAAE,KAAK;IAAO,KAAK;IAAO;GAC9B,WAAW;IAAE,KAAK;IAAc,KAAK;IAAc;GACpD,EACD;GACE,MAAM;GACN,IAAI,KAAK;GACT,MAAM;IAAE,KAAK;IAAS,KAAK;IAAS;GACpC,IAAI;IAAE,KAAK;IAAO,KAAK;IAAO;GAC9B,WAAW;IAAE,KAAK;IAAc,KAAK;IAAc;GACpD,EACD,cACD;AAGH,OAAK,OAAO;AACZ,OAAK,KAAK;AAEV,OAAK,MAAM,MAAM,KAAK,oBAAoB,QAAQ,CAChD,KAAI;AACF,MAAG,KAAK;WACD,KAAK;AACZ,WAAQ,MAAM,IAAI;;;;CAMxB,iBAAiB,MAAY,WAAmB;EAC9C,MAAM,eAAe,KAAK,UAAU,KAAK,OAAO;GAAE,GAAG,EAAE;GAAG,GAAG,EAAE;GAAG,EAAE;EACpE,MAAM,eAAe,UAAU,KAAK,OAAO;GAAE,GAAG,EAAE;GAAG,GAAG,EAAE;GAAG,EAAE;AAE/D,MAAI,CAAC,KAAK,kBACR,MAAK,OACH;GACE,MAAM;GACN,IAAI,KAAK;GACT,MAAM;IAAE,KAAK,KAAK;IAAM,KAAK,KAAK;IAAM;GACxC,IAAI;IAAE,KAAK,KAAK;IAAI,KAAK,KAAK;IAAI;GAClC,WAAW;IAAE,KAAK;IAAc,KAAK;IAAc;GACpD,EACD;GACE,MAAM;GACN,IAAI,KAAK;GACT,MAAM;IAAE,KAAK,KAAK;IAAM,KAAK,KAAK;IAAM;GACxC,IAAI;IAAE,KAAK,KAAK;IAAI,KAAK,KAAK;IAAI;GAClC,WAAW;IAAE,KAAK;IAAc,KAAK;IAAc;GACpD,EACD,sBACD;AAGH,OAAK,YAAY,UAAU,KAAK,MAAM,EAAE,OAAO,CAAC;AAEhD,OAAK,MAAM,MAAM,KAAK,oBAAoB,QAAQ,CAChD,KAAI;AACF,MAAG,KAAK;WACD,KAAK;AACZ,WAAQ,MAAM,IAAI;;;;;;;;CAUxB,QAAQ,MAAc,IAAY;AAChC,MAAI,KAAK,OAAO,GAAG,GAAI,QAAO;AAC9B,MAAI,KAAK,aAAa,GAAG,SAAU,QAAO;AAC1C,MAAI,KAAK,SAAS,GAAG,KAAM,QAAO;AAClC,OAAK,MAAM,QAAQ,KAAK,MAAM,QAAQ,CACpC,KACG,KAAK,SAAS,KAAK,MAAM,KAAK,OAAO,GAAG,MACxC,KAAK,SAAS,GAAG,MAAM,KAAK,OAAO,KAAK,GAEzC,QAAO;AAIX,MAAI,KAAK,YAAY,MAAM,GAAG,CAC5B,QAAO;AAGT,SAAO;;;CAIT,YAAY,MAAc,IAAqB;EAC7C,MAAM,0BAAU,IAAI,KAAa;EACjC,MAAM,QAAQ,CAAC,GAAG,SAAS;AAE3B,SAAO,MAAM,SAAS,GAAG;GACvB,MAAM,kBAAkB,MAAM,KAAK;AACnC,OAAI,oBAAoB,KAAK,SAAU,QAAO;AAC9C,OAAI,QAAQ,IAAI,gBAAgB,CAAE;AAClC,WAAQ,IAAI,gBAAgB;GAE5B,MAAM,SAAS,KAAK,SAAS,IAAI,gBAAgB;AACjD,OAAI,CAAC,OAAQ;AAEb,QAAK,MAAM,UAAU,OAAO,QAAQ,QAAQ,CAC1C,KAAI,OAAO,SAAS,WAAW,QAC7B;SAAK,MAAM,QAAQ,KAAK,MAAM,QAAQ,CACpC,KAAI,KAAK,SAAS,OAAO,IAAI;KAC3B,MAAM,eAAe,KAAK,QAAQ,IAAI,KAAK,GAAG;AAC9C,SAAI,aACF,OAAM,KAAK,aAAa,SAAS;;;;AAQ7C,SAAO;;;CAIT,SAAS,MAAY;AACnB,MAAI,KAAK,MAAM,OAAO,KAAK,GAAG,EAAE;AAC9B,OAAI,CAAC,KAAK,kBACR,MAAK,OACH;IACE,MAAM;IACN,IAAI,KAAK;IACT,MAAM,KAAK;IACX,IAAI,KAAK;IACT,MAAM,KAAK;IACX,OAAO,KAAK;IACb,EACD;IACE,MAAM;IACN,IAAI,KAAK;IACT,MAAM,KAAK;IACX,IAAI,KAAK;IACT,MAAM,KAAK;IACX,OAAO,KAAK;IACb,EACD,YACD;AAEH,QAAK,SAAS,KAAK,KAAK,GAAG;AAC3B,QAAK,MAAM,MAAM,KAAK,kBAAkB,QAAQ,CAC9C,KAAI;AACF,OAAG,KAAK;YACD,KAAK;AACZ,YAAQ,MAAM,IAAI;;;;;CAO1B,SAAS;AACP,SAAO;GACL,UAAU,MAAM,KAAK,KAAK,SAAS,QAAQ,CAAC,CAAC,KAAK,OAAO;IACvD,IAAI,EAAE;IACN,UAAU;KAAE,GAAG,EAAE,SAAS;KAAG,GAAG,EAAE,SAAS;KAAG;IAC9C,OAAO,EAAE;IACT,UAAU,EAAE;IACZ,SAAS,MAAM,KAAK,EAAE,QAAQ,QAAQ,CAAC,CAAC,KAAK,OAAO;KAClD,IAAI,EAAE;KACN,MAAM,EAAE;KACR,MAAM,EAAE;KACR,QAAQ;MAAE,GAAG,EAAE,OAAO;MAAG,GAAG,EAAE,OAAO;MAAG;KACzC,EAAE;IACJ,EAAE;GACH,OAAO,MAAM,KAAK,KAAK,MAAM,QAAQ,CAAC,CAAC,KAAK,OAAO;IACjD,IAAI,EAAE;IACN,MAAM,EAAE;IACR,IAAI,EAAE;IACN,MAAM,EAAE;IACR,WAAW,EAAE,UAAU,KAAK,OAAO;KAAE,GAAG,EAAE;KAAG,GAAG,EAAE;KAAG,EAAE;IACvD,OAAO,EAAE;IACV,EAAE;GACH,QAAQ,MAAM,KAAK,KAAK,OAAO,QAAQ,CAAC,CAAC,KAAK,OAAO;IACnD,IAAI,EAAE;IACN,MAAM,EAAE;IACR,UAAU,MAAM,KAAK,EAAE,SAAS;IAChC,QAAQ,MAAM,KAAK,EAAE,OAAO;IAC5B,UAAU;KAAE,GAAG,EAAE,SAAS;KAAG,GAAG,EAAE,SAAS;KAAG;IAC9C,UAAU,EAAE;IACb,EAAE;GACJ;;;;;;CAOH,SAAS,MAAW;AAClB,OAAK,SAAS,OAAO;AACrB,OAAK,MAAM,OAAO;AAClB,OAAK,QAAQ,OAAO;AACpB,OAAK,OAAO,OAAO;AACnB,OAAK,MAAM;AACX,OAAK,MAAM;AACX,OAAK,MAAM;AACX,OAAK,MAAM;AACX,OAAK,WAAW,EAAE;AAClB,OAAK,WAAW,EAAE;AAClB,OAAK,WAAW,EAAE;AAClB,OAAK,WAAW,EAAE;AAElB,OAAK,MAAM,SAAS,KAAK,UAAU;GACjC,MAAM,SAAS,IAAI,OAAO,MAAM,IAAI,MAAM,MAAM;AAChD,UAAO,SAAS,IAAI,MAAM,SAAS,GAAG,MAAM,SAAS,EAAE;AACvD,UAAO,WAAW,MAAM;AACxB,QAAK,SAAS,IAAI,OAAO,IAAI,OAAO;AACpC,QAAK,MAAM,KAAK,IAAI,KAAK,KAAK,OAAO,KAAK,EAAE;AAE5C,QAAK,YAAY,OAAO;AAExB,QAAK,MAAM,SAAS,MAAM,SAAS;IACjC,MAAM,SAAS,IAAI,OAAO,MAAM,IAAI,OAAO,IAAI,MAAM,MAAM,MAAM,KAAK;AACtE,WAAO,OAAO,IAAI,MAAM,OAAO,GAAG,MAAM,OAAO,EAAE;AACjD,SAAK,QAAQ,IAAI,OAAO,IAAI,OAAO;AACnC,WAAO,QAAQ,IAAI,OAAO,IAAI,OAAO;AACrC,SAAK,MAAM,KAAK,IAAI,KAAK,KAAK,OAAO,KAAK,EAAE;;;AAIhD,OAAK,MAAM,SAAS,KAAK,OAAO;GAC9B,MAAM,OAAO,IAAI,KAAK,MAAM,IAAI,MAAM,MAAM,MAAM,IAAI,MAAM,MAAM,MAAM,MAAM;AAC9E,OAAI,MAAM,UACR,MAAK,YAAY,MAAM,UAAU,KAAK,MAAW,IAAI,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC;AAEtE,QAAK,MAAM,IAAI,KAAK,IAAI,KAAK;AAC7B,QAAK,MAAM,KAAK,IAAI,KAAK,KAAK,KAAK,KAAK,EAAE;;AAG5C,MAAI,KAAK,OACP,MAAK,MAAM,SAAS,KAAK,QAAQ;GAC/B,MAAM,QAAQ,IAAI,MAAM,MAAM,IAAI,MAAM,KAAK;AAC7C,SAAM,SAAS,IAAI,MAAM,SAAS,GAAG,MAAM,SAAS,EAAE;AACtD,SAAM,WAAW,MAAM;AACvB,QAAK,MAAM,OAAO,MAAM,SACtB,OAAM,IAAI,IAAI;AAEhB,OAAI,MAAM,OACR,MAAK,MAAM,OAAO,MAAM,OACtB,OAAM,SAAS,IAAI;AAGvB,QAAK,OAAO,IAAI,MAAM,IAAI,MAAM;AAChC,QAAK,MAAM,KAAK,IAAI,KAAK,KAAK,MAAM,KAAK,EAAE;;AAG/C,OAAK,gBAAgB"}
|
package/dist/core/elements.d.ts
CHANGED
|
@@ -1,70 +1,133 @@
|
|
|
1
1
|
//#region src/core/elements.d.ts
|
|
2
|
+
/** Simple 2D Vector class for coordinates and offsets. */
|
|
2
3
|
declare class Vec2 {
|
|
3
4
|
x: number;
|
|
4
5
|
y: number;
|
|
5
6
|
constructor(x?: number, y?: number);
|
|
7
|
+
/** Sets the x and y components. Returns this instance for chaining. */
|
|
6
8
|
set(x: number, y: number): this;
|
|
9
|
+
/** Copies values from another Vec2. Returns this instance for chaining. */
|
|
7
10
|
copy(other: Vec2): this;
|
|
11
|
+
/** Returns a new Vec2 with the same x and y values. */
|
|
8
12
|
clone(): Vec2;
|
|
9
13
|
}
|
|
14
|
+
/** Defines the direction of data flow for a socket. */
|
|
10
15
|
declare enum SocketKind {
|
|
16
|
+
/** Accepts incoming data flow from a link. */
|
|
11
17
|
INPUT = "INPUT",
|
|
18
|
+
/** Emits outgoing data flow into a link. */
|
|
12
19
|
OUTPUT = "OUTPUT"
|
|
13
20
|
}
|
|
14
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* A connection point on an entity.
|
|
23
|
+
* Sockets manage data flow values and their relative offset from the node's center.
|
|
24
|
+
*/
|
|
15
25
|
declare class Socket {
|
|
16
26
|
#private;
|
|
27
|
+
/** The ID of the entity this socket belongs to. */
|
|
17
28
|
entityId: number;
|
|
29
|
+
/** Whether this socket is an INPUT or OUTPUT. */
|
|
18
30
|
kind: SocketKind;
|
|
31
|
+
/** A unique name for the socket within the entity (e.g., 'exec', 'value'). */
|
|
19
32
|
name: string;
|
|
33
|
+
/** The relative offset of the socket center from the entity's position center. */
|
|
20
34
|
offset: Vec2;
|
|
35
|
+
/** The current value held by this socket, used for reactive data flow. */
|
|
21
36
|
value: any;
|
|
22
37
|
constructor(id: number, entityId: number, kind: SocketKind, name?: string);
|
|
38
|
+
/** Unique identifier for the socket. */
|
|
23
39
|
get id(): number;
|
|
24
40
|
}
|
|
25
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* A primary node element in the graph.
|
|
43
|
+
*
|
|
44
|
+
* Entities have a position, custom inner data, and a collection of sockets.
|
|
45
|
+
* @template T The type of custom data stored in the `inner` property.
|
|
46
|
+
*/
|
|
26
47
|
declare class Entity<T = any> {
|
|
27
48
|
#private;
|
|
49
|
+
/** Custom data associated with the node. */
|
|
28
50
|
inner: T;
|
|
51
|
+
/** The local position of the entity (relative to its parent group if applicable). */
|
|
29
52
|
position: Vec2;
|
|
53
|
+
/** Collection of sockets attached to this entity. */
|
|
30
54
|
sockets: Map<number, Socket>;
|
|
55
|
+
/** The ID of the parent group, or null if it's at the root. */
|
|
31
56
|
parentId: number | null;
|
|
32
57
|
constructor(id: number, inner: T);
|
|
58
|
+
/** Updates the custom data for this entity. */
|
|
33
59
|
setInner(newInner: T): void;
|
|
60
|
+
/** Unique identifier for the entity. */
|
|
34
61
|
get id(): number;
|
|
62
|
+
/**
|
|
63
|
+
* Updates the entity's local position and triggers internal move listeners.
|
|
64
|
+
* **Note:** This is usually called by the Context engine.
|
|
65
|
+
*/
|
|
35
66
|
move(x: number, y: number): void;
|
|
67
|
+
/**
|
|
68
|
+
* Internal subscription for position changes.
|
|
69
|
+
* Used by the Context to keep the QuadTree synchronized.
|
|
70
|
+
*/
|
|
36
71
|
onMove(cb: (pos: Vec2) => void): () => void;
|
|
37
72
|
}
|
|
38
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* A hierarchical container for entities and other groups.
|
|
75
|
+
* Groups allow for organized topology and relative coordinate systems.
|
|
76
|
+
*/
|
|
39
77
|
declare class Group {
|
|
40
78
|
#private;
|
|
79
|
+
/** Human-readable label for the group. */
|
|
41
80
|
name: string;
|
|
81
|
+
/** Set of entity IDs currently inside this group. */
|
|
42
82
|
entities: Set<number>;
|
|
83
|
+
/** Set of nested group IDs currently inside this group. */
|
|
43
84
|
groups: Set<number>;
|
|
85
|
+
/** The local position of the group (relative to its parent group if applicable). */
|
|
44
86
|
position: Vec2;
|
|
87
|
+
/** The ID of the parent group, or null if it's at the root. */
|
|
45
88
|
parentId: number | null;
|
|
46
89
|
constructor(id: number, name?: string);
|
|
90
|
+
/** Unique identifier for the group. */
|
|
47
91
|
get id(): number;
|
|
92
|
+
/** Internal: Adds an entity ID to the group set. */
|
|
48
93
|
add(entityId: number): void;
|
|
94
|
+
/** Internal: Removes an entity ID from the group set. */
|
|
49
95
|
remove(entityId: number): void;
|
|
96
|
+
/** Internal: Adds a group ID to the nested groups set. */
|
|
50
97
|
addGroup(groupId: number): void;
|
|
98
|
+
/** Internal: Removes a group ID from the nested groups set. */
|
|
51
99
|
removeGroup(groupId: number): void;
|
|
52
100
|
}
|
|
101
|
+
/** Visual routing style for a link. */
|
|
53
102
|
declare enum LinkKind {
|
|
103
|
+
/** Straight line between sockets. */
|
|
54
104
|
LINE = "LINE",
|
|
105
|
+
/** Orthogonal steps with sharp corners. */
|
|
55
106
|
STEP = "STEP",
|
|
107
|
+
/** Orthogonal steps with rounded corners. */
|
|
56
108
|
SMOOTH_STEP = "SMOOTH_STEP",
|
|
109
|
+
/** Smooth cubic bezier curve. */
|
|
57
110
|
BEZIER = "BEZIER"
|
|
58
111
|
}
|
|
59
|
-
/**
|
|
112
|
+
/**
|
|
113
|
+
* A connection between two sockets.
|
|
114
|
+
* Links define the topology of the graph and the path for data flow.
|
|
115
|
+
* @template T Type of optional custom data associated with the link.
|
|
116
|
+
*/
|
|
60
117
|
declare class Link<T = any> {
|
|
61
118
|
#private;
|
|
119
|
+
/** Source Socket ID. Must be an OUTPUT. */
|
|
62
120
|
from: number;
|
|
121
|
+
/** Target Socket ID. Must be an INPUT. */
|
|
63
122
|
to: number;
|
|
123
|
+
/** Visual style for the link. */
|
|
64
124
|
kind: LinkKind;
|
|
125
|
+
/** Custom intermediate points for routing the link path. */
|
|
65
126
|
waypoints: Vec2[];
|
|
127
|
+
/** Optional custom data for the link (e.g., labels, types). */
|
|
66
128
|
inner: T;
|
|
67
129
|
constructor(id: number, from: number, to: number, kind?: LinkKind, inner?: T);
|
|
130
|
+
/** Unique identifier for the link. */
|
|
68
131
|
get id(): number;
|
|
69
132
|
}
|
|
70
133
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elements.d.ts","names":[],"sources":["../../src/core/elements.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"elements.d.ts","names":[],"sources":["../../src/core/elements.ts"],"mappings":";;cACa,IAAA;EAEF,CAAA;EACA,CAAA;cADA,CAAA,WACA,CAAA;EADA;EAKT,GAAA,CAAI,CAAA,UAAW,CAAA;;EAOf,IAAA,CAAK,KAAA,EAAO,IAAA;EAXH;EAkBT,KAAA,CAAA,GAAK,IAAA;AAAA;;aAMK,UAAA;EAbE;EAeZ,KAAA;EARA;EAUA,MAAA;AAAA;;AAJF;;;cAWa,MAAA;EAAA;EAAA;EAGX,QAAA;;EAEA,IAAA,EAAM,UAAA;EAIE;EAFR,IAAA;EAM0D;EAJ1D,MAAA,EAAQ,IAAA;;EAER,KAAA;cAEY,EAAA,UAAY,QAAA,UAAkB,IAAA,EAAM,UAAA,EAAY,IAAA;EARtD;EAAA,IAgBF,EAAA,CAAA;AAAA;;;;;;;cAWO,MAAA;EAAA;EAXP;EAaJ,KAAA,EAAO,CAAA;EAbD;EAeN,QAAA,EAAU,IAAA;EAJO;EAMjB,OAAA,EAAS,GAAA,SAAY,MAAA;EAJd;EAQP,QAAA;cAEY,EAAA,UAAY,KAAA,EAAO,CAAA;EANtB;EAYT,QAAA,CAAS,QAAA,EAAU,CAAA;EAAA;EAAA,IAKf,EAAA,CAAA;EAmBiB;;;;EAXrB,IAAA,CAAK,CAAA,UAAW,CAAA;EA7BT;;;;EAwCP,MAAA,CAAO,EAAA,GAAK,GAAA,EAAK,IAAA;AAAA;;;;;cAYN,KAAA;EAAA;EApCQ;EAuCnB,IAAA;EAlCI;EAoCJ,QAAA,EAAU,GAAA;EA5BL;EA8BL,MAAA,EAAQ,GAAA;EAnBR;EAqBA,QAAA,EAAU,IAAA;EArBE;EAuBZ,QAAA;cAEY,EAAA,UAAY,IAAA;EAzBM;EAAA,IA+B1B,EAAA,CAAA;EAnBY;EAwBhB,GAAA,CAAI,QAAA;EAnBM;EAwBV,MAAA,CAAO,QAAA;EApBG;EAyBV,QAAA,CAAS,OAAA;EAzBK;EA8Bd,WAAA,CAAY,OAAA;AAAA;;aAMF,QAAA;EAtCV;EAwCA,IAAA;EAtCA;EAwCA,IAAA;EAtCA;EAwCA,WAAA;EAtCY;EAwCZ,MAAA;AAAA;;;;;;cAQW,IAAA;EAAA;EAtBC;EAyBZ,IAAA;EAzB2B;EA2B3B,EAAA;EArBkB;EAuBlB,IAAA,EAAM,QAAA;EAvBY;EAyBlB,SAAA,EAAW,IAAA;EArBX;EAuBA,KAAA,EAAO,CAAA;cAEK,EAAA,UAAY,IAAA,UAAc,EAAA,UAAY,IAAA,GAAI,QAAA,EAAkB,KAAA,GAAO,CAAA;EArBzE;EAAA,IA8BF,EAAA,CAAA;AAAA"}
|
package/dist/core/elements.js
CHANGED
|
@@ -1,35 +1,50 @@
|
|
|
1
1
|
//#region src/core/elements.ts
|
|
2
|
+
/** Simple 2D Vector class for coordinates and offsets. */
|
|
2
3
|
var Vec2 = class Vec2 {
|
|
3
4
|
constructor(x = 0, y = 0) {
|
|
4
5
|
this.x = x;
|
|
5
6
|
this.y = y;
|
|
6
7
|
}
|
|
8
|
+
/** Sets the x and y components. Returns this instance for chaining. */
|
|
7
9
|
set(x, y) {
|
|
8
10
|
this.x = x;
|
|
9
11
|
this.y = y;
|
|
10
12
|
return this;
|
|
11
13
|
}
|
|
14
|
+
/** Copies values from another Vec2. Returns this instance for chaining. */
|
|
12
15
|
copy(other) {
|
|
13
16
|
this.x = other.x;
|
|
14
17
|
this.y = other.y;
|
|
15
18
|
return this;
|
|
16
19
|
}
|
|
20
|
+
/** Returns a new Vec2 with the same x and y values. */
|
|
17
21
|
clone() {
|
|
18
22
|
return new Vec2(this.x, this.y);
|
|
19
23
|
}
|
|
20
24
|
};
|
|
25
|
+
/** Defines the direction of data flow for a socket. */
|
|
21
26
|
let SocketKind = /* @__PURE__ */ function(SocketKind) {
|
|
27
|
+
/** Accepts incoming data flow from a link. */
|
|
22
28
|
SocketKind["INPUT"] = "INPUT";
|
|
29
|
+
/** Emits outgoing data flow into a link. */
|
|
23
30
|
SocketKind["OUTPUT"] = "OUTPUT";
|
|
24
31
|
return SocketKind;
|
|
25
32
|
}({});
|
|
26
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* A connection point on an entity.
|
|
35
|
+
* Sockets manage data flow values and their relative offset from the node's center.
|
|
36
|
+
*/
|
|
27
37
|
var Socket = class {
|
|
28
38
|
#id;
|
|
39
|
+
/** The ID of the entity this socket belongs to. */
|
|
29
40
|
entityId;
|
|
41
|
+
/** Whether this socket is an INPUT or OUTPUT. */
|
|
30
42
|
kind;
|
|
43
|
+
/** A unique name for the socket within the entity (e.g., 'exec', 'value'). */
|
|
31
44
|
name;
|
|
45
|
+
/** The relative offset of the socket center from the entity's position center. */
|
|
32
46
|
offset = new Vec2();
|
|
47
|
+
/** The current value held by this socket, used for reactive data flow. */
|
|
33
48
|
value = null;
|
|
34
49
|
constructor(id, entityId, kind, name = "") {
|
|
35
50
|
this.#id = id;
|
|
@@ -37,32 +52,52 @@ var Socket = class {
|
|
|
37
52
|
this.kind = kind;
|
|
38
53
|
this.name = name;
|
|
39
54
|
}
|
|
55
|
+
/** Unique identifier for the socket. */
|
|
40
56
|
get id() {
|
|
41
57
|
return this.#id;
|
|
42
58
|
}
|
|
43
59
|
};
|
|
44
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* A primary node element in the graph.
|
|
62
|
+
*
|
|
63
|
+
* Entities have a position, custom inner data, and a collection of sockets.
|
|
64
|
+
* @template T The type of custom data stored in the `inner` property.
|
|
65
|
+
*/
|
|
45
66
|
var Entity = class {
|
|
67
|
+
/** Custom data associated with the node. */
|
|
46
68
|
inner;
|
|
69
|
+
/** The local position of the entity (relative to its parent group if applicable). */
|
|
47
70
|
position = new Vec2();
|
|
71
|
+
/** Collection of sockets attached to this entity. */
|
|
48
72
|
sockets = /* @__PURE__ */ new Map();
|
|
49
73
|
#id;
|
|
50
74
|
#onMove = [];
|
|
75
|
+
/** The ID of the parent group, or null if it's at the root. */
|
|
51
76
|
parentId = null;
|
|
52
77
|
constructor(id, inner) {
|
|
53
78
|
this.#id = id;
|
|
54
79
|
this.inner = inner;
|
|
55
80
|
}
|
|
81
|
+
/** Updates the custom data for this entity. */
|
|
56
82
|
setInner(newInner) {
|
|
57
83
|
this.inner = newInner;
|
|
58
84
|
}
|
|
85
|
+
/** Unique identifier for the entity. */
|
|
59
86
|
get id() {
|
|
60
87
|
return this.#id;
|
|
61
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Updates the entity's local position and triggers internal move listeners.
|
|
91
|
+
* **Note:** This is usually called by the Context engine.
|
|
92
|
+
*/
|
|
62
93
|
move(x, y) {
|
|
63
94
|
this.position.set(x, y);
|
|
64
95
|
for (const cb of this.#onMove) cb(this.position);
|
|
65
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Internal subscription for position changes.
|
|
99
|
+
* Used by the Context to keep the QuadTree synchronized.
|
|
100
|
+
*/
|
|
66
101
|
onMove(cb) {
|
|
67
102
|
this.#onMove.push(cb);
|
|
68
103
|
return () => {
|
|
@@ -70,48 +105,75 @@ var Entity = class {
|
|
|
70
105
|
};
|
|
71
106
|
}
|
|
72
107
|
};
|
|
73
|
-
/**
|
|
108
|
+
/**
|
|
109
|
+
* A hierarchical container for entities and other groups.
|
|
110
|
+
* Groups allow for organized topology and relative coordinate systems.
|
|
111
|
+
*/
|
|
74
112
|
var Group = class {
|
|
75
113
|
#id;
|
|
114
|
+
/** Human-readable label for the group. */
|
|
76
115
|
name;
|
|
116
|
+
/** Set of entity IDs currently inside this group. */
|
|
77
117
|
entities = /* @__PURE__ */ new Set();
|
|
118
|
+
/** Set of nested group IDs currently inside this group. */
|
|
78
119
|
groups = /* @__PURE__ */ new Set();
|
|
120
|
+
/** The local position of the group (relative to its parent group if applicable). */
|
|
79
121
|
position = new Vec2();
|
|
122
|
+
/** The ID of the parent group, or null if it's at the root. */
|
|
80
123
|
parentId = null;
|
|
81
124
|
constructor(id, name = "") {
|
|
82
125
|
this.#id = id;
|
|
83
126
|
this.name = name;
|
|
84
127
|
}
|
|
128
|
+
/** Unique identifier for the group. */
|
|
85
129
|
get id() {
|
|
86
130
|
return this.#id;
|
|
87
131
|
}
|
|
132
|
+
/** Internal: Adds an entity ID to the group set. */
|
|
88
133
|
add(entityId) {
|
|
89
134
|
this.entities.add(entityId);
|
|
90
135
|
}
|
|
136
|
+
/** Internal: Removes an entity ID from the group set. */
|
|
91
137
|
remove(entityId) {
|
|
92
138
|
this.entities.delete(entityId);
|
|
93
139
|
}
|
|
140
|
+
/** Internal: Adds a group ID to the nested groups set. */
|
|
94
141
|
addGroup(groupId) {
|
|
95
142
|
this.groups.add(groupId);
|
|
96
143
|
}
|
|
144
|
+
/** Internal: Removes a group ID from the nested groups set. */
|
|
97
145
|
removeGroup(groupId) {
|
|
98
146
|
this.groups.delete(groupId);
|
|
99
147
|
}
|
|
100
148
|
};
|
|
149
|
+
/** Visual routing style for a link. */
|
|
101
150
|
let LinkKind = /* @__PURE__ */ function(LinkKind) {
|
|
151
|
+
/** Straight line between sockets. */
|
|
102
152
|
LinkKind["LINE"] = "LINE";
|
|
153
|
+
/** Orthogonal steps with sharp corners. */
|
|
103
154
|
LinkKind["STEP"] = "STEP";
|
|
155
|
+
/** Orthogonal steps with rounded corners. */
|
|
104
156
|
LinkKind["SMOOTH_STEP"] = "SMOOTH_STEP";
|
|
157
|
+
/** Smooth cubic bezier curve. */
|
|
105
158
|
LinkKind["BEZIER"] = "BEZIER";
|
|
106
159
|
return LinkKind;
|
|
107
160
|
}({});
|
|
108
|
-
/**
|
|
161
|
+
/**
|
|
162
|
+
* A connection between two sockets.
|
|
163
|
+
* Links define the topology of the graph and the path for data flow.
|
|
164
|
+
* @template T Type of optional custom data associated with the link.
|
|
165
|
+
*/
|
|
109
166
|
var Link = class {
|
|
110
167
|
#id;
|
|
168
|
+
/** Source Socket ID. Must be an OUTPUT. */
|
|
111
169
|
from;
|
|
170
|
+
/** Target Socket ID. Must be an INPUT. */
|
|
112
171
|
to;
|
|
172
|
+
/** Visual style for the link. */
|
|
113
173
|
kind;
|
|
174
|
+
/** Custom intermediate points for routing the link path. */
|
|
114
175
|
waypoints = [];
|
|
176
|
+
/** Optional custom data for the link (e.g., labels, types). */
|
|
115
177
|
inner;
|
|
116
178
|
constructor(id, from, to, kind = LinkKind.LINE, inner = {}) {
|
|
117
179
|
this.#id = id;
|
|
@@ -120,6 +182,7 @@ var Link = class {
|
|
|
120
182
|
this.kind = kind;
|
|
121
183
|
this.inner = inner;
|
|
122
184
|
}
|
|
185
|
+
/** Unique identifier for the link. */
|
|
123
186
|
get id() {
|
|
124
187
|
return this.#id;
|
|
125
188
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"elements.js","names":["#id","#onMove"],"sources":["../../src/core/elements.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"elements.js","names":["#id","#onMove"],"sources":["../../src/core/elements.ts"],"sourcesContent":["/** Simple 2D Vector class for coordinates and offsets. */\nexport class Vec2 {\n constructor(\n public x: number = 0,\n public y: number = 0\n ) {}\n\n /** Sets the x and y components. Returns this instance for chaining. */\n set(x: number, y: number) {\n this.x = x;\n this.y = y;\n return this;\n }\n\n /** Copies values from another Vec2. Returns this instance for chaining. */\n copy(other: Vec2) {\n this.x = other.x;\n this.y = other.y;\n return this;\n }\n\n /** Returns a new Vec2 with the same x and y values. */\n clone() {\n return new Vec2(this.x, this.y);\n }\n}\n\n/** Defines the direction of data flow for a socket. */\nexport enum SocketKind {\n /** Accepts incoming data flow from a link. */\n INPUT = 'INPUT',\n /** Emits outgoing data flow into a link. */\n OUTPUT = 'OUTPUT'\n}\n\n/**\n * A connection point on an entity.\n * Sockets manage data flow values and their relative offset from the node's center.\n */\nexport class Socket {\n #id: number;\n /** The ID of the entity this socket belongs to. */\n entityId: number;\n /** Whether this socket is an INPUT or OUTPUT. */\n kind: SocketKind;\n /** A unique name for the socket within the entity (e.g., 'exec', 'value'). */\n name: string;\n /** The relative offset of the socket center from the entity's position center. */\n offset: Vec2 = new Vec2();\n /** The current value held by this socket, used for reactive data flow. */\n value: any = null;\n\n constructor(id: number, entityId: number, kind: SocketKind, name: string = '') {\n this.#id = id;\n this.entityId = entityId;\n this.kind = kind;\n this.name = name;\n }\n\n /** Unique identifier for the socket. */\n get id() {\n return this.#id;\n }\n}\n\n/**\n * A primary node element in the graph.\n *\n * Entities have a position, custom inner data, and a collection of sockets.\n * @template T The type of custom data stored in the `inner` property.\n */\nexport class Entity<T = any> {\n /** Custom data associated with the node. */\n inner: T;\n /** The local position of the entity (relative to its parent group if applicable). */\n position: Vec2 = new Vec2();\n /** Collection of sockets attached to this entity. */\n sockets: Map<number, Socket> = new Map();\n #id: number;\n #onMove: ((pos: Vec2) => void)[] = [];\n /** The ID of the parent group, or null if it's at the root. */\n parentId: number | null = null;\n\n constructor(id: number, inner: T) {\n this.#id = id;\n this.inner = inner;\n }\n\n /** Updates the custom data for this entity. */\n setInner(newInner: T) {\n this.inner = newInner;\n }\n\n /** Unique identifier for the entity. */\n get id() {\n return this.#id;\n }\n\n /**\n * Updates the entity's local position and triggers internal move listeners.\n * **Note:** This is usually called by the Context engine.\n */\n move(x: number, y: number) {\n this.position.set(x, y);\n for (const cb of this.#onMove) {\n cb(this.position);\n }\n }\n\n /**\n * Internal subscription for position changes.\n * Used by the Context to keep the QuadTree synchronized.\n */\n onMove(cb: (pos: Vec2) => void) {\n this.#onMove.push(cb);\n return () => {\n this.#onMove = this.#onMove.filter((c) => c !== cb);\n };\n }\n}\n\n/**\n * A hierarchical container for entities and other groups.\n * Groups allow for organized topology and relative coordinate systems.\n */\nexport class Group {\n #id: number;\n /** Human-readable label for the group. */\n name: string;\n /** Set of entity IDs currently inside this group. */\n entities: Set<number> = new Set();\n /** Set of nested group IDs currently inside this group. */\n groups: Set<number> = new Set();\n /** The local position of the group (relative to its parent group if applicable). */\n position: Vec2 = new Vec2();\n /** The ID of the parent group, or null if it's at the root. */\n parentId: number | null = null;\n\n constructor(id: number, name: string = '') {\n this.#id = id;\n this.name = name;\n }\n\n /** Unique identifier for the group. */\n get id() {\n return this.#id;\n }\n\n /** Internal: Adds an entity ID to the group set. */\n add(entityId: number) {\n this.entities.add(entityId);\n }\n\n /** Internal: Removes an entity ID from the group set. */\n remove(entityId: number) {\n this.entities.delete(entityId);\n }\n\n /** Internal: Adds a group ID to the nested groups set. */\n addGroup(groupId: number) {\n this.groups.add(groupId);\n }\n\n /** Internal: Removes a group ID from the nested groups set. */\n removeGroup(groupId: number) {\n this.groups.delete(groupId);\n }\n}\n\n/** Visual routing style for a link. */\nexport enum LinkKind {\n /** Straight line between sockets. */\n LINE = 'LINE',\n /** Orthogonal steps with sharp corners. */\n STEP = 'STEP',\n /** Orthogonal steps with rounded corners. */\n SMOOTH_STEP = 'SMOOTH_STEP',\n /** Smooth cubic bezier curve. */\n BEZIER = 'BEZIER'\n}\n\n/**\n * A connection between two sockets.\n * Links define the topology of the graph and the path for data flow.\n * @template T Type of optional custom data associated with the link.\n */\nexport class Link<T = any> {\n #id: number;\n /** Source Socket ID. Must be an OUTPUT. */\n from: number;\n /** Target Socket ID. Must be an INPUT. */\n to: number;\n /** Visual style for the link. */\n kind: LinkKind;\n /** Custom intermediate points for routing the link path. */\n waypoints: Vec2[] = [];\n /** Optional custom data for the link (e.g., labels, types). */\n inner: T;\n\n constructor(id: number, from: number, to: number, kind = LinkKind.LINE, inner: T = {} as T) {\n this.#id = id;\n this.from = from;\n this.to = to;\n this.kind = kind;\n this.inner = inner;\n }\n\n /** Unique identifier for the link. */\n get id() {\n return this.#id;\n }\n}\n"],"mappings":";;AACA,IAAa,OAAb,MAAa,KAAK;CAChB,YACE,AAAO,IAAY,GACnB,AAAO,IAAY,GACnB;EAFO;EACA;;;CAIT,IAAI,GAAW,GAAW;AACxB,OAAK,IAAI;AACT,OAAK,IAAI;AACT,SAAO;;;CAIT,KAAK,OAAa;AAChB,OAAK,IAAI,MAAM;AACf,OAAK,IAAI,MAAM;AACf,SAAO;;;CAIT,QAAQ;AACN,SAAO,IAAI,KAAK,KAAK,GAAG,KAAK,EAAE;;;;AAKnC,IAAY,kDAAL;;AAEL;;AAEA;;;;;;;AAOF,IAAa,SAAb,MAAoB;CAClB;;CAEA;;CAEA;;CAEA;;CAEA,SAAe,IAAI,MAAM;;CAEzB,QAAa;CAEb,YAAY,IAAY,UAAkB,MAAkB,OAAe,IAAI;AAC7E,QAAKA,KAAM;AACX,OAAK,WAAW;AAChB,OAAK,OAAO;AACZ,OAAK,OAAO;;;CAId,IAAI,KAAK;AACP,SAAO,MAAKA;;;;;;;;;AAUhB,IAAa,SAAb,MAA6B;;CAE3B;;CAEA,WAAiB,IAAI,MAAM;;CAE3B,0BAA+B,IAAI,KAAK;CACxC;CACA,UAAmC,EAAE;;CAErC,WAA0B;CAE1B,YAAY,IAAY,OAAU;AAChC,QAAKA,KAAM;AACX,OAAK,QAAQ;;;CAIf,SAAS,UAAa;AACpB,OAAK,QAAQ;;;CAIf,IAAI,KAAK;AACP,SAAO,MAAKA;;;;;;CAOd,KAAK,GAAW,GAAW;AACzB,OAAK,SAAS,IAAI,GAAG,EAAE;AACvB,OAAK,MAAM,MAAM,MAAKC,OACpB,IAAG,KAAK,SAAS;;;;;;CAQrB,OAAO,IAAyB;AAC9B,QAAKA,OAAQ,KAAK,GAAG;AACrB,eAAa;AACX,SAAKA,SAAU,MAAKA,OAAQ,QAAQ,MAAM,MAAM,GAAG;;;;;;;;AASzD,IAAa,QAAb,MAAmB;CACjB;;CAEA;;CAEA,2BAAwB,IAAI,KAAK;;CAEjC,yBAAsB,IAAI,KAAK;;CAE/B,WAAiB,IAAI,MAAM;;CAE3B,WAA0B;CAE1B,YAAY,IAAY,OAAe,IAAI;AACzC,QAAKD,KAAM;AACX,OAAK,OAAO;;;CAId,IAAI,KAAK;AACP,SAAO,MAAKA;;;CAId,IAAI,UAAkB;AACpB,OAAK,SAAS,IAAI,SAAS;;;CAI7B,OAAO,UAAkB;AACvB,OAAK,SAAS,OAAO,SAAS;;;CAIhC,SAAS,SAAiB;AACxB,OAAK,OAAO,IAAI,QAAQ;;;CAI1B,YAAY,SAAiB;AAC3B,OAAK,OAAO,OAAO,QAAQ;;;;AAK/B,IAAY,8CAAL;;AAEL;;AAEA;;AAEA;;AAEA;;;;;;;;AAQF,IAAa,OAAb,MAA2B;CACzB;;CAEA;;CAEA;;CAEA;;CAEA,YAAoB,EAAE;;CAEtB;CAEA,YAAY,IAAY,MAAc,IAAY,OAAO,SAAS,MAAM,QAAW,EAAE,EAAO;AAC1F,QAAKA,KAAM;AACX,OAAK,OAAO;AACZ,OAAK,KAAK;AACV,OAAK,OAAO;AACZ,OAAK,QAAQ;;;CAIf,IAAI,KAAK;AACP,SAAO,MAAKA"}
|