@eventcatalog/visualiser 5.1.2 → 5.2.1
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/dist/{chunk-RHE5IMXC.mjs → chunk-QQUJTD6O.mjs} +1856 -1326
- package/dist/chunk-QQUJTD6O.mjs.map +1 -0
- package/dist/index.d.mts +5 -14
- package/dist/index.d.ts +5 -14
- package/dist/index.js +1701 -1417
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -3
- package/dist/node-card.css +262 -0
- package/dist/studio.css +8 -36
- package/dist/studio.d.mts +263 -127
- package/dist/studio.mjs +1016 -1192
- package/dist/studio.mjs.map +1 -1
- package/dist/styles-core.css +283 -9
- package/dist/styles.css +283 -9
- package/package.json +2 -2
- package/dist/chunk-RHE5IMXC.mjs.map +0 -1
package/dist/studio.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/studio/canvas-doc.ts","../src/studio/edges.ts","../src/studio/node-types.ts","../src/studio/grouping.ts","../src/studio/clipboard.ts","../src/studio/entity-handles.ts","../src/studio/flow-state.ts","../src/studio/layout.ts","../src/studio/placement.ts","../src/studio/level-layout.ts","../src/studio/levels.ts","../src/studio/live-moves.ts","../src/studio/smooth.ts","../src/studio/use-counter-scale.ts","../src/studio/model-canvas.ts","../src/studio/diagram-file.ts","../src/studio/export-image.ts","../src/studio/components/canvas-nodes.tsx","../src/studio/components/TeamNode.tsx","../src/studio/components/Comments.tsx","../src/studio/components/status.ts","../src/studio/components/Picture.tsx","../src/studio/components/ClientLogos.tsx","../src/studio/components/ContextMenu.tsx","../src/studio/components/DragGhost.tsx","../src/studio/components/Hotspots.tsx","../src/studio/components/icons.ts","../src/studio/components/CanvasControls.tsx","../src/studio/components/ContainerChooser.tsx","../src/studio/components/EditButton.tsx","../src/studio/components/Palette.tsx","../src/studio/components/Shortcuts.tsx","../src/studio/components/EmptyCanvas.tsx","../src/studio/components/NodeCard.tsx","../src/studio/components/RemeasureHandles.tsx"],"sourcesContent":["import * as Y from \"yjs\";\nimport type { Connection, Edge, Node, XYPosition } from \"@xyflow/react\";\nimport type { CopiedEdgeRoute, EdgeRoute } from \"../layout\";\nimport { createEdge, getEdgeLabel } from \"./edges\";\nimport {\n fitGroup,\n getAbsolutePosition,\n withDescendants,\n withParent,\n} from \"./grouping\";\nimport {\n getNodeDefinition,\n getNodeName,\n getNodeSize,\n isGroupType,\n} from \"./node-types\";\n\n/**\n * Everything a canvas holds, as operations on its Yjs document: nodes and edges, where things are on each level,\n * comment threads, hotspots and the canvas's status. The same functions run in the browser (people, WebMCP) and on a\n * server (MCP tools), so people and agents edit a canvas the same way.\n */\n\nexport type Author = {\n name: string;\n color: string;\n agent?: boolean;\n /** A picture from their sign-in provider (SSO), shown over their initials */\n picture?: string;\n};\nexport type Message = {\n id: string;\n text: string;\n author: Author;\n createdAt: number;\n};\n/** Where a comment is pinned: a canvas position, or a node (and the offset from its top left) so it moves with it */\nexport type CommentAnchor = {\n position: XYPosition;\n nodeId?: string;\n offset?: XYPosition;\n level?: 1 | 2;\n};\nexport type Thread = CommentAnchor & {\n id: string;\n author: Author;\n createdAt: number;\n resolved: boolean;\n messages: Message[];\n};\nexport type HotspotSeverity = \"critical\" | \"warning\" | \"info\";\n/** A hotspot: flagged on a node (shown on it, wherever it goes), or at a place on the canvas */\nexport type Hotspot = {\n id: string;\n severity: HotspotSeverity;\n title: string;\n description?: string;\n nodeId?: string;\n /** Where it is when it's not on a node */\n position: XYPosition;\n /** The level that place is on (L1 or L2: they're laid out on their own); none, L3 */\n level?: 1 | 2;\n author: Author;\n createdAt: number;\n};\n/** Where a canvas's design is: being worked on, up for review, agreed, or decided against */\nexport const CANVAS_STATUSES = [\n \"draft\",\n \"proposed\",\n \"accepted\",\n \"rejected\",\n] as const;\nexport type CanvasStatus = (typeof CANVAS_STATUSES)[number];\n/** A canvas's status being changed: by whom, when, and why (e.g. \"Agreed in the architecture review\") */\nexport type StatusChange = {\n status: CanvasStatus;\n by: Author;\n at: number;\n note?: string;\n};\nexport type CanvasMeta = {\n title?: string;\n /** Draft until someone changes it */\n status?: CanvasStatus;\n /** Every status change, oldest first (the last few hundred) */\n statusHistory?: StatusChange[];\n createdAt?: number;\n createdBy?: string;\n /** When the canvas was last laid out, so everyone's canvas glides the nodes into place */\n layoutAt?: number;\n /** Locked (looked at, not changed), by whom: for everyone on it, in a live session too */\n lockedBy?: string | null;\n /** L1 and L2 as the diagram the canvas was opened from showed them (see DiagramLevels) */\n diagramLevels?: DiagramLevels;\n};\n\n/** A level of detail as a diagram showed it: its nodes (laid out) and edges, by canvas node ids where they're the same */\nexport type DiagramLevel = { nodes: Node[]; edges: Edge[] };\n\n/**\n * L1 and L2 of the diagram a canvas was opened from (the visualiser's \"Open in Studio\"), shown as they were while the\n * canvas's structure is what was opened (`structure`, from getStructureKey): moving nodes keeps them, changing what's\n * on the canvas or how it's connected doesn't (the levels are then worked out from the canvas)\n */\nexport type DiagramLevels = {\n structure: string;\n 1?: DiagramLevel;\n 2?: DiagramLevel;\n /** Levels the diagram doesn't have, and why (as the diagram says) */\n unavailable?: { 1?: string; 2?: string };\n};\n\n/** Who locked the canvas, if it's locked */\nexport const getLock = (doc: Y.Doc) =>\n (getCanvasMaps(doc).meta.get(\"lockedBy\") as string | null | undefined) ??\n null;\n\n/** Locks the canvas for everyone (by a name), or unlocks it (null); nothing written if it's already so */\nexport const setLock = (doc: Y.Doc, by: string | null) => {\n if (getLock(doc) === by) return;\n getCanvasMaps(doc).meta.set(\"lockedBy\", by);\n};\n\nexport const shortId = () => crypto.randomUUID().slice(0, 8);\n\nexport const getCanvasMaps = (doc: Y.Doc) => ({\n nodes: doc.getMap<Node>(\"nodes\"),\n edges: doc.getMap<Edge>(\"edges\"),\n threads: doc.getMap<Y.Map<unknown>>(\"threads\"),\n /** Each hotspot whole (edited by replacing it: they're short) */\n hotspots: doc.getMap<Hotspot>(\"hotspots\"),\n meta: doc.getMap<unknown>(\"meta\"),\n /** Where things are on L1 and L2 (see LevelPlace), one entry per node and level (`1:<node id>`) */\n levelLayouts: doc.getMap<LevelPlace>(\"levelLayouts\"),\n});\n\n/**\n * Where a node is on L1 or L2, as people arranged it there (or as the diagram it was opened from had it): its\n * top-left corner, relative to the container it's shown in on that level, and a container's size\n */\nexport type LevelPlace = {\n x: number;\n y: number;\n width?: number;\n height?: number;\n};\n\n/** The places on a level, by node id */\nexport const readLevelLayout = (doc: Y.Doc, level: 1 | 2) => {\n const prefix = `${level}:`;\n const places = new Map<string, LevelPlace>();\n getCanvasMaps(doc).levelLayouts.forEach((place, key) => {\n if (key.startsWith(prefix)) places.set(key.slice(prefix.length), place);\n });\n return places;\n};\n\nconst samePlace = (a: LevelPlace | undefined, b: LevelPlace) =>\n !!a &&\n a.x === b.x &&\n a.y === b.y &&\n a.width === b.width &&\n a.height === b.height;\n\n/**\n * Puts nodes where they go on a level (in one transaction). Places that haven't changed aren't written: everyone\n * looking at the level works out the same places for what's new on it, and each write re-arranges the level for\n * everyone else.\n */\nexport const setLevelPlaces = (\n doc: Y.Doc,\n level: 1 | 2,\n places: ReadonlyMap<string, LevelPlace>,\n) =>\n doc.transact(() => {\n const { levelLayouts } = getCanvasMaps(doc);\n places.forEach((place, id) => {\n const key = `${level}:${id}`;\n if (!samePlace(levelLayouts.get(key), place))\n levelLayouts.set(key, place);\n });\n });\n\n// Only the design is shared. Selection, measured sizes and drag state stay with each user.\nexport const toSharedNode = ({\n id,\n type,\n position,\n data,\n width,\n height,\n parentId,\n zIndex,\n}: Node): Node => ({\n id,\n type,\n position,\n data,\n ...(width ? { width } : {}),\n ...(height ? { height } : {}),\n // Inside a container (its position is then relative to the container)\n ...(parentId ? { parentId } : {}),\n ...(zIndex !== undefined ? { zIndex } : {}),\n});\n\n/** A new node of a type, centred on a canvas position */\nexport const buildNode = (\n type: string,\n data: Record<string, unknown>,\n center: XYPosition,\n): Node => {\n const definition = getNodeDefinition(type);\n const size = getNodeSize(type);\n return toSharedNode({\n id: `${type}-${shortId()}`,\n type,\n position: { x: center.x - size.width / 2, y: center.y - size.height / 2 },\n data,\n ...(definition?.defaultSize && !definition.autoSize\n ? definition.autoHeight\n ? { width: size.width }\n : size\n : {}),\n // Containers sit behind what's in them and the connections between them\n ...(isGroupType(type) && { zIndex: -1 }),\n });\n};\n\n// ---- Meta ----\n\nexport const readMeta = (doc: Y.Doc) =>\n getCanvasMaps(doc).meta.toJSON() as CanvasMeta;\n\nexport const setMeta = (doc: Y.Doc, meta: Partial<CanvasMeta>) =>\n doc.transact(() => {\n const map = getCanvasMaps(doc).meta;\n Object.entries(meta).forEach(([key, value]) =>\n value === undefined ? map.delete(key) : map.set(key, value),\n );\n });\n\n// ---- Status ----\n\nconst MAX_STATUS_HISTORY = 200;\n\nexport const getCanvasStatus = (meta: CanvasMeta): CanvasStatus =>\n meta.status ?? \"draft\";\n\n/** Changes a canvas's status (and records who did it). Returns false if it already had that status. */\nexport const setCanvasStatus = (\n doc: Y.Doc,\n status: CanvasStatus,\n by: Author,\n note?: string,\n) => {\n let changed = false;\n doc.transact(() => {\n const meta = readMeta(doc);\n if (getCanvasStatus(meta) === status) return;\n const change: StatusChange = {\n status,\n by,\n at: Date.now(),\n ...(note?.trim() && { note: note.trim() }),\n };\n const map = getCanvasMaps(doc).meta;\n map.set(\"status\", status);\n map.set(\n \"statusHistory\",\n [...(meta.statusHistory ?? []), change].slice(-MAX_STATUS_HISTORY),\n );\n changed = true;\n });\n return changed;\n};\n\n/** Accepted and rejected canvases are decided: changing what's on them makes them a draft again */\nexport const isDecided = (status: CanvasStatus) =>\n status === \"accepted\" || status === \"rejected\";\n\n/** A decided canvas whose nodes or edges were changed goes back to draft, recorded as changed by `by` */\nexport const reopenIfDecided = (doc: Y.Doc, by: Author) => {\n const status = getCanvasStatus(readMeta(doc));\n if (isDecided(status))\n setCanvasStatus(doc, \"draft\", by, `Changed after it was ${status}`);\n};\n\n/**\n * Runs `fn` (which may change the canvas), and if it changed nodes or edges, sends a decided canvas back to draft.\n * Comments don't count: reviewing an accepted design keeps it accepted.\n */\nexport const reopeningIfEdited = <T>(\n doc: Y.Doc,\n by: Author,\n fn: () => T,\n): T => {\n let result!: T;\n // In one transaction (the one it's already in, if it is): what it changed is known before it ends\n doc.transact((transaction) => {\n result = fn();\n if (changesNodesOrEdges(transaction)) reopenIfDecided(doc, by);\n });\n return result;\n};\n\n/** Whether a transaction changed the canvas's nodes or edges (not just its comments or meta) */\nexport const changesNodesOrEdges = (transaction: Y.Transaction) => {\n const { nodes, edges } = getCanvasMaps(transaction.doc);\n return [...transaction.changed.keys()].some(\n (type) => type === (nodes as unknown) || type === (edges as unknown),\n );\n};\n\n// ---- Nodes and edges ----\n\nexport const addNodes = (doc: Y.Doc, nodes: Node[], edges: Edge[] = []) =>\n doc.transact(() => {\n const maps = getCanvasMaps(doc);\n nodes.forEach((node) => maps.nodes.set(node.id, toSharedNode(node)));\n edges.forEach((edge) => maps.edges.set(edge.id, edge));\n });\n\n/**\n * Moves a node, and resizes it if a size is given, in one write. Nodes are only written when they change: every\n * write is sent to everyone, re-renders the node for them, and is kept in the document (and the undo stack), even\n * when it writes what was already there.\n */\nexport const placeNode = (\n doc: Y.Doc,\n id: string,\n position: XYPosition,\n size?: { width: number; height: number },\n) => {\n const { nodes } = getCanvasMaps(doc);\n const node = nodes.get(id);\n if (!node) return false;\n const moved =\n node.position.x !== position.x || node.position.y !== position.y;\n const resized =\n !!size && (node.width !== size.width || node.height !== size.height);\n if (moved || resized)\n nodes.set(id, {\n ...node,\n position,\n ...(size && { width: size.width, height: size.height }),\n });\n return true;\n};\n\nexport const moveNode = (doc: Y.Doc, id: string, position: XYPosition) =>\n placeNode(doc, id, position);\n\n/** Resize a node: both sides, or just its width or height (e.g. text, whose height follows what's in it) */\nexport const resizeNode = (\n doc: Y.Doc,\n id: string,\n size: { width: number; height: number },\n attributes: true | \"width\" | \"height\" = true,\n) => {\n const { nodes } = getCanvasMaps(doc);\n const node = nodes.get(id);\n const width = attributes !== \"height\" && node?.width !== size.width;\n const height = attributes !== \"width\" && node?.height !== size.height;\n if (node && (width || height))\n nodes.set(id, {\n ...node,\n ...(attributes !== \"height\" && { width: size.width }),\n ...(attributes !== \"width\" && { height: size.height }),\n });\n return !!node;\n};\n\n/** Grow a container to fit what's in it (moving them clear of its header if needed), never shrinking it */\n/**\n * The sizes nodes are rendered at (in the browser), by id. The document doesn't have them, so without them\n * containers are fitted to the size each type renders at at most.\n */\nexport type RenderedSizes = ReadonlyMap<\n string,\n { width: number; height: number }\n>;\n\nconst withRenderedSizes = (nodes: Node[], sizes?: RenderedSizes) =>\n sizes\n ? nodes.map((node) =>\n sizes.has(node.id) ? { ...node, measured: sizes.get(node.id) } : node,\n )\n : nodes;\n\nexport const fitGroupToChildren = (\n doc: Y.Doc,\n groupId: string,\n sizes?: RenderedSizes,\n) =>\n doc.transact(() => {\n const { nodes } = getCanvasMaps(doc);\n const fit = fitGroup(\n groupId,\n withRenderedSizes(Array.from(nodes.values()), sizes),\n );\n const group = nodes.get(groupId);\n if (!fit || !group) return;\n if (fit.shift.x || fit.shift.y) {\n // Children move right/down and the container left/up by the same amount: nothing moves on the canvas\n nodes.forEach((child, id) => {\n if (child.parentId === groupId)\n nodes.set(id, {\n ...child,\n position: {\n x: child.position.x + fit.shift.x,\n y: child.position.y + fit.shift.y,\n },\n });\n });\n }\n nodes.set(groupId, {\n ...group,\n position: {\n x: group.position.x - fit.shift.x,\n y: group.position.y - fit.shift.y,\n },\n width: fit.width,\n height: fit.height,\n });\n });\n\n/** The containers a node is in grow to fit it (innermost first), e.g. after it's added or resized */\nexport const fitContainersAround = (\n doc: Y.Doc,\n nodeId: string,\n sizes?: RenderedSizes,\n) =>\n doc.transact(() => {\n const { nodes } = getCanvasMaps(doc);\n for (let id = nodes.get(nodeId)?.parentId; id; id = nodes.get(id)?.parentId)\n fitGroupToChildren(doc, id, sizes);\n });\n\n/**\n * A node moved into (or out of) a container: where it is on the canvas, or put at `at` (in its new parent), e.g. when\n * it's moved on L1 or L2, where it was dropped isn't a place on the canvas\n */\nexport const setNodeParent = (\n doc: Y.Doc,\n nodeId: string,\n parentId: string | undefined,\n sizes?: RenderedSizes,\n at?: XYPosition,\n) =>\n doc.transact(() => {\n const { nodes } = getCanvasMaps(doc);\n const node = nodes.get(nodeId);\n if (!node || node.parentId === parentId) return false;\n const moved = at\n ? { ...node, parentId, position: at }\n : withParent(node, parentId, Array.from(nodes.values()));\n nodes.set(nodeId, toSharedNode(moved));\n if (parentId) fitGroupToChildren(doc, parentId, sizes);\n return true;\n });\n\n/**\n * Nodes moved into (or out of) containers together, e.g. a selection dropped in one, as one change: each where it is\n * on the canvas, or at its `at` (in its new parent). The containers they went in (and those around them) are fitted\n * once they're all in, so one growing doesn't move where the next was put. Returns the ids of those moved.\n */\nexport const setNodeParents = (\n doc: Y.Doc,\n moves: { id: string; parentId: string | undefined; at?: XYPosition }[],\n sizes?: RenderedSizes,\n) =>\n doc.transact(() => {\n const { nodes } = getCanvasMaps(doc);\n const moved: string[] = [];\n for (const { id, parentId, at } of moves) {\n const node = nodes.get(id);\n if (!node || node.parentId === parentId) continue;\n nodes.set(\n id,\n toSharedNode(\n at\n ? { ...node, parentId, position: at }\n : withParent(node, parentId, Array.from(nodes.values())),\n ),\n );\n moved.push(id);\n }\n // Each container once, innermost first\n const containers: string[] = [];\n for (const id of moved) {\n for (\n let parent = nodes.get(id)?.parentId;\n parent;\n parent = nodes.get(parent)?.parentId\n )\n if (!containers.includes(parent)) containers.push(parent);\n }\n const depth = (id: string) => {\n let level = 0;\n for (\n let parent = nodes.get(id)?.parentId;\n parent;\n parent = nodes.get(parent)?.parentId\n )\n level++;\n return level;\n };\n containers\n .sort((a, b) => depth(b) - depth(a))\n .forEach((id) => fitGroupToChildren(doc, id, sizes));\n return moved;\n });\n\nexport const updateNodeData = (\n doc: Y.Doc,\n id: string,\n updater: (data: Record<string, unknown>) => Record<string, unknown>,\n) => {\n const { nodes } = getCanvasMaps(doc);\n const node = nodes.get(id);\n if (node) nodes.set(id, { ...node, data: updater(node.data) });\n return !!node;\n};\n\n/**\n * How a connection is drawn, as the visualiser's layout routes it (in data.route, which the visualiser's edges\n * are drawn along): the points it goes through, where its label goes, and where its nodes were (top-left) when\n * it was routed, for it to follow them when they move\n */\nexport type { EdgeRoute };\n\n/** An edge's route, if it has one */\nexport const getEdgeRoute = (edge: Pick<Edge, \"data\">) =>\n (edge.data as { route?: EdgeRoute } | undefined)?.route;\n\n/** Routes connections (by edge id), in one transaction. Connections not in it lose any route they had. */\nexport const setEdgeRoutes = (\n doc: Y.Doc,\n routes: ReadonlyMap<string, EdgeRoute>,\n) =>\n doc.transact(() => {\n const { edges } = getCanvasMaps(doc);\n edges.forEach((edge, id) => {\n const route = routes.get(id);\n if (route) edges.set(id, { ...edge, data: { ...edge.data, route } });\n else if (getEdgeRoute(edge)) {\n const { route: _, ...data } = edge.data!;\n edges.set(id, { ...edge, data });\n }\n });\n });\n\n/**\n * What's on a canvas and how it's connected, not where: its nodes (not notes), what they're in and called, and its\n * connections. The same for the same canvas wherever it's worked out (the server, any browser).\n */\nexport const getStructureKey = (nodes: Node[], edges: Edge[]) => {\n const parts = [\n ...nodes\n .filter((node) => node.type !== \"note\")\n .map(\n (node) =>\n `${node.id}:${node.type}:${node.parentId ?? \"\"}:${getNodeName(node.type, node.data)}`,\n )\n .sort(),\n \"#\",\n ...edges\n .map(\n (edge) => `${edge.source}>${edge.target}:${String(edge.label ?? \"\")}`,\n )\n .sort(),\n ];\n // FNV-1a, so it's short enough to keep in the canvas\n let hash = 0x811c9dc5;\n for (const char of parts.join(\"|\"))\n hash = Math.imul(hash ^ char.charCodeAt(0), 0x01000193);\n return `${parts.length}-${(hash >>> 0).toString(36)}`;\n};\n\n/** The diagram's L1 or L2 while the canvas still has the structure it was opened with (`structure`, its key now) */\nexport const getDiagramLevel = (\n levels: DiagramLevels | undefined,\n level: 1 | 2,\n structure: string,\n) =>\n levels?.[level] &&\n !levels.unavailable?.[level] &&\n levels.structure === structure\n ? levels[level]\n : undefined;\n\n/** Why the diagram doesn't have a level, while the canvas still has the structure it was opened with */\nexport const getDiagramLevelUnavailable = (\n levels: DiagramLevels | undefined,\n level: 1 | 2,\n structure: string,\n) =>\n levels?.unavailable?.[level] && levels.structure === structure\n ? levels.unavailable[level]\n : undefined;\n\n/** What a new canvas starts with: its nodes, the connections between them (by node id) with their routes, and the\n * levels of the diagram it's opened from */\nexport type CanvasContent = {\n nodes: Node[];\n connections: {\n from: string;\n to: string;\n label?: string;\n route?: CopiedEdgeRoute;\n }[];\n levels?: Pick<DiagramLevels, 1 | 2 | \"unavailable\">;\n};\n\n/**\n * Puts a new canvas's content on it (in one transaction), with its containers fitted to what's in them. Routes\n * are from where the nodes are put.\n */\nexport const addCanvasContent = (\n doc: Y.Doc,\n { nodes, connections, levels }: CanvasContent,\n) =>\n doc.transact(() => {\n addNodes(doc, nodes);\n nodes.forEach((node) => node.parentId && fitContainersAround(doc, node.id));\n const placed = new Map(getCanvasMaps(doc).nodes.entries());\n const routes = new Map<string, EdgeRoute>();\n connections.forEach(({ from, to, label, route }) => {\n const edge = connectNodes(doc, { source: from, target: to }, label);\n const [source, target] = [placed.get(from), placed.get(to)];\n if (!route || \"error\" in edge || !source || !target) return;\n const { sourceHeight, targetHeight, ...drawn } = route;\n routes.set(edge.id, {\n ...drawn,\n source: {\n ...getAbsolutePosition(source, placed),\n ...(sourceHeight && { height: sourceHeight }),\n },\n target: {\n ...getAbsolutePosition(target, placed),\n ...(targetHeight && { height: targetHeight }),\n },\n });\n });\n if (routes.size) setEdgeRoutes(doc, routes);\n if (levels) {\n const maps = getCanvasMaps(doc);\n const structure = getStructureKey(\n Array.from(maps.nodes.values()),\n Array.from(maps.edges.values()),\n );\n setMeta(doc, { diagramLevels: { structure, ...levels } });\n }\n });\n\n/** Connect two nodes with an EventCatalog-labelled edge. Returns the edge, or why it couldn't be made. */\n/** Whether a connection joins the same handles as another (a node's default handle is null) */\nconst sameEnds = (\n edge: Pick<Edge, \"sourceHandle\" | \"targetHandle\">,\n connection: Partial<Connection>,\n) =>\n (edge.sourceHandle ?? null) === (connection.sourceHandle ?? null) &&\n (edge.targetHandle ?? null) === (connection.targetHandle ?? null);\n\nexport const connectNodes = (\n doc: Y.Doc,\n connection: Pick<Connection, \"source\" | \"target\"> & Partial<Connection>,\n label?: string,\n): Edge | { error: string } => {\n const { nodes, edges } = getCanvasMaps(doc);\n const source = nodes.get(connection.source);\n const target = nodes.get(connection.target);\n if (!source)\n return { error: `Node \"${connection.source}\" is not on the canvas` };\n if (!target)\n return { error: `Node \"${connection.target}\" is not on the canvas` };\n if (source.id === target.id)\n return { error: \"A node cannot be connected to itself\" };\n // (two things are joined once, except at different places: e.g. two of an entity's properties)\n const existing = Array.from(edges.values()).find(\n (edge) =>\n edge.source === source.id &&\n edge.target === target.id &&\n sameEnds(edge, connection),\n );\n if (existing) return existing;\n const edge = createEdge(\n {\n source: source.id,\n target: target.id,\n sourceHandle: connection.sourceHandle ?? null,\n targetHandle: connection.targetHandle ?? null,\n },\n source.type,\n target.type,\n );\n const created = label === undefined ? edge : { ...edge, label };\n edges.set(created.id, created);\n return created;\n};\n\n/**\n * Moves a connection to new ends (dragged to another node), keeping it the same connection. Its label follows\n * the new ends if it was EventCatalog's wording, and is kept if someone wrote it.\n */\nexport const reconnectEdge = (\n doc: Y.Doc,\n edgeId: string,\n connection: Connection,\n): Edge | { error: string } =>\n doc.transact(() => {\n const { nodes, edges } = getCanvasMaps(doc);\n const edge = edges.get(edgeId);\n const source = nodes.get(connection.source);\n const target = nodes.get(connection.target);\n if (!edge) return { error: `Connection \"${edgeId}\" is not on the canvas` };\n if (!source || !target)\n return { error: \"Connections join two nodes on the canvas\" };\n if (source.id === target.id)\n return { error: \"A node cannot be connected to itself\" };\n const duplicate = Array.from(edges.values()).find(\n (other) =>\n other.id !== edgeId &&\n other.source === source.id &&\n other.target === target.id &&\n sameEnds(other, connection),\n );\n if (duplicate) return { error: \"Those nodes are already connected\" };\n\n const defaultLabel = getEdgeLabel(\n nodes.get(edge.source)?.type,\n nodes.get(edge.target)?.type,\n );\n const moved = createEdge(connection, source.type, target.type);\n const written = (edge.data as { customLabel?: string } | undefined)\n ?.customLabel;\n const reconnected: Edge = {\n ...moved,\n id: edge.id,\n ...(edge.label !== undefined &&\n edge.label !== defaultLabel && { label: edge.label }),\n ...(written && { data: { ...moved.data, customLabel: written } }),\n };\n edges.set(edgeId, reconnected);\n return reconnected;\n });\n\n/**\n * What a connection says: written by someone (kept as it's written, and in the model), or, with nothing written,\n * EventCatalog's wording for what it joins again\n */\nexport const setEdgeLabel = (\n doc: Y.Doc,\n edgeId: string,\n label: string | undefined,\n) =>\n doc.transact(() => {\n const { nodes, edges } = getCanvasMaps(doc);\n const edge = edges.get(edgeId);\n if (!edge) return false;\n const { customLabel: _, ...data } = (edge.data ?? {}) as Record<\n string,\n unknown\n >;\n edges.set(edgeId, {\n ...edge,\n label:\n label ??\n getEdgeLabel(\n nodes.get(edge.source)?.type,\n nodes.get(edge.target)?.type,\n ),\n data: label ? { ...data, customLabel: label } : data,\n });\n return true;\n });\n\nexport const deleteEdges = (doc: Y.Doc, ids: string[]) =>\n doc.transact(() => ids.forEach((id) => getCanvasMaps(doc).edges.delete(id)));\n\n/** Delete nodes (containers with what's in them), the edges to them, and leave their comments where they were */\nexport const deleteNodes = (doc: Y.Doc, ids: string[]) =>\n doc.transact(() => {\n const { nodes, edges, threads, hotspots, levelLayouts } =\n getCanvasMaps(doc);\n const all = Array.from(nodes.values());\n const lookup = new Map(all.map((node) => [node.id, node]));\n const removed = withDescendants(ids, all);\n threads.forEach((thread) => {\n const nodeId = thread.get(\"nodeId\") as string | undefined;\n const node =\n nodeId && removed.has(nodeId) ? nodes.get(nodeId) : undefined;\n if (!node) return;\n const offset = (thread.get(\"offset\") as XYPosition) ?? { x: 0, y: 0 };\n const position = getAbsolutePosition(node, lookup);\n thread.set(\"position\", {\n x: position.x + offset.x,\n y: position.y + offset.y,\n });\n thread.delete(\"nodeId\");\n thread.delete(\"offset\");\n });\n // Hotspots on them stay too, where their node was (its top right corner)\n hotspots.forEach((hotspot, id) => {\n const node =\n hotspot.nodeId && removed.has(hotspot.nodeId)\n ? nodes.get(hotspot.nodeId)\n : undefined;\n if (!node) return;\n const position = getAbsolutePosition(node, lookup);\n const { nodeId: _, ...rest } = hotspot;\n hotspots.set(id, {\n ...rest,\n position: {\n x: position.x + (node.measured?.width ?? node.width ?? 0),\n y: position.y,\n },\n });\n });\n removed.forEach((id) => {\n nodes.delete(id);\n // Where it was on L1 and L2 (undoing the delete puts it back there)\n levelLayouts.delete(`1:${id}`);\n levelLayouts.delete(`2:${id}`);\n });\n edges.forEach((edge, id) => {\n if (removed.has(edge.source) || removed.has(edge.target))\n edges.delete(id);\n });\n });\n\n// ---- Comments ----\n// Each thread is a nested Y.Map and its messages a Y.Array, so concurrent replies (and resolving while\n// someone replies) all merge.\n\nexport const readThreads = (doc: Y.Doc) =>\n Array.from(getCanvasMaps(doc).threads.values())\n .map((thread) => thread.toJSON() as Thread)\n .sort((a, b) => a.createdAt - b.createdAt);\n\nconst anchorEntries = (anchor: CommentAnchor): [string, unknown][] => [\n [\"position\", anchor.position],\n ...(anchor.nodeId && anchor.offset\n ? ([\n [\"nodeId\", anchor.nodeId],\n [\"offset\", anchor.offset],\n ] as [string, unknown][])\n : anchor.level\n ? ([[\"level\", anchor.level]] as [string, unknown][])\n : []),\n];\n\n/** Threads as they were (from a saved canvas: their ids, authors and messages kept) */\nexport const addThreads = (doc: Y.Doc, threads: Thread[]) => {\n const { threads: shared } = getCanvasMaps(doc);\n for (const thread of threads) {\n const messages = new Y.Array<Message>();\n messages.push(thread.messages);\n shared.set(\n thread.id,\n new Y.Map<unknown>([\n [\"id\", thread.id],\n ...anchorEntries(thread),\n [\"author\", thread.author],\n [\"createdAt\", thread.createdAt],\n [\"resolved\", thread.resolved],\n [\"messages\", messages],\n ]),\n );\n }\n};\n\nexport const createThread = (\n doc: Y.Doc,\n anchor: CommentAnchor,\n text: string,\n author: Author,\n) => {\n const id = shortId();\n const now = Date.now();\n const messages = new Y.Array<Message>();\n messages.push([{ id: shortId(), text, author, createdAt: now }]);\n const thread = new Y.Map<unknown>([\n [\"id\", id],\n ...anchorEntries(anchor),\n [\"author\", author],\n [\"createdAt\", now],\n [\"resolved\", false],\n [\"messages\", messages],\n ]);\n getCanvasMaps(doc).threads.set(id, thread);\n return id;\n};\n\nconst getThread = (doc: Y.Doc, id: string) =>\n getCanvasMaps(doc).threads.get(id);\n\nexport const replyToThread = (\n doc: Y.Doc,\n threadId: string,\n text: string,\n author: Author,\n) => {\n const messages = getThread(doc, threadId)?.get(\"messages\") as\n | Y.Array<Message>\n | undefined;\n messages?.push([{ id: shortId(), text, author, createdAt: Date.now() }]);\n return !!messages;\n};\n\nexport const setThreadResolved = (\n doc: Y.Doc,\n threadId: string,\n resolved: boolean,\n) => {\n const thread = getThread(doc, threadId);\n thread?.set(\"resolved\", resolved);\n return !!thread;\n};\n\n/** Move a thread's pin, attaching it to a node (anchor.nodeId) or to the canvas */\nexport const moveThread = (\n doc: Y.Doc,\n threadId: string,\n anchor: CommentAnchor,\n) => {\n const thread = getThread(doc, threadId);\n if (!thread) return false;\n doc.transact(() => {\n thread.set(\"position\", anchor.position);\n if (anchor.nodeId && anchor.offset) {\n thread.set(\"nodeId\", anchor.nodeId);\n thread.set(\"offset\", anchor.offset);\n thread.delete(\"level\");\n } else {\n thread.delete(\"nodeId\");\n thread.delete(\"offset\");\n if (anchor.level) thread.set(\"level\", anchor.level);\n else thread.delete(\"level\");\n }\n });\n return true;\n};\n\nexport const deleteThread = (doc: Y.Doc, threadId: string) => {\n const { threads } = getCanvasMaps(doc);\n const exists = threads.has(threadId);\n threads.delete(threadId);\n return exists;\n};\n\n/** Deletes comment threads in one change (one undo brings them all back) */\nexport const deleteThreads = (doc: Y.Doc, threadIds: string[]) =>\n doc.transact(() => threadIds.forEach((id) => deleteThread(doc, id)));\n\n/** Moves comment threads in one change, e.g. ones that moved with what was dragged */\nexport const moveThreads = (\n doc: Y.Doc,\n moves: { threadId: string; anchor: CommentAnchor }[],\n) =>\n doc.transact(() =>\n moves.forEach(({ threadId, anchor }) => moveThread(doc, threadId, anchor)),\n );\n\n// ---- Hotspots ----\n\nexport const readHotspots = (doc: Y.Doc) =>\n Array.from(getCanvasMaps(doc).hotspots.values()).sort(\n (a, b) => a.createdAt - b.createdAt,\n );\n\n/** Hotspots as they were (from a saved canvas, or the agent's diagram) */\nexport const addHotspots = (doc: Y.Doc, hotspots: Hotspot[]) => {\n const { hotspots: shared } = getCanvasMaps(doc);\n doc.transact(() =>\n hotspots.forEach((hotspot) => shared.set(hotspot.id, hotspot)),\n );\n};\n\nexport const createHotspot = (\n doc: Y.Doc,\n hotspot: Omit<Hotspot, \"id\" | \"createdAt\">,\n) => {\n const id = shortId();\n getCanvasMaps(doc).hotspots.set(id, {\n ...hotspot,\n id,\n createdAt: Date.now(),\n });\n return id;\n};\n\n/** Change what a hotspot says (or where it is: on a node, or at a place) */\nexport const updateHotspot = (\n doc: Y.Doc,\n id: string,\n fields: Partial<Omit<Hotspot, \"id\" | \"createdAt\" | \"author\">>,\n) => {\n const { hotspots } = getCanvasMaps(doc);\n const hotspot = hotspots.get(id);\n if (!hotspot) return false;\n const next = { ...hotspot, ...fields };\n // Moved off its node (to a place): not on it any more; and a place on L3 has no level\n if (\"nodeId\" in fields && !fields.nodeId) delete next.nodeId;\n if (\"level\" in fields && !fields.level) delete next.level;\n if (!next.description) delete next.description;\n hotspots.set(id, next);\n return true;\n};\n\nexport const deleteHotspot = (doc: Y.Doc, id: string) => {\n const { hotspots } = getCanvasMaps(doc);\n const exists = hotspots.has(id);\n hotspots.delete(id);\n return exists;\n};\n\n// ---- Reading a whole canvas ----\n\nexport const readCanvas = (doc: Y.Doc) => {\n const { nodes, edges } = getCanvasMaps(doc);\n return {\n meta: readMeta(doc),\n nodes: Array.from(nodes.values()),\n edges: Array.from(edges.values()),\n threads: readThreads(doc),\n hotspots: readHotspots(doc),\n };\n};\n","import type { Connection, Edge, EdgeMarker } from \"@xyflow/react\";\n\n/** Connections on a canvas, labelled with EventCatalog's wording (e.g. \"publishes event\", \"subscribed by\") */\n\n/** Node types that are messages, and their catalog collection */\nexport const MESSAGE_COLLECTIONS: Record<string, string> = {\n event: \"events\",\n command: \"commands\",\n query: \"queries\",\n};\n\nexport const EDGE_COLOR = \"#6b7280\";\nexport const EDGE_MARKER: EdgeMarker = {\n type: \"arrowclosed\",\n color: EDGE_COLOR,\n width: 18,\n height: 18,\n};\n\nconst PRODUCERS = [\n \"service\",\n \"agent\",\n \"actor\",\n \"externalSystem\",\n \"view\",\n // Domains send messages themselves too (`sends` in a domain's frontmatter), as a box or a card. Studio on the\n // web's model only has services sending and receiving (model-canvas.ts), so these edges are labelled but not\n // kept as relations there\n \"domain-group\",\n \"context-domain\",\n];\nconst PRODUCER_LABELS: Record<string, string> = {\n commands: \"invokes\",\n events: \"publishes \\nevent\",\n queries: \"requests\",\n};\nconst MESSAGE_LABELS: Record<string, string> = {\n commands: \"accepts\",\n events: \"subscribed by\",\n queries: \"accepts\",\n};\n\nconst getCollection = (sourceType?: string, targetType?: string) =>\n MESSAGE_COLLECTIONS[sourceType ?? \"\"] ??\n MESSAGE_COLLECTIONS[targetType ?? \"\"];\n\nexport const getEdgeLabel = (sourceType = \"\", targetType = \"\"): string => {\n const sourceCollection = MESSAGE_COLLECTIONS[sourceType];\n const targetCollection = MESSAGE_COLLECTIONS[targetType];\n\n // Who owns what, and the domain model: a team owns what it's connected to, entities are managed and referenced\n if (sourceType === \"team\") return \"owns\";\n if (sourceType === \"entity\" && targetType === \"entity\") return \"references\";\n if (targetType === \"entity\") return sourceCollection ? \"carries\" : \"manages\";\n if (PRODUCERS.includes(sourceType) && targetCollection)\n return PRODUCER_LABELS[targetCollection];\n // One message leading to another (e.g. an event that causes a command)\n if (sourceCollection && targetCollection) return \"triggers\";\n if (sourceCollection && targetType === \"channel\") return \"sent to\";\n if (sourceCollection) return MESSAGE_LABELS[sourceCollection];\n if (sourceType === \"channel\") return \"routes to\";\n if (targetType === \"channel\") return \"publishes to\";\n if (targetType === \"data\") return \"writes to\";\n if (sourceType === \"data\") return \"read by\";\n if (sourceType === \"actor\") return \"uses\";\n if (targetType === \"view\") return \"serves\";\n if (targetType === \"externalSystem\") return \"calls\";\n if (targetType === \"actor\") return \"notifies\";\n return \"\";\n};\n\n/** Message edges get the animated envelope edge from the visualiser, everything else a labelled smooth step edge */\nexport const createEdge = (\n connection: Connection,\n sourceType?: string,\n targetType?: string,\n): Edge => {\n const collection = getCollection(sourceType, targetType);\n return {\n id: `edge-${crypto.randomUUID().slice(0, 8)}`,\n source: connection.source,\n target: connection.target,\n sourceHandle: connection.sourceHandle ?? null,\n targetHandle: connection.targetHandle ?? null,\n type: collection ? \"animated\" : \"smoothstep\",\n label: getEdgeLabel(sourceType, targetType),\n markerEnd: EDGE_MARKER,\n data: collection ? { message: { collection } } : {},\n };\n};\n","/**\n * The kinds of node people (and agents) can put on a canvas, and what's in their data. Shared by the browser and\n * the server, so it has no UI in it: the icons for each type are in components/icons.ts.\n */\n\nexport type NodeCategory =\n | \"boundaries\"\n | \"people\"\n | \"messages\"\n | \"architecture\"\n | \"data\"\n | \"other\";\n\nexport const NODE_CATEGORIES: { id: NodeCategory; label: string }[] = [\n { id: \"boundaries\", label: \"Boundaries\" },\n // What's deployed (services, UIs, agents) and what's outside it: drawn first, then what flows between them\n { id: \"architecture\", label: \"Services\" },\n { id: \"messages\", label: \"Messages\" },\n // Where data lives: all data nodes, of EventCatalog's kinds (container_type)\n { id: \"data\", label: \"Data\" },\n // Who's involved: who uses the architecture (actors) and who owns it (teams)\n { id: \"people\", label: \"People\" },\n { id: \"other\", label: \"Other\" },\n];\n\n/** The catalog collections whose resources can go on a canvas */\nexport const CATALOG_COLLECTIONS = [\n \"domains\",\n \"systems\",\n \"services\",\n \"events\",\n \"commands\",\n \"queries\",\n \"channels\",\n \"containers\",\n] as const;\n\nexport type CatalogCollection = (typeof CATALOG_COLLECTIONS)[number];\nexport const isCatalogCollection = (\n collection: string,\n): collection is CatalogCollection =>\n (CATALOG_COLLECTIONS as readonly string[]).includes(collection);\n\n/** Domains and systems as containers: boxes other nodes sit in */\nexport const GROUP_TYPES = {\n domain: \"domain-group\",\n system: \"system-group\",\n} as const;\nexport const isGroupType = (type?: string) =>\n type === GROUP_TYPES.domain || type === GROUP_TYPES.system;\n\nexport type NodeDefinition = {\n /** React Flow node type, matches the visualiser node component keys */\n type: string;\n /** Its key in the components list when several share a node type (the kinds of data store); else its type */\n id?: string;\n label: string;\n /** What it is, in a few words (beside its name in the components list) */\n summary?: string;\n category: NodeCategory;\n /** Not in the components list (still drawn, for canvases that have them) */\n unlisted?: boolean;\n /** Where the resource lives inside node.data (e.g. `service` for data.service). Undefined = data root */\n resourceKey?: string;\n /** Nodes that are sized on the canvas (containers, notes, text) start at this size */\n defaultSize?: { width: number; height: number };\n /** Only its width is set: its height follows what's in it (notes) */\n autoHeight?: boolean;\n /** Neither is set: it's as big as what's in it (text, as Excalidraw's; defaultSize is only where it's put) */\n autoSize?: boolean;\n /**\n * The first level of detail that shows it (it's on the more detailed ones too, see levels.ts): L1 domains, systems\n * and actors, L2 services, data stores, text and the like, L3 messages and channels. Notes are on every level.\n */\n firstLevel: 1 | 2 | 3;\n createData: () => Record<string, unknown>;\n};\n\nconst resource = (name: string, summary: string) => ({\n name,\n version: \"0.0.1\",\n summary,\n owners: [],\n});\n\n/** The kinds of data store in the components list (EventCatalog's container types; agents can use the others too) */\nconst DATA_KINDS = [\n {\n containerType: \"database\",\n label: \"Database\",\n name: \"New Database\",\n summary: \"Tables, e.g. PostgreSQL\",\n },\n {\n containerType: \"cache\",\n label: \"Cache\",\n name: \"New Cache\",\n summary: \"Fast data, e.g. Redis\",\n },\n {\n containerType: \"searchIndex\",\n label: \"Search index\",\n name: \"New Search Index\",\n summary: \"Search, e.g. Elasticsearch\",\n },\n {\n containerType: \"objectStore\",\n label: \"Object store\",\n name: \"New Object Store\",\n summary: \"Files and blobs, e.g. S3\",\n },\n] as const;\n\nexport const nodeDefinitions: NodeDefinition[] = [\n {\n type: GROUP_TYPES.domain,\n firstLevel: 1,\n label: \"Domain\",\n summary: \"A business area, e.g. Sales\",\n category: \"boundaries\",\n resourceKey: \"domain\",\n defaultSize: { width: 720, height: 460 },\n createData: () => ({ domain: { name: \"New Domain\", version: \"0.0.1\" } }),\n },\n {\n type: GROUP_TYPES.system,\n firstLevel: 1,\n label: \"System\",\n summary: \"Services doing one job\",\n category: \"boundaries\",\n resourceKey: \"system\",\n defaultSize: { width: 560, height: 360 },\n createData: () => ({ system: { name: \"New System\", version: \"0.0.1\" } }),\n },\n {\n type: \"service\",\n firstLevel: 2,\n category: \"architecture\",\n label: \"Service\",\n summary: \"An API, worker or function\",\n resourceKey: \"service\",\n createData: () => ({\n mode: \"full\",\n service: {\n ...resource(\"New Service\", \"Describe what this service does.\"),\n sends: [],\n receives: [],\n },\n }),\n },\n {\n type: \"event\",\n firstLevel: 3,\n category: \"messages\",\n label: \"Event\",\n summary: \"Something that happened\",\n resourceKey: \"message\",\n createData: () => ({\n mode: \"full\",\n message: resource(\"NewEvent\", \"Something happened.\"),\n }),\n },\n {\n type: \"command\",\n firstLevel: 3,\n category: \"messages\",\n label: \"Command\",\n summary: \"A request to do something\",\n resourceKey: \"message\",\n createData: () => ({\n mode: \"full\",\n message: resource(\"NewCommand\", \"Asks a service to do something.\"),\n }),\n },\n {\n type: \"query\",\n firstLevel: 3,\n category: \"messages\",\n label: \"Query\",\n summary: \"A request for data\",\n resourceKey: \"message\",\n createData: () => ({\n mode: \"full\",\n message: resource(\"NewQuery\", \"Asks for some information.\"),\n }),\n },\n {\n type: \"channel\",\n firstLevel: 3,\n // With the messages it carries\n category: \"messages\",\n label: \"Channel\",\n summary: \"A topic, queue or bus\",\n resourceKey: \"channel\",\n createData: () => ({\n mode: \"full\",\n channel: {\n ...resource(\"new.channel\", \"Where messages are routed.\"),\n protocols: [],\n },\n }),\n },\n {\n type: \"view\",\n firstLevel: 2,\n category: \"architecture\",\n label: \"View\",\n summary: \"A screen or app people use\",\n resourceKey: \"view\",\n createData: () => ({\n mode: \"full\",\n view: resource(\"New View\", \"What the user sees.\"),\n }),\n },\n {\n type: \"externalSystem\",\n firstLevel: 1,\n category: \"architecture\",\n label: \"External System\",\n summary: \"A third party you use\",\n resourceKey: \"externalSystem\",\n createData: () => ({\n mode: \"full\",\n externalSystem: resource(\"External System\", \"A third party system.\"),\n }),\n },\n {\n type: \"agent\",\n // The detail of how things work, like messages: shown on L3 (L1 and L2 draw past it)\n firstLevel: 3,\n category: \"architecture\",\n label: \"Agent\",\n summary: \"An AI agent at work\",\n resourceKey: \"agent\",\n createData: () => ({\n mode: \"full\",\n agent: {\n ...resource(\"New Agent\", \"What this agent does.\"),\n sends: [],\n receives: [],\n },\n }),\n },\n {\n type: \"actor\",\n firstLevel: 1,\n // Who uses the architecture: customers, operators, partners (Studio's actors)\n category: \"people\",\n label: \"Actor\",\n summary: \"Someone who uses it\",\n // Drawn like the visualiser's actors (by name only); the summary is for agents and the properties panel\n createData: () => ({ mode: \"full\", name: \"Customer\", summary: \"\" }),\n },\n {\n type: \"team\",\n firstLevel: 1,\n // Who owns what: connected to a domain, system or service, it's its owner (EventCatalog's owners)\n category: \"people\",\n label: \"Team\",\n summary: \"Who owns what\",\n resourceKey: \"team\",\n createData: () => ({\n mode: \"full\",\n team: resource(\"New Team\", \"What this team looks after.\"),\n }),\n },\n {\n type: \"text\",\n // On the bar at the top (T, N), not in the palette\n unlisted: true,\n firstLevel: 2,\n category: \"other\",\n label: \"Text\",\n defaultSize: { width: 240, height: 40 },\n autoSize: true,\n createData: () => ({ text: \"Add some text\" }),\n },\n {\n type: \"note\",\n // On the bar at the top (T, N), not in the palette\n unlisted: true,\n firstLevel: 1,\n category: \"other\",\n label: \"Sticky Note\",\n // About square, like a post-it (taller if more is written on it)\n defaultSize: { width: 200, height: 176 },\n autoHeight: true,\n createData: () => ({ text: \"\", color: \"yellow\" }),\n },\n // The kinds of data store: all data nodes (EventCatalog's containers), told apart by their container_type\n ...DATA_KINDS.map(\n ({ containerType, label, name, summary }): NodeDefinition => ({\n type: \"data\",\n ...(containerType !== \"database\" && { id: `data:${containerType}` }),\n firstLevel: 2,\n category: \"data\",\n label,\n summary,\n resourceKey: \"data\",\n createData: () => ({\n mode: \"full\",\n data: {\n ...resource(name, \"Stores data.\"),\n container_type: containerType,\n },\n }),\n }),\n ),\n {\n type: \"entity\",\n // The domain model: detail, like messages (L3)\n firstLevel: 3,\n // The domain's data model, with the stores it's kept in\n category: \"data\",\n label: \"Entity\",\n summary: \"Part of the domain model\",\n resourceKey: \"entity\",\n createData: () => ({\n mode: \"full\",\n entity: {\n ...resource(\"NewEntity\", \"Something the domain keeps track of.\"),\n properties: [\n { name: \"id\", type: \"string\", required: true },\n { name: \"createdAt\", type: \"string\" },\n ],\n },\n }),\n },\n];\n\n/** A component's key in the components list (and what's dragged from it) */\nexport const componentKey = (definition: NodeDefinition) =>\n definition.id ?? definition.type;\n\n/** The types people and agents can add (not the unlisted ones), each once (the kinds of data store are all `data`) */\nexport const COMPONENT_TYPES = [\n ...new Set(\n nodeDefinitions\n .filter((definition) => !definition.unlisted)\n .map((definition) => definition.type),\n ),\n] as [string, ...string[]];\n\n// By key: a node type finds its own (for data, the database), a kind of data store its kind\nconst definitionsByType = new Map(\n nodeDefinitions.map((definition) => [componentKey(definition), definition]),\n);\n\n// Node types that only come from the catalog (not in the components list)\nconst catalogNodeTypes: Record<\n string,\n { label: string; resourceKey: string; firstLevel: 1 | 2 | 3 }\n> = {\n system: { label: \"System\", resourceKey: \"system\", firstLevel: 1 },\n \"context-domain\": { label: \"Domain\", resourceKey: \"domain\", firstLevel: 1 },\n};\n\nexport const getNodeDefinition = (type?: string) =>\n type ? definitionsByType.get(type) : undefined;\n\nexport const getNodeLabel = (type?: string) =>\n getNodeDefinition(type)?.label ??\n catalogNodeTypes[type ?? \"\"]?.label ??\n \"Node\";\n\n// About the size the visualiser's resource cards render at\nexport const DEFAULT_NODE_SIZE = { width: 240, height: 112 };\n\n/** The size a new node of a type starts at (or, for cards, about the size it renders at) */\nexport const getNodeSize = (type?: string) =>\n getNodeDefinition(type)?.defaultSize ?? DEFAULT_NODE_SIZE;\n\nconst getResourceKey = (type?: string) =>\n getNodeDefinition(type)?.resourceKey ??\n catalogNodeTypes[type ?? \"\"]?.resourceKey;\n\n/** The resource object for a node (e.g. data.service), or the data itself for flat nodes */\nexport const getResource = (\n type: string | undefined,\n data: Record<string, unknown>,\n): Record<string, unknown> => {\n const key = getResourceKey(type);\n return key ? ((data[key] as Record<string, unknown>) ?? {}) : data;\n};\n\n/** Sticky notes sit on the canvas wherever they're put, never inside a container */\n// Notes and text go anywhere, never in a container (one that's in one is taken out when it's next moved)\nexport const canGoInContainer = (type?: string) => !isWrittenOnCanvas(type);\n\n/**\n * Whether a container can hold a kind of node, as EventCatalog's domains and systems do: a domain holds anything\n * (subdomains, systems, services...), a system anything but a domain\n */\nexport const canHold = (containerType?: string, type?: string) =>\n canGoInContainer(type) &&\n (containerType === GROUP_TYPES.domain ||\n (containerType === GROUP_TYPES.system &&\n type !== GROUP_TYPES.domain &&\n type !== \"context-domain\"));\n\n/**\n * The level (L1, L2 or L3) a sticky note or text was written on: it's only shown there. Ones from before they had\n * levels are on L3, the canvas people edit. Other nodes are on every level they fit in, so they have none.\n */\nexport const getNoteLevel = (node: {\n type?: string;\n data: Record<string, unknown>;\n}): 1 | 2 | 3 | undefined =>\n isWrittenOnCanvas(node.type)\n ? ((node.data.level as 1 | 2 | undefined) ?? 3)\n : undefined;\n\n/** Whether a node is on a level's canvas as itself: everything on L3, but notes and text only on their level */\nexport const isOnLevel = (\n node: { type?: string; data: Record<string, unknown> },\n level: 1 | 2 | 3,\n) => !isWrittenOnCanvas(node.type) || getNoteLevel(node) === level;\n\n/** Whether a level of detail shows a kind of node (so it can be added there, and stay there) */\nexport const isShownOnLevel = (type: string | undefined, level: 1 | 2 | 3) =>\n level >=\n (getNodeDefinition(type)?.firstLevel ??\n catalogNodeTypes[type ?? \"\"]?.firstLevel ??\n 3);\n\n/** Whether a node's resource has a version (actors, notes and text don't) */\nexport const isVersioned = (type?: string) => !!getResourceKey(type);\n\n/** Notes and text: written on the canvas itself (their text is their data, not a resource with a name) */\nexport const isWrittenOnCanvas = (type?: string) =>\n type === \"note\" || type === \"text\";\n\n/** Returns new node data with fields of the resource changed */\nexport const updateResource = (\n type: string | undefined,\n data: Record<string, unknown>,\n fields: Record<string, unknown>,\n) => {\n const key = getResourceKey(type);\n return key\n ? { ...data, [key]: { ...getResource(type, data), ...fields } }\n : { ...data, ...fields };\n};\n\n/** A node's name, as people and agents see it */\nexport const getNodeName = (\n type: string | undefined,\n data: Record<string, unknown>,\n fallback = \"node\",\n) => String(getResource(type, data).name ?? data.text ?? fallback);\n","import type { Node, XYPosition } from \"@xyflow/react\";\nimport {\n canGoInContainer,\n canHold,\n getNodeSize,\n isGroupType,\n} from \"./node-types\";\n\n/**\n * Containers: domains and systems shown as boxes that other nodes sit in.\n * A node inside one has its parentId, and its position is relative to the container.\n */\n\n/** Room around what's in a container, and for its header */\nexport const GROUP_PADDING = { top: 80, right: 40, bottom: 40, left: 40 };\n\ntype Rect = { x: number; y: number; width: number; height: number };\n\nconst byId = (nodes: Node[]) => new Map(nodes.map((node) => [node.id, node]));\n\n/** A node's size: as rendered (in the browser), as set (containers, notes), or what its type renders at */\nexport const sizeOf = (node: Node) => ({\n width: node.measured?.width ?? node.width ?? getNodeSize(node.type).width,\n height: node.measured?.height ?? node.height ?? getNodeSize(node.type).height,\n});\n\n/** Nodes are positioned relative to their container, so walk up the chain to get the canvas position */\nexport const getAbsolutePosition = (\n node: Node,\n lookup: Map<string, Node>,\n): XYPosition => {\n const parent = node.parentId ? lookup.get(node.parentId) : undefined;\n if (!parent) return node.position;\n const parentPosition = getAbsolutePosition(parent, lookup);\n return {\n x: parentPosition.x + node.position.x,\n y: parentPosition.y + node.position.y,\n };\n};\n\nexport const getAbsoluteRect = (\n node: Node,\n lookup: Map<string, Node>,\n): Rect => ({\n ...getAbsolutePosition(node, lookup),\n ...sizeOf(node),\n});\n\nconst getDepth = (node: Node, lookup: Map<string, Node>): number => {\n const parent = node.parentId ? lookup.get(node.parentId) : undefined;\n return parent ? 1 + getDepth(parent, lookup) : 0;\n};\n\nconst isDescendantOf = (\n node: Node,\n ancestorId: string,\n lookup: Map<string, Node>,\n): boolean => {\n if (!node.parentId) return false;\n if (node.parentId === ancestorId) return true;\n const parent = lookup.get(node.parentId);\n return parent ? isDescendantOf(parent, ancestorId, lookup) : false;\n};\n\nconst containsPoint = (rect: Rect, point: XYPosition) =>\n point.x >= rect.x &&\n point.x <= rect.x + rect.width &&\n point.y >= rect.y &&\n point.y <= rect.y + rect.height;\n\n/** React Flow needs containers before what's in them in the nodes array */\nexport const sortByHierarchy = (nodes: Node[]): Node[] => {\n const lookup = byId(nodes);\n return nodes\n .map((node, index) => ({ node, index, depth: getDepth(node, lookup) }))\n .sort((a, b) => a.depth - b.depth || a.index - b.index)\n .map(({ node }) => node);\n};\n\n/** The innermost container under the centre of a node (never itself, or one of its own children) */\nexport const findDropTarget = (\n nodeId: string,\n nodes: Node[],\n): Node | undefined => {\n const lookup = byId(nodes);\n const node = lookup.get(nodeId);\n // Sticky notes and text go anywhere, never in a container (one that's in one is taken out when it's next moved)\n if (!node || !canGoInContainer(node.type)) return undefined;\n const rect = getAbsoluteRect(node, lookup);\n const center = { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 };\n return nodes\n .filter(\n (candidate) =>\n canHold(candidate.type, node.type) &&\n candidate.id !== nodeId &&\n !isDescendantOf(candidate, nodeId, lookup),\n )\n .filter((candidate) =>\n containsPoint(getAbsoluteRect(candidate, lookup), center),\n )\n .sort((a, b) => getDepth(b, lookup) - getDepth(a, lookup))[0];\n};\n\n/**\n * Where what's dragged goes when it's dropped: the containers it moves into (or out of, with no target), for the\n * ones whose container changes. A selection follows the node held by the pointer: when that one goes into a\n * container, or out of one, everything with it that can go there goes too (sticky notes and text never go in one).\n * When it stays where it is, each one goes into the container under its middle, as one dragged alone does.\n */\nexport const findDropTargets = (\n grabbedId: string,\n draggedIds: Iterable<string>,\n nodes: Node[],\n): { id: string; target: Node | undefined }[] => {\n const lookup = byId(nodes);\n const dragged = new Set(draggedIds);\n // What's moved itself: not what's in a container dragged with it (that moves with its container)\n const roots = [...dragged].filter((id) => {\n const parentId = lookup.get(id)?.parentId;\n return lookup.has(id) && (!parentId || !dragged.has(parentId));\n });\n let held = lookup.get(grabbedId);\n while (held?.parentId && dragged.has(held.parentId))\n held = lookup.get(held.parentId);\n const heldTarget =\n held && canGoInContainer(held.type)\n ? findDropTarget(held.id, nodes)\n : undefined;\n const followHeld =\n !!held && canGoInContainer(held.type) && heldTarget?.id !== held.parentId;\n const canFollow = (node: Node) =>\n canGoInContainer(node.type) &&\n (!heldTarget ||\n (canHold(heldTarget.type, node.type) &&\n heldTarget.id !== node.id &&\n !isDescendantOf(heldTarget, node.id, lookup)));\n return roots.flatMap((id) => {\n const node = lookup.get(id)!;\n const target =\n followHeld && canFollow(node) ? heldTarget : findDropTarget(id, nodes);\n return target?.id === node.parentId ? [] : [{ id, target }];\n });\n};\n\n/** The innermost container at a canvas point, for things dropped there (that can hold a kind of node, when given) */\nexport const findGroupAtPoint = (\n point: XYPosition,\n nodes: Node[],\n type?: string,\n): Node | undefined => {\n const lookup = byId(nodes);\n return nodes\n .filter(\n (candidate) =>\n (type ? canHold(candidate.type, type) : isGroupType(candidate.type)) &&\n containsPoint(getAbsoluteRect(candidate, lookup), point),\n )\n .sort((a, b) => getDepth(b, lookup) - getDepth(a, lookup))[0];\n};\n\n/** The container something added goes in: the one asked for (by id), else the one it's dropped on */\nexport const containerFor = (\n point: XYPosition,\n nodes: Node[],\n inside?: string,\n type?: string,\n): Node | undefined =>\n inside\n ? nodes.find(\n (node) =>\n node.id === inside &&\n (type ? canHold(node.type, type) : isGroupType(node.type)),\n )\n : findGroupAtPoint(point, nodes, type);\n\n/** A node moved into (or out of, without a parentId) a container, staying in the same place on the canvas */\nexport const withParent = (\n node: Node,\n parentId: string | undefined,\n nodes: Node[],\n): Node => {\n const lookup = byId(nodes);\n const absolute = getAbsolutePosition(node, lookup);\n const parent = parentId ? lookup.get(parentId) : undefined;\n const parentPosition = parent\n ? getAbsolutePosition(parent, lookup)\n : { x: 0, y: 0 };\n const { parentId: _, extent: __, ...rest } = node;\n return {\n ...rest,\n ...(parent && { parentId: parent.id }),\n position: {\n x: absolute.x - parentPosition.x,\n y: absolute.y - parentPosition.y,\n },\n };\n};\n\n/** The least room left between something dropped in a container and what's already in it */\nexport const DROP_GAP = 32;\n\n/**\n * How much more moving something out past its container's edges (making it grow) counts than moving it further:\n * more up and left, where the container grows by moving on the canvas (towards what's there), than down and right\n */\nconst GROWTH_COST = { down: 4, up: 12 };\n\nconst overlaps = (a: Rect, b: Rect, gap: number) =>\n a.x < b.x + b.width + gap &&\n b.x < a.x + a.width + gap &&\n a.y < b.y + b.height + gap &&\n b.y < a.y + a.height + gap;\n\n/** How far a rect is past the edges of an area: above and left of it, and below and right of it */\nconst pastEdges = (rect: Rect, area: Rect) => ({\n up: Math.max(0, area.x - rect.x) + Math.max(0, area.y - rect.y),\n down:\n Math.max(0, rect.x + rect.width - (area.x + area.width)) +\n Math.max(0, rect.y + rect.height - (area.y + area.height)),\n});\n\n/** Where a rect goes inside an area, moved as little as it can be (its top left, when it's bigger than the area) */\nconst into = (rect: Rect, area: Rect): XYPosition => ({\n x: Math.max(area.x, Math.min(rect.x, area.x + area.width - rect.width)),\n y: Math.max(area.y, Math.min(rect.y, area.y + area.height - rect.height)),\n});\n\n/**\n * Where a rect goes so it's not on (or within `gap` of) an obstacle: the free place that's the least move from where\n * it is, counting a move out past the area's edges (its container growing) as `GROWTH_COST` times more (more up and\n * left). Looked for by stepping beside what's in the way (right, left, below, above), a few steps deep, from where it\n * is and from there moved into the area. Boxed in: below everything.\n */\nconst freeSpot = (\n rect: Rect,\n obstacles: Rect[],\n area: Rect,\n gap: number,\n): XYPosition => {\n const at = (position: XYPosition) => ({ ...rect, ...position });\n const inTheWay = (position: XYPosition) =>\n obstacles.filter((obstacle) => overlaps(at(position), obstacle, gap));\n const cost = (position: XYPosition) => {\n const past = pastEdges(at(position), area);\n return (\n Math.hypot(position.x - rect.x, position.y - rect.y) +\n GROWTH_COST.up * past.up +\n GROWTH_COST.down * past.down\n );\n };\n const seen = new Set<string>();\n let best: XYPosition | undefined;\n let frontier: XYPosition[] = [];\n const consider = (position: XYPosition) => {\n const key = `${position.x},${position.y}`;\n if (seen.has(key)) return;\n seen.add(key);\n if (best && cost(position) >= cost(best)) return;\n if (inTheWay(position).length) frontier.push(position);\n else best = position;\n };\n consider({ x: rect.x, y: rect.y });\n consider(into(rect, area));\n for (let depth = 0; depth < 4 && frontier.length; depth++) {\n const from = frontier.sort((a, b) => cost(a) - cost(b)).slice(0, 24);\n frontier = [];\n for (const position of from) {\n for (const obstacle of inTheWay(position)) {\n consider({ x: obstacle.x + obstacle.width + gap, y: position.y });\n consider({ x: obstacle.x - gap - rect.width, y: position.y });\n consider({ x: position.x, y: obstacle.y + obstacle.height + gap });\n consider({ x: position.x, y: obstacle.y - gap - rect.height });\n }\n }\n }\n return (\n best ?? {\n x: rect.x,\n y: Math.max(\n ...obstacles.map((obstacle) => obstacle.y + obstacle.height + gap),\n ),\n }\n );\n};\n\n/**\n * Where things dropped in containers go in them (relative to the container): where they were dropped when that's\n * free and inside it, else the nearest free place, keeping inside the container (so it doesn't grow over what's around\n * it) unless there's no room. What's dropped stays clear of what's in the container and of each other. `moves` are\n * what `findDropTargets` returns; ones taken out of a container aren't placed (they stay where they were dropped).\n * `nudged` when any had to move from where it was dropped (to show it gliding there).\n */\nexport const placeDropped = (\n nodes: Node[],\n moves: { id: string; target: Node | undefined }[],\n gap = DROP_GAP,\n): { places: Map<string, XYPosition>; nudged: boolean } => {\n const lookup = byId(nodes);\n const places = new Map<string, XYPosition>();\n let nudged = false;\n const moved = new Set(moves.map(({ id }) => id));\n const byTarget = new Map<string, string[]>();\n for (const { id, target } of moves) {\n if (target)\n byTarget.set(target.id, [...(byTarget.get(target.id) ?? []), id]);\n }\n for (const [targetId, ids] of byTarget) {\n const container = lookup.get(targetId)!;\n const size = sizeOf(container);\n // Inside its padding, under its header\n const area = {\n x: GROUP_PADDING.left,\n y: GROUP_PADDING.top,\n width: Math.max(0, size.width - GROUP_PADDING.left - GROUP_PADDING.right),\n height: Math.max(\n 0,\n size.height - GROUP_PADDING.top - GROUP_PADDING.bottom,\n ),\n };\n const obstacles = nodes\n .filter((node) => node.parentId === targetId && !moved.has(node.id))\n .map((node) => ({ ...node.position, ...sizeOf(node) }));\n const dropped = ids.flatMap((id) => {\n const node = lookup.get(id);\n if (!node) return [];\n const inside = withParent(node, targetId, nodes);\n return [{ id, rect: { ...inside.position, ...sizeOf(node) } }];\n });\n // What's dropped in a free place inside it first, so it keeps that place and the rest go round it\n const settled = (rect: Rect) => {\n const past = pastEdges(rect, area);\n return (\n !past.up &&\n !past.down &&\n !obstacles.some((obstacle) => overlaps(rect, obstacle, gap))\n );\n };\n dropped.sort((a, b) => Number(settled(b.rect)) - Number(settled(a.rect)));\n for (const { id, rect } of dropped) {\n const spot = freeSpot(rect, obstacles, area, gap);\n if (spot.x !== rect.x || spot.y !== rect.y) nudged = true;\n places.set(id, spot);\n obstacles.push({ ...rect, ...spot });\n }\n }\n return { places, nudged };\n};\n\n/** A canvas point, relative to a container */\nexport const toRelativePosition = (\n point: XYPosition,\n parentId: string,\n nodes: Node[],\n): XYPosition => {\n const lookup = byId(nodes);\n const parent = lookup.get(parentId);\n if (!parent) return point;\n const parentPosition = getAbsolutePosition(parent, lookup);\n return { x: point.x - parentPosition.x, y: point.y - parentPosition.y };\n};\n\n/** Nodes and everything inside them (deleted with their container) */\nexport const withDescendants = (ids: string[], nodes: Node[]): Set<string> => {\n const lookup = byId(nodes);\n const result = new Set(ids);\n nodes.forEach((node) => {\n if (ids.some((id) => isDescendantOf(node, id, lookup))) result.add(node.id);\n });\n return result;\n};\n\n/**\n * The size a container needs to fit what's inside it, never smaller than it is, and how far its children\n * must shift when some sit above or left of its content area (so the header stays clear).\n */\nexport const fitGroup = (groupId: string, nodes: Node[]) => {\n const lookup = byId(nodes);\n const group = lookup.get(groupId);\n const children = nodes.filter((node) => node.parentId === groupId);\n if (!group || children.length === 0) return undefined;\n const rects = children.map((child) => ({\n ...child.position,\n ...sizeOf(child),\n }));\n const shift = {\n x: Math.max(\n 0,\n GROUP_PADDING.left - Math.min(...rects.map((rect) => rect.x)),\n ),\n y: Math.max(\n 0,\n GROUP_PADDING.top - Math.min(...rects.map((rect) => rect.y)),\n ),\n };\n const current = sizeOf(group);\n return {\n shift,\n width: Math.max(\n current.width,\n Math.max(...rects.map((rect) => rect.x + rect.width)) +\n shift.x +\n GROUP_PADDING.right,\n ),\n height: Math.max(\n current.height,\n Math.max(...rects.map((rect) => rect.y + rect.height)) +\n shift.y +\n GROUP_PADDING.bottom,\n ),\n };\n};\n\n/** How far a dragged node's middle can go past a container's edge and still be kept in it (growing it) */\nexport const KEEP_IN_CONTAINER_MARGIN = 160;\n\n/** A node's place and size as shown while something's dragged */\nexport type NodePreview = {\n position: XYPosition;\n width?: number;\n height?: number;\n};\n\n/**\n * Containers growing to fit what's being dragged in them, on every side, as a preview of where things will be.\n * `containerIds` are the containers around what's dragged, innermost first. `start` is the canvas when the drag\n * started, and `now` the canvas as shown (with the dragged nodes where they are now). A dragged node is kept in a\n * container while its middle is within `KEEP_IN_CONTAINER_MARGIN` of where the container was, and dropping it\n * further away takes it out, so the container goes back to its size. A container growing up or left moves, and\n * what's in it moves the other way, so nothing moves on the canvas.\n *\n * Returns, by id, where containers and the nodes in them that aren't dragged go (positions relative to their\n * containers), and their sizes for containers.\n */\nexport const previewContainerGrowth = (\n containerIds: string[],\n draggedIds: ReadonlySet<string>,\n start: ReadonlyMap<string, Node>,\n now: ReadonlyMap<string, Node>,\n): Map<string, NodePreview> => {\n const previews = new Map<string, NodePreview>();\n // Where each container's top left was on the canvas when the drag started (moving a container grown up or\n // left is offset by what's in it moving the other way, so only its own shift changes it)\n const startOrigin = (id: string) =>\n getAbsolutePosition(start.get(id)!, start as Map<string, Node>);\n const shifts = new Map<string, XYPosition>();\n\n for (const id of containerIds) {\n const container = start.get(id);\n if (!container) continue;\n const origin = startOrigin(id);\n const startSize = sizeOf(container);\n // Everything in it, in its coordinates when the drag started\n const items: { rect: Rect }[] = [];\n for (const node of start.values()) {\n if (node.parentId !== id) continue;\n if (draggedIds.has(node.id)) {\n const current = now.get(node.id);\n if (!current) continue;\n const at = getAbsoluteRect(current, now as Map<string, Node>);\n const middle = { x: at.x + at.width / 2, y: at.y + at.height / 2 };\n const kept =\n middle.x >= origin.x - KEEP_IN_CONTAINER_MARGIN &&\n middle.x <= origin.x + startSize.width + KEEP_IN_CONTAINER_MARGIN &&\n middle.y >= origin.y - KEEP_IN_CONTAINER_MARGIN &&\n middle.y <= origin.y + startSize.height + KEEP_IN_CONTAINER_MARGIN;\n if (kept)\n items.push({\n rect: { ...at, x: at.x - origin.x, y: at.y - origin.y },\n });\n continue;\n }\n // A container inside it that's grown: where it's grown to\n const inner = previews.get(node.id);\n const innerShift = shifts.get(node.id) ?? { x: 0, y: 0 };\n items.push({\n rect: {\n x: node.position.x - innerShift.x,\n y: node.position.y - innerShift.y,\n ...(inner?.width && inner.height\n ? { width: inner.width, height: inner.height }\n : sizeOf(node)),\n },\n });\n }\n\n const shift = { x: 0, y: 0 };\n let width = startSize.width;\n let height = startSize.height;\n if (items.length > 0) {\n shift.x = Math.max(\n 0,\n GROUP_PADDING.left - Math.min(...items.map(({ rect }) => rect.x)),\n );\n shift.y = Math.max(\n 0,\n GROUP_PADDING.top - Math.min(...items.map(({ rect }) => rect.y)),\n );\n width =\n Math.max(\n startSize.width,\n Math.max(...items.map(({ rect }) => rect.x + rect.width)) +\n GROUP_PADDING.right,\n ) + shift.x;\n height =\n Math.max(\n startSize.height,\n Math.max(...items.map(({ rect }) => rect.y + rect.height)) +\n GROUP_PADDING.bottom,\n ) + shift.y;\n }\n shifts.set(id, shift);\n previews.set(id, {\n position: {\n x: container.position.x - shift.x,\n y: container.position.y - shift.y,\n },\n width,\n height,\n });\n // What's in it moves the other way. Not what's dragged: React Flow places it against the container as it is.\n for (const node of start.values()) {\n if (node.parentId !== id || draggedIds.has(node.id)) continue;\n const own = previews.get(node.id);\n const base = own?.position ?? node.position;\n previews.set(node.id, {\n ...own,\n position: { x: base.x + shift.x, y: base.y + shift.y },\n });\n }\n }\n return previews;\n};\n","import type { Edge, Node, XYPosition } from \"@xyflow/react\";\nimport { shortId, toSharedNode } from \"./canvas-doc\";\nimport {\n findGroupAtPoint,\n getAbsolutePosition,\n sizeOf,\n sortByHierarchy,\n withDescendants,\n} from \"./grouping\";\nimport { canGoInContainer } from \"./node-types\";\n\n/**\n * Copying and pasting nodes, within a canvas or between canvases (through the system clipboard). What's copied is\n * the selected nodes, everything inside selected containers, and the connections between them. Comments aren't.\n */\n\n/** The clipboard type Studio reads first (other apps get a plain text list of what was copied) */\nexport const CLIPBOARD_TYPE = \"application/x-eventcatalog-studio+json\";\nconst MARKER = \"eventcatalog-studio/nodes@1\";\n\nexport type ClipboardContent = {\n marker: typeof MARKER;\n nodes: Node[];\n edges: Edge[];\n};\n\n/** What's copied when these nodes are selected, or null if there's nothing to copy */\nexport const copyNodes = (\n nodes: Node[],\n edges: Edge[],\n selectedIds: string[],\n): ClipboardContent | null => {\n if (selectedIds.length === 0) return null;\n const lookup = new Map(nodes.map((node) => [node.id, node]));\n const ids = withDescendants(selectedIds, nodes);\n const copied = sortByHierarchy(nodes.filter((node) => ids.has(node.id))).map(\n (node) => {\n const shared = toSharedNode(node);\n // Copied without its container: where it is on the canvas\n if (shared.parentId && !ids.has(shared.parentId)) {\n const { parentId: _, ...rest } = shared;\n return { ...rest, position: getAbsolutePosition(node, lookup) };\n }\n return shared;\n },\n );\n return {\n marker: MARKER,\n nodes: copied,\n edges: edges\n .filter((edge) => ids.has(edge.source) && ids.has(edge.target))\n .map(({ selected: _, ...edge }) => edge),\n };\n};\n\n/** Copied content read back from the clipboard, if it's Studio's */\nexport const readClipboard = (\n text: string | undefined,\n): ClipboardContent | null => {\n if (!text) return null;\n try {\n const content = JSON.parse(text) as Partial<ClipboardContent>;\n return content.marker === MARKER &&\n Array.isArray(content.nodes) &&\n Array.isArray(content.edges)\n ? (content as ClipboardContent)\n : null;\n } catch {\n return null;\n }\n};\n\n/**\n * Copies of the content to add to the canvas, with new ids: centred on a point (e.g. the pointer), or moved by an\n * offset from where they were copied. Copies that land in a container on the canvas go inside it.\n */\nexport const pasteNodes = (\n content: ClipboardContent,\n existing: Node[],\n place: { at: XYPosition } | { offset: XYPosition },\n): { nodes: Node[]; edges: Edge[] } => {\n const ids = new Map(\n content.nodes.map((node) => [\n node.id,\n `${node.type ?? \"node\"}-${shortId()}`,\n ]),\n );\n const roots = content.nodes.filter((node) => !node.parentId);\n const offset =\n \"offset\" in place ? place.offset : offsetToCentre(roots, place.at);\n\n const lookup = new Map(existing.map((node) => [node.id, node]));\n const nodes = content.nodes.map((node): Node => {\n const id = ids.get(node.id)!;\n if (node.parentId) return { ...node, id, parentId: ids.get(node.parentId) };\n const position = {\n x: node.position.x + offset.x,\n y: node.position.y + offset.y,\n };\n const { width, height } = sizeOf(node);\n const container = canGoInContainer(node.type)\n ? findGroupAtPoint(\n { x: position.x + width / 2, y: position.y + height / 2 },\n existing,\n )\n : undefined;\n if (!container) return { ...node, id, position };\n const origin = getAbsolutePosition(container, lookup);\n return {\n ...node,\n id,\n parentId: container.id,\n position: { x: position.x - origin.x, y: position.y - origin.y },\n };\n });\n\n return {\n nodes,\n edges: content.edges.map((edge) => ({\n ...edge,\n id: `edge-${shortId()}`,\n source: ids.get(edge.source)!,\n target: ids.get(edge.target)!,\n })),\n };\n};\n\n/** How far to move nodes so the middle of them is at a point */\nconst offsetToCentre = (roots: Node[], at: XYPosition): XYPosition => {\n if (roots.length === 0) return { x: 0, y: 0 };\n const left = Math.min(...roots.map((node) => node.position.x));\n const top = Math.min(...roots.map((node) => node.position.y));\n const right = Math.max(\n ...roots.map((node) => node.position.x + sizeOf(node).width),\n );\n const bottom = Math.max(\n ...roots.map((node) => node.position.y + sizeOf(node).height),\n );\n return { x: at.x - (left + right) / 2, y: at.y - (top + bottom) / 2 };\n};\n","/**\n * Where a connection joins an entity: a property's row (the visualiser's `<property>-target` on its left and\n * `<property>-source` on its right), or the entity as a whole: its header (the visualiser's target there, and a\n * source the canvas adds beside it).\n */\nexport const ENTITY_SOURCE_HANDLE = \"__entity-source\";\n","import type { Edge, Node, XYPosition } from \"@xyflow/react\";\n\n/**\n * The design (nodes and edges) comes from the shared document; some state stays with each person: what they\n * have selected, what they're dragging and resizing, and the sizes React Flow measured in their browser.\n */\nexport const LOCAL_NODE_KEYS = [\n \"selected\",\n \"dragging\",\n \"resizing\",\n \"measured\",\n] as const satisfies readonly (keyof Node)[];\nexport const LOCAL_EDGE_KEYS = [\n \"selected\",\n] as const satisfies readonly (keyof Edge)[];\n\n/** A shared item with the local-only state of the one already shown. Nothing else is kept from the local one. */\nexport const withLocalState = <T extends object>(\n shared: T,\n local: T | undefined,\n localKeys: readonly (keyof T)[],\n): T => {\n if (!local) return shared;\n const kept: Partial<T> = {};\n for (const key of localKeys)\n if (local[key] !== undefined) kept[key] = local[key];\n return { ...shared, ...kept };\n};\n\n/**\n * Applies changes to shared items (by id) to the items shown, keeping every unchanged item as the same object\n * (so React Flow doesn't re-render it) and the order they were first seen in (new ones go at the end).\n * `getShared` returns an item's shared value, or undefined if it was deleted. Returns `local` itself when\n * nothing changed.\n */\nexport const patchShared = <T extends { id: string }>(\n local: T[],\n changedIds: Iterable<string>,\n getShared: (id: string) => T | undefined,\n localKeys: readonly (keyof T)[],\n): T[] => {\n const indexById = new Map(local.map((item, index) => [item.id, index]));\n let next: T[] | undefined;\n const removed = new Set<string>();\n const added: T[] = [];\n\n for (const id of changedIds) {\n const shared = getShared(id);\n const index = indexById.get(id);\n if (!shared) {\n if (index !== undefined) removed.add(id);\n continue;\n }\n if (index === undefined) {\n added.push(shared);\n continue;\n }\n next ??= [...local];\n next[index] = withLocalState(shared, local[index], localKeys);\n }\n\n if (!next && removed.size === 0 && added.length === 0) return local;\n const patched = next ?? local;\n return [\n ...(removed.size\n ? patched.filter((item) => !removed.has(item.id))\n : patched),\n ...added,\n ];\n};\n\n/** Whether two plain values (what nodes and edges hold) are the same, comparing what's in them */\nconst isSame = (a: unknown, b: unknown): boolean => {\n if (Object.is(a, b)) return true;\n if (\n !a ||\n !b ||\n typeof a !== \"object\" ||\n typeof b !== \"object\" ||\n Array.isArray(a) !== Array.isArray(b)\n )\n return false;\n const keys = Object.keys(a);\n return (\n keys.length === Object.keys(b).length &&\n keys.every((key) =>\n isSame(\n (a as Record<string, unknown>)[key],\n (b as Record<string, unknown>)[key],\n ),\n )\n );\n};\n\n/**\n * Items worked out again (e.g. a level arranged again), keeping each one that hasn't changed as the object already\n * shown (so React Flow doesn't re-render it), and the local-only state of the ones that have. Returns `previous`\n * itself when nothing changed.\n */\nexport const keepUnchanged = <T extends { id: string }>(\n previous: T[],\n next: T[],\n localKeys: readonly (keyof T)[],\n): T[] => {\n const shown = new Map(previous.map((item) => [item.id, item]));\n const local = new Set<PropertyKey>(localKeys);\n const kept = next.map((item) => {\n const before = shown.get(item.id);\n if (!before) return item;\n const keys = new Set([...Object.keys(before), ...Object.keys(item)]) as Set<\n keyof T\n >;\n const same = [...keys].every(\n (key) => local.has(key) || isSame(before[key], item[key]),\n );\n return same ? before : withLocalState(item, before, localKeys);\n });\n return kept.length === previous.length &&\n kept.every((item, index) => item === previous[index])\n ? previous\n : kept;\n};\n\n/** Where nodes being dragged are, by id, until they're dropped (and saved) */\nexport type Moves = ReadonlyMap<string, XYPosition>;\n\nconst samePosition = (a: XYPosition, b: XYPosition) =>\n a.x === b.x && a.y === b.y;\n\n/**\n * Nodes moved to the positions given (e.g. where someone else is dragging them), except ones being dragged\n * here. Returns `nodes` itself when none move.\n */\nexport const withPositions = (nodes: Node[], positions: Moves): Node[] => {\n if (positions.size === 0) return nodes;\n let next: Node[] | undefined;\n nodes.forEach((node, index) => {\n const position = positions.get(node.id);\n if (!position || node.dragging || samePosition(position, node.position))\n return;\n next ??= [...nodes];\n next[index] = { ...node, position };\n });\n return next ?? nodes;\n};\n\n/**\n * After shared changes are applied (`next`, from `previous`): nodes being dragged here stay where they're being\n * dragged (when they're dropped, the drop is saved and wins). Returns `next` itself when none are.\n */\nexport const keepDragged = (next: Node[], previous: Node[]): Node[] => {\n if (next === previous) return next;\n const dragged = new Map(\n previous\n .filter((node) => node.dragging)\n .map((node) => [node.id, node.position]),\n );\n if (dragged.size === 0) return next;\n let kept: Node[] | undefined;\n next.forEach((node, index) => {\n const position = dragged.get(node.id);\n if (!position || samePosition(position, node.position)) return;\n kept ??= [...next];\n kept[index] = { ...node, position };\n });\n return kept ?? next;\n};\n","import type { Edge, Node, XYPosition } from \"@xyflow/react\";\nimport { layoutWithElk } from \"../layout\";\nimport { getEdgeRoute, type EdgeRoute } from \"./canvas-doc\";\nimport { isGroupType, isOnLevel } from \"./node-types\";\n\n/**\n * Lays a canvas out with the same ELK layout as EventCatalog's visualiser (left to right, edges routed\n * around nodes, containers laid out with what's in them and sized to fit). Nodes are sized as rendered when\n * they have been (in the browser), or by their type.\n */\nexport const layoutGraph = (nodes: Node[], edges: Edge[]) =>\n layoutWithElk({ nodes, edges });\n\n/** The layout sizes containers with style.width/height; the canvas sizes them with width/height */\nexport const withGroupSizes = (nodes: Node[]): Node[] =>\n nodes.map((node) => {\n const { width, height, ...style } = node.style ?? {};\n if (typeof width !== \"number\" || typeof height !== \"number\") return node;\n return { ...node, width, height, style };\n });\n\nexport type LayoutResult = {\n /** Where each node goes (relative to its container, if it's in one), and containers' new sizes */\n nodes: Map<\n string,\n { position: XYPosition; size?: { width: number; height: number } }\n >;\n /** How each connection is drawn (around the nodes), by edge id */\n routes: Map<string, EdgeRoute>;\n};\n\n/**\n * The canvas laid out: new positions for its nodes, new sizes for containers, and routes for the connections\n * (drawn like the visualiser's: around the nodes, following them when they're moved, and as a plain step once\n * they've moved too far for it). Notes added on L1 or L2 aren't on this canvas, so they stay where they are.\n */\nexport const getLayoutPositions = async (\n nodes: Node[],\n edges: Edge[],\n): Promise<LayoutResult> => {\n const onCanvas = nodes.filter((node) => isOnLevel(node, 3));\n if (onCanvas.length === 0) return { nodes: new Map(), routes: new Map() };\n const ids = new Set(onCanvas.map((node) => node.id));\n const between = edges.filter(\n (edge) => ids.has(edge.source) && ids.has(edge.target),\n );\n const laidOut = await layoutGraph(onCanvas, between);\n return {\n nodes: new Map(\n withGroupSizes(laidOut.nodes).map((node) => [\n node.id,\n {\n position: node.position,\n ...(isGroupType(node.type) &&\n node.width &&\n node.height && {\n size: { width: node.width, height: node.height },\n }),\n },\n ]),\n ),\n routes: new Map(\n laidOut.edges.flatMap((edge) => {\n const route = getEdgeRoute(edge);\n return route ? [[edge.id, route] as const] : [];\n }),\n ),\n };\n};\n","import type { Node, XYPosition } from \"@xyflow/react\";\nimport {\n fitGroup,\n getAbsolutePosition,\n GROUP_PADDING,\n sizeOf,\n} from \"./grouping\";\n\n/**\n * Where agents put what they add without a position, the way an architect would: next to what it connects to,\n * following the flow left to right (what sends to it on its left, what it sends to on its right), lined up with\n * it, and stacked around it when several things connect to the same node. Nothing already on the canvas moves.\n * Things connected to nothing go in a row below what's there. Containers are filled first, so what goes around them\n * leaves room for what they grow to hold.\n */\n\n/** A connection between two nodes, from the one that sends to the one that receives */\nexport type Link = { source: string; target: string };\n\n/** Between connected nodes side by side (room for the labels on their connections), and nodes stacked in a column */\nconst GAP = { x: 200, y: 80 };\n/** The least room left around nodes */\nconst CLEARANCE = { x: 120, y: 60 };\n/** Between what's on the canvas and things connected to nothing added below it */\nconst BELOW_GAP = 120;\n/** Things connected to nothing go side by side (so connecting them later is easy), this many to a row */\nconst ROW_LENGTH = 4;\n/** How far to look for free space before giving up and going below everything */\nconst MAX_ROWS = 12;\nconst MAX_COLUMNS = 8;\n\ntype Rect = { x: number; y: number; width: number; height: number };\ntype Anchor = { rect: Rect; centerY: number; upstream: boolean };\n\nconst rectOf = (node: Node): Rect => ({ ...node.position, ...sizeOf(node) });\n\nconst tooClose = (a: Rect, b: Rect) =>\n a.x < b.x + b.width + CLEARANCE.x &&\n b.x < a.x + a.width + CLEARANCE.x &&\n a.y < b.y + b.height + CLEARANCE.y &&\n b.y < a.y + a.height + CLEARANCE.y;\n\nconst below = (rects: Rect[]): XYPosition => ({\n x: Math.min(...rects.map((rect) => rect.x)),\n y: Math.max(...rects.map((rect) => rect.y + rect.height)) + BELOW_GAP,\n});\n\n/** 0, 1, -1, 2, -2, …: rows below and above in turn, so things stacked around a node stay centred on it */\nconst rowOffset = (row: number) => (row % 2 ? (row + 1) / 2 : -row / 2);\n\n/**\n * Where the nodes to place go on the canvas (not relative to their containers: containers that grow to fit them\n * move what's in them, but nothing moves on the canvas). They're among `nodes`, with their containers set.\n * Everything else in `nodes` stays where it is.\n */\nexport const placeNodes = (\n nodes: Node[],\n toPlace: string[],\n links: Link[],\n): Map<string, XYPosition> => {\n const working = new Map(nodes.map((node) => [node.id, node]));\n const remaining = new Set(toPlace.filter((id) => working.has(id)));\n\n const neighbours = new Map<string, { id: string; upstream: boolean }[]>();\n const addNeighbour = (\n id: string,\n neighbour: { id: string; upstream: boolean },\n ) => neighbours.set(id, [...(neighbours.get(id) ?? []), neighbour]);\n for (const { source, target } of links) {\n addNeighbour(source, { id: target, upstream: false });\n addNeighbour(target, { id: source, upstream: true });\n }\n\n const depthOf = (id: string | undefined): number => {\n const node = id ? working.get(id) : undefined;\n return node ? 1 + depthOf(node.parentId) : 0;\n };\n\n /** The node, or the container it's in, that sits directly in a level (undefined for the canvas itself) */\n const atLevel = (id: string, level: string | undefined) => {\n let node = working.get(id);\n while (node && node.parentId !== level)\n node = node.parentId ? working.get(node.parentId) : undefined;\n return node;\n };\n\n /** The containers things are put in grow to fit them (innermost first), as they will on the canvas */\n const growing = new Set<string>();\n for (const id of remaining) {\n for (\n let parentId = working.get(id)!.parentId;\n parentId;\n parentId = working.get(parentId)?.parentId\n )\n growing.add(parentId);\n }\n const fitContainers = () => {\n const containers = [...growing]\n .filter((id) => working.has(id))\n .sort((a, b) => depthOf(b) - depthOf(a));\n for (const id of containers) {\n const fit = fitGroup(\n id,\n [...working.values()].filter(\n (node) => node.parentId !== id || !remaining.has(node.id),\n ),\n );\n if (!fit) continue;\n const container = working.get(id)!;\n // Growing up or left: what's in it moves the other way, so nothing moves on the canvas\n if (fit.shift.x || fit.shift.y) {\n for (const child of working.values()) {\n if (child.parentId !== id) continue;\n working.set(child.id, {\n ...child,\n position: {\n x: child.position.x + fit.shift.x,\n y: child.position.y + fit.shift.y,\n },\n });\n }\n }\n working.set(id, {\n ...container,\n position: {\n x: container.position.x - fit.shift.x,\n y: container.position.y - fit.shift.y,\n },\n width: fit.width,\n height: fit.height,\n });\n }\n };\n\n // Innermost containers first, then outwards to the canvas\n const levels = [\n ...new Set([...remaining].map((id) => working.get(id)!.parentId)),\n ].sort((a, b) => depthOf(b) - depthOf(a));\n\n for (const level of levels) {\n fitContainers();\n const parent = level ? working.get(level) : undefined;\n const origin = parent\n ? getAbsolutePosition(parent, working)\n : { x: 0, y: 0 };\n // Inside a container: clear of its header, so it grows down rather than up\n const start = parent\n ? { x: GROUP_PADDING.left, y: GROUP_PADDING.top }\n : { x: 0, y: 0 };\n const todo = [...remaining].filter(\n (id) => working.get(id)!.parentId === level,\n );\n // Things connected to nothing: a row below what was there, each to the right of what's been placed so far\n let row: { y: number; length: number } | undefined;\n const placedHere: Rect[] = [];\n const obstacles = () =>\n [...working.values()]\n .filter((node) => node.parentId === level && !remaining.has(node.id))\n .map(rectOf);\n\n /** What a node connects to that's already placed: the node itself, or the container it's in, at this level */\n const anchorsOf = (id: string): Anchor[] =>\n (neighbours.get(id) ?? []).flatMap(({ id: other, upstream }) => {\n const shown = atLevel(other, level);\n if (!shown || shown.id === id || remaining.has(shown.id)) return [];\n const node = working.get(other)!;\n // Lined up with the node itself, even when it's inside a container\n const centerY =\n getAbsolutePosition(node, working).y +\n sizeOf(node).height / 2 -\n origin.y;\n return [{ rect: rectOf(shown), centerY, upstream }];\n });\n\n /** Nothing placed to start from: the first one with nothing sending to it, so the flow grows left to right */\n const startOf = (ids: string[]) =>\n ids.find(\n (id) =>\n !(neighbours.get(id) ?? []).some(({ id: other, upstream }) => {\n const shown = atLevel(other, level);\n return (\n upstream && shown && shown.id !== id && ids.includes(shown.id)\n );\n }),\n ) ?? ids[0];\n\n const findSpot = (\n from: XYPosition,\n size: { width: number; height: number },\n direction: 1 | -1,\n ): XYPosition => {\n const rects = obstacles();\n for (let column = 0; column < MAX_COLUMNS; column++) {\n const x = from.x + direction * column * (size.width + GAP.x);\n for (let row = 0; row < MAX_ROWS * 2; row++) {\n const spot = {\n x,\n y: from.y + rowOffset(row) * (size.height + GAP.y),\n };\n if (parent && spot.y < GROUP_PADDING.top) continue;\n if (!rects.some((rect) => tooClose({ ...spot, ...size }, rect)))\n return spot;\n }\n }\n return rects.length ? below(rects) : start;\n };\n\n while (todo.length > 0) {\n const candidates = todo.map((id) => ({ id, anchors: anchorsOf(id) }));\n const connected = candidates.reduce((best, candidate) =>\n candidate.anchors.length > best.anchors.length ? candidate : best,\n );\n const { id, anchors } =\n connected.anchors.length > 0\n ? connected\n : { id: startOf(todo), anchors: [] };\n const node = working.get(id)!;\n const size = sizeOf(node);\n\n let spot: XYPosition;\n if (anchors.length > 0) {\n const upstream = anchors.filter((anchor) => anchor.upstream);\n const downstream = anchors.filter((anchor) => !anchor.upstream);\n const x = upstream.length\n ? Math.max(...upstream.map(({ rect }) => rect.x + rect.width)) + GAP.x\n : Math.min(...downstream.map(({ rect }) => rect.x)) -\n GAP.x -\n size.width;\n const centerY =\n anchors.reduce((sum, anchor) => sum + anchor.centerY, 0) /\n anchors.length;\n spot = findSpot(\n { x, y: centerY - size.height / 2 },\n size,\n upstream.length ? 1 : -1,\n );\n } else {\n const rects = obstacles();\n if (!row || row.length === ROW_LENGTH) {\n spot = findSpot(rects.length ? below(rects) : start, size, 1);\n row = { y: spot.y, length: 1 };\n } else {\n spot = findSpot(\n {\n x:\n Math.max(...placedHere.map((rect) => rect.x + rect.width)) +\n GAP.x,\n y: row.y,\n },\n size,\n 1,\n );\n row.length++;\n }\n }\n\n const position = { x: Math.round(spot.x), y: Math.round(spot.y) };\n working.set(id, { ...node, position });\n placedHere.push({ ...position, ...size });\n remaining.delete(id);\n todo.splice(todo.indexOf(id), 1);\n }\n }\n\n fitContainers();\n return new Map(\n toPlace\n .filter((id) => working.has(id))\n .map((id) => [id, getAbsolutePosition(working.get(id)!, working)]),\n );\n};\n","import type { Edge, Node } from \"@xyflow/react\";\nimport { getNodeSize as getLayoutSize } from \"../layout\";\nimport type { LevelPlace } from \"./canvas-doc\";\nimport { fitGroup, getAbsolutePosition } from \"./grouping\";\nimport { getNodeSize, isGroupType } from \"./node-types\";\nimport { placeNodes } from \"./placement\";\n\n/**\n * L1 and L2 as people arrange them. A level's content comes from the canvas (see levels.ts), but where things are on\n * it is its own: each level keeps a layout (a LevelPlace per node, in the canvas), so things stay where they're put.\n * Nothing on a level moves when something's added: new things are placed next to what they connect to (like agents\n * place what they add) and containers grow to fit.\n */\n\ntype Graph = { nodes: Node[]; edges: Edge[] };\n\n/** A container's size: as it's being worked on (width and height), or as laid out (levels size containers with style) */\nconst containerSize = (node: Node) => {\n if (node.width && node.height)\n return { width: node.width, height: node.height };\n const { width, height } = node.style ?? {};\n return typeof width === \"number\" && typeof height === \"number\"\n ? { width, height }\n : undefined;\n};\n\n/** The size the visualiser's layout gives a container with nothing in it (levels leave containers' size to it) */\nconst emptyContainerSize = ({ type }: Pick<Node, \"type\">) =>\n getLayoutSize({ id: \"\", type, position: { x: 0, y: 0 }, data: {} });\n\n/**\n * The size something new of a type is shown at on L1 or L2: L1 shows domains and systems with nothing in them as\n * cards, L2 as empty containers\n */\nexport const getLevelNodeSize = (type: string | undefined, level: 1 | 2) => {\n if (!isGroupType(type)) return getNodeSize(type);\n return level === 1 ? getNodeSize() : emptyContainerSize({ type });\n};\n\n/** Where a node is on a level, and a container's size */\nconst placeOf = (node: Node): LevelPlace => ({\n x: node.position.x,\n y: node.position.y,\n ...(isGroupType(node.type) && containerSize(node)),\n});\n\n/** A level's nodes where they are, by id (not its notes, which are kept on the canvas): what its layout keeps */\nexport const levelPlaces = (nodes: Node[]) =>\n new Map(\n nodes\n .filter((node) => node.type !== \"note\")\n .map((node) => [node.id, placeOf(node)]),\n );\n\n/**\n * A level arranged: each node where the level's layout has it, else where the diagram the canvas was opened from had\n * it (`fallback`), and anything with neither placed next to what it connects to. Containers grow to fit what's in\n * them. `placed` is where things the layout didn't have were put, and containers that grew (to keep, so they stay\n * there). Undefined when nothing on the level has a place yet: it's laid out from scratch then.\n */\nexport const arrangeLevel = (\n graph: Graph,\n layout: ReadonlyMap<string, LevelPlace>,\n fallback: ReadonlyMap<string, LevelPlace> = new Map(),\n): { graph: Graph; placed: Map<string, LevelPlace> } | undefined => {\n const known = (id: string) => layout.get(id) ?? fallback.get(id);\n if (!graph.nodes.some((node) => known(node.id))) return undefined;\n\n const placed = new Map<string, LevelPlace>();\n // Containers carry their size as width and height while they're worked on (what placement and fitting read)\n let nodes: Node[] = graph.nodes.map((node) => {\n const place = known(node.id);\n const size = isGroupType(node.type)\n ? place?.width && place.height\n ? { width: place.width, height: place.height }\n : (containerSize(node) ?? emptyContainerSize(node))\n : undefined;\n return {\n ...node,\n position: place ? { x: place.x, y: place.y } : { x: 0, y: 0 },\n ...size,\n };\n });\n\n // Anything new, next to what it connects to (on the level), moving nothing that's there\n const toPlace = nodes\n .filter((node) => !known(node.id))\n .map((node) => node.id);\n if (toPlace.length) {\n const positions = placeNodes(nodes, toPlace, graph.edges);\n const lookup = new Map(nodes.map((node) => [node.id, node]));\n nodes = nodes.map((node) => {\n const at = positions.get(node.id);\n if (!at) return node;\n const parent = node.parentId ? lookup.get(node.parentId) : undefined;\n const origin = parent\n ? getAbsolutePosition(parent, lookup)\n : { x: 0, y: 0 };\n const moved = {\n ...node,\n position: { x: at.x - origin.x, y: at.y - origin.y },\n };\n placed.set(node.id, placeOf(moved));\n return moved;\n });\n }\n\n // Containers grow to fit what's in them (the innermost first), moving nothing on the level\n const byId = new Map(nodes.map((node) => [node.id, node]));\n const depth = (node: Node): number => {\n const parent = node.parentId ? byId.get(node.parentId) : undefined;\n return parent ? 1 + depth(parent) : 0;\n };\n const containers = nodes\n .filter((node) => isGroupType(node.type))\n .sort((a, b) => depth(b) - depth(a));\n for (const { id } of containers) {\n const fit = fitGroup(id, nodes);\n const current = nodes.find((node) => node.id === id)!;\n const { x: dx, y: dy } = fit?.shift ?? { x: 0, y: 0 };\n if (\n !fit ||\n (!dx &&\n !dy &&\n fit.width === current.width &&\n fit.height === current.height)\n )\n continue;\n nodes = nodes.map((node) => {\n if (node.parentId === id && (dx || dy)) {\n const shifted = {\n ...node,\n position: { x: node.position.x + dx, y: node.position.y + dy },\n };\n placed.set(node.id, placeOf(shifted));\n return shifted;\n }\n if (node.id !== id) return node;\n const grown = {\n ...node,\n position: { x: node.position.x - dx, y: node.position.y - dy },\n width: fit.width,\n height: fit.height,\n };\n placed.set(id, placeOf(grown));\n return grown;\n });\n }\n\n return {\n graph: {\n edges: graph.edges,\n // Containers drawn at their size with style, like levels laid out from scratch\n nodes: nodes.map(({ width, height, ...node }) =>\n isGroupType(node.type) && width && height\n ? { ...node, style: { ...node.style, width, height } }\n : node,\n ),\n },\n placed,\n };\n};\n\n/**\n * A level's edges drawn along the routes the diagram the canvas was opened from had for the same connections (between\n * the same two nodes), once the level's worked out from the canvas: routes follow their nodes when they move, so\n * connections the diagram had stay drawn around what's in their way\n */\nexport const withDiagramRoutes = (edges: Edge[], diagramEdges: Edge[] = []) => {\n const routes = new Map(\n diagramEdges.flatMap((edge) =>\n edge.data?.route\n ? [[`${edge.source}>${edge.target}`, edge.data.route] as const]\n : [],\n ),\n );\n if (routes.size === 0) return edges;\n return edges.map((edge) => {\n const route = routes.get(`${edge.source}>${edge.target}`);\n return route && !edge.data?.route\n ? { ...edge, data: { ...edge.data, route } }\n : edge;\n });\n};\n","import { MarkerType, type Edge, type Node } from \"@xyflow/react\";\nimport { getMessagesLabel } from \"../layout\";\nimport { MESSAGE_COLLECTIONS } from \"./edges\";\nimport { GROUP_TYPES, isGroupType, isWrittenOnCanvas } from \"./node-types\";\n\n/**\n * Levels of detail, the same as EventCatalog's diagrams:\n * - L1: domains, systems and how they relate (services folded into the system or domain that contains them)\n * - L2: services and data stores, with messages, channels and agents hidden (the nodes either side connected directly)\n * - L3: everything, including messages and channels (the canvas people edit)\n *\n * What a domain or system contains is what sits inside it (as a container), or what it's connected to with\n * \"contains\" (as a card, which catalog domains and systems get when their services are on the canvas).\n */\nexport type Level = 1 | 2 | 3;\n\nexport const LEVELS: { level: Level; description: string }[] = [\n { level: 1, description: \"Domains, systems and their relationships\" },\n { level: 2, description: \"Services and data stores\" },\n { level: 3, description: \"Everything, including messages and channels\" },\n];\n\n// Domains and systems: as cards (what they contain is connected with \"contains\") or containers (it's inside)\nconst CONTAINER_TYPES = new Set([\n \"system\",\n \"context-domain\",\n GROUP_TYPES.system,\n GROUP_TYPES.domain,\n]);\nconst isSystem = (node: Node) =>\n node.type === \"system\" || node.type === GROUP_TYPES.system;\nconst isDomain = (node: Node) =>\n node.type === \"context-domain\" || node.type === GROUP_TYPES.domain;\n\nconst isMessage = (node: Node) => !!MESSAGE_COLLECTIONS[node.type ?? \"\"];\nconst isCarrier = (node: Node) => isMessage(node) || node.type === \"channel\";\n// Agents are L3 detail: on L1 and L2 the nodes either side of one are connected past it (as through a message)\nconst isAgent = (node: Node) => node.type === \"agent\";\n// Entities are the domain model, L3 detail: on L1 and L2 they're left out (they aren't a way between two things)\nconst isEntity = (node: Node) => node.type === \"entity\";\nconst isContainer = (node: Node) => CONTAINER_TYPES.has(node.type ?? \"\");\nconst messageName = (node: Node) =>\n String(\n (node.data as { message?: { name?: string } }).message?.name ?? node.id,\n );\n\n// Edges as the visualiser's levels draw them: what's folded together is joined by a plain line, and what was joined\n// through hidden messages or channels by a dashed, muted one (\"bridged\"), each with the visualiser's arrow. On L1\n// the visualiser folds messages into the domain or system they're in, so edges to and from them are plain.\nconst EDGE_STROKE = \"var(--ec-edge-stroke, #6b7280)\";\nconst MUTED = \"rgb(var(--ec-page-text-muted))\";\nconst FOLDED_EDGE = {\n type: \"smoothstep\",\n style: { strokeWidth: 1, stroke: EDGE_STROKE },\n markerEnd: { type: MarkerType.ArrowClosed, width: 20, height: 20 },\n} satisfies Partial<Edge>;\nconst BRIDGED_EDGE = {\n type: \"smoothstep\",\n style: { strokeWidth: 1.5, stroke: MUTED, strokeDasharray: \"5 5\" },\n markerEnd: {\n type: MarkerType.ArrowClosed,\n width: 20,\n height: 20,\n color: MUTED,\n },\n} satisfies Partial<Edge>;\n\n/** What a node becomes at a level: kept (as itself or another node), carried through (messages, channels) or dropped */\ntype Representative =\n | { kind: \"node\"; id: string }\n | { kind: \"carrier\" }\n | { kind: \"drop\" };\n\n/**\n * Collapse a graph: each node is kept, replaced by another node (e.g. a service by its system), carried through\n * (messages and channels: the nodes either side get connected directly, \"bridged\") or dropped. Edges between two\n * nodes that are kept as they are stay as they were (`keepDirect`, for L2); the rest are merged per pair and kind\n * (folded or bridged), labelled with the messages they carry.\n *\n * With `relationships` (L1), edges drawn straight between two nodes that are kept as they are (e.g. one system to\n * another) are relationships, like the visualiser's context relationships: labelled as they were, and shown\n * instead of the messages between the same two nodes (either way).\n */\nconst collapseGraph = (\n nodes: Node[],\n edges: Edge[],\n representativeOf: (node: Node) => Representative,\n {\n keepDirect = false,\n relationships = false,\n foldsMessagesInto,\n }: {\n keepDirect?: boolean;\n relationships?: boolean;\n /** Nodes the messages they send or receive are folded into (L1: domains and systems), so edges through them are plain */\n foldsMessagesInto?: (node: Node) => boolean;\n } = {},\n) => {\n const byId = new Map(nodes.map((node) => [node.id, node]));\n // Whether one node is inside another (e.g. a system in its domain): they're not connected, one holds the other\n const isInside = (id: string, containerId: string) => {\n for (\n let node = byId.get(id);\n node?.parentId;\n node = byId.get(node.parentId)\n )\n if (node.parentId === containerId) return true;\n return false;\n };\n const representatives = new Map(\n nodes.map((node) => [node.id, representativeOf(node)]),\n );\n const outgoing = new Map<string, Edge[]>();\n edges.forEach((edge) =>\n outgoing.set(edge.source, [...(outgoing.get(edge.source) ?? []), edge]),\n );\n\n type Merged = {\n source: string;\n target: string;\n bridged: boolean;\n relationship: boolean;\n messages: Map<string, string>;\n labels: string[];\n /** To the container holding what it was to (hidden at this level): said as it was written (e.g. \"manages\") */\n intoContainer: boolean;\n };\n const merged = new Map<string, Merged>();\n const kept: Edge[] = [];\n const addMessage = (messages: Map<string, string>, node: Node) => {\n if (isMessage(node))\n messages.set(messageName(node), MESSAGE_COLLECTIONS[node.type!]);\n };\n // The nearest container of a node that's shown at this level (as itself)\n const shownContainerOf = (node: Node) => {\n for (\n let parent = node.parentId ? byId.get(node.parentId) : undefined;\n parent;\n parent = parent.parentId ? byId.get(parent.parentId) : undefined\n ) {\n const rep = representatives.get(parent.id);\n if (rep?.kind === \"node\" && rep.id === parent.id) return parent.id;\n }\n return undefined;\n };\n\n edges.forEach((edge) => {\n const from = representatives.get(edge.source);\n if (from?.kind !== \"node\") return;\n const to = representatives.get(edge.target);\n const direct =\n from.id === edge.source && to?.kind === \"node\" && to.id === edge.target;\n if (keepDirect && direct) return kept.push(edge);\n // Follow the edge through carried nodes to the node(s) it reaches, collecting the messages on the way\n const stack = [\n {\n id: edge.target,\n messages: new Map<string, string>(),\n labels: [String(edge.label ?? \"\")],\n bridged: false,\n },\n ];\n const visited = new Set<string>();\n addMessage(stack[0].messages, byId.get(edge.source)!);\n while (stack.length) {\n const current = stack.pop()!;\n if (visited.has(current.id)) continue;\n visited.add(current.id);\n const node = byId.get(current.id);\n let reached = representatives.get(current.id);\n if (!node || !reached) continue;\n const messages = new Map(current.messages);\n addMessage(messages, node);\n if (reached.kind === \"carrier\" && outgoing.get(current.id)?.length) {\n (outgoing.get(current.id) ?? []).forEach((next) =>\n stack.push({\n id: next.target,\n messages,\n labels: [] as string[],\n bridged: true,\n }),\n );\n continue;\n }\n // It ends at something this level hides (an entity, or a message nothing receives): it goes to what holds it, if\n // that's shown (e.g. a service publishing into another system's event, or managing its entity, connects to it)\n let intoContainer = false;\n if (reached.kind !== \"node\") {\n const container = shownContainerOf(node);\n if (!container) continue;\n reached = { kind: \"node\", id: container };\n intoContainer = true;\n }\n // Edges inside what was collapsed disappear, and so do edges to what a node is in (e.g. a service loose in a\n // domain, folded into it, and a system in the same domain)\n if (\n from.id === reached.id ||\n isInside(from.id, reached.id) ||\n isInside(reached.id, from.id)\n )\n continue;\n const relationship =\n relationships && direct && current.id === edge.target;\n const key = `${relationship ? \"relationship\" : current.bridged ? \"bridged\" : \"level\"}-${from.id}-${reached.id}`;\n const entry: Merged = merged.get(key) ?? {\n source: from.id,\n target: reached.id,\n bridged: current.bridged,\n relationship,\n messages: new Map(),\n labels: [],\n intoContainer,\n };\n messages.forEach((collection, name) =>\n entry.messages.set(name, collection),\n );\n // (to a message's container, the message says it: \"publishes OrderPlaced\", not \"publishes event\")\n if (!(intoContainer && isMessage(node)))\n entry.labels.push(...current.labels.filter(Boolean));\n entry.intoContainer ||= intoContainer;\n merged.set(key, entry);\n }\n });\n\n const keptIds = new Set(\n [...representatives.values()].flatMap((rep) =>\n rep.kind === \"node\" ? [rep.id] : [],\n ),\n );\n // A relationship between two nodes is shown instead of the messages between them (either way)\n const related = new Set(\n [...merged.values()]\n .filter((entry) => entry.relationship)\n .flatMap(({ source, target }) => [\n `${source}>${target}`,\n `${target}>${source}`,\n ]),\n );\n // Actors' connections are relationships too, labelled as they were (even when what they use is folded)\n const isActor = (id: string) => byId.get(id)?.type === \"actor\";\n const labelOf = ({\n source,\n target,\n bridged,\n relationship,\n messages,\n labels,\n intoContainer,\n }: Merged) => {\n const written = labels.length ? [...new Set(labels)].join(\", \") : undefined;\n if (relationship) return written;\n // Into a container: the messages, and what else it does there (e.g. \"manages\")\n if (intoContainer)\n return (\n [getMessagesLabel(messages), written].filter(Boolean).join(\" \\n\") ||\n undefined\n );\n return (\n getMessagesLabel(messages) ??\n (!bridged && (isActor(source) || isActor(target)) ? written : undefined)\n );\n };\n return {\n nodes: nodes.filter((node) => keptIds.has(node.id)),\n edges: [\n ...kept,\n ...[...merged.entries()]\n .filter(\n ([, entry]) =>\n entry.relationship ||\n !related.has(`${entry.source}>${entry.target}`),\n )\n .map(([id, entry]): Edge => {\n const label = labelOf(entry);\n const folded = [entry.source, entry.target].some((nodeId) => {\n const node = byId.get(nodeId);\n return !!node && !!foldsMessagesInto?.(node);\n });\n return {\n id,\n source: entry.source,\n target: entry.target,\n ...(entry.bridged && !folded ? BRIDGED_EDGE : FOLDED_EDGE),\n ...(label && { label }),\n };\n }),\n ],\n };\n};\n\n/**\n * The system and domain each node is in: the containers it sits inside, or the domain and system cards\n * connected to it with \"contains\"\n */\nconst getContainers = (nodes: Node[], edges: Edge[]) => {\n const byId = new Map(nodes.map((node) => [node.id, node]));\n const containers = new Map<string, { system?: string; domain?: string }>();\n const add = (nodeId: string, container: Node) => {\n const entry = containers.get(nodeId) ?? {};\n if (isSystem(container)) entry.system ??= container.id;\n else entry.domain ??= container.id;\n containers.set(nodeId, entry);\n };\n for (const node of nodes) {\n for (\n let parent = node.parentId ? byId.get(node.parentId) : undefined;\n parent;\n parent = parent.parentId ? byId.get(parent.parentId) : undefined\n ) {\n if (isContainer(parent)) add(node.id, parent);\n }\n }\n for (const edge of edges) {\n const container = byId.get(edge.source);\n if (container && isContainer(container) && edge.label === \"contains\")\n add(edge.target, container);\n }\n return containers;\n};\n\n/**\n * Containers are sized by the layout: to fit what's in them, or (empty) the size the visualiser lays empty groups\n * out at. Same ids, so switching levels grows and shrinks them.\n */\nconst sizedByLayout = ({ nodes, edges }: { nodes: Node[]; edges: Edge[] }) => ({\n edges,\n nodes: nodes.map((node) =>\n isGroupType(node.type)\n ? { ...node, width: undefined, height: undefined, measured: undefined }\n : node,\n ),\n});\n\n/** L2: messages, channels and agents hidden, the nodes either side connected directly */\nconst level2 = (nodes: Node[], edges: Edge[]) =>\n collapseGraph(\n nodes,\n edges,\n (node) =>\n isEntity(node)\n ? { kind: \"drop\" }\n : isCarrier(node) || isAgent(node)\n ? { kind: \"carrier\" }\n : { kind: \"node\", id: node.id },\n {\n keepDirect: true,\n },\n );\n\n/** Whether a node is inside a container, at any depth */\nconst isWithin = (node: Node, containerId: string, byId: Map<string, Node>) => {\n for (let parent = node.parentId; parent; parent = byId.get(parent)?.parentId)\n if (parent === containerId) return true;\n return false;\n};\n\n/**\n * L1 as EventCatalog's diagrams draw it: systems as cards with what's in them counted, and domains with nothing\n * shown in them (no system, in them or their subdomains, or subdomain) as domain cards\n */\nconst asSystemsLevel = (\n { nodes, edges }: { nodes: Node[]; edges: Edge[] },\n {\n all,\n allEdges,\n containers,\n }: {\n all: Node[];\n allEdges: Edge[];\n containers: ReturnType<typeof getContainers>;\n },\n) => {\n const byId = new Map(all.map((node) => [node.id, node]));\n const count = (id: string, matches: (node: Node) => boolean) =>\n all.filter(\n (node) => matches(node) && containers.get(node.id)?.system === id,\n ).length;\n // The messages a system's services send and receive\n const messagesOf = (id: string) => {\n const services = new Set(\n all\n .filter((node) => containers.get(node.id)?.system === id)\n .map((node) => node.id),\n );\n const messages = new Set<string>();\n for (const edge of allEdges) {\n const [inside, other] = services.has(edge.source)\n ? [edge.source, edge.target]\n : [edge.target, edge.source];\n if (\n services.has(inside) &&\n byId.get(other) &&\n isMessage(byId.get(other)!)\n )\n messages.add(other);\n }\n return messages.size;\n };\n return {\n edges,\n nodes: nodes.map((node): Node => {\n const { id, parentId, position, data } = node;\n if (node.type === GROUP_TYPES.system)\n return {\n id,\n type: \"system\",\n position,\n ...(parentId && { parentId }),\n data: {\n mode: \"full\",\n ...data,\n servicesCount: count(\n id,\n (child) => child.type === \"service\" || child.type === \"agent\",\n ),\n containersCount: count(id, (child) => child.type === \"data\"),\n messagesCount: messagesOf(id),\n },\n };\n // A domain container stays one while something is shown in it (a system, or a subdomain shown as a card)\n if (\n node.type === GROUP_TYPES.domain &&\n !all.some((other) => isSystem(other) && isWithin(other, id, byId)) &&\n !nodes.some((other) => isWithin(other, id, byId))\n )\n return {\n id,\n type: \"context-domain\",\n position,\n ...(parentId && { parentId }),\n data: {\n mode: \"full\",\n ...data,\n subdomain: !!parentId,\n systemsCount: 0,\n servicesCount: all.filter(\n (other) => other.type === \"service\" && isWithin(other, id, byId),\n ).length,\n },\n };\n return node;\n }),\n };\n};\n\n/** L1: services folded into their system (or domain); actors, external systems and loose services stay */\nconst level1 = (nodes: Node[], edges: Edge[]) => {\n const containers = getContainers(nodes, edges);\n const collapsed = collapseGraph(\n nodes,\n edges,\n (node) => {\n const container = containers.get(node.id);\n if (isEntity(node)) return { kind: \"drop\" };\n // Systems stay (inside their domain's container, if they're in one); everything else folds into its system or domain\n if (isContainer(node) && (isSystem(node) || !container?.system))\n return { kind: \"node\", id: node.id };\n if (container?.system) return { kind: \"node\", id: container.system };\n // Messages and channels connect the systems either side, even when they sit in a domain rather than a system\n // (the visualiser has them outside its domains; catalog domains on a canvas hold their messages)\n if (isCarrier(node)) return { kind: \"carrier\" };\n if (container?.domain) return { kind: \"node\", id: container.domain };\n if (isAgent(node)) return { kind: \"carrier\" };\n if (node.type === \"data\" || isWrittenOnCanvas(node.type))\n return { kind: \"drop\" };\n return { kind: \"node\", id: node.id };\n },\n { relationships: true, foldsMessagesInto: isContainer },\n );\n return asSystemsLevel(collapsed, { all: nodes, allEdges: edges, containers });\n};\n\n/**\n * The graph for a level (not laid out: positions come from the layout). Notes aren't in it: the ones added on the\n * level are shown where they were put, over its layout.\n */\nexport const getLevelGraph = (nodes: Node[], edges: Edge[], level: Level) => {\n if (level === 3) return { nodes, edges };\n const withoutNotes = nodes.filter((node) => !isWrittenOnCanvas(node.type));\n return sizedByLayout(\n level === 1 ? level1(withoutNotes, edges) : level2(withoutNotes, edges),\n );\n};\n\n/** Why a level can't be shown for this canvas, if it can't */\nexport const getLevelUnavailableReason = (\n nodes: Node[],\n level: Level,\n): string | undefined => {\n // Like the visualiser: L1 needs systems, or domains to relate (one domain on its own has nothing to show)\n if (level === 1 && !nodes.some(isSystem) && nodes.filter(isDomain).length < 2)\n return \"Not available: add a system, or more than one domain, to see how they relate\";\n return undefined;\n};\n","import { useEffect, useState } from \"react\";\nimport type { XYPosition } from \"@xyflow/react\";\nimport type { Moving, PresenceSource } from \"./presence\";\nimport { createSmoother } from \"./smooth\";\n\n/**\n * Comment pins and hotspot markers being dragged in a live room: what I drag goes out with my presence (`send`, and\n * `null` once it's dropped: the drop goes in the document), and what the others drag comes from theirs (`source`).\n * On the level shown, as their places are.\n */\nexport type LiveMoves = {\n send: (moving: Moving[] | null) => void;\n source: PresenceSource;\n level: 1 | 2 | 3;\n};\n\n/** Sends where something of this kind is now, as it's dragged (or `null`, dropped) */\nexport const sendMove = (\n live: LiveMoves | undefined,\n kind: NonNullable<Moving[\"kind\"]>,\n id: string,\n at: XYPosition | null,\n) =>\n live?.send(\n at && [\n {\n id,\n kind,\n x: at.x,\n y: at.y,\n ...(live.level !== 3 && { level: live.level }),\n },\n ],\n );\n\nconst NONE: ReadonlyMap<string, XYPosition> = new Map();\n\n/**\n * Where the others are dragging things of this kind on the level shown (by id), read from their presence. Changes\n * (re-rendering only the layer using it) only while someone drags one.\n */\nexport function useRemoteMoves(\n live: LiveMoves | undefined,\n kind: NonNullable<Moving[\"kind\"]>,\n) {\n const [moves, setMoves] = useState(NONE);\n const source = live?.source;\n const level = live?.level;\n useEffect(() => {\n if (!source) return;\n let shown = \"\";\n // (gliding, a step a frame, rather than jumping as each position arrives)\n const glide = createSmoother((at) => setMoves(at.size ? at : NONE));\n const show = (peers: ReturnType<PresenceSource[\"current\"]>) => {\n const found = new Map<string, XYPosition>();\n peers.forEach((peer) =>\n peer.moving?.forEach(\n (move) =>\n move.kind === kind &&\n (move.level ?? 3) === level &&\n found.set(move.id, { x: move.x, y: move.y }),\n ),\n );\n const key = [...found]\n .map(([id, { x, y }]) => `${id}:${x}:${y}`)\n .join(\"|\");\n if (key === shown) return;\n shown = key;\n glide.set(found);\n };\n show(source.current());\n const unsubscribe = source.subscribe(show);\n return () => {\n unsubscribe();\n glide.stop();\n setMoves(NONE);\n };\n }, [source, level, kind]);\n return moves;\n}\n","/**\n * Smooths what the others in a live room are moving. Their positions arrive about 30 times a second (and unevenly,\n * as the network goes), while the screen draws 60 to 120 times a second: shown as they arrive, what they drag steps\n * along and stutters. Here each one glides to where it was last said to be, a step every frame, easing in about\n * EASE_MS (a little behind them, smoothly). Frames only run while something's still gliding.\n */\ntype XY = { x: number; y: number };\n\nconst EASE_MS = 45;\n// Close enough to stop (in canvas pixels)\nconst SETTLED_PX = 0.5;\n\nexport type Smoother = {\n /** Where each thing (by id) is now, as the others say; anything left out stops being shown straight away */\n set: (targets: ReadonlyMap<string, XY>) => void;\n stop: () => void;\n};\n\nexport function createSmoother(\n apply: (shown: ReadonlyMap<string, XY>) => void,\n): Smoother {\n let targets: ReadonlyMap<string, XY> = new Map();\n const shown = new Map<string, XY>();\n let frame = 0;\n let last = 0;\n\n const step = (now: number) => {\n frame = 0;\n // (the first frame after a pause steps as one frame would)\n const elapsed = last ? Math.min(now - last, 100) : 16;\n last = now;\n const ease = 1 - Math.exp(-elapsed / EASE_MS);\n let gliding = false;\n for (const [id, to] of targets) {\n const from = shown.get(id);\n if (!from) {\n // New: where it's said to be (it starts where they picked it up, next to where it is here)\n shown.set(id, to);\n continue;\n }\n const x = from.x + (to.x - from.x) * ease;\n const y = from.y + (to.y - from.y) * ease;\n if (Math.abs(to.x - x) < SETTLED_PX && Math.abs(to.y - y) < SETTLED_PX)\n shown.set(id, to);\n else {\n shown.set(id, {\n x: Math.round(x * 10) / 10,\n y: Math.round(y * 10) / 10,\n });\n gliding = true;\n }\n }\n apply(new Map(shown));\n if (gliding) frame = requestAnimationFrame(step);\n else last = 0;\n };\n\n return {\n set(next) {\n targets = next;\n // What they've let go of goes straight away (its drop arrives in the document)\n let dropped = false;\n for (const id of shown.keys())\n if (!next.has(id)) (shown.delete(id), (dropped = true));\n if (dropped && !next.size) {\n cancelAnimationFrame(frame);\n frame = 0;\n last = 0;\n return apply(new Map());\n }\n if (!frame) frame = requestAnimationFrame(step);\n },\n stop() {\n cancelAnimationFrame(frame);\n frame = 0;\n last = 0;\n shown.clear();\n targets = new Map();\n },\n };\n}\n","import { useLayoutEffect, type RefObject } from \"react\";\nimport { useStoreApi } from \"@xyflow/react\";\n\n/** 1 / zoom, for things drawn in the canvas's coordinates that stay the same size on screen (`scale(var(...))`) */\nexport const COUNTER_SCALE = \"--studio-counter-scale\";\n\n/**\n * Keeps COUNTER_SCALE on an element as the canvas zooms, outside React: what's counter-scaled with it (e.g. comment\n * pins) stays the same size on screen without re-rendering on every frame of a zoom\n */\nexport function useCounterScale(ref: RefObject<HTMLElement | null>) {\n const store = useStoreApi();\n useLayoutEffect(() => {\n const apply = (zoom: number) =>\n ref.current?.style.setProperty(COUNTER_SCALE, String(1 / zoom));\n apply(store.getState().transform[2]);\n return store.subscribe((state, previous) => {\n if (state.transform[2] !== previous.transform[2])\n apply(state.transform[2]);\n });\n }, [store, ref]);\n}\n","/**\n * The model (what agents send, links carry and files keep) as Studio's canvas (React Flow nodes and edges, as\n * Studio's canvas-doc keeps them), and back. Each resource is a node with the resource's id, so what's arranged,\n * linked and saved lines up with the agent's ids. Relations are edges (what each edge stands for is kept on it);\n * notes are sticky note and text nodes, on their level; where things are goes in the model's layout.\n */\nimport type { Edge, Node, XYPosition } from \"@xyflow/react\";\nimport type {\n Hotspot as ModelHotspot,\n Layout,\n Model,\n Note,\n Relation,\n Resource,\n ResourceType,\n} from \"../model\";\nimport { MESSAGE_TYPES } from \"../model\";\nimport {\n shortId,\n type Hotspot,\n type LevelPlace,\n type Thread,\n} from \"./canvas-doc\";\nimport { createEdge } from \"./edges\";\nimport { ENTITY_SOURCE_HANDLE } from \"./entity-handles\";\nimport { getAbsolutePosition, sortByHierarchy } from \"./grouping\";\nimport { getLayoutPositions } from \"./layout\";\nimport {\n GROUP_TYPES,\n getNodeDefinition,\n getResource,\n isGroupType,\n isWrittenOnCanvas,\n} from \"./node-types\";\nimport { placeNodes, type Link } from \"./placement\";\nimport { ENTITY_TARGET_HANDLE_ID } from \"../index\";\n\n/** Canvas node types for each type of resource (Studio's, which are the visualiser's) */\nconst NODE_TYPE: Record<ResourceType, string> = {\n domain: GROUP_TYPES.domain,\n system: GROUP_TYPES.system,\n service: \"service\",\n event: \"event\",\n command: \"command\",\n query: \"query\",\n channel: \"channel\",\n container: \"data\",\n actor: \"actor\",\n \"external-system\": \"externalSystem\",\n agent: \"agent\",\n view: \"view\",\n entity: \"entity\",\n team: \"team\",\n};\nconst RESOURCE_TYPE: Record<string, ResourceType> = {\n ...Object.fromEntries(\n Object.entries(NODE_TYPE).map(([resource, node]) => [\n node,\n resource as ResourceType,\n ]),\n ),\n // Catalog domains and systems as cards (Studio's catalog adds them; kept if a canvas has them)\n system: \"system\",\n \"context-domain\": \"domain\",\n};\nexport const resourceTypeOf = (nodeType?: string) =>\n RESOURCE_TYPE[nodeType ?? \"\"];\n\nconst LEVEL_NUMBER = { overview: 1, services: 2, messages: 3 } as const;\nconst LEVEL_NAME = { 1: \"overview\", 2: \"services\", 3: \"messages\" } as const;\n\n/** The edge's relations, and the ends they were drawn between (an edge moved to other ends stands for something else) */\ntype EdgeRelations = { relations: Relation[]; ends: string };\nconst endsOf = (edge: Pick<Edge, \"source\" | \"target\">) =>\n `${edge.source}->${edge.target}`;\n\nexport type ModelCanvasContent = {\n nodes: Node[];\n edges: Edge[];\n levelLayouts: Record<1 | 2, Map<string, LevelPlace>>;\n /** Comment threads people left on it */\n threads?: Thread[];\n /** What's flagged on it (by people, or the agent) */\n hotspots?: Hotspot[];\n /** A live room's document as this browser kept it: the canvas starts from that instead (see local-canvas.ts) */\n doc?: Uint8Array;\n};\n\n// Who flagged a hotspot the agent sent without saying\nconst AGENT_AUTHOR = { name: \"Agent\", color: \"#7c3aed\", agent: true };\n\n/** The model's hotspots as the canvas has them: on their resource's node, or at their place */\nconst toCanvasHotspots = (hotspots: ModelHotspot[]): Hotspot[] =>\n hotspots.map((hotspot) => ({\n id: hotspot.id ?? shortId(),\n severity: hotspot.severity ?? \"warning\",\n title: hotspot.title,\n ...(hotspot.description && { description: hotspot.description }),\n ...(hotspot.resource && { nodeId: hotspot.resource }),\n position: hotspot.position ?? { x: 0, y: 0 },\n ...(!hotspot.resource && hotspot.level && { level: hotspot.level }),\n author: hotspot.author ?? AGENT_AUTHOR,\n createdAt: hotspot.createdAt ?? Date.now(),\n }));\n\n/** A resource's node data, as Studio's components for its type create it (and the resource itself, to keep what the canvas doesn't show) */\nexport function resourceNodeData(resource: Resource): Record<string, unknown> {\n const type = NODE_TYPE[resource.type];\n const fields = {\n name: resource.name,\n version: resource.version ?? \"0.0.1\",\n summary: resource.summary ?? \"\",\n owners: resource.owners ?? [],\n };\n const defaults = getNodeDefinition(type)?.createData() ?? {};\n const shared = { resource };\n switch (resource.type) {\n case \"domain\":\n return resource.card\n ? {\n ...shared,\n mode: \"full\",\n navigable: false,\n domain: { id: resource.id, ...fields },\n }\n : {\n ...shared,\n domain: {\n id: resource.id,\n name: resource.name,\n version: fields.version,\n },\n };\n case \"system\":\n return resource.card\n ? {\n ...shared,\n mode: \"full\",\n navigable: false,\n system: { id: resource.id, ...fields },\n }\n : {\n ...shared,\n system: {\n id: resource.id,\n name: resource.name,\n version: fields.version,\n },\n };\n case \"actor\":\n return {\n ...defaults,\n ...shared,\n name: resource.name,\n summary: resource.summary ?? \"\",\n };\n case \"channel\":\n return {\n ...defaults,\n ...shared,\n channel: {\n ...fields,\n protocols: resource.technology ? [resource.technology] : [],\n },\n };\n case \"container\":\n return {\n ...defaults,\n ...shared,\n data: {\n ...fields,\n container_type: resource.containerType ?? \"database\",\n technology: resource.technology,\n },\n };\n case \"entity\":\n return {\n ...defaults,\n ...shared,\n entity: { ...fields, properties: resource.properties ?? [] },\n };\n default: {\n const key = getNodeDefinition(type)?.resourceKey ?? type;\n return {\n ...defaults,\n ...shared,\n [key]: {\n ...((defaults as Record<string, Record<string, unknown>>)[key] ?? {}),\n ...fields,\n },\n };\n }\n }\n}\n\n/** The edges the model's relations are drawn as, between the nodes of the resources they join */\nfunction edgesFor(model: Model, byId: Map<string, Resource>): Edge[] {\n const drawn = new Map<string, Edge & { data: EdgeRelations }>();\n const channelsOf = new Map<string, string[]>();\n model.relations\n .filter((r) => r.kind === \"routes-through\")\n .forEach((r) =>\n channelsOf.set(r.from, [...(channelsOf.get(r.from) ?? []), r.to]),\n );\n const draw = (source: string, target: string, relation: Relation) => {\n const [from, to] = [byId.get(source), byId.get(target)];\n if (!from || !to || source === target) return;\n const key = `${source}->${target}`;\n const fields =\n from.type === \"entity\" || to.type === \"entity\"\n ? `:${relation.fromField ?? \"\"}:${relation.toField ?? \"\"}`\n : \"\";\n const existing = drawn.get(key + fields);\n if (existing) return void existing.data.relations.push(relation);\n // An entity's connections are to and from its properties' rows (or its header, for the whole entity)\n const sourceHandle =\n from.type === \"entity\"\n ? relation.fromField\n ? `${relation.fromField}-source`\n : ENTITY_SOURCE_HANDLE\n : null;\n const targetHandle =\n to.type === \"entity\"\n ? relation.toField\n ? `${relation.toField}-target`\n : ENTITY_TARGET_HANDLE_ID\n : null;\n const edge = createEdge(\n { source, target, sourceHandle, targetHandle },\n NODE_TYPE[from.type],\n NODE_TYPE[to.type],\n );\n drawn.set(key + fields, {\n ...edge,\n id: key + fields,\n // What someone wrote on it (any connection), else EventCatalog's wording\n ...(relation.label && { label: relation.label }),\n data: {\n ...edge.data,\n relations: [relation],\n ends: key,\n ...(relation.label && { customLabel: relation.label }),\n },\n });\n };\n for (const relation of model.relations) {\n switch (relation.kind) {\n case \"receives\": {\n // Through the message's channels, when it has any\n const channels = channelsOf.get(relation.to);\n if (channels?.length)\n channels.forEach((channel) => draw(channel, relation.from, relation));\n else draw(relation.to, relation.from, relation);\n break;\n }\n // A data store is read by a service: drawn from the store\n case \"reads\":\n draw(relation.to, relation.from, relation);\n break;\n default:\n draw(relation.from, relation.to, relation);\n }\n }\n // Guessed by the agent: amber and dotted, as the diagram draws them\n return [...drawn.values()].map((edge) =>\n edge.data.relations.every((r) => r.inferred)\n ? {\n ...edge,\n label: edge.label ? `${edge.label} \\n(inferred)` : \"(inferred)\",\n style: { stroke: \"#d97706\", strokeDasharray: \"2 4\" },\n markerEnd: {\n type: \"arrowclosed\",\n color: \"#d97706\",\n width: 18,\n height: 18,\n },\n }\n : edge,\n );\n}\n\nconst placeOf = (place: { x: number; y: number }) => ({\n x: place.x,\n y: place.y,\n});\n\n/**\n * The model on a canvas: where the model's layout puts things, what's new placed next to what it connects to,\n * and laid out with the visualiser's layout when nothing has a place yet\n */\n/** A resource's canvas node type: domains and systems as containers, or as cards when they're drawn as cards */\nconst nodeTypeOf = (resource: Resource) =>\n resource.card && resource.type === \"domain\"\n ? \"context-domain\"\n : resource.card && resource.type === \"system\"\n ? \"system\"\n : NODE_TYPE[resource.type];\nconst isCardType = (type?: string) =>\n type === \"context-domain\" || type === \"system\";\n\nexport async function modelToCanvas(\n model: Model,\n seed?: { nodes: Node[] },\n): Promise<ModelCanvasContent> {\n const byId = new Map(model.resources.map((r) => [r.id, r]));\n const saved = model.layout?.messages ?? {};\n let nodes: Node[] = sortByHierarchy(\n model.resources.map((resource) => {\n const parent = resource.parent ? byId.get(resource.parent) : undefined;\n const place = saved[resource.id];\n const group =\n !resource.card &&\n (resource.type === \"domain\" || resource.type === \"system\");\n const size = group\n ? place?.width && place.height\n ? { width: place.width, height: place.height }\n : getNodeDefinition(NODE_TYPE[resource.type])?.defaultSize\n : undefined;\n return {\n id: resource.id,\n type: nodeTypeOf(resource),\n position: place ? placeOf(place) : { x: 0, y: 0 },\n data: resourceNodeData(resource),\n ...(size && { width: size.width, height: size.height }),\n ...(parent &&\n !parent.card &&\n (parent.type === \"domain\" || parent.type === \"system\") && {\n parentId: parent.id,\n }),\n // Containers sit behind what's in them and the connections between them\n ...(group && { zIndex: -1 }),\n } satisfies Node;\n }),\n );\n const edges = edgesFor(model, byId);\n\n // Places are relative to the container a node is in: one outside its container wasn't set by the view (e.g. an\n // agent guessed where something new goes, in canvas coordinates), so it's placed as something new is\n const lookup = new Map(nodes.map((node) => [node.id, node]));\n const misplaced = (node: Node) => {\n const parent = node.parentId ? lookup.get(node.parentId) : undefined;\n if (!parent || !saved[node.id]) return false;\n const { x, y } = node.position;\n const slack = 20;\n return (\n x < -slack ||\n y < -slack ||\n (parent.width !== undefined && x > parent.width) ||\n (parent.height !== undefined && y > parent.height)\n );\n };\n const unplaced = nodes\n .filter((node) => !saved[node.id] || misplaced(node))\n .map((node) => node.id);\n const seeded =\n unplaced.length === nodes.length && seed\n ? placesFromSeed(seed.nodes, nodes)\n : undefined;\n if (seeded) {\n // Nothing has a place: where the diagram it was drawn as put things (so the agent's build ends where the canvas starts)\n nodes = nodes.map((node) =>\n seeded.has(node.id) ? { ...node, ...seeded.get(node.id)! } : node,\n );\n } else if (unplaced.length === nodes.length && nodes.length) {\n // Nothing has a place: laid out as the visualiser lays a diagram out\n const layout = await getLayoutPositions(nodes, edges);\n nodes = nodes.map((node) => {\n const laidOut = layout.nodes.get(node.id);\n return laidOut\n ? {\n ...node,\n position: laidOut.position,\n ...(laidOut.size && laidOut.size),\n }\n : node;\n });\n } else if (unplaced.length) {\n // Some new (e.g. the agent added them): next to what they connect to, nothing else moves\n const links: Link[] = edges.map(({ source, target }) => ({\n source,\n target,\n }));\n const places = placeNodes(nodes, unplaced, links);\n // Placed in canvas coordinates: what's in a container is positioned relative to it (a new service in a new domain\n // was drawn as far from its domain as the domain is from the canvas's corner)\n const byNodeId = new Map(nodes.map((node) => [node.id, node]));\n const canvasAt = (node: Node): XYPosition => {\n const placed = places.get(node.id);\n if (placed) return placed;\n const parent = node.parentId ? byNodeId.get(node.parentId) : undefined;\n if (!parent) return node.position;\n const parentAt = canvasAt(parent);\n return {\n x: parentAt.x + node.position.x,\n y: parentAt.y + node.position.y,\n };\n };\n nodes = nodes.map((node) => {\n const placed = places.get(node.id);\n if (!placed) return node;\n const parent = node.parentId ? byNodeId.get(node.parentId) : undefined;\n const parentAt = parent ? canvasAt(parent) : { x: 0, y: 0 };\n return {\n ...node,\n position: { x: placed.x - parentAt.x, y: placed.y - parentAt.y },\n };\n });\n }\n\n return {\n nodes: [...nodes, ...notesToNodes(model.notes ?? [], nodes)],\n edges,\n levelLayouts: {\n 1: new Map(Object.entries(model.layout?.overview ?? {})),\n 2: new Map(Object.entries(model.layout?.services ?? {})),\n },\n threads: (model.comments ?? []) as Thread[],\n hotspots: toCanvasHotspots(model.hotspots ?? []),\n };\n}\n\n/**\n * Where a diagram (the visualiser's graph of the model, with its own ids for domains and systems) puts each resource's\n * node, relative to the container it's in on the canvas, and containers' sizes. Undefined unless it has them all.\n */\nfunction placesFromSeed(seedNodes: Node[], nodes: Node[]) {\n const seedLookup = new Map(seedNodes.map((node) => [node.id, node]));\n const seedOf = (node: Node) =>\n seedLookup.get(node.id) ?? seedLookup.get(`${node.type}-${node.id}`);\n const absolute = new Map<string, XYPosition>();\n for (const node of nodes) {\n const found = seedOf(node);\n if (!found) return undefined;\n absolute.set(node.id, getAbsolutePosition(found, seedLookup));\n }\n return new Map(\n nodes.map((node) => {\n const found = seedOf(node)!;\n const at = absolute.get(node.id)!;\n const parentAt = node.parentId ? absolute.get(node.parentId) : undefined;\n const width =\n typeof found.style?.width === \"number\"\n ? found.style.width\n : found.width;\n const height =\n typeof found.style?.height === \"number\"\n ? found.style.height\n : found.height;\n return [\n node.id,\n {\n position: parentAt\n ? { x: at.x - parentAt.x, y: at.y - parentAt.y }\n : at,\n ...(isGroupType(node.type) && width && height && { width, height }),\n },\n ] as const;\n }),\n );\n}\n\n/** Notes as sticky note (or text) nodes, on their level: put where they were, else beside what they're about */\nfunction notesToNodes(notes: Note[], nodes: Node[]): Node[] {\n const lookup = new Map(nodes.map((node) => [node.id, node]));\n const bottom = nodes.length\n ? Math.max(\n ...nodes.map(\n (node) => getAbsolutePosition(node, lookup).y + (node.height ?? 120),\n ),\n )\n : 0;\n const beside = new Map<string, number>();\n return notes.map((note, index) => {\n const type = note.kind === \"text\" ? \"text\" : \"note\";\n const about = note.resource ? lookup.get(note.resource) : undefined;\n let position: XYPosition;\n if (note.x !== undefined && note.y !== undefined)\n position = { x: note.x, y: note.y };\n else if (about) {\n // To the right of it, stacked when it has several\n const stacked = beside.get(about.id) ?? 0;\n beside.set(about.id, stacked + 1);\n const at = getAbsolutePosition(about, lookup);\n position = {\n x: at.x + (about.width ?? 260) + 40,\n y: at.y + stacked * 200,\n };\n } else position = { x: index * 240, y: bottom + 120 };\n const level = note.level ? LEVEL_NUMBER[note.level] : undefined;\n return {\n id: `note-${index}`,\n type,\n position,\n // Text is as wide as what's written (its size is its font's)\n ...(type === \"note\" && { width: note.width ?? 200 }),\n data: {\n text: note.text,\n ...(type === \"note\" && { color: note.color ?? \"yellow\" }),\n // Studio keeps a note on L3 unless it says otherwise\n ...(level && level !== 3 && { level }),\n ...(note.resource && { resource: note.resource }),\n ...(note.author && { author: note.author }),\n ...(note.createdAt && { createdAt: note.createdAt }),\n ...(note.fontSize && { fontSize: note.fontSize }),\n ...(note.angle && { angle: note.angle }),\n },\n } satisfies Node;\n });\n}\n\n// ---- Back to the model ----\n\nconst PRODUCERS = new Set<ResourceType>([\n \"service\",\n \"agent\",\n \"view\",\n \"actor\",\n \"external-system\",\n]);\n\n/**\n * What a new connection between two nodes means, from their types: sends and receives between services (and the\n * like) and messages, routes through from a message to a channel, writes and reads with data stores, and\n * otherwise a \"connects\" described by the edge's label\n */\nfunction relationsForEdge(\n edge: Edge,\n from: Resource,\n to: Resource,\n routedThrough: (channel: string) => string[],\n): Relation[] {\n const label =\n typeof edge.label === \"string\" && edge.label.trim()\n ? edge.label.replace(/\\s+/g, \" \").trim()\n : undefined;\n if (PRODUCERS.has(from.type) && MESSAGE_TYPES.has(to.type))\n return [{ from: from.id, to: to.id, kind: \"sends\" }];\n if (MESSAGE_TYPES.has(from.type) && PRODUCERS.has(to.type))\n return [{ from: to.id, to: from.id, kind: \"receives\" }];\n if (MESSAGE_TYPES.has(from.type) && to.type === \"channel\")\n return [{ from: from.id, to: to.id, kind: \"routes-through\" }];\n if (from.type === \"channel\" && PRODUCERS.has(to.type)) {\n const messages = routedThrough(from.id);\n if (messages.length)\n return messages.map((message) => ({\n from: to.id,\n to: message,\n kind: \"receives\" as const,\n }));\n }\n if (\n (from.type === \"service\" || from.type === \"agent\") &&\n to.type === \"container\"\n )\n return [{ from: from.id, to: to.id, kind: \"writes\" }];\n if (\n from.type === \"container\" &&\n (to.type === \"service\" || to.type === \"agent\")\n )\n return [{ from: to.id, to: from.id, kind: \"reads\" }];\n return [\n { from: from.id, to: to.id, kind: \"connects\", ...(label && { label }) },\n ];\n}\n\nconst round = (value: number) => Math.round(value);\nconst placeFor = (node: Node) => ({\n x: round(node.position.x),\n y: round(node.position.y),\n ...(isGroupType(node.type) &&\n node.width &&\n node.height && { width: round(node.width), height: round(node.height) }),\n});\nconst placesOf = (\n places: ReadonlyMap<string, LevelPlace>,\n ids: Set<string>,\n) => {\n const kept = [...places].filter(([id]) => ids.has(id));\n return kept.length\n ? Object.fromEntries(\n kept.map(([id, place]) => [\n id,\n {\n x: round(place.x),\n y: round(place.y),\n ...(place.width &&\n place.height && {\n width: round(place.width),\n height: round(place.height),\n }),\n },\n ]),\n )\n : undefined;\n};\n\n/** The canvas as the model: its resources, relations and notes (through what's still on it), and where things are */\nexport function canvasToModel(\n nodes: Node[],\n edges: Edge[],\n levelLayouts: Record<1 | 2, ReadonlyMap<string, LevelPlace>>,\n base: Model,\n threads: Thread[] = [],\n hotspots: Hotspot[] = [],\n): Model {\n const lookup = new Map(nodes.map((node) => [node.id, node]));\n const resourceNodes = nodes.filter(\n (node) => !isWrittenOnCanvas(node.type) && resourceTypeOf(node.type),\n );\n const resources: Resource[] = resourceNodes.map((node) => {\n const type = resourceTypeOf(node.type)!;\n const kept = (node.data.resource as Resource | undefined) ?? undefined;\n const fields = getResource(node.type, node.data);\n const parent = node.parentId && lookup.get(node.parentId);\n const summary = String(fields.summary ?? \"\").trim();\n const version = String(fields.version ?? kept?.version ?? \"\").trim();\n const { parent: _, card: __, ...rest } = kept ?? ({} as Partial<Resource>);\n return {\n ...rest,\n id: node.id,\n type,\n name: String(fields.name ?? kept?.name ?? node.id).trim() || node.id,\n ...(summary ? { summary } : { summary: undefined }),\n ...(version && { version }),\n ...(type === \"entity\" &&\n Array.isArray(fields.properties) && {\n properties: fields.properties as Resource[\"properties\"],\n }),\n // Its kind of data store, as it is on the canvas (a database is the default, so it isn't written)\n ...(type === \"container\" && {\n containerType:\n fields.container_type && fields.container_type !== \"database\"\n ? (fields.container_type as Resource[\"containerType\"])\n : undefined,\n }),\n ...(isCardType(node.type) && { card: true }),\n ...(parent && resourceTypeOf(parent.type) && { parent: parent.id }),\n } as Resource;\n });\n const byId = new Map(resources.map((r) => [r.id, r]));\n\n // Messages through each channel, as the canvas has them now\n const routed = new Map<string, string[]>();\n edges.forEach((edge) => {\n const [from, to] = [byId.get(edge.source), byId.get(edge.target)];\n if (from && to && MESSAGE_TYPES.has(from.type) && to.type === \"channel\")\n routed.set(to.id, [...(routed.get(to.id) ?? []), from.id]);\n });\n const seen = new Set<string>();\n const relations: Relation[] = [];\n for (const edge of edges) {\n const [from, to] = [byId.get(edge.source), byId.get(edge.target)];\n if (!from || !to) continue;\n const kept = edge.data as Partial<EdgeRelations> | undefined;\n // What it was drawn for, while it joins the same ends; a connection made (or moved) here, from what it joins\n const drawnFor =\n kept?.relations && kept.ends === endsOf(edge)\n ? kept.relations.filter((r) => byId.has(r.from) && byId.has(r.to))\n : relationsForEdge(\n edge,\n from,\n to,\n (channel) => routed.get(channel) ?? [],\n );\n // Which of an entity's properties it's joined at, as it's drawn now\n const fieldOf = (handle: string | null | undefined, suffix: string) =>\n handle && handle.endsWith(suffix) && handle !== ENTITY_SOURCE_HANDLE\n ? handle.slice(0, -suffix.length)\n : undefined;\n const atFields = (relation: Relation): Relation => {\n if (\n relation.kind !== \"connects\" ||\n relation.from !== edge.source ||\n (from.type !== \"entity\" && to.type !== \"entity\")\n )\n return relation;\n const { fromField: _f, toField: _t, ...rest } = relation;\n const fromField =\n from.type === \"entity\"\n ? fieldOf(edge.sourceHandle, \"-source\")\n : undefined;\n const toField =\n to.type === \"entity\"\n ? fieldOf(edge.targetHandle, \"-target\")\n : undefined;\n return {\n ...rest,\n ...(fromField && { fromField }),\n ...(toField && { toField }),\n };\n };\n // What's written on it is on what it was drawn for (a connects is described by it; the others say it instead)\n const written = (edge.data as { customLabel?: string } | undefined)\n ?.customLabel;\n const withLabel = (relation: Relation): Relation => {\n if (written) return { ...relation, label: written };\n if (relation.kind === \"connects\") return relation;\n const { label: _, ...rest } = relation;\n return rest;\n };\n for (const relation of drawnFor.map(atFields).map(withLabel)) {\n const key = `${relation.from}|${relation.kind}|${relation.to}|${relation.fromField ?? \"\"}|${relation.toField ?? \"\"}`;\n if (!seen.has(key)) (relations.push(relation), seen.add(key));\n }\n }\n\n const notes: Note[] = nodes\n .filter((node) => isWrittenOnCanvas(node.type))\n .map((node) => {\n const at = getAbsolutePosition(node, lookup);\n const level = (node.data.level as 1 | 2 | undefined) ?? undefined;\n const resource =\n typeof node.data.resource === \"string\" && byId.has(node.data.resource)\n ? node.data.resource\n : undefined;\n return {\n text: String(node.data.text ?? \"\").slice(0, 1000),\n ...(node.type === \"text\" && { kind: \"text\" as const }),\n ...(node.type === \"note\" && node.data.color\n ? { color: node.data.color as Note[\"color\"] }\n : {}),\n ...(resource && { resource }),\n ...(typeof node.data.author === \"string\" && {\n author: node.data.author,\n }),\n ...(typeof node.data.createdAt === \"number\" && {\n createdAt: node.data.createdAt,\n }),\n ...(typeof node.data.fontSize === \"number\" && {\n fontSize: node.data.fontSize,\n }),\n ...(typeof node.data.angle === \"number\" &&\n node.data.angle !== 0 && { angle: node.data.angle }),\n level: LEVEL_NAME[level ?? 3],\n x: round(at.x),\n y: round(at.y),\n ...(node.type === \"note\" &&\n node.width && {\n width: Math.min(800, Math.max(120, round(node.width))),\n }),\n };\n });\n\n // A team connected to something owns it (as EventCatalog's owners): its name is in that resource's owners, while\n // the connection's there (owners that aren't a team on the canvas, e.g. ones the agent found, are kept)\n const teams = resources.filter((r) => r.type === \"team\");\n if (teams.length) {\n const teamNames = new Set(teams.map((team) => team.name));\n const ownedBy = new Map<string, string[]>();\n for (const relation of relations) {\n const team = byId.get(relation.from);\n if (team?.type !== \"team\" || relation.kind !== \"connects\") continue;\n ownedBy.set(relation.to, [\n ...(ownedBy.get(relation.to) ?? []),\n team.name,\n ]);\n }\n for (const resource of resources) {\n if (resource.type === \"team\") continue;\n const owners = [\n ...new Set([\n ...(resource.owners ?? []).filter((owner) => !teamNames.has(owner)),\n ...(ownedBy.get(resource.id) ?? []),\n ]),\n ];\n if (owners.length) resource.owners = owners;\n else delete resource.owners;\n }\n }\n\n const ids = new Set(resources.map((r) => r.id));\n const layout: Layout = {\n messages: Object.fromEntries(\n resourceNodes.map((node) => [node.id, placeFor(node)]),\n ),\n overview: placesOf(levelLayouts[1], ids),\n services: placesOf(levelLayouts[2], ids),\n };\n return {\n title: base.title,\n resources,\n relations,\n ...(notes.length && { notes }),\n ...(threads.length && { comments: threads }),\n // On a resource still on the canvas, else where they are\n ...(hotspots.length && {\n hotspots: hotspots.map(({ nodeId, position, level, ...hotspot }) =>\n nodeId && ids.has(nodeId)\n ? { ...hotspot, resource: nodeId }\n : { ...hotspot, position, ...(level && { level }) },\n ),\n }),\n layout,\n };\n}\n","/**\n * \"Save to file\" and \"Open\": a diagram as a .eventcatalog file (JSON: the model, with its notes, comments and\n * hotspots, and where it was focused), as drawing tools save theirs. The same file in Studio on the web and in\n * EventCatalog's Studio, so a diagram moves between them.\n */\nimport {\n LEVELS,\n Model,\n validateModel,\n type ArchitecturePayload,\n type Level,\n} from \"../model\";\n\nexport const DIAGRAM_FILE_EXTENSION = \".eventcatalog\";\nconst FILE_TYPE = \"eventcatalog-diagram\";\nconst FILE_VERSION = 1;\n// Big enough for any diagram the server accepts (its requests are limited to 1MB)\nconst MAX_FILE_SIZE = 2 * 1024 * 1024;\n\ntype DiagramFile = {\n type: typeof FILE_TYPE;\n version: number;\n source: string;\n model: Model;\n focus?: string;\n level?: Level;\n};\n\nexport const fileNameFor = (title: string, extension: string) =>\n `${\n title\n .replace(/[^\\w\\- ]+/g, \"\")\n .trim()\n .replace(/\\s+/g, \"-\")\n .toLowerCase() || \"diagram\"\n }${extension}`;\n\nexport function toDiagramFile(\n model: Model,\n { focus, level }: { focus?: string; level?: Level } = {},\n): string {\n const file: DiagramFile = {\n type: FILE_TYPE,\n version: FILE_VERSION,\n source: \"https://www.eventcatalog.dev\",\n model,\n focus,\n level,\n };\n return JSON.stringify(file, null, 2);\n}\n\n/** The diagram in a .eventcatalog file (or a bare model, as the agent writes them), or why it can't be opened */\nexport async function readDiagramFile(\n file: File,\n): Promise<\n Pick<ArchitecturePayload, \"model\" | \"focus\" | \"level\"> | { error: string }\n> {\n if (file.size > MAX_FILE_SIZE)\n return { error: `${file.name} is too big to be a diagram.` };\n let json: unknown;\n try {\n json = JSON.parse(await file.text());\n } catch {\n return {\n error: `${file.name} isn't a diagram file: save one with \"Save to file\".`,\n };\n }\n const saved =\n json &&\n typeof json === \"object\" &&\n (json as { type?: unknown }).type === FILE_TYPE\n ? (json as Partial<DiagramFile>)\n : undefined;\n if (saved && (saved.version ?? 0) > FILE_VERSION)\n return {\n error: `${file.name} was saved by a newer version: open it at eventcatalog.dev.`,\n };\n const parsed = Model.safeParse(saved ? saved.model : json);\n if (!parsed.success)\n return {\n error: `${file.name} isn't a diagram file: save one with \"Save to file\".`,\n };\n const { errors } = validateModel(parsed.data);\n if (errors.length)\n return { error: `${file.name} can't be drawn: ${errors[0]}` };\n const focus =\n saved?.focus && parsed.data.resources.some((r) => r.id === saved.focus)\n ? saved.focus\n : undefined;\n const level =\n saved?.level && LEVELS.includes(saved.level) ? saved.level : undefined;\n return { model: parsed.data, focus, level };\n}\n\n/** Downloads a file (text, or base64 for binary files such as images) */\nexport function downloadFile({\n name,\n mimeType,\n text,\n base64,\n}: {\n name: string;\n mimeType: string;\n text?: string;\n base64?: string;\n}) {\n const href =\n base64 !== undefined\n ? `data:${mimeType};base64,${base64}`\n : URL.createObjectURL(new Blob([text ?? \"\"], { type: mimeType }));\n const link = document.createElement(\"a\");\n link.href = href;\n link.download = name;\n link.click();\n if (href.startsWith(\"blob:\"))\n setTimeout(() => URL.revokeObjectURL(href), 1000);\n return true;\n}\n\n/** A name typed for the file, made safe to save, with the extension on the end */\nexport function cleanFileName(name: string, extension: string) {\n // No path characters, and no leading dots (hidden files)\n const cleaned = name\n .replace(/[\\\\/:*?\"<>|\\u0000-\\u001f]+/g, \"\")\n .trim()\n .replace(/^\\.+/, \"\");\n const base = cleaned.toLowerCase().endsWith(extension)\n ? cleaned.slice(0, -extension.length).trim()\n : cleaned;\n return `${base || \"diagram\"}${extension}`;\n}\n\n// The browser's save dialog (File System Access API: Chromium browsers, and not in frames such as chats)\ntype WritableFile = {\n createWritable: () => Promise<{\n write: (data: string) => Promise<void>;\n close: () => Promise<void>;\n }>;\n name: string;\n};\ntype SaveFilePicker = (options: {\n suggestedName: string;\n types: { description: string; accept: Record<string, string[]> }[];\n}) => Promise<WritableFile>;\nexport type SavedFileHandle = WritableFile;\n\nexport const canPickWhereToSave = () => {\n try {\n return (\n typeof (window as unknown as { showSaveFilePicker?: unknown })\n .showSaveFilePicker === \"function\" && window.self === window.top\n );\n } catch {\n return false;\n }\n};\n\n/** Writes to a file picked (or picked before): the handle, undefined when they cancelled */\nexport async function saveToPickedFile(\n text: string,\n {\n suggestedName,\n handle,\n }: { suggestedName: string; handle?: SavedFileHandle },\n) {\n const picker = (window as unknown as { showSaveFilePicker: SaveFilePicker })\n .showSaveFilePicker;\n let file = handle;\n if (!file) {\n try {\n file = await picker({\n suggestedName,\n types: [\n {\n description: \"EventCatalog diagram\",\n accept: { \"application/json\": [DIAGRAM_FILE_EXTENSION] },\n },\n ],\n });\n } catch (error) {\n if ((error as Error)?.name === \"AbortError\") return undefined;\n throw error;\n }\n }\n const writable = await file.createWritable();\n await writable.write(text);\n await writable.close();\n return file;\n}\n\n/** Asks for a .eventcatalog file to open */\nexport function pickDiagramFile(): Promise<File | undefined> {\n return new Promise((resolve) => {\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.accept = `${DIAGRAM_FILE_EXTENSION},application/json,.json`;\n input.onchange = () => resolve(input.files?.[0]);\n input.oncancel = () => resolve(undefined);\n input.click();\n });\n}\n","/**\n * \"Export image…\": the whole canvas (and its sticky notes and text) as a PNG, as the visualiser exports a diagram\n * (its helpers in utils/export-image.ts), with \"Made with EventCatalog\" in its bottom right corner. Each app saves it\n * its own way (downloaded, or through the chat it's in).\n */\nimport { toPng } from \"html-to-image\";\nimport {\n addExportBranding,\n getExportImageDimensions,\n injectExportStyles,\n} from \"../utils/export-image\";\n\nconst PIXEL_RATIO = 2;\n\nconst translateOf = (element: HTMLElement) => {\n const matrix = new DOMMatrix(getComputedStyle(element).transform);\n return { x: matrix.e, y: matrix.f };\n};\n\n/** What's drawn, in the diagram's coordinates: its nodes (React Flow places them with transforms) and notes */\nfunction drawnBounds(viewport: HTMLElement) {\n const rects: { x: number; y: number; width: number; height: number }[] = [];\n viewport\n .querySelectorAll<HTMLElement>(\".react-flow__node\")\n .forEach((node) => {\n const { x, y } = translateOf(node);\n rects.push({ x, y, width: node.offsetWidth, height: node.offsetHeight });\n });\n viewport.querySelectorAll<HTMLElement>(\".studio-note\").forEach((note) => {\n rects.push({\n x: note.offsetLeft,\n y: note.offsetTop,\n width: note.offsetWidth,\n height: note.offsetHeight,\n });\n });\n if (!rects.length) return undefined;\n const left = Math.min(...rects.map((r) => r.x));\n const top = Math.min(...rects.map((r) => r.y));\n return {\n x: left,\n y: top,\n width: Math.max(...rects.map((r) => r.x + r.width)) - left,\n height: Math.max(...rects.map((r) => r.y + r.height)) - top,\n };\n}\n\n/** The canvas in `container` as a PNG (a data URL), or undefined when there's nothing on it */\nexport async function canvasImage(\n container: HTMLElement,\n): Promise<string | undefined> {\n const viewport = container.querySelector<HTMLElement>(\n \".react-flow__viewport\",\n );\n const bounds = viewport && drawnBounds(viewport);\n if (!viewport || !bounds) return undefined;\n const { width, height, viewport: view } = getExportImageDimensions(bounds);\n const removeExportStyles = injectExportStyles(viewport);\n // Without the selection outlines\n container.classList.add(\"ec-exporting\");\n let dataUrl: string;\n try {\n dataUrl = await toPng(viewport, {\n backgroundColor: getComputedStyle(document.body).backgroundColor,\n width,\n height,\n pixelRatio: PIXEL_RATIO,\n style: {\n width: `${width}px`,\n height: `${height}px`,\n transform: `translate(${view.x}px, ${view.y}px) scale(${view.zoom})`,\n },\n });\n } finally {\n removeExportStyles();\n container.classList.remove(\"ec-exporting\");\n }\n return addExportBranding(dataUrl, PIXEL_RATIO);\n}\n","import {\n createContext,\n memo,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n} from \"react\";\nimport {\n Handle,\n NodeResizeControl,\n NodeResizer,\n Position,\n ResizeControlVariant,\n useReactFlow,\n useStoreApi,\n useUpdateNodeInternals,\n type NodeProps,\n type NodeTypes,\n} from \"@xyflow/react\";\nimport { ENTITY_SOURCE_HANDLE } from \"../entity-handles\";\nimport {\n diagramNodeComponents,\n DomainCardNode,\n EntityNode,\n memoNode,\n SystemGroupNode,\n} from \"../../index\";\nimport { TeamNode } from \"./TeamNode\";\nimport type { Editing } from \"../presence\";\nimport { GROUP_PADDING } from \"../grouping\";\nimport { getNodeName, getNoteLevel, GROUP_TYPES } from \"../node-types\";\n\n/** How the canvas draws each kind of node: the visualiser's nodes, notes and text written on the canvas, and resizable containers */\n\nexport type UpdateNodeData = (\n id: string,\n updater: (data: Record<string, unknown>) => Record<string, unknown>,\n) => void;\n\n// Notes are edited in place, so their callbacks need to reach the shared design\nexport const UpdateNodeDataContext = createContext<UpdateNodeData>(() => {});\n\n// What's being written on a note or text as it's typed (a live session shows it to the others), and done (null)\n/** Tells a live room what's being changed on a note or text as it changes (nothing: done) */\nexport const EditingContext = createContext<(editing: Editing | null) => void>(\n () => {},\n);\n\n// Which container something dragged would drop into, to highlight it\nexport const DropTargetContext = createContext<string | null>(null);\n\n// Text just put on the canvas with the text tool: written straight away\nexport const StartWritingContext = createContext<string | null>(null);\n\n// The canvas locked: looked at, not changed (nothing written, scaled, turned or resized)\nexport const LockedContext = createContext(false);\n\nconst SystemGroupComponent: NodeTypes[string] = SystemGroupNode;\n\n/** The handles that set a node's width, on either side (its height follows what's written in it) */\nfunction WidthHandles() {\n return (\n <>\n {/* Horizontal only: otherwise React Flow saves the height too, and it stops growing with what's written */}\n <NodeResizeControl\n position=\"left\"\n variant={ResizeControlVariant.Line}\n resizeDirection=\"horizontal\"\n minWidth={80}\n className=\"studio-width-handle\"\n />\n <NodeResizeControl\n position=\"right\"\n variant={ResizeControlVariant.Line}\n resizeDirection=\"horizontal\"\n minWidth={80}\n className=\"studio-width-handle\"\n />\n </>\n );\n}\n\n/**\n * What's written on a note or text, and writing it: Enter starts a new line, Escape or ⌘/Ctrl + Enter (or clicking\n * away) finishes, and it's saved for everyone then\n */\nfunction Writing({\n id,\n text,\n editing,\n onDone,\n placeholder,\n className,\n style,\n growWidth = false,\n}: {\n id: string;\n text: string;\n editing: boolean;\n /** Writing it is done, with what's written */\n onDone: (text: string) => void;\n placeholder: string;\n className: string;\n /** e.g. its font size, for text scaled on the canvas */\n style?: CSSProperties;\n /** The box is as wide as what's written, lines only breaking where they're broken (text, as Excalidraw's) */\n growWidth?: boolean;\n}) {\n const updateNodeData = useContext(UpdateNodeDataContext);\n const liveEdit = useContext(EditingContext);\n // Focused once it's shown: React Flow keeps a new node hidden until it's measured, and hidden fields can't take focus\n const areaRef = useRef<HTMLTextAreaElement | null>(null);\n useEffect(() => {\n if (!editing) return;\n let frame = 0;\n let tries = 0;\n const focus = () => {\n const area = areaRef.current;\n if (!area || document.activeElement === area) return;\n // Without scrolling: the browser would scroll the canvas to it, moving everything on it\n area.focus({ preventScroll: true });\n if (document.activeElement !== area && ++tries < 30)\n frame = requestAnimationFrame(focus);\n };\n focus();\n return () => cancelAnimationFrame(frame);\n }, [editing]);\n // The box grows with what's written (the node's height follows it)\n const fit = (area: HTMLTextAreaElement) => {\n if (growWidth) {\n area.style.width = \"0\";\n area.style.width = `${area.scrollWidth + 2}px`;\n }\n area.style.height = \"auto\";\n area.style.height = `${area.scrollHeight}px`;\n };\n if (!editing)\n return (\n <p className={className} style={style}>\n {text ||\n (placeholder && <span className=\"opacity-50\">{placeholder}</span>)}\n </p>\n );\n return (\n <textarea\n ref={(area) => {\n areaRef.current = area;\n if (area) fit(area);\n }}\n defaultValue={text}\n placeholder={placeholder}\n wrap={growWidth ? \"off\" : undefined}\n onFocus={(event) => event.currentTarget.select()}\n onInput={(event) => {\n fit(event.currentTarget);\n liveEdit({ id, text: event.currentTarget.value });\n }}\n onBlur={(event) => {\n const value = event.currentTarget.value;\n onDone(value);\n if (value !== text)\n updateNodeData(id, (current) => ({ ...current, text: value }));\n // Done (after what's written is saved, so the others don't see it go back in between)\n liveEdit(null);\n }}\n onKeyDown={(event) => {\n if (\n event.key === \"Escape\" ||\n (event.key === \"Enter\" && (event.metaKey || event.ctrlKey))\n )\n event.currentTarget.blur();\n }}\n className={`nodrag nopan nowheel block w-full resize-none overflow-hidden bg-transparent outline-none ${className}`}\n style={style}\n />\n );\n}\n\n/** A sticky note's colours: soft paper colours, readable in light and dark themes (the names are the visualiser's) */\nconst NOTE_COLORS: Record<string, { fill: string; border: string }> = {\n yellow: { fill: \"#fef9c3\", border: \"#fde047\" },\n blue: { fill: \"#dbeafe\", border: \"#93c5fd\" },\n green: { fill: \"#dcfce7\", border: \"#86efac\" },\n pink: { fill: \"#fce7f3\", border: \"#f9a8d4\" },\n purple: { fill: \"#ede9fe\", border: \"#c4b5fd\" },\n gray: { fill: \"#f3f4f6\", border: \"#d1d5db\" },\n};\n\n/**\n * A sticky note: a few lines on paper, about as wide as a card and as tall as what's on it. Double click it to\n * write; when it's selected, its colour can be changed and its width set.\n */\nconst StickyNote = memo(function StickyNote({ id, data, selected }: NodeProps) {\n const updateNodeData = useContext(UpdateNodeDataContext);\n // A note just put on the canvas is written on straight away\n const [editing, setEditing] = useState(\n useContext(StartWritingContext) === id,\n );\n const locked = useContext(LockedContext);\n const colorName =\n typeof data.color === \"string\" && NOTE_COLORS[data.color]\n ? data.color\n : \"yellow\";\n const color = NOTE_COLORS[colorName];\n return (\n <div\n className=\"studio-note\"\n style={{ background: color.fill, borderColor: color.border }}\n onDoubleClick={() => !locked && setEditing(true)}\n >\n {selected && !editing && !locked && (\n <>\n <WidthHandles />\n <div\n className=\"nodrag nopan studio-note-colors\"\n role=\"radiogroup\"\n aria-label=\"Note colour\"\n >\n {Object.entries(NOTE_COLORS).map(([name, { fill, border }]) => (\n <button\n key={name}\n role=\"radio\"\n aria-checked={name === colorName}\n title={name.charAt(0).toUpperCase() + name.slice(1)}\n onClick={() =>\n updateNodeData(id, (current) => ({ ...current, color: name }))\n }\n className=\"studio-note-color\"\n style={{\n background: fill,\n borderColor:\n name === colorName ? \"rgb(var(--ec-page-text))\" : border,\n }}\n />\n ))}\n </div>\n </>\n )}\n <Writing\n id={id}\n text={String(data.text ?? \"\")}\n editing={editing}\n onDone={() => setEditing(false)}\n placeholder=\"\"\n className=\"studio-note-body\"\n />\n {/* The level it's on (it's only shown there), and when it was written */}\n <span className=\"studio-note-level\">\n L{getNoteLevel({ type: \"note\", data })} note\n </span>\n {typeof data.createdAt === \"number\" && (\n <span className=\"studio-note-date\">\n {new Date(data.createdAt).toLocaleDateString(undefined, {\n day: \"numeric\",\n month: \"short\",\n })}\n </span>\n )}\n </div>\n );\n});\n\n/**\n * Text written straight on the canvas (titles, labels, notes to self), as Excalidraw's: as big as what's written,\n * in a box with corners to scale it (its font grows with it) and a handle above to turn it. Double click it to write.\n */\n/** Text's size when it's first written */\nexport const TEXT_FONT_SIZE = 22;\nconst clampFont = (size: number) =>\n Math.round(Math.min(160, Math.max(10, size)));\n/** Turned to between -180 and 180 degrees */\nconst normaliseAngle = (angle: number) =>\n Math.round(((((angle + 180) % 360) + 360) % 360) - 180);\nconst TEXT_CORNERS = [\n \"top-left\",\n \"top-right\",\n \"bottom-left\",\n \"bottom-right\",\n] as const;\n\n/** Follows the pointer until it's let go (for handles that aren't React Flow's) */\nconst followPointer = (\n onMove: (event: PointerEvent) => void,\n onEnd: () => void,\n) => {\n const end = () => {\n window.removeEventListener(\"pointermove\", onMove);\n window.removeEventListener(\"pointerup\", end);\n window.removeEventListener(\"pointercancel\", end);\n onEnd();\n };\n window.addEventListener(\"pointermove\", onMove);\n window.addEventListener(\"pointerup\", end);\n window.addEventListener(\"pointercancel\", end);\n};\n\nconst TextNode = memo(function TextNode({ id, data, selected }: NodeProps) {\n const [editing, setEditing] = useState(\n useContext(StartWritingContext) === id,\n );\n const { deleteElements } = useReactFlow();\n const updateNodeData = useContext(UpdateNodeDataContext);\n const liveEdit = useContext(EditingContext);\n const boxRef = useRef<HTMLDivElement>(null);\n // Scaled and turned live while a handle is dragged, saved when it's let go\n const savedFont =\n typeof data.fontSize === \"number\" ? data.fontSize : TEXT_FONT_SIZE;\n const savedAngle = typeof data.angle === \"number\" ? data.angle : 0;\n const [scaling, setScaling] = useState<number | null>(null);\n const [turning, setTurning] = useState<number | null>(null);\n const fontSize = scaling ?? savedFont;\n const angle = turning ?? savedAngle;\n\n // A corner scales it by how far it's dragged from the opposite corner\n const startScaling =\n (corner: (typeof TEXT_CORNERS)[number]) => (event: React.PointerEvent) => {\n event.stopPropagation();\n event.preventDefault();\n const rect = boxRef.current!.getBoundingClientRect();\n const anchor = {\n x: corner.endsWith(\"left\") ? rect.right : rect.left,\n y: corner.startsWith(\"top\") ? rect.bottom : rect.top,\n };\n const from = Math.max(\n Math.hypot(event.clientX - anchor.x, event.clientY - anchor.y),\n 1,\n );\n let next = savedFont;\n followPointer(\n (move) => {\n const size = clampFont(\n (savedFont *\n Math.hypot(move.clientX - anchor.x, move.clientY - anchor.y)) /\n from,\n );\n if (size === next) return;\n setScaling((next = size));\n liveEdit({ id, fontSize: size });\n },\n () => {\n setScaling(null);\n if (next !== savedFont)\n updateNodeData(id, (current) => ({ ...current, fontSize: next }));\n // (after it's saved, so the others don't see it go back in between)\n liveEdit(null);\n },\n );\n };\n // The handle above turns it about its middle (in steps of 15° with Shift held)\n const startTurning = (event: React.PointerEvent) => {\n event.stopPropagation();\n event.preventDefault();\n const rect = boxRef.current!.getBoundingClientRect();\n const centre = {\n x: rect.left + rect.width / 2,\n y: rect.top + rect.height / 2,\n };\n let next = savedAngle;\n followPointer(\n (move) => {\n const turned =\n (Math.atan2(move.clientY - centre.y, move.clientX - centre.x) * 180) /\n Math.PI +\n 90;\n const to = normaliseAngle(\n move.shiftKey ? Math.round(turned / 15) * 15 : turned,\n );\n if (to === next) return;\n setTurning((next = to));\n liveEdit({ id, angle: to });\n },\n () => {\n setTurning(null);\n if (next !== savedAngle)\n updateNodeData(id, (current) => ({ ...current, angle: next }));\n liveEdit(null);\n },\n );\n };\n\n // Text left empty goes, as Excalidraw's does\n const done = (text: string) => {\n setEditing(false);\n if (!text.trim()) void deleteElements({ nodes: [{ id }] });\n };\n const locked = useContext(LockedContext);\n const framed =\n (selected || scaling !== null || turning !== null) && !editing && !locked;\n return (\n <div\n ref={boxRef}\n className={`studio-text ${framed ? \"is-framed\" : \"\"}`}\n style={angle ? { transform: `rotate(${angle}deg)` } : undefined}\n onDoubleClick={() => !locked && setEditing(true)}\n >\n {framed && (\n <>\n {TEXT_CORNERS.map((corner) => (\n <span\n key={corner}\n className={`nodrag nopan studio-text-corner is-${corner}`}\n onPointerDown={startScaling(corner)}\n />\n ))}\n <span\n className=\"nodrag nopan studio-text-turn\"\n title=\"Rotate (Shift: 15° steps)\"\n onPointerDown={startTurning}\n />\n </>\n )}\n <Writing\n id={id}\n text={String(data.text ?? \"\")}\n editing={editing}\n onDone={done}\n placeholder={editing ? \"\" : \"Double-click to write\"}\n className=\"studio-text-body\"\n style={{ fontSize }}\n growWidth\n />\n </div>\n );\n});\n\n/** A domain inside another one is a subdomain (badged as one, like the visualiser), unless its data says otherwise */\nconst useDomainData = ({\n type,\n data,\n parentId,\n}: Pick<NodeProps, \"type\" | \"data\" | \"parentId\">) =>\n useMemo(() => {\n const isDomain = type === GROUP_TYPES.domain || type === \"context-domain\";\n return isDomain && parentId && data.subdomain === undefined\n ? { ...data, subdomain: true }\n : data;\n }, [type, data, parentId]);\n\n/**\n * An entity as the visualiser draws EventCatalog's (its properties listed). The canvas keeps an entity's fields in\n * data.entity, as it keeps every resource's; the visualiser reads a catalog entry (data.entity.data)\n */\nconst EntityCard = memo(function EntityCard(props: NodeProps) {\n const data = useMemo(\n () => ({ ...props.data, entity: { data: props.data.entity ?? {} } }),\n [props.data],\n );\n return (\n <>\n <EntityNode {...props} data={data} />\n {/* From the entity as a whole (its header): the visualiser's only start at a property's row */}\n <Handle\n type=\"source\"\n position={Position.Right}\n id={ENTITY_SOURCE_HANDLE}\n className=\"studio-entity-source\"\n />\n </>\n );\n});\n\n/** A domain card, badged as a subdomain when it's in another domain */\nconst DomainCard = memo(function DomainCard(props: NodeProps) {\n return <DomainCardNode {...props} data={useDomainData(props)} />;\n});\n\n/**\n * A domain or system as a container: resizable when selected, highlighted when something's dragged over it.\n * Like frames in design tools, it's moved and selected by its header, and dragging inside it draws a selection\n * box (its body lets the pointer through to the canvas: see studio.css).\n */\nconst GroupNode = memo(function GroupNode(props: NodeProps) {\n const isDropTarget = useContext(DropTargetContext) === props.id;\n const locked = useContext(LockedContext);\n const data = useDomainData(props);\n const store = useStoreApi();\n // Its handles (where edges meet its sides) measured again when its size changes: resizing it (NodeResizer) sets its\n // measured size first, so React Flow sees no change when it renders at that size and keeps the handles where the\n // sides were. A size that eases in (fitted to what's in it, or someone else's resize) is measured again by\n // RemeasureHandles once it's done; this one measures mid-transition, which that corrects.\n const updateNodeInternals = useUpdateNodeInternals();\n useEffect(() => {\n updateNodeInternals(props.id);\n }, [updateNodeInternals, props.id, props.width, props.height]);\n // Where what's inside has to stay (with room around it and for the header), in the container's parent's\n // coordinates: found when a resize starts, so it can't be resized smaller than what's in it\n const contents = useRef<{\n left: number;\n top: number;\n right: number;\n bottom: number;\n } | null>(null);\n const onResizeStart = useCallback(() => {\n const { nodeLookup } = store.getState();\n const container = nodeLookup.get(props.id);\n const children = [...nodeLookup.values()].filter(\n (node) => node.parentId === props.id,\n );\n if (!container || children.length === 0) {\n contents.current = null;\n return;\n }\n const { x, y } = container.position;\n const size = (node: (typeof children)[number]) => ({\n width: node.measured.width ?? node.width ?? 0,\n height: node.measured.height ?? node.height ?? 0,\n });\n const own = size(container);\n // A side already closer in than that (e.g. something placed in the padding) can still move out, just not in\n contents.current = {\n left: Math.max(\n x +\n Math.min(...children.map((node) => node.position.x)) -\n GROUP_PADDING.left,\n x,\n ),\n top: Math.max(\n y +\n Math.min(...children.map((node) => node.position.y)) -\n GROUP_PADDING.top,\n y,\n ),\n right: Math.min(\n x +\n Math.max(\n ...children.map((node) => node.position.x + size(node).width),\n ) +\n GROUP_PADDING.right,\n x + own.width,\n ),\n bottom: Math.min(\n y +\n Math.max(\n ...children.map((node) => node.position.y + size(node).height),\n ) +\n GROUP_PADDING.bottom,\n y + own.height,\n ),\n };\n }, [store, props.id]);\n const shouldResize = useCallback(\n (\n _: unknown,\n {\n x,\n y,\n width,\n height,\n }: { x: number; y: number; width: number; height: number },\n ) => {\n const bounds = contents.current;\n return (\n !bounds ||\n (x <= bounds.left &&\n y <= bounds.top &&\n x + width >= bounds.right &&\n y + height >= bounds.bottom)\n );\n },\n [],\n );\n return (\n <div style={{ width: \"100%\", height: \"100%\", position: \"relative\" }}>\n <NodeResizer\n isVisible={props.selected && !locked}\n onResizeStart={onResizeStart}\n shouldResize={shouldResize}\n minWidth={240}\n minHeight={160}\n lineClassName=\"!border-[rgb(var(--ec-accent))]\"\n handleClassName=\"!h-2.5 !w-2.5 !rounded-sm !border-2 !bg-[rgb(var(--ec-card-bg))] !border-[rgb(var(--ec-accent))]\"\n />\n <SystemGroupComponent {...props} data={data} />\n {/* The header (and the badge on its border) */}\n <div className=\"ec-group-grip absolute inset-x-0 -top-3 h-[60px] cursor-grab\" />\n {isDropTarget ? (\n // What's dragged over it goes in it when it's dropped\n <div className=\"ec-drop-target\">\n <span className=\"ec-drop-target-label\">\n Drop to add to{\" \"}\n {getNodeName(props.type, props.data, \"this container\")}\n </span>\n </div>\n ) : (\n props.selected && <div className=\"ec-group-selected\" />\n )}\n </div>\n );\n});\n\nconst components: NodeTypes = {\n // Everything the visualiser draws, drawn the same (so a diagram's levels look as they do there). It types its\n // components' props as nodes (Node<Data>) rather than React Flow's NodeProps, which they're rendered with.\n ...(diagramNodeComponents as unknown as NodeTypes),\n // Written on the canvas\n note: StickyNote,\n text: TextNode,\n // Actors look like the visualiser's actors on its architecture diagrams\n actor: diagramNodeComponents[\"context-actor\"] as NodeTypes[string],\n \"context-domain\": DomainCard,\n // The domain model, and who owns what\n entity: EntityCard,\n team: TeamNode,\n // Domains and systems as containers\n [GROUP_TYPES.domain]: GroupNode,\n [GROUP_TYPES.system]: GroupNode,\n};\n\n// React Flow gives every node its position, which changes on every frame it moves (dragged, in a dragged container,\n// or gliding to a layout): like the visualiser's, nodes render again only when something else changes\nexport const nodeTypes: NodeTypes = Object.fromEntries(\n Object.entries(components).map(([type, component]) => [\n type,\n memoNode(component),\n ]),\n);\n","/**\n * A team: who owns what. Drawn like the visualiser's cards (a coloured border, its kind on a tab over the top edge,\n * its name and summary), in the team colour. Connected to a domain, system or service, it's that resource's owner.\n */\nimport { memo } from \"react\";\nimport { Handle, Position, type NodeProps } from \"@xyflow/react\";\nimport { Users } from \"lucide-react\";\n\ntype TeamData = {\n mode?: string;\n team?: { name?: string; summary?: string; version?: string };\n};\n\nexport const TeamNode = memo(function TeamNode({ data, selected }: NodeProps) {\n const { mode = \"full\", team = {} } = data as TeamData;\n const name = team.name || \"Team\";\n return (\n <div\n className={`relative min-w-44 max-w-60 rounded-xl border-2 border-emerald-500 ${selected ? \"ring-2 ring-emerald-400/60 ring-offset-2\" : \"\"}`}\n style={{\n background: \"rgb(var(--ec-card-bg))\",\n boxShadow: \"0 2px 12px rgba(16, 185, 129, 0.15)\",\n }}\n >\n <Handle type=\"target\" position={Position.Left} />\n <Handle type=\"source\" position={Position.Right} />\n <div className=\"absolute -top-2.5 left-2.5 z-10 flex items-center\">\n <span className=\"inline-flex items-center gap-1 rounded bg-emerald-500 px-1.5 py-0.5 text-[7px] font-bold uppercase tracking-widest text-white shadow-sm\">\n <Users className=\"h-2.5 w-2.5\" strokeWidth={2.5} />\n Team\n </span>\n </div>\n <div className=\"flex items-start gap-2 px-3 pb-2.5 pt-3.5\">\n <span className=\"mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-emerald-500/10 text-emerald-600\">\n <Users className=\"h-3.5 w-3.5\" />\n </span>\n <div className=\"min-w-0\">\n <div\n className=\"truncate text-[13px] font-semibold leading-snug text-[rgb(var(--ec-page-text))]\"\n title={name}\n >\n {name}\n </div>\n {mode === \"full\" && team.summary && (\n <div\n className=\"mt-1 line-clamp-2 text-[9px] leading-relaxed text-[rgb(var(--ec-page-text-muted))]\"\n title={team.summary}\n >\n {team.summary}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n});\n\nexport default TeamNode;\n","import {\n createContext,\n memo,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n type PointerEvent as ReactPointerEvent,\n type ReactNode,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n useInternalNode,\n useReactFlow,\n type Node,\n type XYPosition,\n} from \"@xyflow/react\";\nimport { CanvasPortal } from \"../../utils/flow-portals\";\nimport {\n Check,\n GripVertical,\n Maximize2,\n RotateCcw,\n Trash2,\n X,\n} from \"lucide-react\";\nimport { getAbsolutePosition } from \"../grouping\";\nimport type { Author, CommentAnchor, Thread } from \"../canvas-doc\";\nimport { COUNTER_SCALE, useCounterScale } from \"../use-counter-scale\";\nimport { isGroupType, isWrittenOnCanvas } from \"../node-types\";\nimport { STATUS } from \"./status\";\nimport { sendMove, useRemoteMoves, type LiveMoves } from \"../live-moves\";\nimport Picture from \"./Picture\";\nimport { AgentMark } from \"./ClientLogos\";\n\n// Each word's first letter (as people's avatars are everywhere else here), or a single word's first two\nconst initials = (name: string) => {\n const words = name.trim().split(/\\s+/).filter(Boolean);\n return (\n words.length > 1 ? words.map((word) => word[0]).join(\"\") : name.trim()\n )\n .slice(0, 2)\n .toUpperCase();\n};\n\nexport const timeAgo = (timestamp: number) => {\n const seconds = Math.round((Date.now() - timestamp) / 1000);\n if (seconds < 60) return \"just now\";\n const minutes = Math.round(seconds / 60);\n if (minutes < 60) return `${minutes}m ago`;\n const hours = Math.round(minutes / 60);\n if (hours < 24) return `${hours}h ago`;\n return new Date(timestamp).toLocaleDateString();\n};\n\n/** Where a pin sits on the canvas: on its node (so it moves with it), or where it was dropped */\nexport const getAnchorPosition = (\n anchor: CommentAnchor,\n nodesById: Map<string, Node>,\n): XYPosition => {\n const node = anchor.nodeId ? nodesById.get(anchor.nodeId) : undefined;\n if (!node || !anchor.offset) return anchor.position;\n // Nodes in containers are positioned relative to them\n const position = getAbsolutePosition(node, nodesById);\n return { x: position.x + anchor.offset.x, y: position.y + anchor.offset.y };\n};\n\n/** Pinned to a node, a comment keeps its offset from the node so it moves with it */\nexport const anchorAt = (\n position: XYPosition,\n node?: Node,\n nodesById?: Map<string, Node>,\n): CommentAnchor => {\n if (!node) return { position };\n const nodePosition = getAbsolutePosition(\n node,\n nodesById ?? new Map([[node.id, node]]),\n );\n return {\n position,\n nodeId: node.id,\n offset: { x: position.x - nodePosition.x, y: position.y - nodePosition.y },\n };\n};\n\nconst DRAG_THRESHOLD_PX = 4;\n\nconst panelClass =\n \"nowheel nodrag nopan absolute z-40 w-72 rounded-xl border shadow-xl bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))]\";\n\n/** The people in a thread, in the order they joined it (the pin shows the first few, like Figma) */\nconst participantsOf = (thread: Thread): Author[] => {\n const seen = new Map<string, Author>([[thread.author.name, thread.author]]);\n for (const message of thread.messages)\n if (!seen.has(message.author.name))\n seen.set(message.author.name, message.author);\n return [...seen.values()];\n};\nconst MAX_PIN_AVATARS = 3;\n/** How long the pointer rests on a pin before it opens its preview (passing over pins leaves them closed) */\nconst PREVIEW_DELAY_MS = 500;\nconst repliesLabel = (count: number) =>\n count === 1 ? \"1 reply\" : `${count} replies`;\n\nfunction Avatar({\n author,\n muted,\n size = \"h-6 w-6\",\n}: {\n author: Author;\n muted?: boolean;\n size?: string;\n}) {\n return (\n <span\n title={author.name}\n className={`relative flex ${size} shrink-0 items-center justify-center rounded-full text-[10px] font-semibold text-white ring-2 ring-[rgb(var(--ec-card-bg))]`}\n style={{\n backgroundColor: muted\n ? \"rgb(var(--ec-page-text-muted))\"\n : author.color,\n }}\n >\n {author.agent ? (\n <AgentMark name={author.name} size={13} />\n ) : (\n initials(author.name)\n )}\n <Picture\n src={author.picture}\n className={`absolute inset-0 h-full w-full ${muted ? \"opacity-50 grayscale\" : \"\"}`}\n />\n </span>\n );\n}\n\n/**\n * A comment pin, like Figma's: a speech bubble with the people in the thread, that opens into a preview of it\n * (who started it, when, what they said and how many replies) once the pointer rests on it. Click opens the\n * thread, dragging moves it: `onDrag` gets the screen point the pin's tip (its bottom left corner) is over,\n * keeping where on the pin it was grabbed.\n */\nfunction Pin({\n author,\n thread,\n active,\n selected,\n resolved,\n onClick,\n onDrag,\n}: {\n author: Author;\n /** The thread it's for (a new comment being written has none yet) */\n thread?: Thread;\n active?: boolean;\n /** Part of what's selected on the canvas (e.g. after selecting everything) */\n selected?: boolean;\n resolved?: boolean;\n onClick?: () => void;\n onDrag?: (tip: XYPosition, phase: \"move\" | \"end\") => void;\n}) {\n const drag = useRef<{\n start: XYPosition;\n grab: XYPosition;\n moved: boolean;\n } | null>(null);\n const [hovered, setHovered] = useState(false);\n const hoverTimer = useRef<ReturnType<typeof setTimeout>>(undefined);\n useEffect(() => () => clearTimeout(hoverTimer.current), []);\n const [pressed, setPressed] = useState(false);\n const tipOf = (event: { clientX: number; clientY: number }) => ({\n x: event.clientX - drag.current!.grab.x,\n y: event.clientY - drag.current!.grab.y,\n });\n const people = thread ? participantsOf(thread) : [author];\n const [first, ...rest] = thread?.messages ?? [];\n // The preview shows while the pointer is over the pin, not while the thread is open or the pin is dragged\n const expanded = !!thread && !!first && hovered && !active && !pressed;\n\n return (\n <button\n onPointerEnter={() => {\n clearTimeout(hoverTimer.current);\n hoverTimer.current = setTimeout(\n () => setHovered(true),\n PREVIEW_DELAY_MS,\n );\n }}\n onPointerLeave={() => {\n clearTimeout(hoverTimer.current);\n setHovered(false);\n }}\n onPointerDown={(event) => {\n if (event.button !== 0) return;\n // Keeps pointer events coming while the pointer is outside the pin (throws if the pointer has gone)\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {}\n setPressed(true);\n const rect = event.currentTarget.getBoundingClientRect();\n drag.current = {\n start: { x: event.clientX, y: event.clientY },\n grab: {\n x: event.clientX - rect.left,\n y: event.clientY - rect.bottom,\n },\n moved: false,\n };\n }}\n onPointerMove={(event) => {\n const current = drag.current;\n if (!current || !onDrag) return;\n const distance = Math.hypot(\n event.clientX - current.start.x,\n event.clientY - current.start.y,\n );\n if (!current.moved && distance < DRAG_THRESHOLD_PX) return;\n current.moved = true;\n onDrag(tipOf(event), \"move\");\n }}\n onPointerUp={(event) => {\n const current = drag.current;\n setPressed(false);\n if (!current) return;\n if (current.moved) onDrag?.(tipOf(event), \"end\");\n else onClick?.();\n drag.current = null;\n }}\n onPointerCancel={() => {\n drag.current = null;\n setPressed(false);\n }}\n // Keyboard activation (pointer clicks are handled on pointer up)\n onClick={(event) => event.detail === 0 && onClick?.()}\n aria-label={\n thread\n ? `Comment by ${thread.author.name}${rest.length ? `, ${repliesLabel(rest.length)}` : \"\"}`\n : \"New comment\"\n }\n className={`block cursor-grab rounded-[18px] rounded-bl-none border p-1 text-left shadow-lg transition-[box-shadow,transform] active:cursor-grabbing bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))] ${\n active ? \"ring-2 ring-[rgb(var(--ec-accent))]\" : \"\"\n } ${expanded ? \"w-64\" : \"\"}`}\n // Selected: a ring in the theme's button colour (strong in light and dark themes)\n style={\n selected\n ? {\n boxShadow:\n \"0 0 0 2px rgb(var(--ec-card-bg)), 0 0 0 4px rgb(var(--ec-button-bg))\",\n }\n : undefined\n }\n >\n {expanded ? (\n <span className=\"block space-y-1 px-1.5 py-1\">\n <span className=\"flex items-center gap-2\">\n <span className=\"flex -space-x-0.5\">\n {people.slice(0, MAX_PIN_AVATARS).map((person) => (\n <Avatar\n key={person.name}\n author={person}\n muted={resolved}\n size=\"h-5 w-5\"\n />\n ))}\n </span>\n <span className=\"min-w-0 truncate text-xs font-semibold\">\n {thread.author.name}\n </span>\n <span className=\"shrink-0 text-[11px] text-[rgb(var(--ec-page-text-muted))]\">\n {timeAgo(first.createdAt)}\n </span>\n </span>\n <span className=\"line-clamp-3 block whitespace-pre-wrap break-words text-xs\">\n {first.text}\n </span>\n {(rest.length > 0 || resolved) && (\n <span className=\"flex items-center gap-2 text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))]\">\n {rest.length > 0 && <span>{repliesLabel(rest.length)}</span>}\n {resolved && (\n <span\n className={`flex items-center gap-0.5 ${STATUS.success.text}`}\n >\n <Check size={11} /> Resolved\n </span>\n )}\n </span>\n )}\n </span>\n ) : (\n <span className=\"flex -space-x-1\">\n {people.slice(0, MAX_PIN_AVATARS).map((person) => (\n <Avatar key={person.name} author={person} muted={resolved} />\n ))}\n {people.length > MAX_PIN_AVATARS && (\n <span className=\"flex h-6 w-6 items-center justify-center rounded-full text-[10px] font-semibold ring-2 ring-[rgb(var(--ec-card-bg))] bg-[rgb(var(--ec-page-border))]\">\n +{people.length - MAX_PIN_AVATARS}\n </span>\n )}\n </span>\n )}\n </button>\n );\n}\n\nfunction Composer({\n placeholder,\n onSubmit,\n onCancel,\n}: {\n placeholder: string;\n onSubmit: (text: string) => void;\n onCancel?: () => void;\n}) {\n const [text, setText] = useState(\"\");\n const submit = () => {\n if (!text.trim()) return;\n onSubmit(text.trim());\n setText(\"\");\n };\n\n return (\n <div className=\"flex items-end gap-2 p-2\">\n <textarea\n autoFocus\n rows={1}\n value={text}\n placeholder={placeholder}\n onChange={(e) => setText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n submit();\n }\n if (e.key === \"Escape\") onCancel?.();\n }}\n className=\"max-h-32 min-h-[34px] flex-1 resize-none rounded-md border px-2 py-1.5 text-sm bg-[rgb(var(--ec-input-bg))] border-[rgb(var(--ec-input-border))] text-[rgb(var(--ec-input-text))]\"\n />\n <button\n onClick={submit}\n disabled={!text.trim()}\n className=\"rounded-md px-2.5 py-1.5 text-xs font-medium disabled:opacity-40 bg-[rgb(var(--ec-button-bg))] text-[rgb(var(--ec-button-text))]\"\n >\n Post\n </button>\n </div>\n );\n}\n\nfunction IconButton({\n title,\n onClick,\n children,\n}: {\n title: string;\n onClick: () => void;\n children: ReactNode;\n}) {\n return (\n <button\n title={title}\n onClick={onClick}\n className=\"rounded p-1 text-[rgb(var(--ec-icon-color))] hover:bg-[rgb(var(--ec-page-border)/0.5)] hover:text-[rgb(var(--ec-icon-hover))]\"\n >\n {children}\n </button>\n );\n}\n\n/** Room kept between a thread's box and the edges of the canvas */\nconst PANEL_MARGIN_PX = 12;\n/** A thread's box is at most this tall: longer threads scroll (or open bigger, in a dialog) */\nconst PANEL_MAX_HEIGHT_PX = 360;\n/** What drags a thread's box around (its header) */\nconst DragPanelContext = createContext<\n ((event: ReactPointerEvent<HTMLElement>) => void) | null\n>(null);\n\n/**\n * The box a thread (or a new comment) opens in, beside its pin. It opens moved up as far as needed to be fully\n * on the canvas, and can be dragged around by its header to see more of the canvas or of a long thread. Where it's\n * been moved is only here, and goes when it closes. With `onClickOutside`, a click anywhere but the box and its pin\n * closes it (as a popover does), unless there's a reply being written in it.\n */\nfunction FloatingPanel({\n children,\n onClickOutside,\n}: {\n children: ReactNode;\n onClickOutside?: () => void;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n const [offset, setOffset] = useState<XYPosition>({ x: 0, y: 0 });\n const offsetRef = useRef(offset);\n offsetRef.current = offset;\n\n const clickedOutside = useRef(onClickOutside);\n clickedOutside.current = onClickOutside;\n const closesOnClickOutside = !!onClickOutside;\n useEffect(() => {\n if (!closesOnClickOutside) return;\n const onPointerDown = (event: PointerEvent) => {\n const element = ref.current;\n // The box and its pin (the pin toggles it itself)\n const own = element?.parentElement;\n if (\n !element ||\n event.button !== 0 ||\n own?.contains(event.target as globalThis.Node)\n )\n return;\n // A reply half written isn't thrown away\n if (element.querySelector(\"textarea\")?.value.trim()) return;\n clickedOutside.current?.();\n };\n // Capture: the canvas stops some pointer events (panning, dragging nodes) from reaching the document\n document.addEventListener(\"pointerdown\", onPointerDown, true);\n return () =>\n document.removeEventListener(\"pointerdown\", onPointerDown, true);\n }, [closesOnClickOutside]);\n\n // Opened low on the canvas, or grown past the bottom of it (replies): moved up so its bottom (and the reply box)\n // can be seen\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n const fit = () => {\n const rect = element.getBoundingClientRect();\n const canvas = element\n .closest(\".react-flow\")\n ?.getBoundingClientRect() ?? { top: 0, bottom: window.innerHeight };\n const up = Math.min(\n rect.bottom - (canvas.bottom - PANEL_MARGIN_PX),\n rect.top - (canvas.top + PANEL_MARGIN_PX),\n );\n if (up > 0) setOffset((current) => ({ x: current.x, y: current.y - up }));\n };\n const observer = new ResizeObserver(fit);\n observer.observe(element);\n return () => observer.disconnect();\n }, []);\n\n // Pin and box are counter-scaled with the zoom, so the box moves by as much as the pointer does on screen\n const startDrag = useCallback((event: ReactPointerEvent<HTMLElement>) => {\n if (event.button !== 0 || (event.target as Element).closest(\"button\"))\n return;\n event.preventDefault();\n const element = event.currentTarget;\n element.setPointerCapture(event.pointerId);\n const start = { x: event.clientX, y: event.clientY };\n const from = offsetRef.current;\n const move = (moveEvent: PointerEvent) =>\n setOffset({\n x: from.x + moveEvent.clientX - start.x,\n y: from.y + moveEvent.clientY - start.y,\n });\n const end = () => {\n element.removeEventListener(\"pointermove\", move);\n element.removeEventListener(\"pointerup\", end);\n element.removeEventListener(\"pointercancel\", end);\n };\n element.addEventListener(\"pointermove\", move);\n element.addEventListener(\"pointerup\", end);\n element.addEventListener(\"pointercancel\", end);\n }, []);\n\n return (\n <div\n ref={ref}\n className={`${panelClass} flex flex-col`}\n style={{\n left: `calc(100% + 8px + ${offset.x}px)`,\n top: offset.y,\n maxHeight: PANEL_MAX_HEIGHT_PX,\n }}\n >\n <DragPanelContext.Provider value={startDrag}>\n {children}\n </DragPanelContext.Provider>\n </div>\n );\n}\n\nfunction ThreadPopover({\n thread,\n onReply,\n onResolve,\n onDelete,\n onClose,\n onExpand,\n}: {\n thread: Thread;\n onReply: (text: string) => void;\n onResolve: (resolved: boolean) => void;\n onDelete: () => void;\n onClose: () => void;\n /** Open it bigger, in a dialog (not there when it's already in one) */\n onExpand?: () => void;\n}) {\n const listRef = useRef<HTMLDivElement>(null);\n const startDrag = useContext(DragPanelContext);\n useEffect(() => {\n listRef.current?.scrollTo({ top: listRef.current.scrollHeight });\n }, [thread.messages.length]);\n\n return (\n <>\n <div\n onPointerDown={startDrag ?? undefined}\n title={startDrag ? \"Drag to move\" : undefined}\n className={`flex shrink-0 select-none items-center justify-between border-b px-3 py-2 border-[rgb(var(--ec-page-border))] ${\n startDrag ? \"cursor-move\" : \"\"\n }`}\n >\n <span className=\"flex items-center gap-1 text-xs font-semibold\">\n {/* It can be dragged by its header: the grip says so */}\n {startDrag && (\n <GripVertical\n size={14}\n aria-hidden\n className=\"-ml-1 text-[rgb(var(--ec-page-text-muted))]\"\n />\n )}\n {thread.resolved ? \"Resolved thread\" : \"Thread\"}\n </span>\n <span className=\"flex items-center gap-0.5\">\n <IconButton\n title={thread.resolved ? \"Reopen\" : \"Resolve\"}\n onClick={() => onResolve(!thread.resolved)}\n >\n {thread.resolved ? <RotateCcw size={14} /> : <Check size={14} />}\n </IconButton>\n <IconButton title=\"Delete thread\" onClick={onDelete}>\n <Trash2 size={14} />\n </IconButton>\n {onExpand && (\n <IconButton title=\"Open bigger\" onClick={onExpand}>\n <Maximize2 size={14} />\n </IconButton>\n )}\n <IconButton title=\"Close\" onClick={onClose}>\n <X size={14} />\n </IconButton>\n </span>\n </div>\n <div\n ref={listRef}\n className=\"min-h-0 flex-1 space-y-3 overflow-y-auto px-3 py-3\"\n >\n {thread.messages.map((message) => (\n <div key={message.id} className=\"flex gap-2\">\n <span\n className=\"relative flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-[10px] font-semibold text-white\"\n style={{ backgroundColor: message.author.color }}\n >\n {message.author.agent ? (\n <AgentMark name={message.author.name} size={13} />\n ) : (\n initials(message.author.name)\n )}\n <Picture src={message.author.picture} />\n </span>\n <div className=\"min-w-0\">\n <p className=\"text-xs\">\n <span className=\"font-semibold\">{message.author.name}</span>{\" \"}\n <span className=\"text-[rgb(var(--ec-page-text-muted))]\">\n {timeAgo(message.createdAt)}\n </span>\n </p>\n <p className=\"whitespace-pre-wrap break-words text-sm\">\n {message.text}\n </p>\n </div>\n </div>\n ))}\n </div>\n <div className=\"shrink-0 border-t border-[rgb(var(--ec-page-border))]\">\n <Composer placeholder=\"Reply\" onSubmit={onReply} onCancel={onClose} />\n </div>\n </>\n );\n}\n\n/** A thread opened bigger, in a dialog over the page (for long threads) */\nfunction ThreadDialog({\n thread,\n onReply,\n onResolve,\n onDelete,\n onShrink,\n onClose,\n}: {\n thread: Thread;\n onReply: (text: string) => void;\n onResolve: (resolved: boolean) => void;\n onDelete: () => void;\n /** Back to the box beside its pin */\n onShrink: () => void;\n onClose: () => void;\n}) {\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) =>\n event.key === \"Escape\" && onShrink();\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, [onShrink]);\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4\"\n // It's in the canvas's React tree (a portal), so its events would reach the canvas: they stop here (clicks in\n // the dialog stop at it)\n onClick={(event) => {\n event.stopPropagation();\n onShrink();\n }}\n onPointerDown={(event) => event.stopPropagation()}\n onMouseDown={(event) => event.stopPropagation()}\n onDoubleClick={(event) => event.stopPropagation()}\n onContextMenu={(event) => event.stopPropagation()}\n onWheel={(event) => event.stopPropagation()}\n >\n <div\n role=\"dialog\"\n aria-label=\"Comment thread\"\n onClick={(event) => event.stopPropagation()}\n className=\"flex max-h-[80vh] w-full max-w-xl flex-col rounded-xl border shadow-2xl bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))]\"\n >\n <ThreadPopover\n thread={thread}\n onReply={onReply}\n onResolve={onResolve}\n onDelete={onDelete}\n onClose={onClose}\n />\n </div>\n </div>\n );\n}\n\n/**\n * Where a pin goes on the canvas, following only the node it's on (if it's on one), counter-scaled (by the layer's\n * COUNTER_SCALE, so zooming doesn't re-render it)\n */\nfunction PinAt({\n anchor,\n zIndex,\n children,\n}: {\n anchor: CommentAnchor;\n zIndex: number;\n children: ReactNode;\n}) {\n const node = useInternalNode(anchor.nodeId ?? \"\");\n const origin =\n anchor.nodeId && anchor.offset\n ? node?.internals.positionAbsolute\n : undefined;\n const { x, y } =\n origin && anchor.offset\n ? { x: origin.x + anchor.offset.x, y: origin.y + anchor.offset.y }\n : anchor.position;\n return (\n <div\n className=\"absolute\"\n style={{\n left: x,\n top: y,\n transform: `scale(var(${COUNTER_SCALE}, 1))`,\n transformOrigin: \"0 0\",\n zIndex,\n }}\n >\n {/* The pin's tip (bottom left corner) sits on the anchor point, and it grows up and right as it opens */}\n <div className=\"nopan nodrag nowheel pointer-events-auto absolute bottom-0 left-0\">\n {children}\n </div>\n </div>\n );\n}\n\n/**\n * Comment pins (and the open thread) on the canvas, in its own coordinates (React Flow's viewport portal) so\n * they move with it without re-rendering, counter-scaled to stay the same size on screen. Each pin follows\n * only its own node, so other nodes moving don't re-render them.\n */\nexport const CommentLayer = memo(function CommentLayer({\n threads,\n author,\n openThreadId,\n draft,\n showResolved,\n onOpen,\n onCreate,\n onCancelDraft,\n onReply,\n onResolve,\n onDelete,\n onMove,\n onMoveDraft,\n selectedIds,\n selectionOffset,\n live,\n}: {\n threads: Thread[];\n author: Author;\n openThreadId: string | null;\n /** Threads that are part of what's selected */\n selectedIds: ReadonlySet<string>;\n /** How far what's selected has been dragged: selected pins not on a node move with it */\n selectionOffset: XYPosition | null;\n draft: CommentAnchor | null;\n showResolved: boolean;\n onOpen: (threadId: string | null) => void;\n onCreate: (text: string) => void;\n onCancelDraft: () => void;\n onReply: (threadId: string, text: string) => void;\n onResolve: (threadId: string, resolved: boolean) => void;\n onDelete: (threadId: string) => void;\n onMove: (threadId: string, anchor: CommentAnchor) => void;\n onMoveDraft: (anchor: CommentAnchor) => void;\n /** In a live room: pins the others are dragging move here as they drag, and mine move for them */\n live?: LiveMoves;\n}) {\n const layer = useRef<HTMLDivElement>(null);\n useCounterScale(layer);\n const { screenToFlowPosition, getInternalNode } = useReactFlow();\n // A pin being dragged stays here until it's dropped, then moves for everyone\n const [moving, setMoving] = useState<{\n threadId: string;\n anchor: CommentAnchor;\n } | null>(null);\n const remote = useRemoteMoves(live, \"comment\");\n // The open thread, shown bigger in a dialog\n const [expandedId, setExpandedId] = useState<string | null>(null);\n const expanded =\n expandedId && expandedId === openThreadId\n ? threads.find((thread) => thread.id === expandedId)\n : undefined;\n\n // While dragging, a pin follows the pointer. Dropped on a node it attaches to it (and moves with it),\n // anywhere else it stays on the canvas.\n // Not domains and systems (a comment over one is at that place), nor notes and text: what it's about\n const nodeUnder = (point: XYPosition) => {\n for (const element of document.elementsFromPoint(point.x, point.y)) {\n const id = element.closest(\".react-flow__node\")?.getAttribute(\"data-id\");\n const node = id ? getInternalNode(id) : undefined;\n if (node && !isGroupType(node.type) && !isWrittenOnCanvas(node.type))\n return node;\n }\n return undefined;\n };\n const anchorFor = (tip: XYPosition, phase: \"move\" | \"end\"): CommentAnchor => {\n const position = screenToFlowPosition(tip);\n const node = phase === \"end\" ? nodeUnder(tip) : undefined;\n if (!node) return { position };\n const origin = node.internals.positionAbsolute;\n return {\n position,\n nodeId: node.id,\n offset: { x: position.x - origin.x, y: position.y - origin.y },\n };\n };\n\n const visible = threads.filter(\n (thread) => showResolved || !thread.resolved || thread.id === openThreadId,\n );\n\n return (\n <CanvasPortal>\n {/* Above nodes (selected ones are raised to 1000) and other people's pointers */}\n <div\n ref={layer}\n className=\"absolute left-0 top-0\"\n style={{ zIndex: 2001 }}\n >\n {visible.map((thread) => {\n const isOpen = thread.id === openThreadId;\n return (\n <PinAt\n key={thread.id}\n anchor={\n moving?.threadId === thread.id\n ? moving.anchor\n : remote.has(thread.id)\n ? { position: remote.get(thread.id)! }\n : selectionOffset &&\n !thread.nodeId &&\n selectedIds.has(thread.id)\n ? {\n position: {\n x: thread.position.x + selectionOffset.x,\n y: thread.position.y + selectionOffset.y,\n },\n }\n : thread\n }\n zIndex={isOpen ? 2 : 1}\n >\n <Pin\n author={thread.author}\n thread={thread}\n active={isOpen}\n selected={selectedIds.has(thread.id)}\n resolved={thread.resolved}\n onClick={() => onOpen(isOpen ? null : thread.id)}\n onDrag={(tip, phase) => {\n const anchor = anchorFor(tip, phase);\n if (phase === \"move\") {\n sendMove(live, \"comment\", thread.id, anchor.position);\n return setMoving({ threadId: thread.id, anchor });\n }\n onMove(thread.id, anchor);\n // (after the drop's in the document, so the others don't see it go back in between)\n sendMove(live, \"comment\", thread.id, null);\n setMoving(null);\n }}\n />\n {/* (not while it's open bigger, in the dialog) */}\n {isOpen && expanded?.id !== thread.id && (\n <FloatingPanel onClickOutside={() => onOpen(null)}>\n <ThreadPopover\n thread={thread}\n onReply={(text) => onReply(thread.id, text)}\n onResolve={(resolved) => onResolve(thread.id, resolved)}\n onDelete={() => onDelete(thread.id)}\n onClose={() => onOpen(null)}\n onExpand={() => setExpandedId(thread.id)}\n />\n </FloatingPanel>\n )}\n </PinAt>\n );\n })}\n\n {expanded &&\n createPortal(\n <ThreadDialog\n thread={expanded}\n onReply={(text) => onReply(expanded.id, text)}\n onResolve={(resolved) => onResolve(expanded.id, resolved)}\n onDelete={() => {\n setExpandedId(null);\n onDelete(expanded.id);\n }}\n onShrink={() => setExpandedId(null)}\n onClose={() => {\n setExpandedId(null);\n onOpen(null);\n }}\n />,\n document.body,\n )}\n\n {draft && (\n <PinAt anchor={draft} zIndex={3}>\n <Pin\n author={author}\n active\n onDrag={(tip, phase) => onMoveDraft(anchorFor(tip, phase))}\n />\n <FloatingPanel>\n <Composer\n placeholder=\"Add a comment\"\n onSubmit={onCreate}\n onCancel={onCancelDraft}\n />\n </FloatingPanel>\n </PinAt>\n )}\n </div>\n </CanvasPortal>\n );\n});\n\n/** All threads, for the left panel. Clicking one opens it on the canvas. */\nexport function CommentList({\n threads,\n showResolved,\n onToggleResolved,\n onOpen,\n}: {\n threads: Thread[];\n showResolved: boolean;\n onToggleResolved: () => void;\n onOpen: (thread: Thread) => void;\n}) {\n const shown = threads\n .filter((thread) => showResolved || !thread.resolved)\n .reverse();\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <label className=\"mx-3 mb-2 flex items-center gap-2 text-xs text-[rgb(var(--ec-page-text-muted))]\">\n <input\n type=\"checkbox\"\n checked={showResolved}\n onChange={onToggleResolved}\n />\n Show resolved\n </label>\n <div className=\"min-h-0 flex-1 space-y-1.5 overflow-y-auto px-3 pb-3\">\n {shown.length === 0 && (\n <p className=\"py-6 text-center text-xs text-[rgb(var(--ec-page-text-muted))]\">\n No comments yet. Right click the canvas, or press C, to add one.\n </p>\n )}\n {shown.map((thread) => {\n const [first, ...replies] = thread.messages;\n return (\n <button\n key={thread.id}\n onClick={() => onOpen(thread)}\n className={`w-full space-y-1 rounded-md border px-2.5 py-2 text-left bg-[rgb(var(--ec-page-bg))] border-[rgb(var(--ec-page-border))] hover:border-[rgb(var(--ec-accent))] ${\n thread.resolved ? \"opacity-60\" : \"\"\n }`}\n >\n <p className=\"flex items-center gap-1.5 text-xs\">\n <span\n className=\"h-2 w-2 shrink-0 rounded-full\"\n style={{ backgroundColor: thread.author.color }}\n />\n <span className=\"font-semibold\">{thread.author.name}</span>\n <span className=\"text-[rgb(var(--ec-page-text-muted))]\">\n {timeAgo(thread.createdAt)}\n </span>\n {thread.resolved && (\n <Check\n size={12}\n className={`ml-auto ${STATUS.success.text}`}\n />\n )}\n </p>\n <p className=\"line-clamp-2 text-xs\">{first?.text}</p>\n {replies.length > 0 && (\n <p className=\"text-[11px] text-[rgb(var(--ec-page-text-muted))]\">\n {replies.length} {replies.length === 1 ? \"reply\" : \"replies\"}\n </p>\n )}\n </button>\n );\n })}\n </div>\n </div>\n );\n}\n","import type { CanvasStatus } from \"../canvas-doc\";\n\n/**\n * Status and destructive colours for the canvas, from the theme's badge colours (EventCatalog has no status\n * variables), so they follow light, dark and custom themes. Kept here rather than repeated in each component.\n */\nexport const STATUS = {\n success: {\n text: \"text-[rgb(var(--ec-badge-color-green-text))]\",\n dot: \"bg-[rgb(var(--ec-badge-color-green-text))]\",\n },\n warning: {\n text: \"text-[rgb(var(--ec-badge-color-yellow-text))]\",\n dot: \"bg-[rgb(var(--ec-badge-color-yellow-text))]\",\n },\n danger: {\n text: \"text-[rgb(var(--ec-badge-color-red-text))]\",\n dot: \"bg-[rgb(var(--ec-badge-color-red-text))]\",\n hover: \"hover:bg-[rgb(var(--ec-badge-color-red-background))]\",\n /** A button that deletes something */\n button:\n \"bg-[rgb(var(--ec-badge-color-red-text))] text-white hover:bg-[rgb(var(--ec-badge-color-red-text)/0.85)]\",\n },\n} as const;\n\n/** How each canvas status looks and what it means (from the theme's badge colours) */\nexport const CANVAS_STATUS_LOOK: Record<\n CanvasStatus,\n { label: string; description: string; pill: string; dot: string }\n> = {\n draft: {\n label: \"Draft\",\n description: \"Being worked on\",\n pill: \"bg-[rgb(var(--ec-badge-color-gray-background))] text-[rgb(var(--ec-badge-color-gray-text))] border-[rgb(var(--ec-badge-color-gray-text)/0.25)]\",\n dot: \"bg-[rgb(var(--ec-badge-color-gray-text))]\",\n },\n proposed: {\n label: \"Proposed\",\n description: \"Ready for review\",\n pill: \"bg-[rgb(var(--ec-badge-color-yellow-background))] text-[rgb(var(--ec-badge-color-yellow-text))] border-[rgb(var(--ec-badge-color-yellow-text)/0.3)]\",\n dot: \"bg-[rgb(var(--ec-badge-color-yellow-text))]\",\n },\n accepted: {\n label: \"Accepted\",\n description: \"The agreed design\",\n pill: \"bg-[rgb(var(--ec-badge-color-green-background))] text-[rgb(var(--ec-badge-color-green-text))] border-[rgb(var(--ec-badge-color-green-text)/0.3)]\",\n dot: \"bg-[rgb(var(--ec-badge-color-green-text))]\",\n },\n rejected: {\n label: \"Rejected\",\n description: \"Decided against, kept for the record\",\n pill: \"bg-[rgb(var(--ec-badge-color-red-background))] text-[rgb(var(--ec-badge-color-red-text))] border-[rgb(var(--ec-badge-color-red-text)/0.3)]\",\n dot: \"bg-[rgb(var(--ec-badge-color-red-text))]\",\n },\n};\n","import { useState } from \"react\";\n\n/**\n * Someone's picture from their sign-in provider (SSO), loaded from there. By default it covers their avatar's\n * initials, which show again if it doesn't load (blocked, expired, or no longer there).\n */\nexport default function Picture({\n src,\n className = \"absolute inset-0 h-full w-full\",\n}: {\n src?: string;\n className?: string;\n}) {\n const [failed, setFailed] = useState<string>();\n if (!src || failed === src) return null;\n return (\n <img\n src={src}\n alt=\"\"\n draggable={false}\n // Some providers (e.g. Google) refuse pictures loaded with a referrer from another site\n referrerPolicy=\"no-referrer\"\n onError={() => setFailed(src)}\n className={`rounded-full object-cover ${className}`}\n />\n );\n}\n","/**\n * The AI clients' logos, for the connect dialog's tabs. From Lobe Icons (@lobehub/icons-static-svg, MIT):\n * https://github.com/lobehub/lobe-icons\n */\nimport type { SVGProps } from \"react\";\nimport { Bot } from \"lucide-react\";\n\ntype LogoProps = SVGProps<SVGSVGElement>;\n\nexport const ClaudeLogo = (props: LogoProps) => (\n <svg viewBox=\"0 0 24 24\" aria-hidden {...props}>\n <path\n fill=\"#D97757\"\n d=\"M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z\"\n />\n </svg>\n);\n\nexport const ClaudeCodeLogo = (props: LogoProps) => (\n <svg viewBox=\"0 0 24 24\" aria-hidden {...props}>\n <path\n fill=\"#D97757\"\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M20.998 10.949H24v3.102h-3v3.028h-1.487V20H18v-2.921h-1.487V20H15v-2.921H9V20H7.488v-2.921H6V20H4.487v-2.921H3V14.05H0V10.95h3V5h17.998v5.949zM6 10.949h1.488V8.102H6v2.847zm10.51 0H18V8.102h-1.49v2.847z\"\n />\n </svg>\n);\n\nexport const OpenAILogo = (props: LogoProps) => (\n <svg viewBox=\"0 0 24 24\" aria-hidden {...props}>\n <path\n fill=\"currentColor\"\n d=\"M9.205 8.658v-2.26c0-.19.072-.333.238-.428l4.543-2.616c.619-.357 1.356-.523 2.117-.523 2.854 0 4.662 2.212 4.662 4.566 0 .167 0 .357-.024.547l-4.71-2.759a.797.797 0 00-.856 0l-5.97 3.473zm10.609 8.8V12.06c0-.333-.143-.57-.429-.737l-5.97-3.473 1.95-1.118a.433.433 0 01.476 0l4.543 2.617c1.309.76 2.189 2.378 2.189 3.948 0 1.808-1.07 3.473-2.76 4.163zM7.802 12.703l-1.95-1.142c-.167-.095-.239-.238-.239-.428V5.899c0-2.545 1.95-4.472 4.591-4.472 1 0 1.927.333 2.712.928L8.23 5.067c-.285.166-.428.404-.428.737v6.898zM12 15.128l-2.795-1.57v-3.33L12 8.658l2.795 1.57v3.33L12 15.128zm1.796 7.23c-1 0-1.927-.332-2.712-.927l4.686-2.712c.285-.166.428-.404.428-.737v-6.898l1.974 1.142c.167.095.238.238.238.428v5.233c0 2.545-1.974 4.472-4.614 4.472zm-5.637-5.303l-4.544-2.617c-1.308-.761-2.188-2.378-2.188-3.948A4.482 4.482 0 014.21 6.327v5.423c0 .333.143.571.428.738l5.947 3.449-1.95 1.118a.432.432 0 01-.476 0zm-.262 3.9c-2.688 0-4.662-2.021-4.662-4.519 0-.19.024-.38.047-.57l4.686 2.71c.286.167.571.167.856 0l5.97-3.448v2.26c0 .19-.07.333-.237.428l-4.543 2.616c-.619.357-1.356.523-2.117.523zm5.899 2.83a5.947 5.947 0 005.827-4.756C22.287 18.339 24 15.84 24 13.296c0-1.665-.713-3.282-1.998-4.448.119-.5.19-.999.19-1.498 0-3.401-2.759-5.947-5.946-5.947-.642 0-1.26.095-1.88.31A5.962 5.962 0 0010.205 0a5.947 5.947 0 00-5.827 4.757C1.713 5.447 0 7.945 0 10.49c0 1.666.713 3.283 1.998 4.448-.119.5-.19 1-.19 1.499 0 3.401 2.759 5.946 5.946 5.946.642 0 1.26-.095 1.88-.309a5.96 5.96 0 004.162 1.713z\"\n />\n </svg>\n);\n\nexport const CursorLogo = (props: LogoProps) => (\n <svg viewBox=\"0 0 24 24\" aria-hidden {...props}>\n <path\n fill=\"currentColor\"\n d=\"M22.106 5.68L12.5.135a.998.998 0 00-.998 0L1.893 5.68a.84.84 0 00-.419.726v11.186c0 .3.16.577.42.727l9.607 5.547a.999.999 0 00.998 0l9.608-5.547a.84.84 0 00.42-.727V6.407a.84.84 0 00-.42-.726zm-.603 1.176L12.228 22.92c-.063.108-.228.064-.228-.061V12.34a.59.59 0 00-.295-.51l-9.11-5.26c-.107-.062-.063-.228.062-.228h18.55c.264 0 .428.286.296.514z\"\n />\n </svg>\n);\n\n/**\n * The logo of the company behind an agent, from the name it joined with (agentName on the MCP tools, e.g. \"Claude\n * Code\", \"Codex\", \"Cursor\"), when it's one we know: shown instead of a robot on its avatar, pointer and comments\n */\nexport const agentLogoFor = (name?: string) => {\n const lowered = (name ?? \"\").toLowerCase();\n if (lowered.includes(\"claude code\")) return ClaudeCodeLogo;\n if (/\\b(claude|anthropic)\\b/.test(lowered)) return ClaudeLogo;\n if (/\\b(codex|chatgpt|openai|gpt)/.test(lowered)) return OpenAILogo;\n if (/\\bcursor\\b/.test(lowered)) return CursorLogo;\n return undefined;\n};\n\n/** An agent's mark: its company's logo when it's one we know (agentLogoFor), else a robot */\nexport function AgentMark({\n name,\n size = 14,\n}: {\n name?: string;\n size?: number;\n}) {\n const Logo = agentLogoFor(name);\n // On a light disc, so the logo keeps its colours on the agent's coloured avatar or label\n return Logo ? (\n <span\n className=\"flex flex-none items-center justify-center rounded-full bg-white\"\n style={{ width: size + 4, height: size + 4, color: \"#111827\" }}\n >\n <Logo width={size - 2} height={size - 2} />\n </span>\n ) : (\n <Bot size={size} />\n );\n}\n","/**\n * The canvas's right-click menu: on a node, commenting on it, flagging it, a note beside it, editing its details,\n * copying, duplicating and deleting it (or the selection it's in), and questions for an agent about it (when the\n * view is in a chat that takes them); on the canvas, putting a comment, hotspot or note there, pasting there, and\n * laying the level shown out again. What an app leaves out isn't offered.\n */\nimport {\n memo,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\nimport type { Node, XYPosition } from \"@xyflow/react\";\nimport {\n ClipboardPaste,\n Copy,\n CopyPlus,\n MessageCircle,\n MessageCircleQuestion,\n Pencil,\n SendToBack,\n StickyNote,\n Trash2,\n TriangleAlert,\n} from \"lucide-react\";\nimport { isWrittenOnCanvas } from \"../node-types\";\nimport { STATUS } from \"./status\";\n\nexport type ContextMenuState = {\n x: number;\n y: number;\n flowPosition: XYPosition;\n node?: Node;\n} | null;\n\n/** The least room left between the menu and the window's edges */\nconst EDGE = 8;\n\n/** Something to ask the agent about the node right clicked */\nexport type MenuQuestion = { label: string; onSelect: () => void };\n\nexport const ContextMenu = memo(function ContextMenu({\n menu,\n questions,\n onCopy,\n onDuplicate,\n onPaste,\n onAddNote,\n onAddComment,\n onAddHotspot,\n onEditDetails,\n onReorder,\n onDeleteNode,\n onClose,\n}: {\n menu: ContextMenuState;\n /** For the node right clicked */\n questions?: MenuQuestion[];\n onCopy: () => void;\n onDuplicate: () => void;\n /** Paste what was last copied where the menu was opened, if anything was */\n onPaste?: () => void;\n /** A sticky note where the menu was opened (on the canvas), or beside the node */\n onAddNote: () => void;\n /** A comment pinned where the menu was opened (on the canvas or the node), on L3 */\n onAddComment?: () => void;\n /** A hotspot on the node right clicked (or where the menu was opened), on L3 */\n onAddHotspot?: () => void;\n /** Opens the node's details (not for notes and text, which are written on the canvas) */\n onEditDetails?: () => void;\n /** Lays the level shown out again (the visualiser's layout), from the canvas's menu */\n onReorder?: () => void;\n onDeleteNode: () => void;\n onClose: () => void;\n}) {\n useEffect(() => {\n if (!menu) return;\n const close = (event: Event) => {\n if (event instanceof KeyboardEvent && event.key !== \"Escape\") return;\n onClose();\n };\n window.addEventListener(\"pointerdown\", close);\n window.addEventListener(\"keydown\", close);\n window.addEventListener(\"wheel\", close);\n return () => {\n window.removeEventListener(\"pointerdown\", close);\n window.removeEventListener(\"keydown\", close);\n window.removeEventListener(\"wheel\", close);\n };\n }, [menu, onClose]);\n\n // Kept in the window: opened near its right or bottom edge, it opens to the left of the pointer, or above it.\n // Measured before it's shown (a layout effect), so it never shows cut off first\n const menuRef = useRef<HTMLDivElement>(null);\n const [placed, setPlaced] = useState<{ left: number; top: number } | null>(\n null,\n );\n useLayoutEffect(() => {\n const element = menuRef.current;\n if (!menu || !element) return setPlaced(null);\n const { width, height } = element.getBoundingClientRect();\n const fit = (at: number, size: number, room: number) =>\n at + size <= room - EDGE\n ? at\n : Math.max(EDGE, Math.min(at - size, room - EDGE - size));\n setPlaced({\n left: fit(menu.x, width, window.innerWidth),\n top: fit(menu.y, height, window.innerHeight),\n });\n }, [menu]);\n\n if (!menu) return null;\n\n const itemClass =\n \"flex w-full items-center gap-2 rounded px-2.5 py-1.5 text-left text-xs hover:bg-[rgb(var(--ec-page-border)/0.5)]\";\n const shortcutClass = \"ml-auto text-[rgb(var(--ec-page-text-muted))]\";\n const item = (\n icon: ReactNode,\n label: string,\n onClick: () => void,\n shortcut?: string,\n className = \"\",\n ) => (\n <button className={`${itemClass} ${className}`} onClick={onClick}>\n {icon}\n {label}\n {shortcut && <span className={shortcutClass}>{shortcut}</span>}\n </button>\n );\n const separator = (\n <div className=\"my-1 h-px bg-[rgb(var(--ec-page-border))]\" />\n );\n\n return (\n <div\n // Keep the window pointerdown listener from closing the menu before a click lands\n onPointerDown={(event) => event.stopPropagation()}\n onContextMenu={(event) => event.preventDefault()}\n ref={menuRef}\n className=\"fixed z-50 w-56 overflow-y-auto rounded-lg border p-1 shadow-xl bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))]\"\n style={{\n left: placed?.left ?? menu.x,\n top: placed?.top ?? menu.y,\n maxHeight: `calc(100vh - ${EDGE * 2}px)`,\n visibility: placed ? \"visible\" : \"hidden\",\n }}\n >\n {menu.node && questions?.length ? (\n <>\n {questions.map((question) => (\n <button\n key={question.label}\n className={itemClass}\n onClick={question.onSelect}\n >\n <MessageCircleQuestion size={14} />\n {question.label}\n </button>\n ))}\n {separator}\n </>\n ) : null}\n {menu.node && (\n <>\n {onAddComment &&\n item(<MessageCircle size={14} />, \"Add comment\", onAddComment, \"C\")}\n {onAddHotspot &&\n !isWrittenOnCanvas(menu.node.type) &&\n item(<TriangleAlert size={14} />, \"Add hotspot\", onAddHotspot, \"A\")}\n {!isWrittenOnCanvas(menu.node.type) &&\n item(<StickyNote size={14} />, \"Add a note\", onAddNote)}\n {onEditDetails &&\n !isWrittenOnCanvas(menu.node.type) &&\n item(<Pencil size={14} />, \"Edit details\", onEditDetails)}\n {item(<Copy size={14} />, \"Copy\", onCopy, \"⌘C\")}\n {item(<CopyPlus size={14} />, \"Duplicate\", onDuplicate, \"⌘D\")}\n {separator}\n {item(\n <Trash2 size={14} />,\n \"Delete\",\n onDeleteNode,\n \"⌫\",\n STATUS.danger.text,\n )}\n </>\n )}\n {!menu.node && (\n <>\n {onAddComment &&\n item(<MessageCircle size={14} />, \"Add comment\", onAddComment, \"C\")}\n {onAddHotspot &&\n item(<TriangleAlert size={14} />, \"Add hotspot\", onAddHotspot, \"A\")}\n {item(<StickyNote size={14} />, \"Add a sticky note\", onAddNote, \"N\")}\n {onPaste &&\n item(<ClipboardPaste size={14} />, \"Paste here\", onPaste, \"⌘V\")}\n {onReorder && (\n <>\n {separator}\n {item(<SendToBack size={14} />, \"Reorder diagram\", onReorder)}\n </>\n )}\n </>\n )}\n </div>\n );\n});\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type DragEvent,\n} from \"react\";\nimport {\n ReactFlow,\n ReactFlowProvider,\n useStoreApi,\n type Node,\n type XYPosition,\n} from \"@xyflow/react\";\nimport { getNodeSize, isGroupType } from \"../node-types\";\nimport { nodeTypes } from \"./canvas-nodes\";\n\n/**\n * Dragging something from the left panel onto the canvas shows the node it becomes, under the pointer, at the\n * canvas's zoom and where it will land (centred on the pointer, as it's dropped). Drawn here rather than as the\n * browser's drag image, which browsers shrink, fade and put a backing behind.\n */\n\n/** What's dragged: the node it becomes */\nexport type DragPreview = { type: string; data: Record<string, unknown> };\n/** Starts dragging `value` as `dragType`, showing `preview` as what's dragged */\nexport type StartDrag = (\n dragType: string,\n value: string,\n preview: DragPreview,\n) => (event: DragEvent) => void;\n\n// Hides the browser's own drag image (a transparent pixel)\nconst NO_DRAG_IMAGE =\n typeof Image === \"undefined\"\n ? undefined\n : Object.assign(new Image(), {\n src: \"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\",\n });\n\n// Room around the node for the badge on its top edge\nconst MARGIN = 16;\nconst PRO_OPTIONS = { hideAttribution: true };\n\ntype Ghost = { preview: DragPreview; zoom: number; at: XYPosition };\n\n/** The ghost of what's being dragged, and how to start dragging something with one */\nexport function useDragGhost() {\n const store = useStoreApi();\n const [ghost, setGhost] = useState<Ghost | null>(null);\n\n const startDrag = useCallback<StartDrag>(\n (dragType, value, preview) => (event) => {\n event.dataTransfer.setData(dragType, value);\n event.dataTransfer.effectAllowed = \"move\";\n if (NO_DRAG_IMAGE) event.dataTransfer.setDragImage(NO_DRAG_IMAGE, 0, 0);\n setGhost({\n preview,\n zoom: store.getState().transform[2],\n at: { x: event.clientX, y: event.clientY },\n });\n },\n [store],\n );\n\n const element = ghost && (\n <DragGhost ghost={ghost} onEnd={() => setGhost(null)} />\n );\n return { startDrag, ghost: element };\n}\n\nfunction DragGhost({ ghost, onEnd }: { ghost: Ghost; onEnd: () => void }) {\n const ref = useRef<HTMLDivElement>(null);\n const { preview, zoom } = ghost;\n const container = isGroupType(preview.type);\n // The size it's added at (containers are sized; cards are drawn at their own size inside this)\n const size = getNodeSize(preview.type);\n // The node is placed with its middle where it's dropped, at the size it's added at\n const offset = {\n x: (size.width / 2) * zoom + MARGIN,\n y: (size.height / 2) * zoom + MARGIN,\n };\n\n // Follows the pointer (as the browser reports it while dragging) without re-rendering, and goes when it's dropped\n useEffect(() => {\n const move = (x: number, y: number) => {\n if (ref.current)\n ref.current.style.transform = `translate(${x - offset.x}px, ${y - offset.y}px)`;\n };\n move(ghost.at.x, ghost.at.y);\n const onDragOver = (event: globalThis.DragEvent) => {\n if (event.clientX || event.clientY) move(event.clientX, event.clientY);\n };\n document.addEventListener(\"dragover\", onDragOver);\n document.addEventListener(\"drop\", onEnd);\n document.addEventListener(\"dragend\", onEnd);\n return () => {\n document.removeEventListener(\"dragover\", onDragOver);\n document.removeEventListener(\"drop\", onEnd);\n document.removeEventListener(\"dragend\", onEnd);\n };\n }, [ghost]);\n\n const nodes = useMemo<Node[]>(\n () => [\n {\n id: \"drag-ghost\",\n type: preview.type,\n position: { x: 0, y: 0 },\n data: preview.data,\n ...(container && size),\n },\n ],\n [preview, container, size],\n );\n const viewport = useMemo(() => ({ x: MARGIN, y: MARGIN, zoom }), [zoom]);\n\n return (\n <div\n ref={ref}\n aria-hidden\n // Sized here: the visualiser's styles make its class fill the window\n className=\"studio-drag-preview eventcatalog-visualizer pointer-events-none fixed left-0 top-0 z-[100] opacity-70\"\n style={{\n width: size.width * zoom + MARGIN * 2,\n height: size.height * zoom + MARGIN * 2,\n }}\n >\n <ReactFlowProvider>\n <ReactFlow\n nodes={nodes}\n nodeTypes={nodeTypes}\n defaultViewport={viewport}\n proOptions={PRO_OPTIONS}\n nodesDraggable={false}\n nodesConnectable={false}\n elementsSelectable={false}\n panOnDrag={false}\n zoomOnScroll={false}\n zoomOnPinch={false}\n preventScrolling={false}\n />\n </ReactFlowProvider>\n </div>\n );\n}\n","/**\n * Hotspots: what an architect (or the agent) flags on the architecture so people find what matters: risks, single\n * points of failure, known problems, the key parts to understand. Each is critical, a warning or info.\n *\n * On a node, a marker sits on its top right corner with its title (and the node glows in its colour, see\n * studio.css); at a place, the marker's there. On L1 and L2 a node shows the hotspots inside it, to go and see them.\n * In the canvas's own coordinates (React Flow's viewport portal), counter-scaled to stay the same size on screen.\n */\nimport {\n memo,\n useLayoutEffect,\n useRef,\n useState,\n type FormEvent,\n type ReactNode,\n type RefObject,\n} from \"react\";\nimport {\n useInternalNode,\n useReactFlow,\n useStoreApi,\n type XYPosition,\n} from \"@xyflow/react\";\nimport { CanvasPortal } from \"../../utils/flow-portals\";\nimport {\n Info,\n OctagonAlert,\n Pencil,\n Trash2,\n TriangleAlert,\n X,\n type LucideIcon,\n} from \"lucide-react\";\nimport type { Hotspot, HotspotSeverity } from \"../canvas-doc\";\nimport { isWrittenOnCanvas } from \"../node-types\";\nimport { AgentMark } from \"./ClientLogos\";\nimport { timeAgo } from \"./Comments\";\nimport { sendMove, useRemoteMoves, type LiveMoves } from \"../live-moves\";\n\nexport const SEVERITIES: Record<\n HotspotSeverity,\n { label: string; color: string; icon: LucideIcon; rank: number }\n> = {\n critical: {\n label: \"Critical\",\n color: \"#dc2626\",\n icon: OctagonAlert,\n rank: 0,\n },\n warning: { label: \"Warning\", color: \"#d97706\", icon: TriangleAlert, rank: 1 },\n info: { label: \"Info\", color: \"#2563eb\", icon: Info, rank: 2 },\n};\nconst SEVERITY_ORDER: HotspotSeverity[] = [\"critical\", \"warning\", \"info\"];\n\n/** Most important first (then oldest first) */\nexport const bySeverity = (a: Hotspot, b: Hotspot) =>\n SEVERITIES[a.severity].rank - SEVERITIES[b.severity].rank ||\n a.createdAt - b.createdAt;\nexport const topSeverity = (hotspots: Hotspot[]) =>\n [...hotspots].sort(bySeverity)[0]?.severity;\n\n/** Hotspots shown together: on a node (its own, or on L1 and L2 also the ones inside it), or one at a place */\nexport type HotspotSpot = {\n key: string;\n nodeId?: string;\n position?: XYPosition;\n hotspots: Hotspot[];\n inside?: boolean;\n};\n/** A hotspot being added: on a node, or at a place */\nexport type HotspotDraft = {\n nodeId?: string;\n position: XYPosition;\n level?: 1 | 2;\n};\nexport type HotspotFields = {\n severity: HotspotSeverity;\n title: string;\n description?: string;\n};\n\n// Markers keep their size on screen as the canvas zooms in, and shrink with it zoomed out (to half their size at\n// most), so they don't cover what they're about; zoomed well out they're just their icon\nconst MARKER_SCALE = \"--studio-hotspot-scale\";\n// What an open marker's panel is scaled by inside it, so it's always its full size on screen (to be read)\nconst PANEL_SCALE = \"--studio-hotspot-panel-scale\";\nconst MIN_SCREEN_SCALE = 0.5;\nconst ICONS_ONLY_BELOW_ZOOM = 0.6;\n\n/** Keeps MARKER_SCALE (and icons only) on the layer as the canvas zooms, outside React, so markers don't re-render */\nfunction useMarkerScale(ref: RefObject<HTMLElement | null>) {\n const store = useStoreApi();\n useLayoutEffect(() => {\n const apply = (zoom: number) => {\n const element = ref.current;\n if (!element) return;\n // In the canvas's coordinates: zoomed in, 1 / zoom (the same size on screen); zoomed out, the canvas's size\n // (1), until that's under MIN_SCREEN_SCALE on screen\n const scale = zoom >= 1 ? 1 / zoom : Math.max(1, MIN_SCREEN_SCALE / zoom);\n element.style.setProperty(MARKER_SCALE, String(scale));\n element.style.setProperty(PANEL_SCALE, String(1 / zoom / scale));\n element.classList.toggle(\"is-icons-only\", zoom < ICONS_ONLY_BELOW_ZOOM);\n };\n apply(store.getState().transform[2]);\n return store.subscribe((state, previous) => {\n if (state.transform[2] !== previous.transform[2])\n apply(state.transform[2]);\n });\n }, [store, ref]);\n}\n\n/** On its node's top right corner (following only that node), or at its place */\nfunction SpotAt({\n nodeId,\n position,\n zIndex,\n children,\n}: {\n nodeId?: string;\n position?: XYPosition;\n zIndex: number;\n children: ReactNode;\n}) {\n const node = useInternalNode(nodeId ?? \"\");\n let at = position;\n if (nodeId) {\n if (!node) return null;\n const { x, y } = node.internals.positionAbsolute;\n at = { x: x + (node.measured.width ?? node.width ?? 0), y };\n }\n if (!at) return null;\n return (\n <div\n className=\"absolute\"\n style={{\n left: at.x,\n top: at.y,\n transform: `scale(var(${MARKER_SCALE}, 1))`,\n transformOrigin: \"0 0\",\n zIndex,\n }}\n >\n {/* The marker's icon is centred on the corner, its title out to the right */}\n <div className=\"nopan nodrag nowheel pointer-events-auto absolute left-[-14px] top-[-14px]\">\n {children}\n </div>\n </div>\n );\n}\n\nfunction SeverityIcon({\n severity,\n size = 13,\n}: {\n severity: HotspotSeverity;\n size?: number;\n}) {\n const { icon: Icon } = SEVERITIES[severity];\n return <Icon size={size} strokeWidth={2.5} aria-hidden />;\n}\n\n/** Where a hotspot is put: on a node (it moves with it), or at a place */\nexport type HotspotPlace = { nodeId?: string; position: XYPosition };\n\n// How far the pointer moves before a press on a marker is a drag (not a click)\nconst DRAG_THRESHOLD_PX = 4;\n// The marker's icon (where it's anchored) is this far from its top left corner\nconst ICON_CENTRE_PX = 14;\n\n/**\n * The marker: its severity's colour and icon, and its title (or how many there are). Click opens it; dragging it\n * moves it: `onDrag` gets the screen point its icon is over, keeping where on the marker it was grabbed\n */\nfunction Marker({\n spot,\n open,\n selected,\n onClick,\n onDrag,\n}: {\n spot: HotspotSpot;\n open: boolean;\n /** Part of what's selected on the canvas (after selecting everything) */\n selected?: boolean;\n onClick: () => void;\n onDrag?: (point: XYPosition, phase: \"move\" | \"end\") => void;\n}) {\n const drag = useRef<{\n start: XYPosition;\n grab: XYPosition;\n moved: boolean;\n } | null>(null);\n const pointOf = (event: { clientX: number; clientY: number }) => ({\n x: event.clientX - drag.current!.grab.x,\n y: event.clientY - drag.current!.grab.y,\n });\n const sorted = [...spot.hotspots].sort(bySeverity);\n const severity = sorted[0].severity;\n const count = sorted.length;\n const label = spot.inside\n ? `${count} hotspot${count === 1 ? \"\" : \"s\"}`\n : count > 1\n ? `${sorted[0].title} +${count - 1}`\n : sorted[0].title;\n return (\n <button\n type=\"button\"\n aria-expanded={open}\n title={sorted\n .map(\n (hotspot) =>\n `${SEVERITIES[hotspot.severity].label}: ${hotspot.title}`,\n )\n .join(\"\\n\")}\n onKeyDown={(event) =>\n (event.key === \"Enter\" || event.key === \" \") && onClick()\n }\n onPointerDown={(event) => {\n if (event.button !== 0) return;\n // Keeps pointer events coming while the pointer is off the marker (throws if the pointer has gone)\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {}\n const rect = event.currentTarget.getBoundingClientRect();\n drag.current = {\n start: { x: event.clientX, y: event.clientY },\n grab: {\n x: event.clientX - rect.left - ICON_CENTRE_PX * (rect.height / 28),\n y: event.clientY - rect.top - rect.height / 2,\n },\n moved: false,\n };\n }}\n onPointerMove={(event) => {\n const current = drag.current;\n if (!current || !onDrag) return;\n if (\n !current.moved &&\n Math.hypot(\n event.clientX - current.start.x,\n event.clientY - current.start.y,\n ) < DRAG_THRESHOLD_PX\n )\n return;\n current.moved = true;\n onDrag(pointOf(event), \"move\");\n }}\n onPointerUp={(event) => {\n const current = drag.current;\n drag.current = null;\n if (!current) return;\n if (current.moved)\n onDrag?.(\n {\n x: event.clientX - current.grab.x,\n y: event.clientY - current.grab.y,\n },\n \"end\",\n );\n else onClick();\n }}\n onPointerCancel={() => (drag.current = null)}\n className={`studio-hotspot-marker flex h-7 max-w-[240px] items-center gap-1.5 rounded-full pl-1 pr-2.5 text-[11px] font-semibold text-white ${onDrag ? \"cursor-grab active:cursor-grabbing\" : \"\"}`}\n style={{\n background: SEVERITIES[severity].color,\n touchAction: \"none\",\n ...(selected && {\n boxShadow:\n \"0 0 0 2px rgb(var(--ec-card-bg)), 0 0 0 4px rgb(var(--ec-button-bg))\",\n }),\n }}\n >\n <span className=\"flex h-5 w-5 flex-none items-center justify-center rounded-full bg-white/20\">\n <SeverityIcon severity={severity} />\n </span>\n <span className=\"studio-hotspot-label truncate\">{label}</span>\n </button>\n );\n}\n\nconst panelClass =\n \"studio-hotspot-panel absolute left-0 top-[34px] w-80 rounded-xl border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg))] text-[rgb(var(--ec-page-text))] shadow-xl\";\nconst inputClass =\n \"block w-full rounded-md border border-[rgb(var(--ec-input-border))] bg-[rgb(var(--ec-input-bg))] px-2.5 py-1.5 text-sm text-[rgb(var(--ec-input-text))] outline-none focus:border-[rgb(var(--ec-accent))]\";\n\n/** Adding or changing one: how important, what it is, and why */\nfunction HotspotForm({\n initial,\n submitLabel,\n onSubmit,\n onCancel,\n}: {\n initial?: HotspotFields;\n submitLabel: string;\n onSubmit: (fields: HotspotFields) => void;\n onCancel: () => void;\n}) {\n const [severity, setSeverity] = useState<HotspotSeverity>(\n initial?.severity ?? \"warning\",\n );\n const [title, setTitle] = useState(initial?.title ?? \"\");\n const [description, setDescription] = useState(initial?.description ?? \"\");\n const submit = (event?: FormEvent) => {\n event?.preventDefault();\n if (!title.trim()) return;\n onSubmit({\n severity,\n title: title.trim(),\n ...(description.trim() && { description: description.trim() }),\n });\n };\n return (\n <form\n onSubmit={submit}\n onKeyDown={(event) => {\n if (event.key === \"Escape\") {\n event.stopPropagation();\n onCancel();\n }\n }}\n className=\"space-y-2.5 p-3\"\n >\n <div role=\"radiogroup\" aria-label=\"How important\" className=\"flex gap-1\">\n {SEVERITY_ORDER.map((value) => {\n const picked = value === severity;\n return (\n <button\n key={value}\n type=\"button\"\n role=\"radio\"\n aria-checked={picked}\n onClick={() => setSeverity(value)}\n className=\"flex flex-1 items-center justify-center gap-1 rounded-md border px-2 py-1.5 text-xs font-semibold transition-colors\"\n style={\n picked\n ? {\n background: SEVERITIES[value].color,\n borderColor: SEVERITIES[value].color,\n color: \"#fff\",\n }\n : {\n borderColor: \"rgb(var(--ec-page-border))\",\n color: SEVERITIES[value].color,\n }\n }\n >\n <SeverityIcon severity={value} size={12} />\n {SEVERITIES[value].label}\n </button>\n );\n })}\n </div>\n <input\n autoFocus\n value={title}\n maxLength={120}\n onChange={(event) => setTitle(event.target.value)}\n placeholder=\"What should people know? e.g. Single point of failure\"\n className={inputClass}\n />\n <textarea\n value={description}\n maxLength={1000}\n rows={3}\n onChange={(event) => setDescription(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" && (event.metaKey || event.ctrlKey))\n submit();\n }}\n placeholder=\"Why it matters, and what to do about it (optional)\"\n className={`${inputClass} resize-none`}\n />\n <div className=\"flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"rounded-md px-3 py-1.5 text-xs font-medium text-[rgb(var(--ec-page-text-muted))] hover:bg-[rgb(var(--ec-content-hover))]!\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n disabled={!title.trim()}\n className=\"rounded-md bg-[rgb(var(--ec-primary-bg))] px-3 py-1.5 text-xs font-semibold text-[rgb(var(--ec-primary-text))] disabled:opacity-40\"\n >\n {submitLabel}\n </button>\n </div>\n </form>\n );\n}\n\nfunction SeverityTag({ severity }: { severity: HotspotSeverity }) {\n return (\n <span\n className=\"inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide text-white\"\n style={{ background: SEVERITIES[severity].color }}\n >\n <SeverityIcon severity={severity} size={10} />\n {SEVERITIES[severity].label}\n </span>\n );\n}\n\n/** One hotspot as it reads: how important, what, why, and who flagged it */\nfunction HotspotItem({\n hotspot,\n actions,\n}: {\n hotspot: Hotspot;\n actions?: ReactNode;\n}) {\n return (\n <div\n className=\"border-l-[3px] pl-2.5\"\n style={{ borderColor: SEVERITIES[hotspot.severity].color }}\n >\n <div className=\"flex items-center gap-2\">\n <SeverityTag severity={hotspot.severity} />\n <span className=\"flex min-w-0 items-center gap-1 truncate text-[11px] text-[rgb(var(--ec-page-text-muted))]\">\n {hotspot.author.agent && (\n <AgentMark name={hotspot.author.name} size={11} />\n )}\n {hotspot.author.name} · {timeAgo(hotspot.createdAt)}\n </span>\n {actions && (\n <span className=\"ml-auto flex flex-none items-center gap-0.5\">\n {actions}\n </span>\n )}\n </div>\n <p className=\"mt-1.5 text-sm font-semibold leading-snug\">\n {hotspot.title}\n </p>\n {hotspot.description && (\n <p className=\"mt-1 whitespace-pre-wrap text-xs leading-relaxed text-[rgb(var(--ec-page-text-muted))]\">\n {hotspot.description}\n </p>\n )}\n </div>\n );\n}\n\nfunction IconButton({\n label,\n onClick,\n children,\n}: {\n label: string;\n onClick: () => void;\n children: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n title={label}\n aria-label={label}\n onClick={onClick}\n className=\"rounded p-1 text-[rgb(var(--ec-icon-color))] hover:bg-[rgb(var(--ec-page-border)/0.5)] hover:text-[rgb(var(--ec-icon-hover))]\"\n >\n {children}\n </button>\n );\n}\n\n/** The hotspots at a marker, opened: read, changed or removed (or, inside a node on L1 and L2, gone to) */\nfunction SpotPanel({\n spot,\n locked,\n onClose,\n onUpdate,\n onDelete,\n onGo,\n}: {\n spot: HotspotSpot;\n locked: boolean;\n onClose: () => void;\n onUpdate: (id: string, fields: HotspotFields) => void;\n onDelete: (id: string) => void;\n onGo: (hotspot: Hotspot) => void;\n}) {\n const [editing, setEditing] = useState<string | null>(null);\n const sorted = [...spot.hotspots].sort(bySeverity);\n return (\n <div className={panelClass}>\n <div className=\"flex items-center justify-between border-b border-[rgb(var(--ec-page-border))] px-3 py-2\">\n <span className=\"text-xs font-semibold\">\n {sorted.length === 1 ? \"Hotspot\" : `${sorted.length} hotspots`}\n </span>\n <IconButton label=\"Close\" onClick={onClose}>\n <X size={14} />\n </IconButton>\n </div>\n <div className=\"max-h-80 space-y-3 overflow-y-auto p-3\">\n {sorted.map((hotspot) =>\n editing === hotspot.id ? (\n <div key={hotspot.id} className=\"-m-3\">\n <HotspotForm\n initial={hotspot}\n submitLabel=\"Save\"\n onCancel={() => setEditing(null)}\n onSubmit={(fields) => {\n onUpdate(hotspot.id, fields);\n setEditing(null);\n }}\n />\n </div>\n ) : spot.inside ? (\n // Inside a node on L1 or L2: goes to it on L3, where it is\n <button\n key={hotspot.id}\n type=\"button\"\n onClick={() => onGo(hotspot)}\n className=\"block w-full rounded-md text-left hover:bg-[rgb(var(--ec-content-hover))]!\"\n >\n <HotspotItem hotspot={hotspot} />\n </button>\n ) : (\n <HotspotItem\n key={hotspot.id}\n hotspot={hotspot}\n actions={\n !locked && (\n <>\n <IconButton\n label=\"Edit\"\n onClick={() => setEditing(hotspot.id)}\n >\n <Pencil size={13} />\n </IconButton>\n <IconButton\n label=\"Remove\"\n onClick={() => onDelete(hotspot.id)}\n >\n <Trash2 size={13} />\n </IconButton>\n </>\n )\n }\n />\n ),\n )}\n </div>\n {spot.inside && (\n <p className=\"border-t border-[rgb(var(--ec-page-border))] px-3 py-2 text-[11px] text-[rgb(var(--ec-page-text-muted))]\">\n Inside this: click one to go to it.\n </p>\n )}\n </div>\n );\n}\n\nexport const HotspotLayer = memo(function HotspotLayer({\n spots,\n openKey,\n draft,\n locked,\n movable,\n selectedIds,\n onMove,\n onDropTarget,\n onOpen,\n onCreate,\n onCancelDraft,\n onUpdate,\n onDelete,\n onGo,\n live,\n}: {\n spots: HotspotSpot[];\n openKey: string | null;\n draft: HotspotDraft | null;\n locked: boolean;\n /** Markers can be dragged to another node, or a place (on the canvas itself, L3) */\n movable: boolean;\n /** Hotspots that are part of what's selected (after selecting everything) */\n selectedIds: ReadonlySet<string> | null;\n /** Moved: the hotspots at a marker, onto a node or to a place */\n onMove: (ids: string[], to: HotspotPlace) => void;\n /** The node a marker being dragged would go on (and its colour), to light it up; none when it's dropped */\n onDropTarget: (\n target: { nodeId: string; severity: HotspotSeverity } | null,\n ) => void;\n onOpen: (key: string | null) => void;\n onCreate: (fields: HotspotFields) => void;\n onCancelDraft: () => void;\n onUpdate: (id: string, fields: HotspotFields) => void;\n onDelete: (id: string) => void;\n onGo: (hotspot: Hotspot) => void;\n /** In a live room: markers the others are dragging move here as they drag, and mine move for them */\n live?: LiveMoves;\n}) {\n const layer = useRef<HTMLDivElement>(null);\n useMarkerScale(layer);\n const { screenToFlowPosition } = useReactFlow();\n // A marker being dragged follows the pointer here until it's dropped, then moves for everyone\n const [moving, setMoving] = useState<{\n key: string;\n position: XYPosition;\n over?: string;\n } | null>(null);\n // (a marker's known by its first hotspot: the others may group them differently)\n const remote = useRemoteMoves(live, \"hotspot\");\n const remoteAt = (spot: HotspotSpot) => {\n for (const hotspot of spot.hotspots)\n if (remote.has(hotspot.id)) return remote.get(hotspot.id);\n };\n // The node under a point on screen it can go on (not notes or text: they're written on the canvas)\n const nodeUnder = (point: XYPosition) => {\n const element = document\n .elementsFromPoint(point.x, point.y)\n .find((el) => el.closest(\".react-flow__node\"));\n const node = element?.closest(\".react-flow__node\");\n const type = [...(node?.classList ?? [])]\n .find((name) => name.startsWith(\"react-flow__node-\"))\n ?.slice(\"react-flow__node-\".length);\n return node && !isWrittenOnCanvas(type)\n ? (node.getAttribute(\"data-id\") ?? undefined)\n : undefined;\n };\n const dragHandler = (spot: HotspotSpot) =>\n movable && !locked && !spot.inside\n ? (point: XYPosition, phase: \"move\" | \"end\") => {\n const position = screenToFlowPosition(point);\n const over = nodeUnder(point);\n if (phase === \"move\") {\n if (over !== moving?.over)\n onDropTarget(\n over\n ? { nodeId: over, severity: topSeverity(spot.hotspots)! }\n : null,\n );\n sendMove(live, \"hotspot\", spot.hotspots[0].id, position);\n return setMoving({ key: spot.key, position, over });\n }\n setMoving(null);\n onDropTarget(null);\n onMove(\n spot.hotspots.map((hotspot) => hotspot.id),\n over ? { nodeId: over, position } : { position },\n );\n // (after the drop's in the document, so the others don't see it go back in between)\n sendMove(live, \"hotspot\", spot.hotspots[0].id, null);\n }\n : undefined;\n return (\n <CanvasPortal>\n {/* Over the nodes (selected ones are raised to 1000), under comments */}\n <div\n ref={layer}\n className=\"absolute left-0 top-0\"\n style={{ zIndex: 2000 }}\n >\n {spots.map((spot) => {\n const open = spot.key === openKey;\n const remotely = remoteAt(spot);\n const dragged =\n moving?.key === spot.key\n ? moving\n : remotely\n ? { position: remotely }\n : undefined;\n return (\n <SpotAt\n key={spot.key}\n nodeId={dragged ? undefined : spot.nodeId}\n position={dragged ? dragged.position : spot.position}\n zIndex={dragged ? 5 : open ? 3 : 1}\n >\n <Marker\n spot={spot}\n open={open}\n selected={\n !!selectedIds &&\n spot.hotspots.some((hotspot) => selectedIds.has(hotspot.id))\n }\n onClick={() => onOpen(open ? null : spot.key)}\n onDrag={dragHandler(spot)}\n />\n {open && !dragged && (\n <SpotPanel\n spot={spot}\n locked={locked}\n onClose={() => onOpen(null)}\n onUpdate={onUpdate}\n onDelete={onDelete}\n onGo={onGo}\n />\n )}\n </SpotAt>\n );\n })}\n {draft && (\n <SpotAt\n nodeId={draft.nodeId}\n position={draft.nodeId ? undefined : draft.position}\n zIndex={4}\n >\n <span\n className=\"studio-hotspot-marker flex h-7 w-7 items-center justify-center rounded-full text-white\"\n style={{ background: SEVERITIES.warning.color }}\n >\n <SeverityIcon severity=\"warning\" />\n </span>\n <div className={panelClass}>\n <HotspotForm\n submitLabel=\"Add hotspot\"\n onSubmit={onCreate}\n onCancel={onCancelDraft}\n />\n </div>\n </SpotAt>\n )}\n </div>\n </CanvasPortal>\n );\n});\n\n/** All of them, most important first, for the panel at the bottom left: clicking one goes to it */\nexport function HotspotList({\n hotspots,\n nameOf,\n onOpen,\n}: {\n hotspots: Hotspot[];\n nameOf: (nodeId: string) => string | undefined;\n onOpen: (hotspot: Hotspot) => void;\n}) {\n const sorted = [...hotspots].sort(bySeverity);\n if (!sorted.length)\n return (\n <p className=\"px-4 py-6 text-center text-xs leading-relaxed text-[rgb(var(--ec-page-text-muted))]\">\n No hotspots yet. Press A, or right-click a node, to flag what people\n should know: a risk, a problem, or the key part.\n </p>\n );\n return (\n <div className=\"space-y-1.5 p-3\">\n {sorted.map((hotspot) => {\n const on = hotspot.nodeId && nameOf(hotspot.nodeId);\n return (\n <button\n key={hotspot.id}\n type=\"button\"\n onClick={() => onOpen(hotspot)}\n className=\"w-full rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-bg))] px-2.5 py-2 text-left hover:border-[rgb(var(--ec-accent))]!\"\n >\n <HotspotItem hotspot={hotspot} />\n {on && (\n <p className=\"mt-1.5 pl-[13px] text-[11px] text-[rgb(var(--ec-page-text-muted))]\">\n On {on}\n </p>\n )}\n </button>\n );\n })}\n </div>\n );\n}\n","import type { LucideIcon } from \"lucide-react\";\nimport {\n ArrowRightLeft,\n Bot,\n Boxes,\n Archive,\n Database,\n DatabaseZap,\n Globe,\n Group,\n Mail,\n MonitorSmartphone,\n ScanSearch,\n Search,\n ServerIcon,\n StickyNote,\n TableProperties,\n Type,\n User,\n Users,\n Zap,\n} from \"lucide-react\";\nimport { GROUP_TYPES } from \"../node-types\";\n\n/** How each kind of node, and each catalog collection, looks in the canvas's lists (the colours are each kind's own) */\nexport type NodeIcon = { icon: LucideIcon; className: string };\n\nexport const NODE_ICONS: Record<string, NodeIcon> = {\n [GROUP_TYPES.domain]: { icon: Boxes, className: \"text-yellow-500\" },\n [GROUP_TYPES.system]: { icon: Group, className: \"text-violet-600\" },\n // Catalog domains and systems added as cards\n \"context-domain\": { icon: Boxes, className: \"text-yellow-500\" },\n system: { icon: Group, className: \"text-violet-600\" },\n service: { icon: ServerIcon, className: \"text-pink-600\" },\n event: { icon: Zap, className: \"text-orange-600\" },\n command: { icon: Mail, className: \"text-blue-600\" },\n query: { icon: Search, className: \"text-green-600\" },\n channel: { icon: ArrowRightLeft, className: \"text-gray-600\" },\n data: { icon: Database, className: \"text-blue-600\" },\n // The other kinds of data store, in the components list\n \"data:cache\": { icon: DatabaseZap, className: \"text-blue-600\" },\n \"data:searchIndex\": { icon: ScanSearch, className: \"text-blue-600\" },\n \"data:objectStore\": { icon: Archive, className: \"text-blue-600\" },\n view: { icon: MonitorSmartphone, className: \"text-sky-600\" },\n externalSystem: { icon: Globe, className: \"text-purple-600\" },\n agent: { icon: Bot, className: \"text-violet-600\" },\n actor: { icon: User, className: \"text-yellow-500\" },\n team: { icon: Users, className: \"text-emerald-600\" },\n // A table of its properties, as the node shows it\n entity: { icon: TableProperties, className: \"text-blue-600\" },\n note: { icon: StickyNote, className: \"text-yellow-500\" },\n text: { icon: Type, className: \"text-[rgb(var(--ec-icon-color))]\" },\n};\n\n/** The catalog's collections, in the order the catalog list shows them, with the icon of the node each becomes */\nexport const CATALOG_GROUPS: ({\n collection: string;\n label: string;\n} & NodeIcon)[] = [\n {\n collection: \"domains\",\n label: \"Domains\",\n ...NODE_ICONS[GROUP_TYPES.domain],\n },\n {\n collection: \"systems\",\n label: \"Systems\",\n ...NODE_ICONS[GROUP_TYPES.system],\n },\n { collection: \"services\", label: \"Services\", ...NODE_ICONS.service },\n { collection: \"events\", label: \"Events\", ...NODE_ICONS.event },\n { collection: \"commands\", label: \"Commands\", ...NODE_ICONS.command },\n { collection: \"queries\", label: \"Queries\", ...NODE_ICONS.query },\n { collection: \"channels\", label: \"Channels\", ...NODE_ICONS.channel },\n { collection: \"containers\", label: \"Data Stores\", ...NODE_ICONS.data },\n];\n","import { memo, type ReactNode } from \"react\";\nimport { useReactFlow, type FitViewOptions } from \"@xyflow/react\";\nimport {\n Hand,\n Lock,\n LockOpen,\n Maximize,\n MessageCircle,\n MessageSquareText,\n MousePointer2,\n Type,\n Redo,\n SendToBack,\n StickyNote,\n TriangleAlert,\n Undo,\n ZoomIn,\n ZoomOut,\n} from \"lucide-react\";\nimport {\n DIAGRAM_FIT_VIEW_OPTIONS,\n Toolbar,\n ToolbarButton,\n ToolbarDivider,\n ZoomLevel,\n} from \"../../index\";\nimport { LEVELS, type Level } from \"../levels\";\nimport type { HotspotSeverity } from \"../canvas-doc\";\nimport { SEVERITIES } from \"./Hotspots\";\n\n// The canvas's bar at the top (lock, select and hand, the levels of detail, notes, text, comments and hotspots),\n// and its controls at the bottom left (zoom, undo, fit and reorder, comments and hotspots). Built from the visualiser's toolbar, so they\n// look and work like a diagram's bar.\n\n// Fitted like the visualiser fits a diagram\nexport const FIT_VIEW_OPTIONS = DIAGRAM_FIT_VIEW_OPTIONS;\n\n/** A tool's icon with its key in the corner, as Excalidraw's tools show theirs */\nfunction WithKey({\n shortcut,\n children,\n}: {\n shortcut: string;\n children: ReactNode;\n}) {\n return (\n <span className=\"relative flex h-8 w-8 items-center justify-center\">\n <span className=\"-translate-x-[3px] -translate-y-[2px]\">{children}</span>\n <span\n aria-hidden\n className=\"absolute bottom-[2px] right-[4px] text-[9px] font-medium leading-none text-[rgb(var(--ec-page-text-muted))] opacity-60\"\n >\n {shortcut}\n </span>\n </span>\n );\n}\n\n/** What to do with the tool picked, under the bar (as Excalidraw says) */\nconst TOOL_HINTS = {\n note: \"Click anywhere to put a sticky note there\",\n text: \"Click anywhere to start typing\",\n comment: \"Click anywhere, or on a node, to comment there\",\n hotspot: \"Click a node, or anywhere, to flag a hotspot there\",\n};\n\n/** The levels of detail: each can always be gone to (one with nothing on it yet is where those things are added) */\nfunction LevelSwitch({\n level,\n onChange,\n unavailable,\n}: {\n level: Level;\n onChange: (level: Level) => void;\n /** Levels this canvas can't show, and why (EventCatalog's Studio: as its diagrams do) */\n unavailable?: Partial<Record<Level, string | undefined>>;\n}) {\n return (\n <div\n role=\"group\"\n aria-label=\"Level of detail\"\n className=\"flex items-center gap-0.5\"\n >\n {LEVELS.map(({ level: value, description }) => (\n <ToolbarButton\n key={value}\n label={`Level ${value}: ${description} (${value})`}\n hint={unavailable?.[value]}\n active={value === level}\n disabled={!!unavailable?.[value]}\n onClick={() => onChange(value)}\n >\n <WithKey shortcut={String(value)}>\n <span className=\"text-xs font-semibold\">L{value}</span>\n </WithKey>\n </ToolbarButton>\n ))}\n </div>\n );\n}\n\nexport default memo(function CanvasControls({\n level,\n onLevelChange,\n unavailableLevels,\n editable,\n locked,\n onToggleLock,\n lockedBy,\n selectMode,\n onSelectMode,\n handMode,\n onHandMode,\n noteMode,\n onToggleNoteMode,\n textMode,\n onToggleTextMode,\n commentMode,\n onToggleCommentMode,\n hotspotMode,\n onToggleHotspotMode,\n extras,\n}: {\n level: Level;\n onLevelChange: (level: Level) => void;\n /** Levels this canvas can't show, and why (greyed out, with the reason) */\n unavailableLevels?: Partial<Record<Level, string | undefined>>;\n /** L3, the canvas itself (comments are there; L1 and L2 are arranged on their own) */\n editable: boolean;\n /** Nothing on the canvas can be changed (until it's unlocked) */\n locked: boolean;\n onToggleLock: () => void;\n /** Who locked it (it's locked for everyone on it) */\n lockedBy?: string | null;\n /** Selecting and moving what's on the canvas (no tool picked) */\n selectMode: boolean;\n onSelectMode: () => void;\n /** The hand: dragging moves around the canvas (nothing on it is picked up) */\n handMode: boolean;\n onHandMode: () => void;\n /** The sticky note tool, on: a click on the canvas puts a note there */\n noteMode: boolean;\n onToggleNoteMode: () => void;\n /** The comment tool, on: a click on the canvas (or a node) pins a comment there */\n commentMode: boolean;\n onToggleCommentMode: () => void;\n /** The hotspot tool, on: a click on a node (or the canvas) flags a hotspot there */\n hotspotMode: boolean;\n onToggleHotspotMode: () => void;\n /** The text tool, on: a click on the canvas writes there */\n textMode: boolean;\n onToggleTextMode: () => void;\n /** More buttons at the end of the bar (e.g. replaying the agent's walkthrough) */\n extras?: ReactNode;\n}) {\n return (\n // At the top, as drawing tools have their tools\n <div className=\"absolute left-1/2 top-3 z-10 -translate-x-1/2\">\n <Toolbar>\n {/* First, as on Excalidraw: locking it, then selecting and moving around */}\n <ToolbarButton\n label={\n locked\n ? `Locked${lockedBy ? ` by ${lockedBy}` : \"\"}: unlock it to change it (for everyone on it)`\n : \"Lock the canvas (it can be looked at, not changed, by everyone on it)\"\n }\n active={locked}\n onClick={onToggleLock}\n >\n {locked ? (\n <Lock className=\"h-4 w-4\" />\n ) : (\n <LockOpen className=\"h-4 w-4\" />\n )}\n </ToolbarButton>\n <ToolbarDivider />\n <ToolbarButton\n label=\"Select (V)\"\n active={selectMode}\n onClick={onSelectMode}\n >\n <WithKey shortcut=\"V\">\n <MousePointer2 className=\"h-4 w-4\" />\n </WithKey>\n </ToolbarButton>\n <ToolbarButton\n label=\"Hand (H): drag to move around\"\n active={handMode}\n onClick={onHandMode}\n >\n <WithKey shortcut=\"H\">\n <Hand className=\"h-4 w-4\" />\n </WithKey>\n </ToolbarButton>\n <ToolbarDivider />\n <LevelSwitch\n level={level}\n onChange={onLevelChange}\n unavailable={unavailableLevels}\n />\n <ToolbarDivider />\n {/* Notes can be added on every level, and are shown on the level they're added on */}\n <ToolbarButton\n label={\n editable\n ? \"Sticky note (N): click where it goes\"\n : `Sticky note (N): on L${level}, where it's clicked`\n }\n active={noteMode}\n disabled={locked}\n hint={locked ? \"The canvas is locked\" : undefined}\n onClick={onToggleNoteMode}\n >\n <WithKey shortcut=\"N\">\n <StickyNote className=\"h-4 w-4 text-yellow-500\" />\n </WithKey>\n </ToolbarButton>\n {/* Excalidraw's text tool: click anywhere and type */}\n <ToolbarButton\n label={\n editable\n ? \"Text (T): click anywhere and type\"\n : `Text (T): on L${level}, where it's clicked`\n }\n active={textMode}\n disabled={locked}\n hint={locked ? \"The canvas is locked\" : undefined}\n onClick={onToggleTextMode}\n >\n <WithKey shortcut=\"T\">\n <Type className=\"h-4 w-4\" />\n </WithKey>\n </ToolbarButton>\n {/* Studio's comments: pinned to the canvas or a node, replied to and resolved */}\n <ToolbarButton\n label=\"Comment (C): click where it goes, or on a node\"\n active={commentMode}\n onClick={onToggleCommentMode}\n >\n <WithKey shortcut=\"C\">\n <MessageCircle className=\"h-4 w-4\" />\n </WithKey>\n </ToolbarButton>\n {/* Hotspots: what people should know about (risks, problems, the key parts), hard to miss */}\n <ToolbarButton\n label=\"Hotspot (A): click a node, or anywhere, to flag it\"\n active={hotspotMode}\n disabled={locked}\n hint={locked ? \"The canvas is locked\" : undefined}\n onClick={onToggleHotspotMode}\n >\n <WithKey shortcut=\"A\">\n <TriangleAlert className=\"h-4 w-4 text-amber-600\" />\n </WithKey>\n </ToolbarButton>\n {extras}\n </Toolbar>\n {(noteMode || textMode || commentMode || hotspotMode) && (\n <p className=\"pointer-events-none mt-2 text-center text-xs text-[rgb(var(--ec-page-text-muted))]\">\n {\n TOOL_HINTS[\n noteMode\n ? \"note\"\n : commentMode\n ? \"comment\"\n : hotspotMode\n ? \"hotspot\"\n : \"text\"\n ]\n }{\" \"}\n ·{\" \"}\n <kbd className=\"rounded border border-[rgb(var(--ec-page-border))] px-1 font-sans text-[11px]\">\n Esc\n </kbd>{\" \"}\n to cancel\n </p>\n )}\n </div>\n );\n});\n\n/** The bottom-left controls, as Excalidraw's: zooming, undo and redo, then fitting it to the view and laying it out again */\nexport const ViewControls = memo(function ViewControls({\n canUndo,\n canRedo,\n onUndo,\n onRedo,\n onReorder,\n reorderLabel,\n locked,\n fitOptions = FIT_VIEW_OPTIONS,\n comments,\n hotspots,\n}: {\n canUndo: boolean;\n canRedo: boolean;\n onUndo: () => void;\n onRedo: () => void;\n /** Lays it out again with the visualiser's layout */\n onReorder: () => void;\n reorderLabel: string;\n locked: boolean;\n /** How the canvas is fitted to the view (clear of what's over it, e.g. the palette) */\n fitOptions?: FitViewOptions;\n /** The comments: how many are open, and showing them all */\n comments?: { open: number; active: boolean; onToggle: () => void };\n /** The hotspots: how many, the most important's severity, and listing them all */\n hotspots?: {\n count: number;\n severity?: HotspotSeverity;\n active: boolean;\n onToggle: () => void;\n };\n}) {\n const { zoomIn, zoomOut, fitView } = useReactFlow();\n return (\n <>\n <Toolbar>\n <ToolbarButton\n label=\"Zoom out\"\n onClick={() => void zoomOut({ duration: 200 })}\n >\n <ZoomOut className=\"h-4 w-4\" />\n </ToolbarButton>\n <ZoomLevel />\n <ToolbarButton\n label=\"Zoom in\"\n onClick={() => void zoomIn({ duration: 200 })}\n >\n <ZoomIn className=\"h-4 w-4\" />\n </ToolbarButton>\n </Toolbar>\n <Toolbar>\n <ToolbarButton\n label=\"Undo (⌘Z)\"\n hint={canUndo ? undefined : \"Nothing to undo\"}\n disabled={!canUndo}\n onClick={onUndo}\n >\n <Undo className=\"h-4 w-4\" />\n </ToolbarButton>\n <ToolbarButton\n label=\"Redo (⇧⌘Z)\"\n hint={canRedo ? undefined : \"Nothing to redo\"}\n disabled={!canRedo}\n onClick={onRedo}\n >\n <Redo className=\"h-4 w-4\" />\n </ToolbarButton>\n </Toolbar>\n <Toolbar>\n <ToolbarButton\n label=\"Fit view (⇧1)\"\n onClick={() => void fitView({ ...fitOptions, duration: 500 })}\n >\n <Maximize className=\"h-4 w-4\" />\n </ToolbarButton>\n <ToolbarButton\n label={reorderLabel}\n hint={locked ? \"The canvas is locked\" : undefined}\n disabled={locked}\n onClick={onReorder}\n >\n <SendToBack className=\"h-4 w-4\" />\n </ToolbarButton>\n </Toolbar>\n {comments && (\n <Toolbar>\n <ToolbarButton\n label={\n comments.open ? `Comments (${comments.open} open)` : \"Comments\"\n }\n active={comments.active}\n onClick={comments.onToggle}\n >\n <span className=\"relative\">\n <MessageSquareText className=\"h-4 w-4\" />\n {comments.open > 0 && (\n <span className=\"absolute -right-2 -top-2 min-w-4 rounded-full bg-[rgb(var(--ec-accent))] px-1 text-center text-[9px] font-semibold leading-4 text-white\">\n {comments.open}\n </span>\n )}\n </span>\n </ToolbarButton>\n {hotspots && (\n <ToolbarButton\n label={\n hotspots.count ? `Hotspots (${hotspots.count})` : \"Hotspots\"\n }\n active={hotspots.active}\n onClick={hotspots.onToggle}\n >\n <span className=\"relative\">\n <TriangleAlert className=\"h-4 w-4\" />\n {hotspots.count > 0 && (\n <span\n className=\"absolute -right-2 -top-2 min-w-4 rounded-full px-1 text-center text-[9px] font-semibold leading-4 text-white\"\n style={{\n background:\n SEVERITIES[hotspots.severity ?? \"warning\"].color,\n }}\n >\n {hotspots.count}\n </span>\n )}\n </span>\n </ToolbarButton>\n )}\n </Toolbar>\n )}\n </>\n );\n});\n","import { useEffect, useState, type ReactElement } from \"react\";\nimport { X } from \"lucide-react\";\n\n/**\n * Asked when a domain or system is put on the canvas: is it a card (connected to what it contains), or a container\n * that what it contains sits inside? Styled like the visualiser's group-by picker (boxes or lanes). One from a catalog\n * can bring what it contains in the catalog inside it (`contents`).\n */\n\nexport type ContainerChoice =\n | { as: \"card\" }\n | { as: \"container\"; withContents?: boolean };\n\nconst plural = (count: number, noun: string) =>\n `${count} ${noun}${count === 1 ? \"\" : \"s\"}`;\n\n// Small pictures of the two ways a domain or system can be on the canvas\nexport const CardPreview = () => (\n <svg viewBox=\"0 0 64 36\" className=\"h-9 w-16\" aria-hidden>\n <rect\n x=\"18\"\n y=\"8\"\n width=\"28\"\n height=\"20\"\n rx=\"4\"\n fill=\"currentColor\"\n fillOpacity=\"0.1\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.5\"\n strokeWidth=\"1.5\"\n />\n <rect\n x=\"23\"\n y=\"13\"\n width=\"14\"\n height=\"3\"\n rx=\"1.5\"\n fill=\"currentColor\"\n fillOpacity=\"0.6\"\n />\n <rect\n x=\"23\"\n y=\"19\"\n width=\"18\"\n height=\"2\"\n rx=\"1\"\n fill=\"currentColor\"\n fillOpacity=\"0.35\"\n />\n <path\n d=\"M46 18h12\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.5\"\n strokeWidth=\"1.5\"\n strokeDasharray=\"2 2\"\n />\n <rect\n x=\"57\"\n y=\"14\"\n width=\"6\"\n height=\"8\"\n rx=\"1.5\"\n fill=\"currentColor\"\n fillOpacity=\"0.4\"\n />\n </svg>\n);\n\nconst ContainerPreview = () => (\n <svg viewBox=\"0 0 64 36\" className=\"h-9 w-16\" aria-hidden>\n <rect\n x=\"4\"\n y=\"2\"\n width=\"56\"\n height=\"32\"\n rx=\"4\"\n fill=\"currentColor\"\n fillOpacity=\"0.08\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.5\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M4 10h56\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.35\"\n strokeWidth=\"1\"\n />\n <rect\n x=\"8\"\n y=\"4.5\"\n width=\"14\"\n height=\"3\"\n rx=\"1.5\"\n fill=\"currentColor\"\n fillOpacity=\"0.6\"\n />\n <rect\n x=\"10\"\n y=\"15\"\n width=\"18\"\n height=\"12\"\n rx=\"2\"\n fill=\"currentColor\"\n fillOpacity=\"0.5\"\n />\n <rect\n x=\"36\"\n y=\"15\"\n width=\"18\"\n height=\"12\"\n rx=\"2\"\n fill=\"currentColor\"\n fillOpacity=\"0.5\"\n />\n </svg>\n);\n\nconst OPTIONS: {\n as: ContainerChoice[\"as\"];\n label: string;\n hint: string;\n Preview: () => ReactElement;\n}[] = [\n {\n as: \"card\",\n label: \"Card\",\n hint: \"Connected to what it contains\",\n Preview: CardPreview,\n },\n {\n as: \"container\",\n label: \"Container\",\n hint: \"What it contains sits inside it\",\n Preview: ContainerPreview,\n },\n];\n\nexport default function ContainerChooser({\n kind,\n name,\n contents,\n position,\n onChoose,\n onCancel,\n}: {\n kind: \"domain\" | \"system\";\n /** Its name, when it has one already (e.g. from a catalog) */\n name?: string;\n /** What it contains in the catalog that isn't on the canvas yet (offered to bring inside it, as a container) */\n contents?: { systems: number; services: number };\n /** Where to show it (screen coordinates) */\n position: { x: number; y: number };\n onChoose: (choice: ContainerChoice) => void;\n onCancel: () => void;\n}) {\n const [withContents, setWithContents] = useState(true);\n const contentsLabel = contents\n ? [\n contents.systems > 0 && plural(contents.systems, \"system\"),\n contents.services > 0 && plural(contents.services, \"service\"),\n ]\n .filter(Boolean)\n .join(\" and \")\n : \"\";\n\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) =>\n event.key === \"Escape\" && onCancel();\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, [onCancel]);\n\n // Kept on screen, next to where it was dropped\n const left = Math.min(\n Math.max(position.x - 160, 12),\n window.innerWidth - 332,\n );\n const top = Math.min(\n Math.max(position.y - 20, 12),\n window.innerHeight - (contentsLabel ? 260 : 200),\n );\n\n return (\n <div className=\"fixed inset-0 z-50\" onPointerDown={onCancel}>\n <div\n role=\"dialog\"\n aria-label={name ? `Add ${name} as` : `Add the ${kind} as`}\n onPointerDown={(event) => event.stopPropagation()}\n className=\"absolute w-80 rounded-lg border p-1.5 shadow-xl bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))]\"\n style={{ left, top }}\n >\n <div className=\"flex items-start justify-between gap-2 px-2 pb-1.5 pt-1\">\n <div className=\"min-w-0\">\n <p className=\"text-[10px] font-semibold uppercase tracking-wider text-[rgb(var(--ec-page-text-muted))]\">\n Add this {kind} as\n </p>\n {name && <p className=\"truncate text-xs font-semibold\">{name}</p>}\n </div>\n <button\n onClick={onCancel}\n aria-label=\"Cancel\"\n className=\"rounded p-0.5 text-[rgb(var(--ec-icon-color))] hover:bg-[rgb(var(--ec-page-border)/0.5)]\"\n >\n <X size={14} />\n </button>\n </div>\n\n <div className=\"grid grid-cols-2 gap-1.5 px-0.5 pb-0.5\">\n {OPTIONS.map(({ as, label, hint, Preview }) => (\n <button\n key={as}\n autoFocus={as === \"container\"}\n onClick={() =>\n onChoose(\n as === \"card\"\n ? { as }\n : { as, withContents: withContents && !!contentsLabel },\n )\n }\n className=\"flex flex-col items-center gap-1 rounded-md border px-2 pb-1.5 pt-2 text-xs outline-none transition-colors border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text-muted))] hover:border-[rgb(var(--ec-accent))] hover:bg-[color-mix(in_srgb,rgb(var(--ec-accent))_8%,transparent)] hover:text-[rgb(var(--ec-accent))] focus-visible:border-[rgb(var(--ec-accent))] focus-visible:text-[rgb(var(--ec-accent))]\"\n >\n <Preview />\n <span className=\"font-semibold\">{label}</span>\n <span className=\"text-center text-[10px] leading-tight text-[rgb(var(--ec-page-text-muted))]\">\n {hint}\n </span>\n </button>\n ))}\n </div>\n\n {contentsLabel && (\n <label className=\"mt-1 flex items-center gap-2 rounded-md px-2 py-1.5 text-[11px] text-[rgb(var(--ec-page-text-muted))]\">\n <input\n type=\"checkbox\"\n checked={withContents}\n onChange={(event) => setWithContents(event.target.checked)}\n />\n As a container, bring its {contentsLabel} inside, with their\n messages and data stores\n </label>\n )}\n </div>\n </div>\n );\n}\n","/**\n * A selected node's Edit button, above its top right corner (Details, when the canvas is locked). It's sized with\n * the canvas, as if it were on it: zoomed out it's small beside a small node, zoomed in it grows with it. Its own\n * component, so only it follows the zoom (not the whole canvas).\n */\nimport { memo } from \"react\";\nimport { NodeToolbar, Position, useStore } from \"@xyflow/react\";\nimport { Info, Pencil } from \"lucide-react\";\n\n// Kept usable when far out, and not huge when far in\nconst MIN_SCALE = 0.4;\nconst MAX_SCALE = 1.6;\nconst OFFSET = 8;\n\nexport default memo(function EditButton({\n nodeId,\n locked,\n onClick,\n}: {\n nodeId: string;\n locked: boolean;\n onClick: () => void;\n}) {\n const zoom = useStore((state) => state.transform[2]);\n const scale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, zoom));\n return (\n <NodeToolbar\n nodeId={nodeId}\n isVisible\n position={Position.Top}\n align=\"end\"\n offset={OFFSET * scale}\n >\n {/* Scaled from its bottom right corner, so it stays on the node's corner */}\n <button\n type=\"button\"\n className=\"studio-edit-button\"\n style={{\n transform: `scale(${scale})`,\n transformOrigin: \"bottom right\",\n }}\n onClick={onClick}\n >\n {locked ? (\n <>\n <Info aria-hidden /> Details\n </>\n ) : (\n <>\n <Pencil aria-hidden /> Edit\n </>\n )}\n </button>\n </NodeToolbar>\n );\n});\n","/**\n * What to put on the canvas, as a drawing tool's palette: a card on the left, under the top left controls, each\n * component a tile to drag onto the canvas (or click, to add it in the middle of what's on screen). Only what the\n * level shows is listed, so what's added stays on it. An app can add tabs beside the components (e.g. EventCatalog's\n * catalog resources and comments), drawn with the same tiles.\n */\nimport {\n memo,\n useCallback,\n useEffect,\n useRef,\n useState,\n type DragEvent,\n type ReactNode,\n} from \"react\";\nimport { ChevronDown, GripVertical, type LucideIcon } from \"lucide-react\";\nimport {\n componentKey,\n GROUP_TYPES,\n isShownOnLevel,\n NODE_CATEGORIES,\n nodeDefinitions,\n} from \"../node-types\";\nimport type { Level } from \"../levels\";\nimport { useDragGhost, type StartDrag } from \"./DragGhost\";\nimport { NODE_ICONS } from \"./icons\";\n\n/** What's dragged from the palette onto the canvas: a component's key (its type, or its kind of data store) */\nexport const COMPONENT_DRAG_TYPE = \"application/eventcatalog-studio\";\n\nconst listedDefinitions = NODE_CATEGORIES.map((category) => ({\n ...category,\n definitions: nodeDefinitions.filter(\n (definition) => definition.category === category.id && !definition.unlisted,\n ),\n}));\n\n// Each component's data, made once, for the node shown while it's dragged. Domains and systems are dragged as the\n// node they'd be as a card (whether they're a card or a container is asked when they're dropped)\nconst cardPreview = (kind: \"domain\" | \"system\") => ({\n type: kind === \"domain\" ? \"context-domain\" : \"system\",\n data: {\n mode: \"full\",\n navigable: false,\n [kind]: {\n name: kind === \"domain\" ? \"New Domain\" : \"New System\",\n version: \"0.0.1\",\n },\n },\n});\nconst componentPreviews = new Map(\n nodeDefinitions.map((definition) => [\n componentKey(definition),\n definition.type === GROUP_TYPES.domain\n ? cardPreview(\"domain\")\n : definition.type === GROUP_TYPES.system\n ? cardPreview(\"system\")\n : { type: definition.type, data: definition.createData() },\n ]),\n);\n\nconst COLLAPSED_KEY = \"eventcatalog-studio-palette-collapsed\";\nconst readCollapsed = () => {\n try {\n return localStorage.getItem(COLLAPSED_KEY) === \"true\";\n } catch {\n return false;\n }\n};\n\n/**\n * A tile in the palette: its icon, its name and what it is, picked up and dragged onto the canvas (or clicked, to\n * add it). Greyed out (`usable` false) where it can't be added, still saying why.\n */\nexport function PaletteItem({\n icon: Icon,\n iconClassName,\n label,\n description,\n usable = true,\n onDragStart,\n onClick,\n title,\n trailing,\n}: {\n icon: LucideIcon;\n iconClassName?: string;\n label: string;\n description?: ReactNode;\n usable?: boolean;\n onDragStart?: (event: DragEvent) => void;\n onClick?: () => void;\n title?: string;\n /** At the end instead of the drag handle (e.g. \"on the canvas\") */\n trailing?: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n draggable={usable && !!onDragStart}\n // (not disabled: it still says why it can't be added)\n aria-disabled={!usable}\n onDragStart={usable ? onDragStart : undefined}\n onClick={usable ? onClick : undefined}\n aria-label={label}\n title={title}\n className={`group flex w-full items-center gap-2.5 rounded-lg border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg))] py-1 pl-1 pr-2 text-left text-[rgb(var(--ec-page-text))] shadow-[0_1px_2px_rgb(0_0_0/0.05)] transition-[transform,box-shadow,border-color] duration-150 ${\n usable\n ? \"cursor-grab hover:-translate-y-px hover:border-[color-mix(in_srgb,rgb(var(--ec-accent))_45%,transparent)]! hover:shadow-[0_4px_12px_rgb(0_0_0/0.08)] active:translate-y-0 active:cursor-grabbing\"\n : \"cursor-not-allowed opacity-40 grayscale\"\n }`}\n >\n <span className=\"flex h-8 w-8 flex-none items-center justify-center rounded-md bg-[rgb(var(--ec-content-hover))]\">\n <Icon size={16} className={iconClassName} />\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-[13px] font-medium leading-tight\">\n {label}\n </span>\n {description && (\n <span className=\"block truncate text-[11px] leading-snug text-[rgb(var(--ec-page-text-muted))]\">\n {description}\n </span>\n )}\n </span>\n {trailing ??\n (usable && onDragStart && (\n // It's picked up and dragged on (a click adds it in the middle): a small handle says so\n <GripVertical\n aria-hidden\n size={14}\n className=\"flex-none text-[rgb(var(--ec-page-text-muted))] opacity-40 transition-opacity group-hover:opacity-80\"\n />\n ))}\n </button>\n );\n}\n\n/** A section of tiles, under a small heading */\nexport function PaletteSection({\n title,\n divided = false,\n children,\n}: {\n title: ReactNode;\n /** A line above it (e.g. what this level doesn't show, at the bottom) */\n divided?: boolean;\n children: ReactNode;\n}) {\n return (\n <section\n className={\n divided ? \"border-t border-[rgb(var(--ec-page-border))] pt-3\" : \"\"\n }\n >\n <h3 className=\"mb-1.5 text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))]\">\n {title}\n </h3>\n <div className=\"space-y-1.5\">{children}</div>\n </section>\n );\n}\n\n/** A tab an app adds beside the components: what it lists, given how to start dragging something onto the canvas */\nexport type PaletteTab = {\n id: string;\n label: string;\n /** A count beside its name (e.g. open comments) */\n badge?: number;\n render: (startDrag: StartDrag) => ReactNode;\n};\n\nconst COMPONENTS_TAB = \"components\";\n\nexport const Palette = memo(function Palette({\n level,\n onAddComponent,\n footer,\n tabs,\n tab,\n onTabChange,\n startCollapsed,\n}: {\n /** The level shown: only what it shows is listed */\n level: Level;\n onAddComponent: (key: string) => void;\n /** At the bottom, under the list (e.g. taking the diagram to EventCatalog) */\n footer?: ReactNode;\n /** More tabs beside the components (the components are the first) */\n tabs?: PaletteTab[];\n /** The tab shown, when the app chooses it (it opens the palette if it's folded away) */\n tab?: string;\n onTabChange?: (tab: string) => void;\n /** Starts folded away, whatever this browser remembers (and doesn't remember it), e.g. in a chat's small view */\n startCollapsed?: boolean;\n}) {\n // What's being dragged onto the canvas, drawn as the node it becomes (see DragGhost)\n const { startDrag, ghost } = useDragGhost();\n // Folded away to see more of the canvas (remembered in this browser)\n const [collapsed, setCollapsed] = useState(\n () => startCollapsed ?? readCollapsed(),\n );\n const remember = (next: boolean) => {\n if (startCollapsed !== undefined) return;\n try {\n localStorage.setItem(COLLAPSED_KEY, String(next));\n } catch {}\n };\n const toggle = useCallback(() => {\n setCollapsed((current) => {\n remember(!current);\n return !current;\n });\n }, []);\n const [ownTab, setOwnTab] = useState(COMPONENTS_TAB);\n const shown =\n tab ??\n (tabs?.some((candidate) => candidate.id === ownTab)\n ? ownTab\n : COMPONENTS_TAB);\n const choose = (next: string) => {\n setOwnTab(next);\n onTabChange?.(next);\n if (collapsed) {\n setCollapsed(false);\n remember(false);\n }\n };\n // Chosen by the app (e.g. the comments from the bottom left controls): shown, opened if it was folded away\n const chosen = useRef(tab);\n useEffect(() => {\n if (tab === chosen.current) return;\n chosen.current = tab;\n if (tab === undefined || !collapsed) return;\n setCollapsed(false);\n remember(false);\n }, [tab]);\n\n // Listed in their categories' order, so the greyed ones keep the same order as the rest\n const unavailable = listedDefinitions.flatMap((category) =>\n category.definitions.filter(\n (definition) => !isShownOnLevel(definition.type, level),\n ),\n );\n\n const tile = (\n definition: (typeof nodeDefinitions)[number],\n usable = true,\n ) => {\n const { label, summary, firstLevel } = definition;\n const key = componentKey(definition);\n const { icon, className } = NODE_ICONS[key] ?? NODE_ICONS[definition.type];\n return (\n <PaletteItem\n key={key}\n icon={icon}\n iconClassName={className}\n label={usable ? label : `${label}: shown from Level ${firstLevel}`}\n description={usable ? summary : `Shown from Level ${firstLevel}`}\n usable={usable}\n onDragStart={startDrag(\n COMPONENT_DRAG_TYPE,\n key,\n componentPreviews.get(key)!,\n )}\n onClick={() => onAddComponent(key)}\n title={\n usable ? `${label}: drag onto the canvas, or click to add` : undefined\n }\n />\n );\n };\n\n const components = (\n <>\n {listedDefinitions.map((category) => {\n const definitions = category.definitions.filter((definition) =>\n isShownOnLevel(definition.type, level),\n );\n if (!definitions.length) return null;\n return (\n <PaletteSection key={category.id} title={category.label}>\n {definitions.map((definition) => tile(definition))}\n </PaletteSection>\n );\n })}\n {/* What this level doesn't show, greyed out at the bottom: they're added on the levels that show them */}\n {unavailable.length > 0 && (\n <PaletteSection title={`Not on Level ${level}`} divided>\n {unavailable.map((definition) => tile(definition, false))}\n </PaletteSection>\n )}\n </>\n );\n const extra = tabs?.find((candidate) => candidate.id === shown);\n const tabButton = (id: string, label: string, badge?: number) => (\n <button\n key={id}\n type=\"button\"\n role=\"tab\"\n aria-selected={shown === id}\n onClick={() => choose(id)}\n className={`flex flex-1 items-center justify-center gap-1 whitespace-nowrap rounded-md px-1.5 py-1 text-xs font-medium ${\n shown === id && !collapsed\n ? \"bg-[rgb(var(--ec-card-bg))] text-[rgb(var(--ec-page-text))] shadow-sm\"\n : \"text-[rgb(var(--ec-page-text-muted))] hover:text-[rgb(var(--ec-page-text))]\"\n }`}\n >\n {label}\n {!!badge && (\n <span className=\"rounded-full bg-[rgb(var(--ec-accent))] px-1.5 text-[10px] leading-4 text-white\">\n {badge}\n </span>\n )}\n </button>\n );\n\n return (\n <div\n // Down to just above the zoom and undo controls (only its header, folded away)\n className={`absolute left-3 top-[62px] z-10 flex w-[264px] flex-col ${collapsed ? \"\" : \"bottom-[68px]\"} rounded-xl border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg))] text-[rgb(var(--ec-page-text))] shadow-[0_8px_24px_rgb(0_0_0/0.08),0_1px_3px_rgb(0_0_0/0.05)]`}\n >\n {tabs?.length ? (\n <div className=\"flex flex-none items-center gap-1 p-2\">\n <div\n role=\"tablist\"\n className=\"flex flex-1 gap-0.5 rounded-lg bg-[rgb(var(--ec-page-border)/0.5)] p-0.5\"\n >\n {tabButton(COMPONENTS_TAB, \"Components\")}\n {tabs.map(({ id, label, badge }) => tabButton(id, label, badge))}\n </div>\n <button\n type=\"button\"\n onClick={toggle}\n aria-expanded={!collapsed}\n aria-label={\n collapsed ? \"Show the palette\" : \"Fold the palette away\"\n }\n className=\"flex-none rounded-md p-1 text-[rgb(var(--ec-page-text-muted))] hover:bg-[rgb(var(--ec-page-border)/0.5)]\"\n >\n <ChevronDown\n aria-hidden\n className={`h-4 w-4 transition-transform ${collapsed ? \"-rotate-90\" : \"\"}`}\n />\n </button>\n </div>\n ) : (\n <button\n type=\"button\"\n onClick={toggle}\n aria-expanded={!collapsed}\n className=\"flex flex-none items-center justify-between rounded-xl px-3.5 py-2.5 text-left text-[13px] font-semibold hover:bg-[rgb(var(--ec-content-hover))]!\"\n >\n {/* What can be added depends on the level shown (what it doesn't show is greyed out below) */}\n <span>Resources</span>\n <ChevronDown\n aria-hidden\n className={`h-4 w-4 text-[rgb(var(--ec-page-text-muted))] transition-transform ${collapsed ? \"-rotate-90\" : \"\"}`}\n />\n </button>\n )}\n {!collapsed && (\n <div className=\"min-h-0 flex-1 space-y-3 overflow-y-auto px-3 pb-3\">\n {extra ? extra.render(startDrag) : components}\n </div>\n )}\n {!collapsed && footer && (\n <div className=\"flex-none border-t border-[rgb(var(--ec-page-border))] px-3 py-2.5\">\n {footer}\n </div>\n )}\n {ghost}\n </div>\n );\n});\n","/**\n * Help: the keyboard shortcuts, as drawing tools list them, in two columns where there's room. Each app shows them in\n * its own dialog, leaving out what it doesn't have (by label).\n */\n\nconst isMac =\n typeof navigator !== \"undefined\" &&\n /Mac|iPhone|iPad/.test(navigator.platform);\nconst MOD = isMac ? \"⌘\" : \"Ctrl\";\n\nexport const SHORTCUTS: { group: string; items: [string, string[]][] }[] = [\n {\n group: \"Tools\",\n items: [\n [\"Select\", [\"V\"]],\n [\"Hand (move around)\", [\"H\"]],\n [\"Sticky note\", [\"N\"]],\n [\"Text\", [\"T\"]],\n [\"Comment\", [\"C\"]],\n [\"Hotspot\", [\"A\"]],\n [\"Level 1 / 2 / 3\", [\"1\", \"2\", \"3\"]],\n [\"Back to selecting\", [\"Esc\"]],\n ],\n },\n {\n group: \"Canvas\",\n items: [\n [\"Select everything\", [MOD, \"A\"]],\n [\"Select several\", [\"⇧\", \"Click\"]],\n [\"Delete what's selected\", [\"Delete\"]],\n [\"Duplicate\", [MOD, \"D\"]],\n [\"Copy / paste\", [MOD, \"C / V\"]],\n [\"Undo / redo\", [MOD, \"Z / ⇧Z\"]],\n [\"Move around\", [\"Scroll\"]],\n [\"Zoom\", [MOD, \"Scroll\"]],\n [\"Fit view\", [\"⇧\", \"1\"]],\n ],\n },\n {\n group: \"Notes and text\",\n items: [\n [\"Write on one\", [\"Double-click\"]],\n [\"Finish writing\", [\"Esc\"]],\n ],\n },\n {\n group: \"Diagram\",\n items: [\n [\"Command palette\", [MOD, \"K\"]],\n [\"Find on canvas\", [MOD, \"F\"]],\n [\"Open a diagram file\", [MOD, \"O\"]],\n [\"Save to file\", [MOD, \"S\"]],\n [\"Export image\", [MOD, \"⇧\", \"E\"]],\n [\"Help\", [\"?\"]],\n ],\n },\n];\n\nexport function ShortcutsList({ omit = [] }: { omit?: string[] }) {\n return (\n <div className=\"grid min-h-0 gap-x-8 gap-y-5 overflow-y-auto px-5 py-4 md:grid-cols-2!\">\n {SHORTCUTS.map(({ group, items }) => ({\n group,\n items: items.filter(([label]) => !omit.includes(label)),\n })).map(({ group, items }) => (\n <section key={group}>\n <h3 className=\"mb-2 text-[11px] font-semibold uppercase tracking-wide text-[rgb(var(--ec-page-text-muted))]\">\n {group}\n </h3>\n <ul className=\"divide-y divide-[rgb(var(--ec-page-border))]\">\n {items.map(([label, keys]) => (\n <li\n key={label}\n className=\"flex items-center justify-between gap-3 py-1.5 text-sm\"\n >\n <span>{label}</span>\n <span className=\"flex gap-1\">\n {keys.map((key) => (\n <kbd\n key={key}\n className=\"min-w-6 rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-content-hover))] px-1.5 py-0.5 text-center font-sans text-xs text-[rgb(var(--ec-page-text-muted))]\"\n >\n {key}\n </kbd>\n ))}\n </span>\n </li>\n ))}\n </ul>\n </section>\n ))}\n </div>\n );\n}\n","/**\n * The canvas with nothing on it (a blank page, or everything deleted), as drawing tools welcome you: the brand, what\n * it's for, and the few things to do from here, drawn on the canvas itself. Tailwind with EventCatalog's theme variables.\n */\nimport { useEffect, useState, type ReactNode } from \"react\";\nimport { CircleHelp, FolderOpen, Plug } from \"lucide-react\";\nimport logoSvg from \"../eventcatalog-logo.svg?raw\";\n\ntype EmptyCanvasProps = {\n /** Opening a .eventcatalog file (not offered when not given, e.g. inside a chat) */\n onOpen?: () => void;\n onHelp: () => void;\n /** How to connect an AI agent to this server (when there's one to connect to) */\n onConnect?: () => void;\n /** The resources panel is on the left, to point to */\n palette?: boolean;\n /** Live sessions can be started (from Share, top right), to point to */\n live?: boolean;\n /** The welcome in the middle (the brand, what it's for, Open, Connect, Help); without it, just the hints */\n welcome?: boolean;\n};\n\n// Hand-drawn, as Excalidraw points at its tools when the canvas is empty\nconst hintText =\n \"font-[Excalifont,Inter,sans-serif] text-[14px] leading-snug text-[color-mix(in_srgb,rgb(var(--ec-page-text))_22%,transparent)]\";\nconst arrow = {\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 1.6,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n} as const;\n\n/** What the tools around the empty canvas are for, each with an arrow to it (on wide enough screens) */\nfunction Hints({ palette, live }: { palette?: boolean; live?: boolean }) {\n return (\n <div aria-hidden className={`hidden md:block! ${hintText}`}>\n {/* To the resources, on the left (low down, clear of the levels hint) */}\n {palette && (\n <div className=\"absolute bottom-[120px] left-[290px] flex items-start gap-1\">\n <svg width=\"56\" height=\"32\" viewBox=\"0 0 70 40\" {...arrow}>\n <path d=\"M66 8 C 45 4, 22 10, 6 26\" />\n <path d=\"M6 26 L15.7 23.4 M6 26 L8.6 16.3\" />\n </svg>\n <p className=\"-mt-0.5 max-w-[160px]\">\n Drag resources onto the canvas, then connect them\n </p>\n </div>\n )}\n {/* To the levels, in the toolbar */}\n <div className=\"absolute left-[calc(50%+6px)] top-[66px] flex -translate-x-1/2 flex-col items-center\">\n <svg width=\"32\" height=\"45\" viewBox=\"0 0 40 56\" {...arrow}>\n <path d=\"M14 54 C 6 38, 10 18, 20 4\" />\n <path d=\"M20 4 L11.8 7.7 M20 4 L19.1 13\" />\n </svg>\n <p className=\"mt-1 whitespace-nowrap\">\n Switch between levels of detail\n </p>\n </div>\n {/* To Share, top right */}\n {live && (\n <div className=\"absolute right-[52px] top-[66px] flex items-end gap-1\">\n <p className=\"mb-[-5px] max-w-[200px] text-right\">\n Start live collaboration with your team or agents\n </p>\n <svg\n width=\"40\"\n height=\"48\"\n viewBox=\"0 0 50 60\"\n className=\"flex-none\"\n {...arrow}\n >\n <path d=\"M6 56 C 30 52, 42 30, 40 4\" />\n <path d=\"M40 4 L36.1 12.1 M40 4 L45.1 11.4\" />\n </svg>\n </div>\n )}\n </div>\n );\n}\n\nconst isMac =\n typeof navigator !== \"undefined\" &&\n /Mac|iPhone|iPad/.test(navigator.platform);\nconst MOD = isMac ? \"Cmd\" : \"Ctrl\";\n\nexport function EmptyCanvas({\n welcome = true,\n onOpen,\n onHelp,\n onConnect,\n palette,\n live,\n}: EmptyCanvasProps) {\n // Something dragged in (a component from the palette): the welcome makes way, so it lands on the canvas. Once it's\n // dropped the canvas is being worked on, so the welcome stays away (e.g. while a domain or system's kind is chosen)\n const [dragging, setDragging] = useState(false);\n const [dropped, setDropped] = useState(false);\n useEffect(() => {\n const start = () => setDragging(true);\n const end = () => setDragging(false);\n const drop = () => {\n setDropped(true);\n setDragging(false);\n };\n document.addEventListener(\"dragstart\", start);\n document.addEventListener(\"dragend\", end);\n document.addEventListener(\"drop\", drop);\n return () => {\n document.removeEventListener(\"dragstart\", start);\n document.removeEventListener(\"dragend\", end);\n document.removeEventListener(\"drop\", drop);\n };\n }, []);\n if (dragging || dropped) return null;\n\n const item = (\n icon: ReactNode,\n label: ReactNode,\n onClick: () => void,\n hint?: ReactNode,\n ) => (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"group flex h-11 w-full items-center gap-3.5 rounded-lg px-3 text-left text-[15px] text-[rgb(var(--ec-page-text-muted))] transition-colors hover:bg-[rgb(var(--ec-content-hover))]! hover:text-[rgb(var(--ec-page-text))]! [&_svg]:h-[18px] [&_svg]:w-[18px] [&_svg]:stroke-[1.75]\"\n >\n <span className=\"flex flex-none\">{icon}</span>\n <span className=\"min-w-0 flex-1 truncate\">{label}</span>\n {hint && <span className=\"flex-none text-[13px] opacity-80\">{hint}</span>}\n </button>\n );\n\n return (\n // On the canvas itself: what's dragged in from the left still lands on it\n <div className=\"pointer-events-none absolute inset-0 z-[5] flex items-center justify-center px-4 pb-16 pt-40\">\n <Hints palette={palette} live={live} />\n {welcome && (\n <div className=\"pointer-events-auto flex w-full max-w-[440px] flex-col items-center\">\n <div className=\"flex items-center gap-3 text-[rgb(var(--ec-page-text))]\">\n <span\n className=\"h-11 w-11 [&_svg]:h-full [&_svg]:w-full\"\n dangerouslySetInnerHTML={{ __html: logoSvg }}\n />\n <span className=\"text-[34px] font-bold tracking-tight\">\n EventCatalog{\" \"}\n <span className=\"font-light text-[rgb(var(--ec-page-text-muted))]\">\n Studio\n </span>\n </span>\n </div>\n <p className=\"mt-5 text-center font-[Excalifont,Inter,sans-serif] text-[22px] leading-snug text-[color-mix(in_srgb,rgb(var(--ec-page-text))_38%,transparent)]\">\n Sketch, design and share architecture with your team and AI agents.\n </p>\n\n <div className=\"mt-10 w-full\">\n {onOpen &&\n item(<FolderOpen aria-hidden />, \"Open\", onOpen, `${MOD}+O`)}\n {onConnect &&\n item(<Plug aria-hidden />, \"Connect to MCP Server\", onConnect)}\n {item(<CircleHelp aria-hidden />, \"Help\", onHelp, \"?\")}\n </div>\n </div>\n )}\n </div>\n );\n}\n","/**\n * A node's card, next to it on the canvas (Studio's way to see and edit a node, in EventCatalog and on the web): it\n * points at the node and follows it as the canvas pans and zooms, goes away when anything else is pressed or on\n * Escape, and its fields save as they're typed (there's nothing to press to keep a change). Styled in studio.css.\n */\nimport {\n useCallback,\n useEffect,\n useRef,\n useState,\n type KeyboardEvent as ReactKeyboardEvent,\n type ReactNode,\n type RefObject,\n} from \"react\";\nimport { Check, X } from \"lucide-react\";\n\nconst MODAL_WIDTH = 300;\nconst GAP = 12;\nconst EDGE = 8;\n/** How far down the modal its arrow is, when there's room */\nconst ARROW_DOWN = 32;\n\n/** pointsAt: how far down the node's middle is (for an arrow from the modal to it), when the modal is beside it */\ntype Anchor = {\n top: number;\n left: number;\n side: \"right\" | \"left\";\n pointsAt?: number;\n};\n\n/**\n * Where to show the modal: next to the node (on its right, or its left when there is no room),\n * kept inside the diagram and following the node as the diagram is panned or zoomed.\n */\nexport function useNodeAnchor(\n nodeId: string,\n containerRef: RefObject<HTMLElement | null>,\n modalRef: RefObject<HTMLElement | null>,\n bottomInset = EDGE,\n) {\n const [anchor, setAnchor] = useState<Anchor | null>(null);\n\n useEffect(() => {\n let frame = 0;\n const update = () => {\n const container = containerRef.current;\n const element = container?.querySelector<HTMLElement>(\n `.react-flow__node[data-id=\"${CSS.escape(nodeId)}\"]`,\n );\n if (container && element) {\n const bounds = container.getBoundingClientRect();\n const rect = element.getBoundingClientRect();\n const height = modalRef.current?.offsetHeight ?? 200;\n const width = modalRef.current?.offsetWidth || MODAL_WIDTH;\n const side =\n rect.right + GAP + width <= bounds.right - EDGE ? \"right\" : \"left\";\n const left =\n side === \"right\"\n ? rect.right - bounds.left + GAP\n : rect.left - bounds.left - GAP - width;\n const clamp = (value: number, max: number) =>\n Math.min(Math.max(value, EDGE), Math.max(max, EDGE));\n // Its top a little above the node's middle, so its arrow (by its header) points at the node\n const top = clamp(\n Math.min(rect.top, rect.top + rect.height / 2 - ARROW_DOWN) -\n bounds.top,\n bounds.height - height - bottomInset,\n );\n const placed = clamp(left, bounds.width - width - EDGE);\n // The node's middle, if it's beside the modal (not covered by it, nor above or below it)\n const middle = rect.top + rect.height / 2 - bounds.top - top;\n const pointsAt =\n placed === left && middle >= 14 && middle <= height - 14\n ? Math.round(middle)\n : undefined;\n const next: Anchor = { side, left: placed, top, pointsAt };\n setAnchor((previous) =>\n previous?.left === next.left &&\n previous?.top === next.top &&\n previous?.side === next.side &&\n previous?.pointsAt === next.pointsAt\n ? previous\n : next,\n );\n }\n frame = requestAnimationFrame(update);\n };\n update();\n return () => cancelAnimationFrame(frame);\n }, [nodeId, containerRef, modalRef, bottomInset]);\n\n return anchor;\n}\n\n/** \"Saved\", for a moment after a change is: what an edit form says under its fields */\nexport function useSavedFlash() {\n const [saved, setSaved] = useState(false);\n const timer = useRef<ReturnType<typeof setTimeout>>(undefined);\n const showSaved = useCallback(() => {\n setSaved(true);\n clearTimeout(timer.current);\n timer.current = setTimeout(() => setSaved(false), 1600);\n }, []);\n useEffect(() => () => clearTimeout(timer.current), []);\n return { saved, showSaved };\n}\n\n/** Under an edit form's fields: that changes save as they're typed, or that one just was */\nexport function EditStatus({ saved }: { saved: boolean }) {\n return (\n <p\n className={`ec-edit-status ${saved ? \"is-saved\" : \"\"}`}\n aria-live=\"polite\"\n >\n {saved ? (\n <>\n <Check aria-hidden /> Saved\n </>\n ) : (\n \"Changes save as you type\"\n )}\n </p>\n );\n}\n\n/**\n * The card: next to the node (pointing at it), its header (the kicker, e.g. the node's type, with a close button,\n * and what's under it, e.g. its edit form) and its body. Pressing anything outside it, or Escape, closes it, saving\n * what's being typed first.\n */\nexport function NodeCard({\n nodeId,\n containerRef,\n label,\n kicker,\n header,\n children,\n width = 340,\n bottomInset = 76,\n onClose,\n}: {\n nodeId: string;\n /** The canvas the node is on, to place the card next to it */\n containerRef: RefObject<HTMLElement | null>;\n /** What the card is about, for screen readers */\n label: string;\n /** The top line, e.g. the node's type and where it is */\n kicker: ReactNode;\n /** The rest of the header, e.g. the node's name and summary, or the form to edit them */\n header: ReactNode;\n /** Under the header, e.g. what it's connected to */\n children?: ReactNode;\n width?: number;\n /** Room to keep clear at the bottom of the canvas (e.g. its controls) */\n bottomInset?: number;\n onClose: () => void;\n}) {\n const cardRef = useRef<HTMLDivElement>(null);\n const anchor = useNodeAnchor(nodeId, containerRef, cardRef, bottomInset);\n\n // Goes away when anything else is pressed (the canvas, another node, dragging one) or on Escape\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n useEffect(() => {\n // What's being typed is saved first (leaving the field saves it)\n const close = () => {\n const active = document.activeElement;\n if (active instanceof HTMLElement && cardRef.current?.contains(active))\n active.blur();\n onCloseRef.current();\n };\n const onPointerDown = (event: PointerEvent) => {\n if (!cardRef.current?.contains(event.target as Node)) close();\n };\n const onKeyDown = (event: KeyboardEvent) =>\n event.key === \"Escape\" && close();\n document.addEventListener(\"pointerdown\", onPointerDown, true);\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"pointerdown\", onPointerDown, true);\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n }, []);\n\n // Opened to edit: the cursor's in its first field, ready to type (once it's shown: hidden, it can't take focus).\n // Nothing on a card that's only read (a locked canvas has no fields)\n const shown = !!anchor;\n const focusedFirst = useRef(false);\n useEffect(() => {\n if (!shown || focusedFirst.current) return;\n focusedFirst.current = true;\n const field = cardRef.current?.querySelector<\n HTMLInputElement | HTMLTextAreaElement\n >(\n \"input:not([readonly]):not([disabled]), textarea:not([readonly]):not([disabled])\",\n );\n if (!field) return;\n field.focus({ preventScroll: true });\n // At the end of what's there, to add to it (fields that have no text cursor, e.g. a checkbox, throw)\n try {\n field.setSelectionRange(field.value.length, field.value.length);\n } catch {}\n }, [shown]);\n\n return (\n <>\n {/* Pointing at the node it's about, so it reads as attached to it */}\n {anchor?.pointsAt !== undefined && (\n <span\n aria-hidden\n className={`ec-doc-card-arrow is-${anchor.side}`}\n style={{\n top: anchor.top + anchor.pointsAt - 7,\n left:\n anchor.side === \"right\"\n ? anchor.left - 6\n : anchor.left + width - 8,\n }}\n />\n )}\n <div\n ref={cardRef}\n className=\"ec-doc-card\"\n role=\"dialog\"\n aria-label={label}\n style={{\n width,\n top: anchor?.top ?? 8,\n left: anchor?.left ?? 8,\n visibility: anchor ? \"visible\" : \"hidden\",\n }}\n >\n <header className=\"ec-doc-card-header\">\n <div className=\"ec-doc-card-kicker\">\n {kicker}\n <button\n type=\"button\"\n className=\"ec-icon-button ec-doc-card-close\"\n aria-label=\"Close\"\n onClick={onClose}\n >\n <X aria-hidden />\n </button>\n </div>\n {header}\n </header>\n {children}\n </div>\n </>\n );\n}\n\n/** How long typing pauses before what's typed is saved (so the canvas keeps up, without saving every key) */\nconst SAVE_DELAY = 250;\n\n/**\n * A field of the resource's, saved as it's typed (and when it's left, or the card closes): there's nothing to press\n * to keep a change. Escape puts it back as it was when it was clicked into.\n */\nexport function EditableText({\n value,\n onSave,\n multiline = false,\n placeholder,\n className = \"\",\n label,\n required = false,\n onSaved,\n}: {\n value: string;\n onSave: (value: string) => void;\n multiline?: boolean;\n placeholder?: string;\n className?: string;\n label: string;\n required?: boolean;\n /** Something was saved (to say so) */\n onSaved?: () => void;\n}) {\n const [draft, setDraft] = useState(value);\n const focused = useRef(false);\n const before = useRef(value);\n const pending = useRef<string | null>(null);\n const timer = useRef<ReturnType<typeof setTimeout>>(undefined);\n const latest = useRef({ value, onSave, onSaved, required });\n latest.current = { value, onSave, onSaved, required };\n // Changed from elsewhere (undo, the agent): shown, unless it's being typed in\n useEffect(() => {\n if (!focused.current) setDraft(value);\n }, [value]);\n\n const flush = () => {\n clearTimeout(timer.current);\n const next = pending.current;\n pending.current = null;\n if (next === null) return;\n const {\n value: saved,\n onSave: save,\n onSaved: said,\n required: needed,\n } = latest.current;\n if ((needed && !next.trim()) || next === saved) return;\n save(next);\n said?.();\n };\n // Saved if the card closes (or the node changes) while it's being typed in\n useEffect(() => flush, []);\n\n const change = (next: string) => {\n setDraft(next);\n pending.current = next;\n clearTimeout(timer.current);\n timer.current = setTimeout(flush, SAVE_DELAY);\n };\n // Escape put it back (and saved that): leaving it then mustn't save what was typed (`draft` here is from before)\n const reverted = useRef(false);\n const leave = () => {\n focused.current = false;\n if (reverted.current) {\n reverted.current = false;\n return;\n }\n const trimmed = draft.trim();\n // A field that can't be empty goes back to what it was\n if (required && !trimmed) {\n setDraft(before.current);\n pending.current = before.current;\n } else {\n if (trimmed !== draft) setDraft(trimmed);\n pending.current = trimmed;\n }\n flush();\n };\n const keys = (\n event: ReactKeyboardEvent<HTMLInputElement | HTMLTextAreaElement>,\n ) => {\n if (event.key === \"Escape\") {\n event.stopPropagation();\n setDraft(before.current);\n pending.current = before.current;\n flush();\n reverted.current = true;\n (event.target as HTMLElement).blur();\n } else if (\n event.key === \"Enter\" &&\n (!multiline || event.metaKey || event.ctrlKey)\n ) {\n event.preventDefault();\n (event.target as HTMLElement).blur();\n }\n };\n const focus = () => {\n focused.current = true;\n before.current = value;\n };\n const fit = (area: HTMLTextAreaElement | null) => {\n if (!area) return;\n area.style.height = \"auto\";\n area.style.height = `${area.scrollHeight + 2}px`;\n };\n return multiline ? (\n <textarea\n ref={fit}\n aria-label={label}\n value={draft}\n rows={2}\n placeholder={placeholder}\n onChange={(event) => {\n change(event.target.value);\n fit(event.target);\n }}\n onFocus={focus}\n onBlur={leave}\n onKeyDown={keys}\n className={`ec-editable ${className}`}\n />\n ) : (\n <input\n aria-label={label}\n value={draft}\n placeholder={placeholder}\n onChange={(event) => change(event.target.value)}\n onFocus={focus}\n onBlur={leave}\n onKeyDown={keys}\n className={`ec-editable ${className}`}\n />\n );\n}\n\n/** A field with its name above it */\nexport function Field({\n label,\n children,\n className = \"\",\n}: {\n label: string;\n children: ReactNode;\n className?: string;\n}) {\n return (\n <label className={`ec-field ${className}`}>\n <span className=\"ec-field-label\">{label}</span>\n {children}\n </label>\n );\n}\n","import { memo, useEffect } from \"react\";\nimport {\n useStore,\n useUpdateNodeInternals,\n type ReactFlowState,\n} from \"@xyflow/react\";\n\nconst selectDomNode = (state: ReactFlowState) => state.domNode;\n\n/**\n * Measures a node's handles again once it has finished animating in or resizing. React Flow measures them when the\n * node appears, part way through its pop in (`studio-node-in`, which scales it), and doesn't again while its size\n * stays the same: edges would join a node short of its sides (far short of a container's). Same for a container\n * growing to fit what's in it (its size eases in, `is-container-resize`). One listener for the whole canvas, and one\n * update a frame for everything that finished in it (a container's width and height transitions end separately).\n * Render it inside `<ReactFlow>`.\n */\nexport const RemeasureHandles = memo(function RemeasureHandles() {\n const domNode = useStore(selectDomNode);\n const updateNodeInternals = useUpdateNodeInternals();\n useEffect(() => {\n if (!domNode) return;\n const pending = new Set<string>();\n let frame = 0;\n const flush = () => {\n frame = 0;\n updateNodeInternals([...pending]);\n pending.clear();\n };\n const remeasure = (event: AnimationEvent | TransitionEvent) => {\n const element = event.target as HTMLElement;\n if (!element.classList?.contains(\"react-flow__node\")) return;\n const resized =\n event.type === \"transitionend\"\n ? [\"width\", \"height\"].includes(\n (event as TransitionEvent).propertyName,\n )\n : (event as AnimationEvent).animationName === \"studio-node-in\";\n const id = element.dataset.id;\n if (!resized || !id) return;\n pending.add(id);\n frame ||= requestAnimationFrame(flush);\n };\n domNode.addEventListener(\"animationend\", remeasure);\n domNode.addEventListener(\"transitionend\", remeasure);\n return () => {\n cancelAnimationFrame(frame);\n domNode.removeEventListener(\"animationend\", remeasure);\n domNode.removeEventListener(\"transitionend\", remeasure);\n };\n }, [domNode, updateNodeInternals]);\n return null;\n});\n"],"mappings":"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","names":["getNodeSize","getNodeSize","getNodeSize","edge","row","id","getNodeSize","byId","LEVELS","byId","resource","byId","placeOf","PRODUCERS","memo","useEffect","useState","Handle","Position","useStoreApi","TeamNode","jsx","jsxs","updateNodeData","useEffect","memo","StickyNote","useState","TextNode","isDomain","EntityCard","Handle","Position","DomainCard","GroupNode","useStoreApi","createContext","memo","useCallback","useContext","useEffect","useRef","useState","useReactFlow","useState","jsx","jsx","Fragment","jsx","jsxs","useRef","useState","useEffect","createContext","useCallback","useContext","memo","CommentLayer","useReactFlow","memo","useEffect","useLayoutEffect","useRef","useState","StickyNote","Trash2","Fragment","jsx","jsxs","memo","ContextMenu","useEffect","useRef","useState","useLayoutEffect","StickyNote","Trash2","useCallback","useEffect","useMemo","useRef","useState","useStoreApi","jsx","useStoreApi","useState","useCallback","useRef","getNodeSize","useEffect","useMemo","memo","useLayoutEffect","useRef","useState","useInternalNode","useReactFlow","useStoreApi","Pencil","Trash2","TriangleAlert","X","Fragment","jsx","jsxs","TriangleAlert","useStoreApi","useLayoutEffect","useInternalNode","DRAG_THRESHOLD_PX","useRef","panelClass","useState","IconButton","X","Pencil","Trash2","memo","HotspotLayer","useReactFlow","Bot","StickyNote","Users","Bot","Users","StickyNote","memo","useReactFlow","MessageCircle","Type","SendToBack","StickyNote","TriangleAlert","Fragment","jsx","jsxs","LEVELS","memo","StickyNote","Type","MessageCircle","TriangleAlert","ViewControls","useReactFlow","SendToBack","useEffect","useState","X","jsx","jsxs","memo","Position","Info","Pencil","Fragment","jsx","jsxs","memo","useCallback","useEffect","useRef","useState","GripVertical","Fragment","jsx","jsxs","GripVertical","memo","Palette","useState","useCallback","useRef","useEffect","components","jsx","jsxs","useEffect","useState","jsx","jsxs","isMac","MOD","useState","useEffect","useCallback","useEffect","useRef","useState","Check","X","Fragment","jsx","jsxs","GAP","EDGE","memo","useEffect","useStore","useUpdateNodeInternals","RemeasureHandles"]}
|
|
1
|
+
{"version":3,"sources":["../src/studio/canvas-doc.ts","../src/studio/edges.ts","../src/studio/grouping.ts","../src/studio/clipboard.ts","../src/studio/connect-new.ts","../src/studio/use-connect-new.ts","../src/studio/entity-handles.ts","../src/studio/flow-state.ts","../src/studio/layout.ts","../src/studio/placement.ts","../src/studio/level-layout.ts","../src/studio/levels.ts","../src/studio/live-moves.ts","../src/studio/smooth.ts","../src/studio/use-counter-scale.ts","../src/studio/model-canvas.ts","../src/studio/diagram-file.ts","../src/studio/export-image.ts","../src/studio/components/canvas-nodes.tsx","../src/studio/components/TeamNode.tsx","../src/studio/components/ConnectChooser.tsx","../src/studio/components/Comments.tsx","../src/studio/components/status.ts","../src/studio/components/Picture.tsx","../src/studio/components/ClientLogos.tsx","../src/studio/components/ContextMenu.tsx","../src/studio/components/DragGhost.tsx","../src/studio/components/Hotspots.tsx","../src/studio/components/CanvasControls.tsx","../src/studio/components/ContainerChooser.tsx","../src/studio/components/EditButton.tsx","../src/studio/components/Palette.tsx","../src/studio/components/Shortcuts.tsx","../src/studio/components/EmptyCanvas.tsx","../src/studio/components/RemeasureHandles.tsx"],"sourcesContent":["import * as Y from \"yjs\";\nimport type { Connection, Edge, Node, XYPosition } from \"@xyflow/react\";\nimport type { CopiedEdgeRoute, EdgeRoute } from \"../layout\";\nimport { createEdge, getEdgeLabel } from \"./edges\";\nimport {\n fitGroup,\n getAbsolutePosition,\n withDescendants,\n withParent,\n} from \"./grouping\";\nimport {\n getNodeDefinition,\n getNodeName,\n getNodeSize,\n isGroupType,\n} from \"./node-types\";\n\n/**\n * Everything a canvas holds, as operations on its Yjs document: nodes and edges, where things are on each level,\n * comment threads, hotspots and the canvas's status. The same functions run in the browser (people, WebMCP) and on a\n * server (MCP tools), so people and agents edit a canvas the same way.\n */\n\nexport type Author = {\n name: string;\n color: string;\n agent?: boolean;\n /** A picture from their sign-in provider (SSO), shown over their initials */\n picture?: string;\n};\nexport type Message = {\n id: string;\n text: string;\n author: Author;\n createdAt: number;\n};\n/** Where a comment is pinned: a canvas position, or a node (and the offset from its top left) so it moves with it */\nexport type CommentAnchor = {\n position: XYPosition;\n nodeId?: string;\n offset?: XYPosition;\n level?: 1 | 2;\n};\nexport type Thread = CommentAnchor & {\n id: string;\n author: Author;\n createdAt: number;\n resolved: boolean;\n messages: Message[];\n};\nexport type HotspotSeverity = \"critical\" | \"warning\" | \"info\";\n/** A hotspot: flagged on a node (shown on it, wherever it goes), or at a place on the canvas */\nexport type Hotspot = {\n id: string;\n severity: HotspotSeverity;\n title: string;\n description?: string;\n nodeId?: string;\n /** Where it is when it's not on a node */\n position: XYPosition;\n /** The level that place is on (L1 or L2: they're laid out on their own); none, L3 */\n level?: 1 | 2;\n author: Author;\n createdAt: number;\n};\n/** Where a canvas's design is: being worked on, up for review, agreed, or decided against */\nexport const CANVAS_STATUSES = [\n \"draft\",\n \"proposed\",\n \"accepted\",\n \"rejected\",\n] as const;\nexport type CanvasStatus = (typeof CANVAS_STATUSES)[number];\n/** A canvas's status being changed: by whom, when, and why (e.g. \"Agreed in the architecture review\") */\nexport type StatusChange = {\n status: CanvasStatus;\n by: Author;\n at: number;\n note?: string;\n};\nexport type CanvasMeta = {\n title?: string;\n /** Draft until someone changes it */\n status?: CanvasStatus;\n /** Every status change, oldest first (the last few hundred) */\n statusHistory?: StatusChange[];\n createdAt?: number;\n createdBy?: string;\n /** When the canvas was last laid out, so everyone's canvas glides the nodes into place */\n layoutAt?: number;\n /** Locked (looked at, not changed), by whom: for everyone on it, in a live session too */\n lockedBy?: string | null;\n /** L1 and L2 as the diagram the canvas was opened from showed them (see DiagramLevels) */\n diagramLevels?: DiagramLevels;\n};\n\n/** A level of detail as a diagram showed it: its nodes (laid out) and edges, by canvas node ids where they're the same */\nexport type DiagramLevel = { nodes: Node[]; edges: Edge[] };\n\n/**\n * L1 and L2 of the diagram a canvas was opened from (the visualiser's \"Open in Studio\"), shown as they were while the\n * canvas's structure is what was opened (`structure`, from getStructureKey): moving nodes keeps them, changing what's\n * on the canvas or how it's connected doesn't (the levels are then worked out from the canvas)\n */\nexport type DiagramLevels = {\n structure: string;\n 1?: DiagramLevel;\n 2?: DiagramLevel;\n /** Levels the diagram doesn't have, and why (as the diagram says) */\n unavailable?: { 1?: string; 2?: string };\n};\n\n/** Who locked the canvas, if it's locked */\nexport const getLock = (doc: Y.Doc) =>\n (getCanvasMaps(doc).meta.get(\"lockedBy\") as string | null | undefined) ??\n null;\n\n/** Locks the canvas for everyone (by a name), or unlocks it (null); nothing written if it's already so */\nexport const setLock = (doc: Y.Doc, by: string | null) => {\n if (getLock(doc) === by) return;\n getCanvasMaps(doc).meta.set(\"lockedBy\", by);\n};\n\nexport const shortId = () => crypto.randomUUID().slice(0, 8);\n\nexport const getCanvasMaps = (doc: Y.Doc) => ({\n nodes: doc.getMap<Node>(\"nodes\"),\n edges: doc.getMap<Edge>(\"edges\"),\n threads: doc.getMap<Y.Map<unknown>>(\"threads\"),\n /** Each hotspot whole (edited by replacing it: they're short) */\n hotspots: doc.getMap<Hotspot>(\"hotspots\"),\n meta: doc.getMap<unknown>(\"meta\"),\n /** Where things are on L1 and L2 (see LevelPlace), one entry per node and level (`1:<node id>`) */\n levelLayouts: doc.getMap<LevelPlace>(\"levelLayouts\"),\n});\n\n/**\n * Where a node is on L1 or L2, as people arranged it there (or as the diagram it was opened from had it): its\n * top-left corner, relative to the container it's shown in on that level, and a container's size\n */\nexport type LevelPlace = {\n x: number;\n y: number;\n width?: number;\n height?: number;\n};\n\n/** The places on a level, by node id */\nexport const readLevelLayout = (doc: Y.Doc, level: 1 | 2) => {\n const prefix = `${level}:`;\n const places = new Map<string, LevelPlace>();\n getCanvasMaps(doc).levelLayouts.forEach((place, key) => {\n if (key.startsWith(prefix)) places.set(key.slice(prefix.length), place);\n });\n return places;\n};\n\nconst samePlace = (a: LevelPlace | undefined, b: LevelPlace) =>\n !!a &&\n a.x === b.x &&\n a.y === b.y &&\n a.width === b.width &&\n a.height === b.height;\n\n/**\n * Puts nodes where they go on a level (in one transaction). Places that haven't changed aren't written: everyone\n * looking at the level works out the same places for what's new on it, and each write re-arranges the level for\n * everyone else.\n */\nexport const setLevelPlaces = (\n doc: Y.Doc,\n level: 1 | 2,\n places: ReadonlyMap<string, LevelPlace>,\n) =>\n doc.transact(() => {\n const { levelLayouts } = getCanvasMaps(doc);\n places.forEach((place, id) => {\n const key = `${level}:${id}`;\n if (!samePlace(levelLayouts.get(key), place))\n levelLayouts.set(key, place);\n });\n });\n\n// Only the design is shared. Selection, measured sizes and drag state stay with each user.\nexport const toSharedNode = ({\n id,\n type,\n position,\n data,\n width,\n height,\n parentId,\n zIndex,\n}: Node): Node => ({\n id,\n type,\n position,\n data,\n ...(width ? { width } : {}),\n ...(height ? { height } : {}),\n // Inside a container (its position is then relative to the container)\n ...(parentId ? { parentId } : {}),\n ...(zIndex !== undefined ? { zIndex } : {}),\n});\n\n/** A new node of a type, centred on a canvas position */\nexport const buildNode = (\n type: string,\n data: Record<string, unknown>,\n center: XYPosition,\n): Node => {\n const definition = getNodeDefinition(type);\n const size = getNodeSize(type);\n return toSharedNode({\n id: `${type}-${shortId()}`,\n type,\n position: { x: center.x - size.width / 2, y: center.y - size.height / 2 },\n data,\n ...(definition?.defaultSize && !definition.autoSize\n ? definition.autoHeight\n ? { width: size.width }\n : size\n : {}),\n // Containers sit behind what's in them and the connections between them\n ...(isGroupType(type) && { zIndex: -1 }),\n });\n};\n\n// ---- Meta ----\n\nexport const readMeta = (doc: Y.Doc) =>\n getCanvasMaps(doc).meta.toJSON() as CanvasMeta;\n\nexport const setMeta = (doc: Y.Doc, meta: Partial<CanvasMeta>) =>\n doc.transact(() => {\n const map = getCanvasMaps(doc).meta;\n Object.entries(meta).forEach(([key, value]) =>\n value === undefined ? map.delete(key) : map.set(key, value),\n );\n });\n\n// ---- Status ----\n\nconst MAX_STATUS_HISTORY = 200;\n\nexport const getCanvasStatus = (meta: CanvasMeta): CanvasStatus =>\n meta.status ?? \"draft\";\n\n/** Changes a canvas's status (and records who did it). Returns false if it already had that status. */\nexport const setCanvasStatus = (\n doc: Y.Doc,\n status: CanvasStatus,\n by: Author,\n note?: string,\n) => {\n let changed = false;\n doc.transact(() => {\n const meta = readMeta(doc);\n if (getCanvasStatus(meta) === status) return;\n const change: StatusChange = {\n status,\n by,\n at: Date.now(),\n ...(note?.trim() && { note: note.trim() }),\n };\n const map = getCanvasMaps(doc).meta;\n map.set(\"status\", status);\n map.set(\n \"statusHistory\",\n [...(meta.statusHistory ?? []), change].slice(-MAX_STATUS_HISTORY),\n );\n changed = true;\n });\n return changed;\n};\n\n/** Accepted and rejected canvases are decided: changing what's on them makes them a draft again */\nexport const isDecided = (status: CanvasStatus) =>\n status === \"accepted\" || status === \"rejected\";\n\n/** A decided canvas whose nodes or edges were changed goes back to draft, recorded as changed by `by` */\nexport const reopenIfDecided = (doc: Y.Doc, by: Author) => {\n const status = getCanvasStatus(readMeta(doc));\n if (isDecided(status))\n setCanvasStatus(doc, \"draft\", by, `Changed after it was ${status}`);\n};\n\n/**\n * Runs `fn` (which may change the canvas), and if it changed nodes or edges, sends a decided canvas back to draft.\n * Comments don't count: reviewing an accepted design keeps it accepted.\n */\nexport const reopeningIfEdited = <T>(\n doc: Y.Doc,\n by: Author,\n fn: () => T,\n): T => {\n let result!: T;\n // In one transaction (the one it's already in, if it is): what it changed is known before it ends\n doc.transact((transaction) => {\n result = fn();\n if (changesNodesOrEdges(transaction)) reopenIfDecided(doc, by);\n });\n return result;\n};\n\n/** Whether a transaction changed the canvas's nodes or edges (not just its comments or meta) */\nexport const changesNodesOrEdges = (transaction: Y.Transaction) => {\n const { nodes, edges } = getCanvasMaps(transaction.doc);\n return [...transaction.changed.keys()].some(\n (type) => type === (nodes as unknown) || type === (edges as unknown),\n );\n};\n\n// ---- Nodes and edges ----\n\nexport const addNodes = (doc: Y.Doc, nodes: Node[], edges: Edge[] = []) =>\n doc.transact(() => {\n const maps = getCanvasMaps(doc);\n nodes.forEach((node) => maps.nodes.set(node.id, toSharedNode(node)));\n edges.forEach((edge) => maps.edges.set(edge.id, edge));\n });\n\n/**\n * Moves a node, and resizes it if a size is given, in one write. Nodes are only written when they change: every\n * write is sent to everyone, re-renders the node for them, and is kept in the document (and the undo stack), even\n * when it writes what was already there.\n */\nexport const placeNode = (\n doc: Y.Doc,\n id: string,\n position: XYPosition,\n size?: { width: number; height: number },\n) => {\n const { nodes } = getCanvasMaps(doc);\n const node = nodes.get(id);\n if (!node) return false;\n const moved =\n node.position.x !== position.x || node.position.y !== position.y;\n const resized =\n !!size && (node.width !== size.width || node.height !== size.height);\n if (moved || resized)\n nodes.set(id, {\n ...node,\n position,\n ...(size && { width: size.width, height: size.height }),\n });\n return true;\n};\n\nexport const moveNode = (doc: Y.Doc, id: string, position: XYPosition) =>\n placeNode(doc, id, position);\n\n/** Resize a node: both sides, or just its width or height (e.g. text, whose height follows what's in it) */\nexport const resizeNode = (\n doc: Y.Doc,\n id: string,\n size: { width: number; height: number },\n attributes: true | \"width\" | \"height\" = true,\n) => {\n const { nodes } = getCanvasMaps(doc);\n const node = nodes.get(id);\n const width = attributes !== \"height\" && node?.width !== size.width;\n const height = attributes !== \"width\" && node?.height !== size.height;\n if (node && (width || height))\n nodes.set(id, {\n ...node,\n ...(attributes !== \"height\" && { width: size.width }),\n ...(attributes !== \"width\" && { height: size.height }),\n });\n return !!node;\n};\n\n/** Grow a container to fit what's in it (moving them clear of its header if needed), never shrinking it */\n/**\n * The sizes nodes are rendered at (in the browser), by id. The document doesn't have them, so without them\n * containers are fitted to the size each type renders at at most.\n */\nexport type RenderedSizes = ReadonlyMap<\n string,\n { width: number; height: number }\n>;\n\nconst withRenderedSizes = (nodes: Node[], sizes?: RenderedSizes) =>\n sizes\n ? nodes.map((node) =>\n sizes.has(node.id) ? { ...node, measured: sizes.get(node.id) } : node,\n )\n : nodes;\n\nexport const fitGroupToChildren = (\n doc: Y.Doc,\n groupId: string,\n sizes?: RenderedSizes,\n) =>\n doc.transact(() => {\n const { nodes } = getCanvasMaps(doc);\n const fit = fitGroup(\n groupId,\n withRenderedSizes(Array.from(nodes.values()), sizes),\n );\n const group = nodes.get(groupId);\n if (!fit || !group) return;\n if (fit.shift.x || fit.shift.y) {\n // Children move right/down and the container left/up by the same amount: nothing moves on the canvas\n nodes.forEach((child, id) => {\n if (child.parentId === groupId)\n nodes.set(id, {\n ...child,\n position: {\n x: child.position.x + fit.shift.x,\n y: child.position.y + fit.shift.y,\n },\n });\n });\n }\n nodes.set(groupId, {\n ...group,\n position: {\n x: group.position.x - fit.shift.x,\n y: group.position.y - fit.shift.y,\n },\n width: fit.width,\n height: fit.height,\n });\n });\n\n/** The containers a node is in grow to fit it (innermost first), e.g. after it's added or resized */\nexport const fitContainersAround = (\n doc: Y.Doc,\n nodeId: string,\n sizes?: RenderedSizes,\n) =>\n doc.transact(() => {\n const { nodes } = getCanvasMaps(doc);\n for (let id = nodes.get(nodeId)?.parentId; id; id = nodes.get(id)?.parentId)\n fitGroupToChildren(doc, id, sizes);\n });\n\n/**\n * A node moved into (or out of) a container: where it is on the canvas, or put at `at` (in its new parent), e.g. when\n * it's moved on L1 or L2, where it was dropped isn't a place on the canvas\n */\nexport const setNodeParent = (\n doc: Y.Doc,\n nodeId: string,\n parentId: string | undefined,\n sizes?: RenderedSizes,\n at?: XYPosition,\n) =>\n doc.transact(() => {\n const { nodes } = getCanvasMaps(doc);\n const node = nodes.get(nodeId);\n if (!node || node.parentId === parentId) return false;\n const moved = at\n ? { ...node, parentId, position: at }\n : withParent(node, parentId, Array.from(nodes.values()));\n nodes.set(nodeId, toSharedNode(moved));\n if (parentId) fitGroupToChildren(doc, parentId, sizes);\n return true;\n });\n\n/**\n * Nodes moved into (or out of) containers together, e.g. a selection dropped in one, as one change: each where it is\n * on the canvas, or at its `at` (in its new parent). The containers they went in (and those around them) are fitted\n * once they're all in, so one growing doesn't move where the next was put. Returns the ids of those moved.\n */\nexport const setNodeParents = (\n doc: Y.Doc,\n moves: { id: string; parentId: string | undefined; at?: XYPosition }[],\n sizes?: RenderedSizes,\n) =>\n doc.transact(() => {\n const { nodes } = getCanvasMaps(doc);\n const moved: string[] = [];\n for (const { id, parentId, at } of moves) {\n const node = nodes.get(id);\n if (!node || node.parentId === parentId) continue;\n nodes.set(\n id,\n toSharedNode(\n at\n ? { ...node, parentId, position: at }\n : withParent(node, parentId, Array.from(nodes.values())),\n ),\n );\n moved.push(id);\n }\n // Each container once, innermost first\n const containers: string[] = [];\n for (const id of moved) {\n for (\n let parent = nodes.get(id)?.parentId;\n parent;\n parent = nodes.get(parent)?.parentId\n )\n if (!containers.includes(parent)) containers.push(parent);\n }\n const depth = (id: string) => {\n let level = 0;\n for (\n let parent = nodes.get(id)?.parentId;\n parent;\n parent = nodes.get(parent)?.parentId\n )\n level++;\n return level;\n };\n containers\n .sort((a, b) => depth(b) - depth(a))\n .forEach((id) => fitGroupToChildren(doc, id, sizes));\n return moved;\n });\n\nexport const updateNodeData = (\n doc: Y.Doc,\n id: string,\n updater: (data: Record<string, unknown>) => Record<string, unknown>,\n) => {\n const { nodes } = getCanvasMaps(doc);\n const node = nodes.get(id);\n if (node) nodes.set(id, { ...node, data: updater(node.data) });\n return !!node;\n};\n\n/**\n * How a connection is drawn, as the visualiser's layout routes it (in data.route, which the visualiser's edges\n * are drawn along): the points it goes through, where its label goes, and where its nodes were (top-left) when\n * it was routed, for it to follow them when they move\n */\nexport type { EdgeRoute };\n\n/** An edge's route, if it has one */\nexport const getEdgeRoute = (edge: Pick<Edge, \"data\">) =>\n (edge.data as { route?: EdgeRoute } | undefined)?.route;\n\n/** Routes connections (by edge id), in one transaction. Connections not in it lose any route they had. */\nexport const setEdgeRoutes = (\n doc: Y.Doc,\n routes: ReadonlyMap<string, EdgeRoute>,\n) =>\n doc.transact(() => {\n const { edges } = getCanvasMaps(doc);\n edges.forEach((edge, id) => {\n const route = routes.get(id);\n if (route) edges.set(id, { ...edge, data: { ...edge.data, route } });\n else if (getEdgeRoute(edge)) {\n const { route: _, ...data } = edge.data!;\n edges.set(id, { ...edge, data });\n }\n });\n });\n\n/**\n * What's on a canvas and how it's connected, not where: its nodes (not notes), what they're in and called, and its\n * connections. The same for the same canvas wherever it's worked out (the server, any browser).\n */\nexport const getStructureKey = (nodes: Node[], edges: Edge[]) => {\n const parts = [\n ...nodes\n .filter((node) => node.type !== \"note\")\n .map(\n (node) =>\n `${node.id}:${node.type}:${node.parentId ?? \"\"}:${getNodeName(node.type, node.data)}`,\n )\n .sort(),\n \"#\",\n ...edges\n .map(\n (edge) => `${edge.source}>${edge.target}:${String(edge.label ?? \"\")}`,\n )\n .sort(),\n ];\n // FNV-1a, so it's short enough to keep in the canvas\n let hash = 0x811c9dc5;\n for (const char of parts.join(\"|\"))\n hash = Math.imul(hash ^ char.charCodeAt(0), 0x01000193);\n return `${parts.length}-${(hash >>> 0).toString(36)}`;\n};\n\n/** The diagram's L1 or L2 while the canvas still has the structure it was opened with (`structure`, its key now) */\nexport const getDiagramLevel = (\n levels: DiagramLevels | undefined,\n level: 1 | 2,\n structure: string,\n) =>\n levels?.[level] &&\n !levels.unavailable?.[level] &&\n levels.structure === structure\n ? levels[level]\n : undefined;\n\n/** Why the diagram doesn't have a level, while the canvas still has the structure it was opened with */\nexport const getDiagramLevelUnavailable = (\n levels: DiagramLevels | undefined,\n level: 1 | 2,\n structure: string,\n) =>\n levels?.unavailable?.[level] && levels.structure === structure\n ? levels.unavailable[level]\n : undefined;\n\n/** What a new canvas starts with: its nodes, the connections between them (by node id) with their routes, and the\n * levels of the diagram it's opened from */\nexport type CanvasContent = {\n nodes: Node[];\n connections: {\n from: string;\n to: string;\n label?: string;\n route?: CopiedEdgeRoute;\n }[];\n levels?: Pick<DiagramLevels, 1 | 2 | \"unavailable\">;\n};\n\n/**\n * Puts a new canvas's content on it (in one transaction), with its containers fitted to what's in them. Routes\n * are from where the nodes are put.\n */\nexport const addCanvasContent = (\n doc: Y.Doc,\n { nodes, connections, levels }: CanvasContent,\n) =>\n doc.transact(() => {\n addNodes(doc, nodes);\n nodes.forEach((node) => node.parentId && fitContainersAround(doc, node.id));\n const placed = new Map(getCanvasMaps(doc).nodes.entries());\n const routes = new Map<string, EdgeRoute>();\n connections.forEach(({ from, to, label, route }) => {\n const edge = connectNodes(doc, { source: from, target: to }, label);\n const [source, target] = [placed.get(from), placed.get(to)];\n if (!route || \"error\" in edge || !source || !target) return;\n const { sourceHeight, targetHeight, ...drawn } = route;\n routes.set(edge.id, {\n ...drawn,\n source: {\n ...getAbsolutePosition(source, placed),\n ...(sourceHeight && { height: sourceHeight }),\n },\n target: {\n ...getAbsolutePosition(target, placed),\n ...(targetHeight && { height: targetHeight }),\n },\n });\n });\n if (routes.size) setEdgeRoutes(doc, routes);\n if (levels) {\n const maps = getCanvasMaps(doc);\n const structure = getStructureKey(\n Array.from(maps.nodes.values()),\n Array.from(maps.edges.values()),\n );\n setMeta(doc, { diagramLevels: { structure, ...levels } });\n }\n });\n\n/** Connect two nodes with an EventCatalog-labelled edge. Returns the edge, or why it couldn't be made. */\n/** Whether a connection joins the same handles as another (a node's default handle is null) */\nconst sameEnds = (\n edge: Pick<Edge, \"sourceHandle\" | \"targetHandle\">,\n connection: Partial<Connection>,\n) =>\n (edge.sourceHandle ?? null) === (connection.sourceHandle ?? null) &&\n (edge.targetHandle ?? null) === (connection.targetHandle ?? null);\n\nexport const connectNodes = (\n doc: Y.Doc,\n connection: Pick<Connection, \"source\" | \"target\"> & Partial<Connection>,\n label?: string,\n): Edge | { error: string } => {\n const { nodes, edges } = getCanvasMaps(doc);\n const source = nodes.get(connection.source);\n const target = nodes.get(connection.target);\n if (!source)\n return { error: `Node \"${connection.source}\" is not on the canvas` };\n if (!target)\n return { error: `Node \"${connection.target}\" is not on the canvas` };\n if (source.id === target.id)\n return { error: \"A node cannot be connected to itself\" };\n // (two things are joined once, except at different places: e.g. two of an entity's properties)\n const existing = Array.from(edges.values()).find(\n (edge) =>\n edge.source === source.id &&\n edge.target === target.id &&\n sameEnds(edge, connection),\n );\n if (existing) return existing;\n const edge = createEdge(\n {\n source: source.id,\n target: target.id,\n sourceHandle: connection.sourceHandle ?? null,\n targetHandle: connection.targetHandle ?? null,\n },\n source.type,\n target.type,\n );\n const created = label === undefined ? edge : { ...edge, label };\n edges.set(created.id, created);\n return created;\n};\n\n/**\n * Moves a connection to new ends (dragged to another node), keeping it the same connection. Its label follows\n * the new ends if it was EventCatalog's wording, and is kept if someone wrote it.\n */\nexport const reconnectEdge = (\n doc: Y.Doc,\n edgeId: string,\n connection: Connection,\n): Edge | { error: string } =>\n doc.transact(() => {\n const { nodes, edges } = getCanvasMaps(doc);\n const edge = edges.get(edgeId);\n const source = nodes.get(connection.source);\n const target = nodes.get(connection.target);\n if (!edge) return { error: `Connection \"${edgeId}\" is not on the canvas` };\n if (!source || !target)\n return { error: \"Connections join two nodes on the canvas\" };\n if (source.id === target.id)\n return { error: \"A node cannot be connected to itself\" };\n const duplicate = Array.from(edges.values()).find(\n (other) =>\n other.id !== edgeId &&\n other.source === source.id &&\n other.target === target.id &&\n sameEnds(other, connection),\n );\n if (duplicate) return { error: \"Those nodes are already connected\" };\n\n const defaultLabel = getEdgeLabel(\n nodes.get(edge.source)?.type,\n nodes.get(edge.target)?.type,\n );\n const moved = createEdge(connection, source.type, target.type);\n const written = (edge.data as { customLabel?: string } | undefined)\n ?.customLabel;\n const reconnected: Edge = {\n ...moved,\n id: edge.id,\n ...(edge.label !== undefined &&\n edge.label !== defaultLabel && { label: edge.label }),\n ...(written && { data: { ...moved.data, customLabel: written } }),\n };\n edges.set(edgeId, reconnected);\n return reconnected;\n });\n\n/**\n * What a connection says: written by someone (kept as it's written, and in the model), or, with nothing written,\n * EventCatalog's wording for what it joins again\n */\nexport const setEdgeLabel = (\n doc: Y.Doc,\n edgeId: string,\n label: string | undefined,\n) =>\n doc.transact(() => {\n const { nodes, edges } = getCanvasMaps(doc);\n const edge = edges.get(edgeId);\n if (!edge) return false;\n const { customLabel: _, ...data } = (edge.data ?? {}) as Record<\n string,\n unknown\n >;\n edges.set(edgeId, {\n ...edge,\n label:\n label ??\n getEdgeLabel(\n nodes.get(edge.source)?.type,\n nodes.get(edge.target)?.type,\n ),\n data: label ? { ...data, customLabel: label } : data,\n });\n return true;\n });\n\nexport const deleteEdges = (doc: Y.Doc, ids: string[]) =>\n doc.transact(() => ids.forEach((id) => getCanvasMaps(doc).edges.delete(id)));\n\n/** Delete nodes (containers with what's in them), the edges to them, and leave their comments where they were */\nexport const deleteNodes = (doc: Y.Doc, ids: string[]) =>\n doc.transact(() => {\n const { nodes, edges, threads, hotspots, levelLayouts } =\n getCanvasMaps(doc);\n const all = Array.from(nodes.values());\n const lookup = new Map(all.map((node) => [node.id, node]));\n const removed = withDescendants(ids, all);\n threads.forEach((thread) => {\n const nodeId = thread.get(\"nodeId\") as string | undefined;\n const node =\n nodeId && removed.has(nodeId) ? nodes.get(nodeId) : undefined;\n if (!node) return;\n const offset = (thread.get(\"offset\") as XYPosition) ?? { x: 0, y: 0 };\n const position = getAbsolutePosition(node, lookup);\n thread.set(\"position\", {\n x: position.x + offset.x,\n y: position.y + offset.y,\n });\n thread.delete(\"nodeId\");\n thread.delete(\"offset\");\n });\n // Hotspots on them stay too, where their node was (its top right corner)\n hotspots.forEach((hotspot, id) => {\n const node =\n hotspot.nodeId && removed.has(hotspot.nodeId)\n ? nodes.get(hotspot.nodeId)\n : undefined;\n if (!node) return;\n const position = getAbsolutePosition(node, lookup);\n const { nodeId: _, ...rest } = hotspot;\n hotspots.set(id, {\n ...rest,\n position: {\n x: position.x + (node.measured?.width ?? node.width ?? 0),\n y: position.y,\n },\n });\n });\n removed.forEach((id) => {\n nodes.delete(id);\n // Where it was on L1 and L2 (undoing the delete puts it back there)\n levelLayouts.delete(`1:${id}`);\n levelLayouts.delete(`2:${id}`);\n });\n edges.forEach((edge, id) => {\n if (removed.has(edge.source) || removed.has(edge.target))\n edges.delete(id);\n });\n });\n\n// ---- Comments ----\n// Each thread is a nested Y.Map and its messages a Y.Array, so concurrent replies (and resolving while\n// someone replies) all merge.\n\nexport const readThreads = (doc: Y.Doc) =>\n Array.from(getCanvasMaps(doc).threads.values())\n .map((thread) => thread.toJSON() as Thread)\n .sort((a, b) => a.createdAt - b.createdAt);\n\nconst anchorEntries = (anchor: CommentAnchor): [string, unknown][] => [\n [\"position\", anchor.position],\n ...(anchor.nodeId && anchor.offset\n ? ([\n [\"nodeId\", anchor.nodeId],\n [\"offset\", anchor.offset],\n ] as [string, unknown][])\n : anchor.level\n ? ([[\"level\", anchor.level]] as [string, unknown][])\n : []),\n];\n\n/** Threads as they were (from a saved canvas: their ids, authors and messages kept) */\nexport const addThreads = (doc: Y.Doc, threads: Thread[]) => {\n const { threads: shared } = getCanvasMaps(doc);\n for (const thread of threads) {\n const messages = new Y.Array<Message>();\n messages.push(thread.messages);\n shared.set(\n thread.id,\n new Y.Map<unknown>([\n [\"id\", thread.id],\n ...anchorEntries(thread),\n [\"author\", thread.author],\n [\"createdAt\", thread.createdAt],\n [\"resolved\", thread.resolved],\n [\"messages\", messages],\n ]),\n );\n }\n};\n\nexport const createThread = (\n doc: Y.Doc,\n anchor: CommentAnchor,\n text: string,\n author: Author,\n) => {\n const id = shortId();\n const now = Date.now();\n const messages = new Y.Array<Message>();\n messages.push([{ id: shortId(), text, author, createdAt: now }]);\n const thread = new Y.Map<unknown>([\n [\"id\", id],\n ...anchorEntries(anchor),\n [\"author\", author],\n [\"createdAt\", now],\n [\"resolved\", false],\n [\"messages\", messages],\n ]);\n getCanvasMaps(doc).threads.set(id, thread);\n return id;\n};\n\nconst getThread = (doc: Y.Doc, id: string) =>\n getCanvasMaps(doc).threads.get(id);\n\nexport const replyToThread = (\n doc: Y.Doc,\n threadId: string,\n text: string,\n author: Author,\n) => {\n const messages = getThread(doc, threadId)?.get(\"messages\") as\n | Y.Array<Message>\n | undefined;\n messages?.push([{ id: shortId(), text, author, createdAt: Date.now() }]);\n return !!messages;\n};\n\nexport const setThreadResolved = (\n doc: Y.Doc,\n threadId: string,\n resolved: boolean,\n) => {\n const thread = getThread(doc, threadId);\n thread?.set(\"resolved\", resolved);\n return !!thread;\n};\n\n/** Move a thread's pin, attaching it to a node (anchor.nodeId) or to the canvas */\nexport const moveThread = (\n doc: Y.Doc,\n threadId: string,\n anchor: CommentAnchor,\n) => {\n const thread = getThread(doc, threadId);\n if (!thread) return false;\n doc.transact(() => {\n thread.set(\"position\", anchor.position);\n if (anchor.nodeId && anchor.offset) {\n thread.set(\"nodeId\", anchor.nodeId);\n thread.set(\"offset\", anchor.offset);\n thread.delete(\"level\");\n } else {\n thread.delete(\"nodeId\");\n thread.delete(\"offset\");\n if (anchor.level) thread.set(\"level\", anchor.level);\n else thread.delete(\"level\");\n }\n });\n return true;\n};\n\nexport const deleteThread = (doc: Y.Doc, threadId: string) => {\n const { threads } = getCanvasMaps(doc);\n const exists = threads.has(threadId);\n threads.delete(threadId);\n return exists;\n};\n\n/** Deletes comment threads in one change (one undo brings them all back) */\nexport const deleteThreads = (doc: Y.Doc, threadIds: string[]) =>\n doc.transact(() => threadIds.forEach((id) => deleteThread(doc, id)));\n\n/** Moves comment threads in one change, e.g. ones that moved with what was dragged */\nexport const moveThreads = (\n doc: Y.Doc,\n moves: { threadId: string; anchor: CommentAnchor }[],\n) =>\n doc.transact(() =>\n moves.forEach(({ threadId, anchor }) => moveThread(doc, threadId, anchor)),\n );\n\n// ---- Hotspots ----\n\nexport const readHotspots = (doc: Y.Doc) =>\n Array.from(getCanvasMaps(doc).hotspots.values()).sort(\n (a, b) => a.createdAt - b.createdAt,\n );\n\n/** Hotspots as they were (from a saved canvas, or the agent's diagram) */\nexport const addHotspots = (doc: Y.Doc, hotspots: Hotspot[]) => {\n const { hotspots: shared } = getCanvasMaps(doc);\n doc.transact(() =>\n hotspots.forEach((hotspot) => shared.set(hotspot.id, hotspot)),\n );\n};\n\nexport const createHotspot = (\n doc: Y.Doc,\n hotspot: Omit<Hotspot, \"id\" | \"createdAt\">,\n) => {\n const id = shortId();\n getCanvasMaps(doc).hotspots.set(id, {\n ...hotspot,\n id,\n createdAt: Date.now(),\n });\n return id;\n};\n\n/** Change what a hotspot says (or where it is: on a node, or at a place) */\nexport const updateHotspot = (\n doc: Y.Doc,\n id: string,\n fields: Partial<Omit<Hotspot, \"id\" | \"createdAt\" | \"author\">>,\n) => {\n const { hotspots } = getCanvasMaps(doc);\n const hotspot = hotspots.get(id);\n if (!hotspot) return false;\n const next = { ...hotspot, ...fields };\n // Moved off its node (to a place): not on it any more; and a place on L3 has no level\n if (\"nodeId\" in fields && !fields.nodeId) delete next.nodeId;\n if (\"level\" in fields && !fields.level) delete next.level;\n if (!next.description) delete next.description;\n hotspots.set(id, next);\n return true;\n};\n\nexport const deleteHotspot = (doc: Y.Doc, id: string) => {\n const { hotspots } = getCanvasMaps(doc);\n const exists = hotspots.has(id);\n hotspots.delete(id);\n return exists;\n};\n\n// ---- Reading a whole canvas ----\n\nexport const readCanvas = (doc: Y.Doc) => {\n const { nodes, edges } = getCanvasMaps(doc);\n return {\n meta: readMeta(doc),\n nodes: Array.from(nodes.values()),\n edges: Array.from(edges.values()),\n threads: readThreads(doc),\n hotspots: readHotspots(doc),\n };\n};\n","import type { Connection, Edge, EdgeMarker } from \"@xyflow/react\";\n\n/** Connections on a canvas, labelled with EventCatalog's wording (e.g. \"publishes event\", \"subscribed by\") */\n\n/** Node types that are messages, and their catalog collection */\nexport const MESSAGE_COLLECTIONS: Record<string, string> = {\n event: \"events\",\n command: \"commands\",\n query: \"queries\",\n};\n\nexport const EDGE_COLOR = \"#6b7280\";\nexport const EDGE_MARKER: EdgeMarker = {\n type: \"arrowclosed\",\n color: EDGE_COLOR,\n width: 18,\n height: 18,\n};\n\nconst PRODUCERS = [\n \"service\",\n \"agent\",\n \"actor\",\n \"externalSystem\",\n \"view\",\n // Domains send messages themselves too (`sends` in a domain's frontmatter), as a box or a card. Studio on the\n // web's model only has services sending and receiving (model-canvas.ts), so these edges are labelled but not\n // kept as relations there\n \"domain-group\",\n \"context-domain\",\n];\nconst PRODUCER_LABELS: Record<string, string> = {\n commands: \"invokes\",\n events: \"publishes \\nevent\",\n queries: \"requests\",\n};\nconst MESSAGE_LABELS: Record<string, string> = {\n commands: \"accepts\",\n events: \"subscribed by\",\n queries: \"accepts\",\n};\n\nconst getCollection = (sourceType?: string, targetType?: string) =>\n MESSAGE_COLLECTIONS[sourceType ?? \"\"] ??\n MESSAGE_COLLECTIONS[targetType ?? \"\"];\n\nexport const getEdgeLabel = (sourceType = \"\", targetType = \"\"): string => {\n const sourceCollection = MESSAGE_COLLECTIONS[sourceType];\n const targetCollection = MESSAGE_COLLECTIONS[targetType];\n\n // Who owns what, and the domain model: a team owns what it's connected to, entities are managed and referenced\n if (sourceType === \"team\") return \"owns\";\n if (sourceType === \"entity\" && targetType === \"entity\") return \"references\";\n if (targetType === \"entity\") return sourceCollection ? \"carries\" : \"manages\";\n if (PRODUCERS.includes(sourceType) && targetCollection)\n return PRODUCER_LABELS[targetCollection];\n // One message leading to another (e.g. an event that causes a command)\n if (sourceCollection && targetCollection) return \"triggers\";\n if (sourceCollection && targetType === \"channel\") return \"sent to\";\n if (sourceCollection) return MESSAGE_LABELS[sourceCollection];\n if (sourceType === \"channel\") return \"routes to\";\n if (targetType === \"channel\") return \"publishes to\";\n if (targetType === \"data\") return \"writes to\";\n if (sourceType === \"data\") return \"read by\";\n if (sourceType === \"actor\") return \"uses\";\n if (targetType === \"view\") return \"serves\";\n if (targetType === \"externalSystem\") return \"calls\";\n if (targetType === \"actor\") return \"notifies\";\n return \"\";\n};\n\n/** Message edges get the animated envelope edge from the visualiser, everything else a labelled smooth step edge */\nexport const createEdge = (\n connection: Connection,\n sourceType?: string,\n targetType?: string,\n): Edge => {\n const collection = getCollection(sourceType, targetType);\n return {\n id: `edge-${crypto.randomUUID().slice(0, 8)}`,\n source: connection.source,\n target: connection.target,\n sourceHandle: connection.sourceHandle ?? null,\n targetHandle: connection.targetHandle ?? null,\n type: collection ? \"animated\" : \"smoothstep\",\n label: getEdgeLabel(sourceType, targetType),\n markerEnd: EDGE_MARKER,\n data: collection ? { message: { collection } } : {},\n };\n};\n","import type { Node, XYPosition } from \"@xyflow/react\";\nimport {\n canGoInContainer,\n canHold,\n getNodeSize,\n isGroupType,\n} from \"./node-types\";\n\n/**\n * Containers: domains and systems shown as boxes that other nodes sit in.\n * A node inside one has its parentId, and its position is relative to the container.\n */\n\n/** Room around what's in a container, and for its header */\nexport const GROUP_PADDING = { top: 80, right: 40, bottom: 40, left: 40 };\n\ntype Rect = { x: number; y: number; width: number; height: number };\n\nconst byId = (nodes: Node[]) => new Map(nodes.map((node) => [node.id, node]));\n\n/** A node's size: as rendered (in the browser), as set (containers, notes), or what its type renders at */\nexport const sizeOf = (node: Node) => ({\n width: node.measured?.width ?? node.width ?? getNodeSize(node.type).width,\n height: node.measured?.height ?? node.height ?? getNodeSize(node.type).height,\n});\n\n/** Nodes are positioned relative to their container, so walk up the chain to get the canvas position */\nexport const getAbsolutePosition = (\n node: Node,\n lookup: Map<string, Node>,\n): XYPosition => {\n const parent = node.parentId ? lookup.get(node.parentId) : undefined;\n if (!parent) return node.position;\n const parentPosition = getAbsolutePosition(parent, lookup);\n return {\n x: parentPosition.x + node.position.x,\n y: parentPosition.y + node.position.y,\n };\n};\n\nexport const getAbsoluteRect = (\n node: Node,\n lookup: Map<string, Node>,\n): Rect => ({\n ...getAbsolutePosition(node, lookup),\n ...sizeOf(node),\n});\n\nconst getDepth = (node: Node, lookup: Map<string, Node>): number => {\n const parent = node.parentId ? lookup.get(node.parentId) : undefined;\n return parent ? 1 + getDepth(parent, lookup) : 0;\n};\n\nconst isDescendantOf = (\n node: Node,\n ancestorId: string,\n lookup: Map<string, Node>,\n): boolean => {\n if (!node.parentId) return false;\n if (node.parentId === ancestorId) return true;\n const parent = lookup.get(node.parentId);\n return parent ? isDescendantOf(parent, ancestorId, lookup) : false;\n};\n\nconst containsPoint = (rect: Rect, point: XYPosition) =>\n point.x >= rect.x &&\n point.x <= rect.x + rect.width &&\n point.y >= rect.y &&\n point.y <= rect.y + rect.height;\n\n/** React Flow needs containers before what's in them in the nodes array */\nexport const sortByHierarchy = (nodes: Node[]): Node[] => {\n const lookup = byId(nodes);\n return nodes\n .map((node, index) => ({ node, index, depth: getDepth(node, lookup) }))\n .sort((a, b) => a.depth - b.depth || a.index - b.index)\n .map(({ node }) => node);\n};\n\n/** The innermost container under the centre of a node (never itself, or one of its own children) */\nexport const findDropTarget = (\n nodeId: string,\n nodes: Node[],\n): Node | undefined => {\n const lookup = byId(nodes);\n const node = lookup.get(nodeId);\n // Sticky notes and text go anywhere, never in a container (one that's in one is taken out when it's next moved)\n if (!node || !canGoInContainer(node.type)) return undefined;\n const rect = getAbsoluteRect(node, lookup);\n const center = { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 };\n return nodes\n .filter(\n (candidate) =>\n canHold(candidate.type, node.type) &&\n candidate.id !== nodeId &&\n !isDescendantOf(candidate, nodeId, lookup),\n )\n .filter((candidate) =>\n containsPoint(getAbsoluteRect(candidate, lookup), center),\n )\n .sort((a, b) => getDepth(b, lookup) - getDepth(a, lookup))[0];\n};\n\n/**\n * Where what's dragged goes when it's dropped: the containers it moves into (or out of, with no target), for the\n * ones whose container changes. A selection follows the node held by the pointer: when that one goes into a\n * container, or out of one, everything with it that can go there goes too (sticky notes and text never go in one).\n * When it stays where it is, each one goes into the container under its middle, as one dragged alone does.\n */\nexport const findDropTargets = (\n grabbedId: string,\n draggedIds: Iterable<string>,\n nodes: Node[],\n): { id: string; target: Node | undefined }[] => {\n const lookup = byId(nodes);\n const dragged = new Set(draggedIds);\n // What's moved itself: not what's in a container dragged with it (that moves with its container)\n const roots = [...dragged].filter((id) => {\n const parentId = lookup.get(id)?.parentId;\n return lookup.has(id) && (!parentId || !dragged.has(parentId));\n });\n let held = lookup.get(grabbedId);\n while (held?.parentId && dragged.has(held.parentId))\n held = lookup.get(held.parentId);\n const heldTarget =\n held && canGoInContainer(held.type)\n ? findDropTarget(held.id, nodes)\n : undefined;\n const followHeld =\n !!held && canGoInContainer(held.type) && heldTarget?.id !== held.parentId;\n const canFollow = (node: Node) =>\n canGoInContainer(node.type) &&\n (!heldTarget ||\n (canHold(heldTarget.type, node.type) &&\n heldTarget.id !== node.id &&\n !isDescendantOf(heldTarget, node.id, lookup)));\n return roots.flatMap((id) => {\n const node = lookup.get(id)!;\n const target =\n followHeld && canFollow(node) ? heldTarget : findDropTarget(id, nodes);\n return target?.id === node.parentId ? [] : [{ id, target }];\n });\n};\n\n/** The innermost container at a canvas point, for things dropped there (that can hold a kind of node, when given) */\nexport const findGroupAtPoint = (\n point: XYPosition,\n nodes: Node[],\n type?: string,\n): Node | undefined => {\n const lookup = byId(nodes);\n return nodes\n .filter(\n (candidate) =>\n (type ? canHold(candidate.type, type) : isGroupType(candidate.type)) &&\n containsPoint(getAbsoluteRect(candidate, lookup), point),\n )\n .sort((a, b) => getDepth(b, lookup) - getDepth(a, lookup))[0];\n};\n\n/** The container something added goes in: the one asked for (by id), else the one it's dropped on */\nexport const containerFor = (\n point: XYPosition,\n nodes: Node[],\n inside?: string,\n type?: string,\n): Node | undefined =>\n inside\n ? nodes.find(\n (node) =>\n node.id === inside &&\n (type ? canHold(node.type, type) : isGroupType(node.type)),\n )\n : findGroupAtPoint(point, nodes, type);\n\n/** A node moved into (or out of, without a parentId) a container, staying in the same place on the canvas */\nexport const withParent = (\n node: Node,\n parentId: string | undefined,\n nodes: Node[],\n): Node => {\n const lookup = byId(nodes);\n const absolute = getAbsolutePosition(node, lookup);\n const parent = parentId ? lookup.get(parentId) : undefined;\n const parentPosition = parent\n ? getAbsolutePosition(parent, lookup)\n : { x: 0, y: 0 };\n const { parentId: _, extent: __, ...rest } = node;\n return {\n ...rest,\n ...(parent && { parentId: parent.id }),\n position: {\n x: absolute.x - parentPosition.x,\n y: absolute.y - parentPosition.y,\n },\n };\n};\n\n/** The least room left between something dropped in a container and what's already in it */\nexport const DROP_GAP = 32;\n\n/**\n * How much more moving something out past its container's edges (making it grow) counts than moving it further:\n * more up and left, where the container grows by moving on the canvas (towards what's there), than down and right\n */\nconst GROWTH_COST = { down: 4, up: 12 };\n\nconst overlaps = (a: Rect, b: Rect, gap: number) =>\n a.x < b.x + b.width + gap &&\n b.x < a.x + a.width + gap &&\n a.y < b.y + b.height + gap &&\n b.y < a.y + a.height + gap;\n\n/** How far a rect is past the edges of an area: above and left of it, and below and right of it */\nconst pastEdges = (rect: Rect, area: Rect) => ({\n up: Math.max(0, area.x - rect.x) + Math.max(0, area.y - rect.y),\n down:\n Math.max(0, rect.x + rect.width - (area.x + area.width)) +\n Math.max(0, rect.y + rect.height - (area.y + area.height)),\n});\n\n/** Where a rect goes inside an area, moved as little as it can be (its top left, when it's bigger than the area) */\nconst into = (rect: Rect, area: Rect): XYPosition => ({\n x: Math.max(area.x, Math.min(rect.x, area.x + area.width - rect.width)),\n y: Math.max(area.y, Math.min(rect.y, area.y + area.height - rect.height)),\n});\n\n/**\n * Where a rect goes so it's not on (or within `gap` of) an obstacle: the free place that's the least move from where\n * it is, counting a move out past the area's edges (its container growing) as `GROWTH_COST` times more (more up and\n * left). Looked for by stepping beside what's in the way (right, left, below, above), a few steps deep, from where it\n * is and from there moved into the area. Boxed in: below everything.\n */\nconst freeSpot = (\n rect: Rect,\n obstacles: Rect[],\n area: Rect,\n gap: number,\n): XYPosition => {\n const at = (position: XYPosition) => ({ ...rect, ...position });\n const inTheWay = (position: XYPosition) =>\n obstacles.filter((obstacle) => overlaps(at(position), obstacle, gap));\n const cost = (position: XYPosition) => {\n const past = pastEdges(at(position), area);\n return (\n Math.hypot(position.x - rect.x, position.y - rect.y) +\n GROWTH_COST.up * past.up +\n GROWTH_COST.down * past.down\n );\n };\n const seen = new Set<string>();\n let best: XYPosition | undefined;\n let frontier: XYPosition[] = [];\n const consider = (position: XYPosition) => {\n const key = `${position.x},${position.y}`;\n if (seen.has(key)) return;\n seen.add(key);\n if (best && cost(position) >= cost(best)) return;\n if (inTheWay(position).length) frontier.push(position);\n else best = position;\n };\n consider({ x: rect.x, y: rect.y });\n consider(into(rect, area));\n for (let depth = 0; depth < 4 && frontier.length; depth++) {\n const from = frontier.sort((a, b) => cost(a) - cost(b)).slice(0, 24);\n frontier = [];\n for (const position of from) {\n for (const obstacle of inTheWay(position)) {\n consider({ x: obstacle.x + obstacle.width + gap, y: position.y });\n consider({ x: obstacle.x - gap - rect.width, y: position.y });\n consider({ x: position.x, y: obstacle.y + obstacle.height + gap });\n consider({ x: position.x, y: obstacle.y - gap - rect.height });\n }\n }\n }\n return (\n best ?? {\n x: rect.x,\n y: Math.max(\n ...obstacles.map((obstacle) => obstacle.y + obstacle.height + gap),\n ),\n }\n );\n};\n\n/**\n * Where things dropped in containers go in them (relative to the container): where they were dropped when that's\n * free and inside it, else the nearest free place, keeping inside the container (so it doesn't grow over what's around\n * it) unless there's no room. What's dropped stays clear of what's in the container and of each other. `moves` are\n * what `findDropTargets` returns; ones taken out of a container aren't placed (they stay where they were dropped).\n * `nudged` when any had to move from where it was dropped (to show it gliding there).\n */\nexport const placeDropped = (\n nodes: Node[],\n moves: { id: string; target: Node | undefined }[],\n gap = DROP_GAP,\n): { places: Map<string, XYPosition>; nudged: boolean } => {\n const lookup = byId(nodes);\n const places = new Map<string, XYPosition>();\n let nudged = false;\n const moved = new Set(moves.map(({ id }) => id));\n const byTarget = new Map<string, string[]>();\n for (const { id, target } of moves) {\n if (target)\n byTarget.set(target.id, [...(byTarget.get(target.id) ?? []), id]);\n }\n for (const [targetId, ids] of byTarget) {\n const container = lookup.get(targetId)!;\n const size = sizeOf(container);\n // Inside its padding, under its header\n const area = {\n x: GROUP_PADDING.left,\n y: GROUP_PADDING.top,\n width: Math.max(0, size.width - GROUP_PADDING.left - GROUP_PADDING.right),\n height: Math.max(\n 0,\n size.height - GROUP_PADDING.top - GROUP_PADDING.bottom,\n ),\n };\n const obstacles = nodes\n .filter((node) => node.parentId === targetId && !moved.has(node.id))\n .map((node) => ({ ...node.position, ...sizeOf(node) }));\n const dropped = ids.flatMap((id) => {\n const node = lookup.get(id);\n if (!node) return [];\n const inside = withParent(node, targetId, nodes);\n return [{ id, rect: { ...inside.position, ...sizeOf(node) } }];\n });\n // What's dropped in a free place inside it first, so it keeps that place and the rest go round it\n const settled = (rect: Rect) => {\n const past = pastEdges(rect, area);\n return (\n !past.up &&\n !past.down &&\n !obstacles.some((obstacle) => overlaps(rect, obstacle, gap))\n );\n };\n dropped.sort((a, b) => Number(settled(b.rect)) - Number(settled(a.rect)));\n for (const { id, rect } of dropped) {\n const spot = freeSpot(rect, obstacles, area, gap);\n if (spot.x !== rect.x || spot.y !== rect.y) nudged = true;\n places.set(id, spot);\n obstacles.push({ ...rect, ...spot });\n }\n }\n return { places, nudged };\n};\n\n/** A canvas point, relative to a container */\nexport const toRelativePosition = (\n point: XYPosition,\n parentId: string,\n nodes: Node[],\n): XYPosition => {\n const lookup = byId(nodes);\n const parent = lookup.get(parentId);\n if (!parent) return point;\n const parentPosition = getAbsolutePosition(parent, lookup);\n return { x: point.x - parentPosition.x, y: point.y - parentPosition.y };\n};\n\n/** Nodes and everything inside them (deleted with their container) */\nexport const withDescendants = (ids: string[], nodes: Node[]): Set<string> => {\n const lookup = byId(nodes);\n const result = new Set(ids);\n nodes.forEach((node) => {\n if (ids.some((id) => isDescendantOf(node, id, lookup))) result.add(node.id);\n });\n return result;\n};\n\n/**\n * The size a container needs to fit what's inside it, never smaller than it is, and how far its children\n * must shift when some sit above or left of its content area (so the header stays clear).\n */\nexport const fitGroup = (groupId: string, nodes: Node[]) => {\n const lookup = byId(nodes);\n const group = lookup.get(groupId);\n const children = nodes.filter((node) => node.parentId === groupId);\n if (!group || children.length === 0) return undefined;\n const rects = children.map((child) => ({\n ...child.position,\n ...sizeOf(child),\n }));\n const shift = {\n x: Math.max(\n 0,\n GROUP_PADDING.left - Math.min(...rects.map((rect) => rect.x)),\n ),\n y: Math.max(\n 0,\n GROUP_PADDING.top - Math.min(...rects.map((rect) => rect.y)),\n ),\n };\n const current = sizeOf(group);\n return {\n shift,\n width: Math.max(\n current.width,\n Math.max(...rects.map((rect) => rect.x + rect.width)) +\n shift.x +\n GROUP_PADDING.right,\n ),\n height: Math.max(\n current.height,\n Math.max(...rects.map((rect) => rect.y + rect.height)) +\n shift.y +\n GROUP_PADDING.bottom,\n ),\n };\n};\n\n/** How far a dragged node's middle can go past a container's edge and still be kept in it (growing it) */\nexport const KEEP_IN_CONTAINER_MARGIN = 160;\n\n/** A node's place and size as shown while something's dragged */\nexport type NodePreview = {\n position: XYPosition;\n width?: number;\n height?: number;\n};\n\n/**\n * Containers growing to fit what's being dragged in them, on every side, as a preview of where things will be.\n * `containerIds` are the containers around what's dragged, innermost first. `start` is the canvas when the drag\n * started, and `now` the canvas as shown (with the dragged nodes where they are now). A dragged node is kept in a\n * container while its middle is within `KEEP_IN_CONTAINER_MARGIN` of where the container was, and dropping it\n * further away takes it out, so the container goes back to its size. A container growing up or left moves, and\n * what's in it moves the other way, so nothing moves on the canvas.\n *\n * Returns, by id, where containers and the nodes in them that aren't dragged go (positions relative to their\n * containers), and their sizes for containers.\n */\nexport const previewContainerGrowth = (\n containerIds: string[],\n draggedIds: ReadonlySet<string>,\n start: ReadonlyMap<string, Node>,\n now: ReadonlyMap<string, Node>,\n): Map<string, NodePreview> => {\n const previews = new Map<string, NodePreview>();\n // Where each container's top left was on the canvas when the drag started (moving a container grown up or\n // left is offset by what's in it moving the other way, so only its own shift changes it)\n const startOrigin = (id: string) =>\n getAbsolutePosition(start.get(id)!, start as Map<string, Node>);\n const shifts = new Map<string, XYPosition>();\n\n for (const id of containerIds) {\n const container = start.get(id);\n if (!container) continue;\n const origin = startOrigin(id);\n const startSize = sizeOf(container);\n // Everything in it, in its coordinates when the drag started\n const items: { rect: Rect }[] = [];\n for (const node of start.values()) {\n if (node.parentId !== id) continue;\n if (draggedIds.has(node.id)) {\n const current = now.get(node.id);\n if (!current) continue;\n const at = getAbsoluteRect(current, now as Map<string, Node>);\n const middle = { x: at.x + at.width / 2, y: at.y + at.height / 2 };\n const kept =\n middle.x >= origin.x - KEEP_IN_CONTAINER_MARGIN &&\n middle.x <= origin.x + startSize.width + KEEP_IN_CONTAINER_MARGIN &&\n middle.y >= origin.y - KEEP_IN_CONTAINER_MARGIN &&\n middle.y <= origin.y + startSize.height + KEEP_IN_CONTAINER_MARGIN;\n if (kept)\n items.push({\n rect: { ...at, x: at.x - origin.x, y: at.y - origin.y },\n });\n continue;\n }\n // A container inside it that's grown: where it's grown to\n const inner = previews.get(node.id);\n const innerShift = shifts.get(node.id) ?? { x: 0, y: 0 };\n items.push({\n rect: {\n x: node.position.x - innerShift.x,\n y: node.position.y - innerShift.y,\n ...(inner?.width && inner.height\n ? { width: inner.width, height: inner.height }\n : sizeOf(node)),\n },\n });\n }\n\n const shift = { x: 0, y: 0 };\n let width = startSize.width;\n let height = startSize.height;\n if (items.length > 0) {\n shift.x = Math.max(\n 0,\n GROUP_PADDING.left - Math.min(...items.map(({ rect }) => rect.x)),\n );\n shift.y = Math.max(\n 0,\n GROUP_PADDING.top - Math.min(...items.map(({ rect }) => rect.y)),\n );\n width =\n Math.max(\n startSize.width,\n Math.max(...items.map(({ rect }) => rect.x + rect.width)) +\n GROUP_PADDING.right,\n ) + shift.x;\n height =\n Math.max(\n startSize.height,\n Math.max(...items.map(({ rect }) => rect.y + rect.height)) +\n GROUP_PADDING.bottom,\n ) + shift.y;\n }\n shifts.set(id, shift);\n previews.set(id, {\n position: {\n x: container.position.x - shift.x,\n y: container.position.y - shift.y,\n },\n width,\n height,\n });\n // What's in it moves the other way. Not what's dragged: React Flow places it against the container as it is.\n for (const node of start.values()) {\n if (node.parentId !== id || draggedIds.has(node.id)) continue;\n const own = previews.get(node.id);\n const base = own?.position ?? node.position;\n previews.set(node.id, {\n ...own,\n position: { x: base.x + shift.x, y: base.y + shift.y },\n });\n }\n }\n return previews;\n};\n","import type { Edge, Node, XYPosition } from \"@xyflow/react\";\nimport { shortId, toSharedNode } from \"./canvas-doc\";\nimport {\n findGroupAtPoint,\n getAbsolutePosition,\n sizeOf,\n sortByHierarchy,\n withDescendants,\n} from \"./grouping\";\nimport { canGoInContainer } from \"./node-types\";\n\n/**\n * Copying and pasting nodes, within a canvas or between canvases (through the system clipboard). What's copied is\n * the selected nodes, everything inside selected containers, and the connections between them. Comments aren't.\n */\n\n/** The clipboard type Studio reads first (other apps get a plain text list of what was copied) */\nexport const CLIPBOARD_TYPE = \"application/x-eventcatalog-studio+json\";\nconst MARKER = \"eventcatalog-studio/nodes@1\";\n\nexport type ClipboardContent = {\n marker: typeof MARKER;\n nodes: Node[];\n edges: Edge[];\n};\n\n/** What's copied when these nodes are selected, or null if there's nothing to copy */\nexport const copyNodes = (\n nodes: Node[],\n edges: Edge[],\n selectedIds: string[],\n): ClipboardContent | null => {\n if (selectedIds.length === 0) return null;\n const lookup = new Map(nodes.map((node) => [node.id, node]));\n const ids = withDescendants(selectedIds, nodes);\n const copied = sortByHierarchy(nodes.filter((node) => ids.has(node.id))).map(\n (node) => {\n const shared = toSharedNode(node);\n // Copied without its container: where it is on the canvas\n if (shared.parentId && !ids.has(shared.parentId)) {\n const { parentId: _, ...rest } = shared;\n return { ...rest, position: getAbsolutePosition(node, lookup) };\n }\n return shared;\n },\n );\n return {\n marker: MARKER,\n nodes: copied,\n edges: edges\n .filter((edge) => ids.has(edge.source) && ids.has(edge.target))\n .map(({ selected: _, ...edge }) => edge),\n };\n};\n\n/** Copied content read back from the clipboard, if it's Studio's */\nexport const readClipboard = (\n text: string | undefined,\n): ClipboardContent | null => {\n if (!text) return null;\n try {\n const content = JSON.parse(text) as Partial<ClipboardContent>;\n return content.marker === MARKER &&\n Array.isArray(content.nodes) &&\n Array.isArray(content.edges)\n ? (content as ClipboardContent)\n : null;\n } catch {\n return null;\n }\n};\n\n/**\n * Copies of the content to add to the canvas, with new ids: centred on a point (e.g. the pointer), or moved by an\n * offset from where they were copied. Copies that land in a container on the canvas go inside it.\n */\nexport const pasteNodes = (\n content: ClipboardContent,\n existing: Node[],\n place: { at: XYPosition } | { offset: XYPosition },\n): { nodes: Node[]; edges: Edge[] } => {\n const ids = new Map(\n content.nodes.map((node) => [\n node.id,\n `${node.type ?? \"node\"}-${shortId()}`,\n ]),\n );\n const roots = content.nodes.filter((node) => !node.parentId);\n const offset =\n \"offset\" in place ? place.offset : offsetToCentre(roots, place.at);\n\n const lookup = new Map(existing.map((node) => [node.id, node]));\n const nodes = content.nodes.map((node): Node => {\n const id = ids.get(node.id)!;\n if (node.parentId) return { ...node, id, parentId: ids.get(node.parentId) };\n const position = {\n x: node.position.x + offset.x,\n y: node.position.y + offset.y,\n };\n const { width, height } = sizeOf(node);\n const container = canGoInContainer(node.type)\n ? findGroupAtPoint(\n { x: position.x + width / 2, y: position.y + height / 2 },\n existing,\n )\n : undefined;\n if (!container) return { ...node, id, position };\n const origin = getAbsolutePosition(container, lookup);\n return {\n ...node,\n id,\n parentId: container.id,\n position: { x: position.x - origin.x, y: position.y - origin.y },\n };\n });\n\n return {\n nodes,\n edges: content.edges.map((edge) => ({\n ...edge,\n id: `edge-${shortId()}`,\n source: ids.get(edge.source)!,\n target: ids.get(edge.target)!,\n })),\n };\n};\n\n/** How far to move nodes so the middle of them is at a point */\nconst offsetToCentre = (roots: Node[], at: XYPosition): XYPosition => {\n if (roots.length === 0) return { x: 0, y: 0 };\n const left = Math.min(...roots.map((node) => node.position.x));\n const top = Math.min(...roots.map((node) => node.position.y));\n const right = Math.max(\n ...roots.map((node) => node.position.x + sizeOf(node).width),\n );\n const bottom = Math.max(\n ...roots.map((node) => node.position.y + sizeOf(node).height),\n );\n return { x: at.x - (left + right) / 2, y: at.y - (top + bottom) / 2 };\n};\n","import type { Connection, NodeChange, XYPosition } from \"@xyflow/react\";\nimport { getEdgeLabel } from \"./edges\";\nimport type { Level } from \"./levels\";\nimport {\n componentKey,\n getNodeDefinition,\n GROUP_TYPES,\n isShownOnLevel,\n isWrittenOnCanvas,\n NODE_CATEGORIES,\n nodeDefinitions,\n type NodeCategory,\n} from \"./node-types\";\n\n/**\n * A connection dragged from a node and let go of on empty canvas: a placeholder is put where it was let go of, and\n * what it is is chosen from a list (as Miro's and n8n's do), so connecting something new doesn't need the palette.\n */\n\n/** The placeholder's node type and id (only ever in this browser, never in the document) */\nexport const CONNECT_PLACEHOLDER = \"connect-placeholder\";\nexport const CONNECT_PLACEHOLDER_EDGE = \"connect-placeholder-edge\";\nexport const CONNECT_PLACEHOLDER_SIZE = { width: 200, height: 66 };\n\n/** The placeholder is only in this browser, shown to React Flow: none of its changes (measured, hovered) go anywhere */\nexport const notPlaceholder = (change: NodeChange) =>\n change.type === \"add\" || change.id !== CONNECT_PLACEHOLDER;\n\n/** The end of the connection on the node it was dragged from, and which end the new node is */\nexport type NewLink = {\n nodeId: string;\n handleId: string | null;\n /** The new node is the connection's target (dragged from a node's source handle), or its source */\n newIs: \"source\" | \"target\";\n};\n\n/** The connection between a new node and the node it was dragged from */\nexport const linkConnection = (newId: string, link: NewLink): Connection =>\n link.newIs === \"target\"\n ? {\n source: link.nodeId,\n sourceHandle: link.handleId,\n target: newId,\n targetHandle: null,\n }\n : {\n source: newId,\n sourceHandle: null,\n target: link.nodeId,\n targetHandle: link.handleId,\n };\n\nexport type ConnectOption = {\n /** Its key in the components list (what's added) */\n key: string;\n /** The node type it becomes (domains and systems become cards: they connect, containers hold) */\n type: string;\n label: string;\n summary?: string;\n category: NodeCategory;\n /** What the connection says (EventCatalog's wording, e.g. \"publishes event\"), when it has a word for it */\n says: string;\n};\n\nconst DOMAIN_CARD = \"context-domain\";\nconst SYSTEM_CARD = \"system\";\ntype CardType = typeof DOMAIN_CARD | typeof SYSTEM_CARD;\n\n/** Domains and systems added from a connection are cards: that's how they're connected on every level */\nexport const connectedType = (type: string) =>\n type === GROUP_TYPES.domain\n ? DOMAIN_CARD\n : type === GROUP_TYPES.system\n ? SYSTEM_CARD\n : type;\n\n/** A domain's or system's card (the visualiser's), rather than a container */\nexport const isCardType = (type: string | undefined): type is CardType =>\n type === DOMAIN_CARD || type === SYSTEM_CARD;\n\n/** A new domain or system card's data: the new domain or system its container would be, shown in full */\nexport const newCardData = (type: CardType): Record<string, unknown> => ({\n mode: \"full\",\n navigable: false,\n ...getNodeDefinition(\n type === DOMAIN_CARD ? GROUP_TYPES.domain : GROUP_TYPES.system,\n )!.createData(),\n});\n\nconst categoryOrder = new Map(\n NODE_CATEGORIES.map((category, index) => [category.id, index]),\n);\n\n/**\n * What can be made at the end of a connection from a node of `fromType`: everything the level shows (not notes or\n * text, which don't connect), the ones EventCatalog has a word for first (e.g. from a service: events, commands,\n * data stores), each group in the palette's order\n */\nexport const getConnectOptions = (\n fromType: string | undefined,\n newIs: NewLink[\"newIs\"],\n level: Level,\n): ConnectOption[] =>\n nodeDefinitions\n .filter(\n (definition) =>\n !definition.unlisted &&\n !isWrittenOnCanvas(definition.type) &&\n isShownOnLevel(definition.type, level),\n )\n .map((definition) => {\n const type = connectedType(definition.type);\n const says =\n newIs === \"target\"\n ? getEdgeLabel(fromType, type)\n : getEdgeLabel(type, fromType);\n return {\n key: componentKey(definition),\n type,\n label: definition.label,\n summary: definition.summary,\n category: definition.category,\n says: says.replace(/\\s+/g, \" \").trim(),\n };\n })\n .sort(\n (a, b) =>\n Number(!a.says) - Number(!b.says) ||\n (categoryOrder.get(a.category) ?? 0) -\n (categoryOrder.get(b.category) ?? 0),\n );\n\n/** The options that match what's typed (by name, what it is, or what the connection says) */\nexport const filterConnectOptions = (\n options: ConnectOption[],\n query: string,\n) => {\n const words = query.toLowerCase().split(/\\s+/).filter(Boolean);\n if (!words.length) return options;\n return options.filter((option) => {\n const text =\n `${option.label} ${option.summary ?? \"\"} ${option.says}`.toLowerCase();\n return words.every((word) => text.includes(word));\n });\n};\n\n/** How far a connection's dragged (on the canvas) before letting go of it makes something new: closer is a click */\nexport const CONNECT_MIN_DISTANCE = 40;\nexport const isAwayFrom = (from: XYPosition, to: XYPosition) =>\n Math.hypot(to.x - from.x, to.y - from.y) >= CONNECT_MIN_DISTANCE;\n\n/**\n * Whether a point on screen is empty canvas in a canvas: not a node (containers let the pointer through their body),\n * an edge or a label counts as canvas (nodes are inside React Flow's pane too)\n */\nexport const isEmptyCanvasAt = (\n point: { x: number; y: number },\n canvas: Element | null | undefined,\n) => {\n const under = document.elementFromPoint(point.x, point.y);\n return (\n !!under?.closest(\".react-flow__pane\") &&\n !under.closest(\".react-flow__node\") &&\n !!canvas?.contains(under)\n );\n};\n\n/**\n * Where a new node goes: its near side where the connection was let go of, out the way it was dragged (to the\n * right of a node, it starts there and grows right; above it, it ends there)\n */\nexport const centreBeyond = (\n from: XYPosition,\n to: XYPosition,\n size: { width: number; height: number },\n): XYPosition => {\n const dx = to.x - from.x;\n const dy = to.y - from.y;\n if (Math.abs(dx) >= Math.abs(dy))\n return { x: to.x + Math.sign(dx || 1) * (size.width / 2), y: to.y };\n return { x: to.x, y: to.y + Math.sign(dy) * (size.height / 2) };\n};\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type RefObject,\n} from \"react\";\nimport {\n useReactFlow,\n type Edge,\n type FinalConnectionState,\n type Node,\n type XYPosition,\n} from \"@xyflow/react\";\nimport {\n centreBeyond,\n CONNECT_PLACEHOLDER,\n CONNECT_PLACEHOLDER_EDGE,\n CONNECT_PLACEHOLDER_SIZE,\n getConnectOptions,\n isAwayFrom,\n isEmptyCanvasAt,\n linkConnection,\n type ConnectOption,\n type NewLink,\n} from \"./connect-new\";\nimport type { ConnectPlaceholderData } from \"./components/ConnectChooser\";\nimport type { Level } from \"./levels\";\nimport { getNodeName, getNodeSize } from \"./node-types\";\n\n/**\n * Connecting to something new, for both Studios' canvases: a connection let go of on empty canvas puts a placeholder\n * there (connected to the node it came from, only in this browser) and a list beside it (ConnectChooser) to choose\n * what it is. The canvas makes what's chosen (`onMake`), where the placeholder was.\n */\n\n/** A connection let go of on empty canvas: from where to where (canvas coordinates), and what can be made there */\ntype Connecting = {\n link: NewLink;\n fromName?: string;\n options: ConnectOption[];\n from: XYPosition;\n to: XYPosition;\n choice?: ConnectOption;\n};\n\nconst PLACEHOLDER_EDGE_STYLE = {\n stroke: \"rgb(var(--ec-accent))\",\n strokeWidth: 1.5,\n strokeDasharray: \"6 4\",\n};\n\n/** Where the placeholder is on the canvas: centred as the node it becomes is (see centreBeyond) */\nconst placeholderPosition = ({ from, to }: Connecting): XYPosition => {\n const center = centreBeyond(from, to, CONNECT_PLACEHOLDER_SIZE);\n return {\n x: center.x - CONNECT_PLACEHOLDER_SIZE.width / 2,\n y: center.y - CONNECT_PLACEHOLDER_SIZE.height / 2,\n };\n};\n\nexport function useConnectNew({\n canvasRef,\n getNode,\n getLevel,\n locked,\n onMake,\n}: {\n /** The canvas: a connection's let go of on empty canvas inside it */\n canvasRef: RefObject<HTMLElement | null>;\n /** A node on the canvas people edit, by id (on L1 and L2 too, what's shown is on it): connections start there */\n getNode: (id: string) => Node | undefined;\n getLevel: () => Level;\n /** Locked: nothing's made (and what's waiting to be chosen goes) */\n locked: boolean;\n /** Makes what was chosen, centred on `center`, connected by `link` (in the same change, so one undo takes both) */\n onMake: (option: ConnectOption, center: XYPosition, link: NewLink) => void;\n}) {\n const { screenToFlowPosition, flowToScreenPosition } = useReactFlow();\n const [connecting, setConnecting] = useState<Connecting | null>(null);\n // Read when the connection ends, not followed: the handlers stay the same\n const latest = useRef({ getNode, getLevel, locked, onMake, connecting });\n latest.current = { getNode, getLevel, locked, onMake, connecting };\n // Dragging an end of a connection already there: React Flow ends it with onConnectEnd too (before onReconnectEnd),\n // and let go of away from a node, it stays as it was\n const reconnecting = useRef(false);\n const onReconnectStart = useCallback(() => {\n reconnecting.current = true;\n }, []);\n const onReconnectEnd = useCallback(() => {\n reconnecting.current = false;\n }, []);\n\n const onConnectEnd = useCallback(\n (event: MouseEvent | TouchEvent, state: FinalConnectionState) => {\n const { fromNode, fromHandle } = state;\n if (\n latest.current.locked ||\n reconnecting.current ||\n state.isValid ||\n state.toNode ||\n !fromNode ||\n !fromHandle\n )\n return;\n const from = latest.current.getNode(fromNode.id);\n if (!from) return;\n const { clientX, clientY } =\n \"changedTouches\" in event ? event.changedTouches[0] : event;\n // Let go of on empty canvas, away from where it started (closer is a click on the handle)\n const to = screenToFlowPosition({ x: clientX, y: clientY });\n if (\n !isAwayFrom(state.from, to) ||\n !isEmptyCanvasAt({ x: clientX, y: clientY }, canvasRef.current)\n )\n return;\n const newIs = fromHandle.type === \"source\" ? \"target\" : \"source\";\n const options = getConnectOptions(\n from.type,\n newIs,\n latest.current.getLevel(),\n );\n if (!options.length) return;\n setConnecting({\n link: { nodeId: from.id, handleId: fromHandle.id ?? null, newIs },\n fromName: getNodeName(from.type, from.data),\n options,\n from: state.from,\n to,\n });\n },\n [screenToFlowPosition, canvasRef],\n );\n\n /** The placeholder node and its connection, to show with the canvas's (nothing while nothing's waiting) */\n const placeholder = useMemo(() => {\n if (!connecting) return null;\n const { choice } = connecting;\n const data: ConnectPlaceholderData = {\n choice: choice && {\n key: choice.key,\n label: choice.label,\n summary: choice.summary,\n },\n };\n const node: Node = {\n id: CONNECT_PLACEHOLDER,\n type: CONNECT_PLACEHOLDER,\n position: placeholderPosition(connecting),\n data,\n draggable: false,\n selectable: false,\n connectable: false,\n focusable: false,\n deletable: false,\n zIndex: 1000,\n };\n const edge: Edge = {\n id: CONNECT_PLACEHOLDER_EDGE,\n ...linkConnection(CONNECT_PLACEHOLDER, connecting.link),\n type: \"smoothstep\",\n style: PLACEHOLDER_EDGE_STYLE,\n selectable: false,\n focusable: false,\n deletable: false,\n };\n return { node, edge };\n }, [connecting]);\n\n const highlight = useCallback(\n (choice: ConnectOption | undefined) =>\n setConnecting((current) =>\n current && current.choice?.key !== choice?.key\n ? { ...current, choice }\n : current,\n ),\n [],\n );\n const cancel = useCallback(() => setConnecting(null), []);\n const choose = useCallback((option: ConnectOption) => {\n const { connecting: at, locked: isLocked, onMake: make } = latest.current;\n setConnecting(null);\n if (!at || isLocked) return;\n // Its near side where the connection was let go of\n make(\n option,\n centreBeyond(at.from, at.to, getNodeSize(option.type)),\n at.link,\n );\n }, []);\n\n useEffect(() => {\n if (locked) setConnecting(null);\n }, [locked]);\n\n /** ConnectChooser's props, beside the placeholder on screen (nothing while nothing's waiting) */\n let chooser = null;\n if (connecting && placeholder) {\n const { x, y } = placeholder.node.position;\n const start = flowToScreenPosition({ x, y });\n const end = flowToScreenPosition({\n x: x + CONNECT_PLACEHOLDER_SIZE.width,\n y: y + CONNECT_PLACEHOLDER_SIZE.height,\n });\n chooser = {\n options: connecting.options,\n fromName: connecting.fromName,\n anchor: {\n x: start.x,\n y: start.y,\n width: end.x - start.x,\n height: end.y - start.y,\n },\n onHighlight: highlight,\n onChoose: choose,\n onCancel: cancel,\n };\n }\n\n return {\n placeholder,\n chooser,\n onConnectEnd,\n onReconnectStart,\n onReconnectEnd,\n cancel,\n };\n}\n","/**\n * Where a connection joins an entity: a property's row (the visualiser's `<property>-target` on its left and\n * `<property>-source` on its right), or the entity as a whole: its header (the visualiser's target there, and a\n * source the canvas adds beside it).\n */\nexport const ENTITY_SOURCE_HANDLE = \"__entity-source\";\n","import type { Edge, Node, XYPosition } from \"@xyflow/react\";\n\n/**\n * The design (nodes and edges) comes from the shared document; some state stays with each person: what they\n * have selected, what they're dragging and resizing, and the sizes React Flow measured in their browser.\n */\nexport const LOCAL_NODE_KEYS = [\n \"selected\",\n \"dragging\",\n \"resizing\",\n \"measured\",\n] as const satisfies readonly (keyof Node)[];\nexport const LOCAL_EDGE_KEYS = [\n \"selected\",\n] as const satisfies readonly (keyof Edge)[];\n\n/** A shared item with the local-only state of the one already shown. Nothing else is kept from the local one. */\nexport const withLocalState = <T extends object>(\n shared: T,\n local: T | undefined,\n localKeys: readonly (keyof T)[],\n): T => {\n if (!local) return shared;\n const kept: Partial<T> = {};\n for (const key of localKeys)\n if (local[key] !== undefined) kept[key] = local[key];\n return { ...shared, ...kept };\n};\n\n/**\n * Applies changes to shared items (by id) to the items shown, keeping every unchanged item as the same object\n * (so React Flow doesn't re-render it) and the order they were first seen in (new ones go at the end).\n * `getShared` returns an item's shared value, or undefined if it was deleted. Returns `local` itself when\n * nothing changed.\n */\nexport const patchShared = <T extends { id: string }>(\n local: T[],\n changedIds: Iterable<string>,\n getShared: (id: string) => T | undefined,\n localKeys: readonly (keyof T)[],\n): T[] => {\n const indexById = new Map(local.map((item, index) => [item.id, index]));\n let next: T[] | undefined;\n const removed = new Set<string>();\n const added: T[] = [];\n\n for (const id of changedIds) {\n const shared = getShared(id);\n const index = indexById.get(id);\n if (!shared) {\n if (index !== undefined) removed.add(id);\n continue;\n }\n if (index === undefined) {\n added.push(shared);\n continue;\n }\n next ??= [...local];\n next[index] = withLocalState(shared, local[index], localKeys);\n }\n\n if (!next && removed.size === 0 && added.length === 0) return local;\n const patched = next ?? local;\n return [\n ...(removed.size\n ? patched.filter((item) => !removed.has(item.id))\n : patched),\n ...added,\n ];\n};\n\n/** Whether two plain values (what nodes and edges hold) are the same, comparing what's in them */\nconst isSame = (a: unknown, b: unknown): boolean => {\n if (Object.is(a, b)) return true;\n if (\n !a ||\n !b ||\n typeof a !== \"object\" ||\n typeof b !== \"object\" ||\n Array.isArray(a) !== Array.isArray(b)\n )\n return false;\n const keys = Object.keys(a);\n return (\n keys.length === Object.keys(b).length &&\n keys.every((key) =>\n isSame(\n (a as Record<string, unknown>)[key],\n (b as Record<string, unknown>)[key],\n ),\n )\n );\n};\n\n/**\n * Items worked out again (e.g. a level arranged again), keeping each one that hasn't changed as the object already\n * shown (so React Flow doesn't re-render it), and the local-only state of the ones that have. Returns `previous`\n * itself when nothing changed.\n */\nexport const keepUnchanged = <T extends { id: string }>(\n previous: T[],\n next: T[],\n localKeys: readonly (keyof T)[],\n): T[] => {\n const shown = new Map(previous.map((item) => [item.id, item]));\n const local = new Set<PropertyKey>(localKeys);\n const kept = next.map((item) => {\n const before = shown.get(item.id);\n if (!before) return item;\n const keys = new Set([...Object.keys(before), ...Object.keys(item)]) as Set<\n keyof T\n >;\n const same = [...keys].every(\n (key) => local.has(key) || isSame(before[key], item[key]),\n );\n return same ? before : withLocalState(item, before, localKeys);\n });\n return kept.length === previous.length &&\n kept.every((item, index) => item === previous[index])\n ? previous\n : kept;\n};\n\n/** Where nodes being dragged are, by id, until they're dropped (and saved) */\nexport type Moves = ReadonlyMap<string, XYPosition>;\n\nconst samePosition = (a: XYPosition, b: XYPosition) =>\n a.x === b.x && a.y === b.y;\n\n/**\n * Nodes moved to the positions given (e.g. where someone else is dragging them), except ones being dragged\n * here. Returns `nodes` itself when none move.\n */\nexport const withPositions = (nodes: Node[], positions: Moves): Node[] => {\n if (positions.size === 0) return nodes;\n let next: Node[] | undefined;\n nodes.forEach((node, index) => {\n const position = positions.get(node.id);\n if (!position || node.dragging || samePosition(position, node.position))\n return;\n next ??= [...nodes];\n next[index] = { ...node, position };\n });\n return next ?? nodes;\n};\n\n/**\n * After shared changes are applied (`next`, from `previous`): nodes being dragged here stay where they're being\n * dragged (when they're dropped, the drop is saved and wins). Returns `next` itself when none are.\n */\nexport const keepDragged = (next: Node[], previous: Node[]): Node[] => {\n if (next === previous) return next;\n const dragged = new Map(\n previous\n .filter((node) => node.dragging)\n .map((node) => [node.id, node.position]),\n );\n if (dragged.size === 0) return next;\n let kept: Node[] | undefined;\n next.forEach((node, index) => {\n const position = dragged.get(node.id);\n if (!position || samePosition(position, node.position)) return;\n kept ??= [...next];\n kept[index] = { ...node, position };\n });\n return kept ?? next;\n};\n","import type { Edge, Node, XYPosition } from \"@xyflow/react\";\nimport { layoutWithElk } from \"../layout\";\nimport { getEdgeRoute, type EdgeRoute } from \"./canvas-doc\";\nimport { isGroupType, isOnLevel } from \"./node-types\";\n\n/**\n * Lays a canvas out with the same ELK layout as EventCatalog's visualiser (left to right, edges routed\n * around nodes, containers laid out with what's in them and sized to fit). Nodes are sized as rendered when\n * they have been (in the browser), or by their type.\n */\nexport const layoutGraph = (nodes: Node[], edges: Edge[]) =>\n layoutWithElk({ nodes, edges });\n\n/** The layout sizes containers with style.width/height; the canvas sizes them with width/height */\nexport const withGroupSizes = (nodes: Node[]): Node[] =>\n nodes.map((node) => {\n const { width, height, ...style } = node.style ?? {};\n if (typeof width !== \"number\" || typeof height !== \"number\") return node;\n return { ...node, width, height, style };\n });\n\nexport type LayoutResult = {\n /** Where each node goes (relative to its container, if it's in one), and containers' new sizes */\n nodes: Map<\n string,\n { position: XYPosition; size?: { width: number; height: number } }\n >;\n /** How each connection is drawn (around the nodes), by edge id */\n routes: Map<string, EdgeRoute>;\n};\n\n/**\n * The canvas laid out: new positions for its nodes, new sizes for containers, and routes for the connections\n * (drawn like the visualiser's: around the nodes, following them when they're moved, and as a plain step once\n * they've moved too far for it). Notes added on L1 or L2 aren't on this canvas, so they stay where they are.\n */\nexport const getLayoutPositions = async (\n nodes: Node[],\n edges: Edge[],\n): Promise<LayoutResult> => {\n const onCanvas = nodes.filter((node) => isOnLevel(node, 3));\n if (onCanvas.length === 0) return { nodes: new Map(), routes: new Map() };\n const ids = new Set(onCanvas.map((node) => node.id));\n const between = edges.filter(\n (edge) => ids.has(edge.source) && ids.has(edge.target),\n );\n const laidOut = await layoutGraph(onCanvas, between);\n return {\n nodes: new Map(\n withGroupSizes(laidOut.nodes).map((node) => [\n node.id,\n {\n position: node.position,\n ...(isGroupType(node.type) &&\n node.width &&\n node.height && {\n size: { width: node.width, height: node.height },\n }),\n },\n ]),\n ),\n routes: new Map(\n laidOut.edges.flatMap((edge) => {\n const route = getEdgeRoute(edge);\n return route ? [[edge.id, route] as const] : [];\n }),\n ),\n };\n};\n","import type { Node, XYPosition } from \"@xyflow/react\";\nimport {\n fitGroup,\n getAbsolutePosition,\n GROUP_PADDING,\n sizeOf,\n} from \"./grouping\";\n\n/**\n * Where agents put what they add without a position, the way an architect would: next to what it connects to,\n * following the flow left to right (what sends to it on its left, what it sends to on its right), lined up with\n * it, and stacked around it when several things connect to the same node. Nothing already on the canvas moves.\n * Things connected to nothing go in a row below what's there. Containers are filled first, so what goes around them\n * leaves room for what they grow to hold.\n */\n\n/** A connection between two nodes, from the one that sends to the one that receives */\nexport type Link = { source: string; target: string };\n\n/** Between connected nodes side by side (room for the labels on their connections), and nodes stacked in a column */\nconst GAP = { x: 200, y: 80 };\n/** The least room left around nodes */\nconst CLEARANCE = { x: 120, y: 60 };\n/** Between what's on the canvas and things connected to nothing added below it */\nconst BELOW_GAP = 120;\n/** Things connected to nothing go side by side (so connecting them later is easy), this many to a row */\nconst ROW_LENGTH = 4;\n/** How far to look for free space before giving up and going below everything */\nconst MAX_ROWS = 12;\nconst MAX_COLUMNS = 8;\n\ntype Rect = { x: number; y: number; width: number; height: number };\ntype Anchor = { rect: Rect; centerY: number; upstream: boolean };\n\nconst rectOf = (node: Node): Rect => ({ ...node.position, ...sizeOf(node) });\n\nconst tooClose = (a: Rect, b: Rect) =>\n a.x < b.x + b.width + CLEARANCE.x &&\n b.x < a.x + a.width + CLEARANCE.x &&\n a.y < b.y + b.height + CLEARANCE.y &&\n b.y < a.y + a.height + CLEARANCE.y;\n\nconst below = (rects: Rect[]): XYPosition => ({\n x: Math.min(...rects.map((rect) => rect.x)),\n y: Math.max(...rects.map((rect) => rect.y + rect.height)) + BELOW_GAP,\n});\n\n/** 0, 1, -1, 2, -2, …: rows below and above in turn, so things stacked around a node stay centred on it */\nconst rowOffset = (row: number) => (row % 2 ? (row + 1) / 2 : -row / 2);\n\n/**\n * Where the nodes to place go on the canvas (not relative to their containers: containers that grow to fit them\n * move what's in them, but nothing moves on the canvas). They're among `nodes`, with their containers set.\n * Everything else in `nodes` stays where it is.\n */\nexport const placeNodes = (\n nodes: Node[],\n toPlace: string[],\n links: Link[],\n): Map<string, XYPosition> => {\n const working = new Map(nodes.map((node) => [node.id, node]));\n const remaining = new Set(toPlace.filter((id) => working.has(id)));\n\n const neighbours = new Map<string, { id: string; upstream: boolean }[]>();\n const addNeighbour = (\n id: string,\n neighbour: { id: string; upstream: boolean },\n ) => neighbours.set(id, [...(neighbours.get(id) ?? []), neighbour]);\n for (const { source, target } of links) {\n addNeighbour(source, { id: target, upstream: false });\n addNeighbour(target, { id: source, upstream: true });\n }\n\n const depthOf = (id: string | undefined): number => {\n const node = id ? working.get(id) : undefined;\n return node ? 1 + depthOf(node.parentId) : 0;\n };\n\n /** The node, or the container it's in, that sits directly in a level (undefined for the canvas itself) */\n const atLevel = (id: string, level: string | undefined) => {\n let node = working.get(id);\n while (node && node.parentId !== level)\n node = node.parentId ? working.get(node.parentId) : undefined;\n return node;\n };\n\n /** The containers things are put in grow to fit them (innermost first), as they will on the canvas */\n const growing = new Set<string>();\n for (const id of remaining) {\n for (\n let parentId = working.get(id)!.parentId;\n parentId;\n parentId = working.get(parentId)?.parentId\n )\n growing.add(parentId);\n }\n const fitContainers = () => {\n const containers = [...growing]\n .filter((id) => working.has(id))\n .sort((a, b) => depthOf(b) - depthOf(a));\n for (const id of containers) {\n const fit = fitGroup(\n id,\n [...working.values()].filter(\n (node) => node.parentId !== id || !remaining.has(node.id),\n ),\n );\n if (!fit) continue;\n const container = working.get(id)!;\n // Growing up or left: what's in it moves the other way, so nothing moves on the canvas\n if (fit.shift.x || fit.shift.y) {\n for (const child of working.values()) {\n if (child.parentId !== id) continue;\n working.set(child.id, {\n ...child,\n position: {\n x: child.position.x + fit.shift.x,\n y: child.position.y + fit.shift.y,\n },\n });\n }\n }\n working.set(id, {\n ...container,\n position: {\n x: container.position.x - fit.shift.x,\n y: container.position.y - fit.shift.y,\n },\n width: fit.width,\n height: fit.height,\n });\n }\n };\n\n // Innermost containers first, then outwards to the canvas\n const levels = [\n ...new Set([...remaining].map((id) => working.get(id)!.parentId)),\n ].sort((a, b) => depthOf(b) - depthOf(a));\n\n for (const level of levels) {\n fitContainers();\n const parent = level ? working.get(level) : undefined;\n const origin = parent\n ? getAbsolutePosition(parent, working)\n : { x: 0, y: 0 };\n // Inside a container: clear of its header, so it grows down rather than up\n const start = parent\n ? { x: GROUP_PADDING.left, y: GROUP_PADDING.top }\n : { x: 0, y: 0 };\n const todo = [...remaining].filter(\n (id) => working.get(id)!.parentId === level,\n );\n // Things connected to nothing: a row below what was there, each to the right of what's been placed so far\n let row: { y: number; length: number } | undefined;\n const placedHere: Rect[] = [];\n const obstacles = () =>\n [...working.values()]\n .filter((node) => node.parentId === level && !remaining.has(node.id))\n .map(rectOf);\n\n /** What a node connects to that's already placed: the node itself, or the container it's in, at this level */\n const anchorsOf = (id: string): Anchor[] =>\n (neighbours.get(id) ?? []).flatMap(({ id: other, upstream }) => {\n const shown = atLevel(other, level);\n if (!shown || shown.id === id || remaining.has(shown.id)) return [];\n const node = working.get(other)!;\n // Lined up with the node itself, even when it's inside a container\n const centerY =\n getAbsolutePosition(node, working).y +\n sizeOf(node).height / 2 -\n origin.y;\n return [{ rect: rectOf(shown), centerY, upstream }];\n });\n\n /** Nothing placed to start from: the first one with nothing sending to it, so the flow grows left to right */\n const startOf = (ids: string[]) =>\n ids.find(\n (id) =>\n !(neighbours.get(id) ?? []).some(({ id: other, upstream }) => {\n const shown = atLevel(other, level);\n return (\n upstream && shown && shown.id !== id && ids.includes(shown.id)\n );\n }),\n ) ?? ids[0];\n\n const findSpot = (\n from: XYPosition,\n size: { width: number; height: number },\n direction: 1 | -1,\n ): XYPosition => {\n const rects = obstacles();\n for (let column = 0; column < MAX_COLUMNS; column++) {\n const x = from.x + direction * column * (size.width + GAP.x);\n for (let row = 0; row < MAX_ROWS * 2; row++) {\n const spot = {\n x,\n y: from.y + rowOffset(row) * (size.height + GAP.y),\n };\n if (parent && spot.y < GROUP_PADDING.top) continue;\n if (!rects.some((rect) => tooClose({ ...spot, ...size }, rect)))\n return spot;\n }\n }\n return rects.length ? below(rects) : start;\n };\n\n while (todo.length > 0) {\n const candidates = todo.map((id) => ({ id, anchors: anchorsOf(id) }));\n const connected = candidates.reduce((best, candidate) =>\n candidate.anchors.length > best.anchors.length ? candidate : best,\n );\n const { id, anchors } =\n connected.anchors.length > 0\n ? connected\n : { id: startOf(todo), anchors: [] };\n const node = working.get(id)!;\n const size = sizeOf(node);\n\n let spot: XYPosition;\n if (anchors.length > 0) {\n const upstream = anchors.filter((anchor) => anchor.upstream);\n const downstream = anchors.filter((anchor) => !anchor.upstream);\n const x = upstream.length\n ? Math.max(...upstream.map(({ rect }) => rect.x + rect.width)) + GAP.x\n : Math.min(...downstream.map(({ rect }) => rect.x)) -\n GAP.x -\n size.width;\n const centerY =\n anchors.reduce((sum, anchor) => sum + anchor.centerY, 0) /\n anchors.length;\n spot = findSpot(\n { x, y: centerY - size.height / 2 },\n size,\n upstream.length ? 1 : -1,\n );\n } else {\n const rects = obstacles();\n if (!row || row.length === ROW_LENGTH) {\n spot = findSpot(rects.length ? below(rects) : start, size, 1);\n row = { y: spot.y, length: 1 };\n } else {\n spot = findSpot(\n {\n x:\n Math.max(...placedHere.map((rect) => rect.x + rect.width)) +\n GAP.x,\n y: row.y,\n },\n size,\n 1,\n );\n row.length++;\n }\n }\n\n const position = { x: Math.round(spot.x), y: Math.round(spot.y) };\n working.set(id, { ...node, position });\n placedHere.push({ ...position, ...size });\n remaining.delete(id);\n todo.splice(todo.indexOf(id), 1);\n }\n }\n\n fitContainers();\n return new Map(\n toPlace\n .filter((id) => working.has(id))\n .map((id) => [id, getAbsolutePosition(working.get(id)!, working)]),\n );\n};\n","import type { Edge, Node } from \"@xyflow/react\";\nimport { getNodeSize as getLayoutSize } from \"../layout\";\nimport type { LevelPlace } from \"./canvas-doc\";\nimport { fitGroup, getAbsolutePosition } from \"./grouping\";\nimport { getNodeSize, isGroupType } from \"./node-types\";\nimport { placeNodes } from \"./placement\";\n\n/**\n * L1 and L2 as people arrange them. A level's content comes from the canvas (see levels.ts), but where things are on\n * it is its own: each level keeps a layout (a LevelPlace per node, in the canvas), so things stay where they're put.\n * Nothing on a level moves when something's added: new things are placed next to what they connect to (like agents\n * place what they add) and containers grow to fit.\n */\n\ntype Graph = { nodes: Node[]; edges: Edge[] };\n\n/** A container's size: as it's being worked on (width and height), or as laid out (levels size containers with style) */\nconst containerSize = (node: Node) => {\n if (node.width && node.height)\n return { width: node.width, height: node.height };\n const { width, height } = node.style ?? {};\n return typeof width === \"number\" && typeof height === \"number\"\n ? { width, height }\n : undefined;\n};\n\n/** The size the visualiser's layout gives a container with nothing in it (levels leave containers' size to it) */\nconst emptyContainerSize = ({ type }: Pick<Node, \"type\">) =>\n getLayoutSize({ id: \"\", type, position: { x: 0, y: 0 }, data: {} });\n\n/**\n * The size something new of a type is shown at on L1 or L2: L1 shows domains and systems with nothing in them as\n * cards, L2 as empty containers\n */\nexport const getLevelNodeSize = (type: string | undefined, level: 1 | 2) => {\n if (!isGroupType(type)) return getNodeSize(type);\n return level === 1 ? getNodeSize() : emptyContainerSize({ type });\n};\n\n/** Where a node is on a level, and a container's size */\nconst placeOf = (node: Node): LevelPlace => ({\n x: node.position.x,\n y: node.position.y,\n ...(isGroupType(node.type) && containerSize(node)),\n});\n\n/** A level's nodes where they are, by id (not its notes, which are kept on the canvas): what its layout keeps */\nexport const levelPlaces = (nodes: Node[]) =>\n new Map(\n nodes\n .filter((node) => node.type !== \"note\")\n .map((node) => [node.id, placeOf(node)]),\n );\n\n/**\n * A level arranged: each node where the level's layout has it, else where the diagram the canvas was opened from had\n * it (`fallback`), and anything with neither placed next to what it connects to. Containers grow to fit what's in\n * them. `placed` is where things the layout didn't have were put, and containers that grew (to keep, so they stay\n * there). Undefined when nothing on the level has a place yet: it's laid out from scratch then.\n */\nexport const arrangeLevel = (\n graph: Graph,\n layout: ReadonlyMap<string, LevelPlace>,\n fallback: ReadonlyMap<string, LevelPlace> = new Map(),\n): { graph: Graph; placed: Map<string, LevelPlace> } | undefined => {\n const known = (id: string) => layout.get(id) ?? fallback.get(id);\n if (!graph.nodes.some((node) => known(node.id))) return undefined;\n\n const placed = new Map<string, LevelPlace>();\n // Containers carry their size as width and height while they're worked on (what placement and fitting read)\n let nodes: Node[] = graph.nodes.map((node) => {\n const place = known(node.id);\n const size = isGroupType(node.type)\n ? place?.width && place.height\n ? { width: place.width, height: place.height }\n : (containerSize(node) ?? emptyContainerSize(node))\n : undefined;\n return {\n ...node,\n position: place ? { x: place.x, y: place.y } : { x: 0, y: 0 },\n ...size,\n };\n });\n\n // Anything new, next to what it connects to (on the level), moving nothing that's there\n const toPlace = nodes\n .filter((node) => !known(node.id))\n .map((node) => node.id);\n if (toPlace.length) {\n const positions = placeNodes(nodes, toPlace, graph.edges);\n const lookup = new Map(nodes.map((node) => [node.id, node]));\n nodes = nodes.map((node) => {\n const at = positions.get(node.id);\n if (!at) return node;\n const parent = node.parentId ? lookup.get(node.parentId) : undefined;\n const origin = parent\n ? getAbsolutePosition(parent, lookup)\n : { x: 0, y: 0 };\n const moved = {\n ...node,\n position: { x: at.x - origin.x, y: at.y - origin.y },\n };\n placed.set(node.id, placeOf(moved));\n return moved;\n });\n }\n\n // Containers grow to fit what's in them (the innermost first), moving nothing on the level\n const byId = new Map(nodes.map((node) => [node.id, node]));\n const depth = (node: Node): number => {\n const parent = node.parentId ? byId.get(node.parentId) : undefined;\n return parent ? 1 + depth(parent) : 0;\n };\n const containers = nodes\n .filter((node) => isGroupType(node.type))\n .sort((a, b) => depth(b) - depth(a));\n for (const { id } of containers) {\n const fit = fitGroup(id, nodes);\n const current = nodes.find((node) => node.id === id)!;\n const { x: dx, y: dy } = fit?.shift ?? { x: 0, y: 0 };\n if (\n !fit ||\n (!dx &&\n !dy &&\n fit.width === current.width &&\n fit.height === current.height)\n )\n continue;\n nodes = nodes.map((node) => {\n if (node.parentId === id && (dx || dy)) {\n const shifted = {\n ...node,\n position: { x: node.position.x + dx, y: node.position.y + dy },\n };\n placed.set(node.id, placeOf(shifted));\n return shifted;\n }\n if (node.id !== id) return node;\n const grown = {\n ...node,\n position: { x: node.position.x - dx, y: node.position.y - dy },\n width: fit.width,\n height: fit.height,\n };\n placed.set(id, placeOf(grown));\n return grown;\n });\n }\n\n return {\n graph: {\n edges: graph.edges,\n // Containers drawn at their size with style, like levels laid out from scratch\n nodes: nodes.map(({ width, height, ...node }) =>\n isGroupType(node.type) && width && height\n ? { ...node, style: { ...node.style, width, height } }\n : node,\n ),\n },\n placed,\n };\n};\n\n/**\n * A level's edges drawn along the routes the diagram the canvas was opened from had for the same connections (between\n * the same two nodes), once the level's worked out from the canvas: routes follow their nodes when they move, so\n * connections the diagram had stay drawn around what's in their way\n */\nexport const withDiagramRoutes = (edges: Edge[], diagramEdges: Edge[] = []) => {\n const routes = new Map(\n diagramEdges.flatMap((edge) =>\n edge.data?.route\n ? [[`${edge.source}>${edge.target}`, edge.data.route] as const]\n : [],\n ),\n );\n if (routes.size === 0) return edges;\n return edges.map((edge) => {\n const route = routes.get(`${edge.source}>${edge.target}`);\n return route && !edge.data?.route\n ? { ...edge, data: { ...edge.data, route } }\n : edge;\n });\n};\n","import { MarkerType, type Edge, type Node } from \"@xyflow/react\";\nimport { getMessagesLabel } from \"../layout\";\nimport { MESSAGE_COLLECTIONS } from \"./edges\";\nimport { GROUP_TYPES, isGroupType, isWrittenOnCanvas } from \"./node-types\";\n\n/**\n * Levels of detail, the same as EventCatalog's diagrams:\n * - L1: domains, systems and how they relate (services folded into the system or domain that contains them)\n * - L2: services and data stores, with messages, channels and agents hidden (the nodes either side connected directly)\n * - L3: everything, including messages and channels (the canvas people edit)\n *\n * What a domain or system contains is what sits inside it (as a container), or what it's connected to with\n * \"contains\" (as a card, which catalog domains and systems get when their services are on the canvas).\n */\nexport type Level = 1 | 2 | 3;\n\nexport const LEVELS: { level: Level; description: string }[] = [\n { level: 1, description: \"Domains, systems and their relationships\" },\n { level: 2, description: \"Services and data stores\" },\n { level: 3, description: \"Everything, including messages and channels\" },\n];\n\n// Domains and systems: as cards (what they contain is connected with \"contains\") or containers (it's inside)\nconst CONTAINER_TYPES = new Set([\n \"system\",\n \"context-domain\",\n GROUP_TYPES.system,\n GROUP_TYPES.domain,\n]);\nconst isSystem = (node: Node) =>\n node.type === \"system\" || node.type === GROUP_TYPES.system;\nconst isDomain = (node: Node) =>\n node.type === \"context-domain\" || node.type === GROUP_TYPES.domain;\n\nconst isMessage = (node: Node) => !!MESSAGE_COLLECTIONS[node.type ?? \"\"];\nconst isCarrier = (node: Node) => isMessage(node) || node.type === \"channel\";\n// Agents are L3 detail: on L1 and L2 the nodes either side of one are connected past it (as through a message)\nconst isAgent = (node: Node) => node.type === \"agent\";\n// Entities are the domain model, L3 detail: on L1 and L2 they're left out (they aren't a way between two things)\nconst isEntity = (node: Node) => node.type === \"entity\";\nconst isContainer = (node: Node) => CONTAINER_TYPES.has(node.type ?? \"\");\nconst messageName = (node: Node) =>\n String(\n (node.data as { message?: { name?: string } }).message?.name ?? node.id,\n );\n\n// Edges as the visualiser's levels draw them: what's folded together is joined by a plain line, and what was joined\n// through hidden messages or channels by a dashed, muted one (\"bridged\"), each with the visualiser's arrow. On L1\n// the visualiser folds messages into the domain or system they're in, so edges to and from them are plain.\nconst EDGE_STROKE = \"var(--ec-edge-stroke, #6b7280)\";\nconst MUTED = \"rgb(var(--ec-page-text-muted))\";\nconst FOLDED_EDGE = {\n type: \"smoothstep\",\n style: { strokeWidth: 1, stroke: EDGE_STROKE },\n markerEnd: { type: MarkerType.ArrowClosed, width: 20, height: 20 },\n} satisfies Partial<Edge>;\nconst BRIDGED_EDGE = {\n type: \"smoothstep\",\n style: { strokeWidth: 1.5, stroke: MUTED, strokeDasharray: \"5 5\" },\n markerEnd: {\n type: MarkerType.ArrowClosed,\n width: 20,\n height: 20,\n color: MUTED,\n },\n} satisfies Partial<Edge>;\n\n/** What a node becomes at a level: kept (as itself or another node), carried through (messages, channels) or dropped */\ntype Representative =\n | { kind: \"node\"; id: string }\n | { kind: \"carrier\" }\n | { kind: \"drop\" };\n\n/**\n * Collapse a graph: each node is kept, replaced by another node (e.g. a service by its system), carried through\n * (messages and channels: the nodes either side get connected directly, \"bridged\") or dropped. Edges between two\n * nodes that are kept as they are stay as they were (`keepDirect`, for L2); the rest are merged per pair and kind\n * (folded or bridged), labelled with the messages they carry.\n *\n * With `relationships` (L1), edges drawn straight between two nodes that are kept as they are (e.g. one system to\n * another) are relationships, like the visualiser's context relationships: labelled as they were, and shown\n * instead of the messages between the same two nodes (either way).\n */\nconst collapseGraph = (\n nodes: Node[],\n edges: Edge[],\n representativeOf: (node: Node) => Representative,\n {\n keepDirect = false,\n relationships = false,\n foldsMessagesInto,\n }: {\n keepDirect?: boolean;\n relationships?: boolean;\n /** Nodes the messages they send or receive are folded into (L1: domains and systems), so edges through them are plain */\n foldsMessagesInto?: (node: Node) => boolean;\n } = {},\n) => {\n const byId = new Map(nodes.map((node) => [node.id, node]));\n // Whether one node is inside another (e.g. a system in its domain): they're not connected, one holds the other\n const isInside = (id: string, containerId: string) => {\n for (\n let node = byId.get(id);\n node?.parentId;\n node = byId.get(node.parentId)\n )\n if (node.parentId === containerId) return true;\n return false;\n };\n const representatives = new Map(\n nodes.map((node) => [node.id, representativeOf(node)]),\n );\n const outgoing = new Map<string, Edge[]>();\n edges.forEach((edge) =>\n outgoing.set(edge.source, [...(outgoing.get(edge.source) ?? []), edge]),\n );\n\n type Merged = {\n source: string;\n target: string;\n bridged: boolean;\n relationship: boolean;\n messages: Map<string, string>;\n labels: string[];\n /** To the container holding what it was to (hidden at this level): said as it was written (e.g. \"manages\") */\n intoContainer: boolean;\n };\n const merged = new Map<string, Merged>();\n const kept: Edge[] = [];\n const addMessage = (messages: Map<string, string>, node: Node) => {\n if (isMessage(node))\n messages.set(messageName(node), MESSAGE_COLLECTIONS[node.type!]);\n };\n // The nearest container of a node that's shown at this level (as itself)\n const shownContainerOf = (node: Node) => {\n for (\n let parent = node.parentId ? byId.get(node.parentId) : undefined;\n parent;\n parent = parent.parentId ? byId.get(parent.parentId) : undefined\n ) {\n const rep = representatives.get(parent.id);\n if (rep?.kind === \"node\" && rep.id === parent.id) return parent.id;\n }\n return undefined;\n };\n\n edges.forEach((edge) => {\n const from = representatives.get(edge.source);\n if (from?.kind !== \"node\") return;\n const to = representatives.get(edge.target);\n const direct =\n from.id === edge.source && to?.kind === \"node\" && to.id === edge.target;\n if (keepDirect && direct) return kept.push(edge);\n // Follow the edge through carried nodes to the node(s) it reaches, collecting the messages on the way\n const stack = [\n {\n id: edge.target,\n messages: new Map<string, string>(),\n labels: [String(edge.label ?? \"\")],\n bridged: false,\n },\n ];\n const visited = new Set<string>();\n addMessage(stack[0].messages, byId.get(edge.source)!);\n while (stack.length) {\n const current = stack.pop()!;\n if (visited.has(current.id)) continue;\n visited.add(current.id);\n const node = byId.get(current.id);\n let reached = representatives.get(current.id);\n if (!node || !reached) continue;\n const messages = new Map(current.messages);\n addMessage(messages, node);\n if (reached.kind === \"carrier\" && outgoing.get(current.id)?.length) {\n (outgoing.get(current.id) ?? []).forEach((next) =>\n stack.push({\n id: next.target,\n messages,\n labels: [] as string[],\n bridged: true,\n }),\n );\n continue;\n }\n // It ends at something this level hides (an entity, or a message nothing receives): it goes to what holds it, if\n // that's shown (e.g. a service publishing into another system's event, or managing its entity, connects to it)\n let intoContainer = false;\n if (reached.kind !== \"node\") {\n const container = shownContainerOf(node);\n if (!container) continue;\n reached = { kind: \"node\", id: container };\n intoContainer = true;\n }\n // Edges inside what was collapsed disappear, and so do edges to what a node is in (e.g. a service loose in a\n // domain, folded into it, and a system in the same domain)\n if (\n from.id === reached.id ||\n isInside(from.id, reached.id) ||\n isInside(reached.id, from.id)\n )\n continue;\n const relationship =\n relationships && direct && current.id === edge.target;\n const key = `${relationship ? \"relationship\" : current.bridged ? \"bridged\" : \"level\"}-${from.id}-${reached.id}`;\n const entry: Merged = merged.get(key) ?? {\n source: from.id,\n target: reached.id,\n bridged: current.bridged,\n relationship,\n messages: new Map(),\n labels: [],\n intoContainer,\n };\n messages.forEach((collection, name) =>\n entry.messages.set(name, collection),\n );\n // (to a message's container, the message says it: \"publishes OrderPlaced\", not \"publishes event\")\n if (!(intoContainer && isMessage(node)))\n entry.labels.push(...current.labels.filter(Boolean));\n entry.intoContainer ||= intoContainer;\n merged.set(key, entry);\n }\n });\n\n const keptIds = new Set(\n [...representatives.values()].flatMap((rep) =>\n rep.kind === \"node\" ? [rep.id] : [],\n ),\n );\n // A relationship between two nodes is shown instead of the messages between them (either way)\n const related = new Set(\n [...merged.values()]\n .filter((entry) => entry.relationship)\n .flatMap(({ source, target }) => [\n `${source}>${target}`,\n `${target}>${source}`,\n ]),\n );\n // Actors' connections are relationships too, labelled as they were (even when what they use is folded)\n const isActor = (id: string) => byId.get(id)?.type === \"actor\";\n const labelOf = ({\n source,\n target,\n bridged,\n relationship,\n messages,\n labels,\n intoContainer,\n }: Merged) => {\n const written = labels.length ? [...new Set(labels)].join(\", \") : undefined;\n if (relationship) return written;\n // Into a container: the messages, and what else it does there (e.g. \"manages\")\n if (intoContainer)\n return (\n [getMessagesLabel(messages), written].filter(Boolean).join(\" \\n\") ||\n undefined\n );\n return (\n getMessagesLabel(messages) ??\n (!bridged && (isActor(source) || isActor(target)) ? written : undefined)\n );\n };\n return {\n nodes: nodes.filter((node) => keptIds.has(node.id)),\n edges: [\n ...kept,\n ...[...merged.entries()]\n .filter(\n ([, entry]) =>\n entry.relationship ||\n !related.has(`${entry.source}>${entry.target}`),\n )\n .map(([id, entry]): Edge => {\n const label = labelOf(entry);\n const folded = [entry.source, entry.target].some((nodeId) => {\n const node = byId.get(nodeId);\n return !!node && !!foldsMessagesInto?.(node);\n });\n return {\n id,\n source: entry.source,\n target: entry.target,\n ...(entry.bridged && !folded ? BRIDGED_EDGE : FOLDED_EDGE),\n ...(label && { label }),\n };\n }),\n ],\n };\n};\n\n/**\n * The system and domain each node is in: the containers it sits inside, or the domain and system cards\n * connected to it with \"contains\"\n */\nconst getContainers = (nodes: Node[], edges: Edge[]) => {\n const byId = new Map(nodes.map((node) => [node.id, node]));\n const containers = new Map<string, { system?: string; domain?: string }>();\n const add = (nodeId: string, container: Node) => {\n const entry = containers.get(nodeId) ?? {};\n if (isSystem(container)) entry.system ??= container.id;\n else entry.domain ??= container.id;\n containers.set(nodeId, entry);\n };\n for (const node of nodes) {\n for (\n let parent = node.parentId ? byId.get(node.parentId) : undefined;\n parent;\n parent = parent.parentId ? byId.get(parent.parentId) : undefined\n ) {\n if (isContainer(parent)) add(node.id, parent);\n }\n }\n for (const edge of edges) {\n const container = byId.get(edge.source);\n if (container && isContainer(container) && edge.label === \"contains\")\n add(edge.target, container);\n }\n return containers;\n};\n\n/**\n * Containers are sized by the layout: to fit what's in them, or (empty) the size the visualiser lays empty groups\n * out at. Same ids, so switching levels grows and shrinks them.\n */\nconst sizedByLayout = ({ nodes, edges }: { nodes: Node[]; edges: Edge[] }) => ({\n edges,\n nodes: nodes.map((node) =>\n isGroupType(node.type)\n ? { ...node, width: undefined, height: undefined, measured: undefined }\n : node,\n ),\n});\n\n/** L2: messages, channels and agents hidden, the nodes either side connected directly */\nconst level2 = (nodes: Node[], edges: Edge[]) =>\n collapseGraph(\n nodes,\n edges,\n (node) =>\n isEntity(node)\n ? { kind: \"drop\" }\n : isCarrier(node) || isAgent(node)\n ? { kind: \"carrier\" }\n : { kind: \"node\", id: node.id },\n {\n keepDirect: true,\n },\n );\n\n/** Whether a node is inside a container, at any depth */\nconst isWithin = (node: Node, containerId: string, byId: Map<string, Node>) => {\n for (let parent = node.parentId; parent; parent = byId.get(parent)?.parentId)\n if (parent === containerId) return true;\n return false;\n};\n\n/**\n * L1 as EventCatalog's diagrams draw it: systems as cards with what's in them counted, and domains with nothing\n * shown in them (no system, in them or their subdomains, or subdomain) as domain cards\n */\nconst asSystemsLevel = (\n { nodes, edges }: { nodes: Node[]; edges: Edge[] },\n {\n all,\n allEdges,\n containers,\n }: {\n all: Node[];\n allEdges: Edge[];\n containers: ReturnType<typeof getContainers>;\n },\n) => {\n const byId = new Map(all.map((node) => [node.id, node]));\n const count = (id: string, matches: (node: Node) => boolean) =>\n all.filter(\n (node) => matches(node) && containers.get(node.id)?.system === id,\n ).length;\n // The messages a system's services send and receive\n const messagesOf = (id: string) => {\n const services = new Set(\n all\n .filter((node) => containers.get(node.id)?.system === id)\n .map((node) => node.id),\n );\n const messages = new Set<string>();\n for (const edge of allEdges) {\n const [inside, other] = services.has(edge.source)\n ? [edge.source, edge.target]\n : [edge.target, edge.source];\n if (\n services.has(inside) &&\n byId.get(other) &&\n isMessage(byId.get(other)!)\n )\n messages.add(other);\n }\n return messages.size;\n };\n return {\n edges,\n nodes: nodes.map((node): Node => {\n const { id, parentId, position, data } = node;\n if (node.type === GROUP_TYPES.system)\n return {\n id,\n type: \"system\",\n position,\n ...(parentId && { parentId }),\n data: {\n mode: \"full\",\n ...data,\n servicesCount: count(\n id,\n (child) => child.type === \"service\" || child.type === \"agent\",\n ),\n containersCount: count(id, (child) => child.type === \"data\"),\n messagesCount: messagesOf(id),\n },\n };\n // A domain container stays one while something is shown in it (a system, or a subdomain shown as a card)\n if (\n node.type === GROUP_TYPES.domain &&\n !all.some((other) => isSystem(other) && isWithin(other, id, byId)) &&\n !nodes.some((other) => isWithin(other, id, byId))\n )\n return {\n id,\n type: \"context-domain\",\n position,\n ...(parentId && { parentId }),\n data: {\n mode: \"full\",\n ...data,\n subdomain: !!parentId,\n systemsCount: 0,\n servicesCount: all.filter(\n (other) => other.type === \"service\" && isWithin(other, id, byId),\n ).length,\n },\n };\n return node;\n }),\n };\n};\n\n/** L1: services folded into their system (or domain); actors, external systems and loose services stay */\nconst level1 = (nodes: Node[], edges: Edge[]) => {\n const containers = getContainers(nodes, edges);\n const collapsed = collapseGraph(\n nodes,\n edges,\n (node) => {\n const container = containers.get(node.id);\n if (isEntity(node)) return { kind: \"drop\" };\n // Systems stay (inside their domain's container, if they're in one); everything else folds into its system or domain\n if (isContainer(node) && (isSystem(node) || !container?.system))\n return { kind: \"node\", id: node.id };\n if (container?.system) return { kind: \"node\", id: container.system };\n // Messages and channels connect the systems either side, even when they sit in a domain rather than a system\n // (the visualiser has them outside its domains; catalog domains on a canvas hold their messages)\n if (isCarrier(node)) return { kind: \"carrier\" };\n if (container?.domain) return { kind: \"node\", id: container.domain };\n if (isAgent(node)) return { kind: \"carrier\" };\n if (node.type === \"data\" || isWrittenOnCanvas(node.type))\n return { kind: \"drop\" };\n return { kind: \"node\", id: node.id };\n },\n { relationships: true, foldsMessagesInto: isContainer },\n );\n return asSystemsLevel(collapsed, { all: nodes, allEdges: edges, containers });\n};\n\n/**\n * The graph for a level (not laid out: positions come from the layout). Notes aren't in it: the ones added on the\n * level are shown where they were put, over its layout.\n */\nexport const getLevelGraph = (nodes: Node[], edges: Edge[], level: Level) => {\n if (level === 3) return { nodes, edges };\n const withoutNotes = nodes.filter((node) => !isWrittenOnCanvas(node.type));\n return sizedByLayout(\n level === 1 ? level1(withoutNotes, edges) : level2(withoutNotes, edges),\n );\n};\n\n/** Why a level can't be shown for this canvas, if it can't */\nexport const getLevelUnavailableReason = (\n nodes: Node[],\n level: Level,\n): string | undefined => {\n // Like the visualiser: L1 needs systems, or domains to relate (one domain on its own has nothing to show)\n if (level === 1 && !nodes.some(isSystem) && nodes.filter(isDomain).length < 2)\n return \"Not available: add a system, or more than one domain, to see how they relate\";\n return undefined;\n};\n","import { useEffect, useState } from \"react\";\nimport type { XYPosition } from \"@xyflow/react\";\nimport type { Moving, PresenceSource } from \"./presence\";\nimport { createSmoother } from \"./smooth\";\n\n/**\n * Comment pins and hotspot markers being dragged in a live room: what I drag goes out with my presence (`send`, and\n * `null` once it's dropped: the drop goes in the document), and what the others drag comes from theirs (`source`).\n * On the level shown, as their places are.\n */\nexport type LiveMoves = {\n send: (moving: Moving[] | null) => void;\n source: PresenceSource;\n level: 1 | 2 | 3;\n};\n\n/** Sends where something of this kind is now, as it's dragged (or `null`, dropped) */\nexport const sendMove = (\n live: LiveMoves | undefined,\n kind: NonNullable<Moving[\"kind\"]>,\n id: string,\n at: XYPosition | null,\n) =>\n live?.send(\n at && [\n {\n id,\n kind,\n x: at.x,\n y: at.y,\n ...(live.level !== 3 && { level: live.level }),\n },\n ],\n );\n\nconst NONE: ReadonlyMap<string, XYPosition> = new Map();\n\n/**\n * Where the others are dragging things of this kind on the level shown (by id), read from their presence. Changes\n * (re-rendering only the layer using it) only while someone drags one.\n */\nexport function useRemoteMoves(\n live: LiveMoves | undefined,\n kind: NonNullable<Moving[\"kind\"]>,\n) {\n const [moves, setMoves] = useState(NONE);\n const source = live?.source;\n const level = live?.level;\n useEffect(() => {\n if (!source) return;\n let shown = \"\";\n // (gliding, a step a frame, rather than jumping as each position arrives)\n const glide = createSmoother((at) => setMoves(at.size ? at : NONE));\n const show = (peers: ReturnType<PresenceSource[\"current\"]>) => {\n const found = new Map<string, XYPosition>();\n peers.forEach((peer) =>\n peer.moving?.forEach(\n (move) =>\n move.kind === kind &&\n (move.level ?? 3) === level &&\n found.set(move.id, { x: move.x, y: move.y }),\n ),\n );\n const key = [...found]\n .map(([id, { x, y }]) => `${id}:${x}:${y}`)\n .join(\"|\");\n if (key === shown) return;\n shown = key;\n glide.set(found);\n };\n show(source.current());\n const unsubscribe = source.subscribe(show);\n return () => {\n unsubscribe();\n glide.stop();\n setMoves(NONE);\n };\n }, [source, level, kind]);\n return moves;\n}\n","/**\n * Smooths what the others in a live room are moving. Their positions arrive about 30 times a second (and unevenly,\n * as the network goes), while the screen draws 60 to 120 times a second: shown as they arrive, what they drag steps\n * along and stutters. Here each one glides to where it was last said to be, a step every frame, easing in about\n * EASE_MS (a little behind them, smoothly). Frames only run while something's still gliding.\n */\ntype XY = { x: number; y: number };\n\nconst EASE_MS = 45;\n// Close enough to stop (in canvas pixels)\nconst SETTLED_PX = 0.5;\n\nexport type Smoother = {\n /** Where each thing (by id) is now, as the others say; anything left out stops being shown straight away */\n set: (targets: ReadonlyMap<string, XY>) => void;\n stop: () => void;\n};\n\nexport function createSmoother(\n apply: (shown: ReadonlyMap<string, XY>) => void,\n): Smoother {\n let targets: ReadonlyMap<string, XY> = new Map();\n const shown = new Map<string, XY>();\n let frame = 0;\n let last = 0;\n\n const step = (now: number) => {\n frame = 0;\n // (the first frame after a pause steps as one frame would)\n const elapsed = last ? Math.min(now - last, 100) : 16;\n last = now;\n const ease = 1 - Math.exp(-elapsed / EASE_MS);\n let gliding = false;\n for (const [id, to] of targets) {\n const from = shown.get(id);\n if (!from) {\n // New: where it's said to be (it starts where they picked it up, next to where it is here)\n shown.set(id, to);\n continue;\n }\n const x = from.x + (to.x - from.x) * ease;\n const y = from.y + (to.y - from.y) * ease;\n if (Math.abs(to.x - x) < SETTLED_PX && Math.abs(to.y - y) < SETTLED_PX)\n shown.set(id, to);\n else {\n shown.set(id, {\n x: Math.round(x * 10) / 10,\n y: Math.round(y * 10) / 10,\n });\n gliding = true;\n }\n }\n apply(new Map(shown));\n if (gliding) frame = requestAnimationFrame(step);\n else last = 0;\n };\n\n return {\n set(next) {\n targets = next;\n // What they've let go of goes straight away (its drop arrives in the document)\n let dropped = false;\n for (const id of shown.keys())\n if (!next.has(id)) (shown.delete(id), (dropped = true));\n if (dropped && !next.size) {\n cancelAnimationFrame(frame);\n frame = 0;\n last = 0;\n return apply(new Map());\n }\n if (!frame) frame = requestAnimationFrame(step);\n },\n stop() {\n cancelAnimationFrame(frame);\n frame = 0;\n last = 0;\n shown.clear();\n targets = new Map();\n },\n };\n}\n","import { useLayoutEffect, type RefObject } from \"react\";\nimport { useStoreApi } from \"@xyflow/react\";\n\n/** 1 / zoom, for things drawn in the canvas's coordinates that stay the same size on screen (`scale(var(...))`) */\nexport const COUNTER_SCALE = \"--studio-counter-scale\";\n\n/**\n * Keeps COUNTER_SCALE on an element as the canvas zooms, outside React: what's counter-scaled with it (e.g. comment\n * pins) stays the same size on screen without re-rendering on every frame of a zoom\n */\nexport function useCounterScale(ref: RefObject<HTMLElement | null>) {\n const store = useStoreApi();\n useLayoutEffect(() => {\n const apply = (zoom: number) =>\n ref.current?.style.setProperty(COUNTER_SCALE, String(1 / zoom));\n apply(store.getState().transform[2]);\n return store.subscribe((state, previous) => {\n if (state.transform[2] !== previous.transform[2])\n apply(state.transform[2]);\n });\n }, [store, ref]);\n}\n","/**\n * The model (what agents send, links carry and files keep) as Studio's canvas (React Flow nodes and edges, as\n * Studio's canvas-doc keeps them), and back. Each resource is a node with the resource's id, so what's arranged,\n * linked and saved lines up with the agent's ids. Relations are edges (what each edge stands for is kept on it);\n * notes are sticky note and text nodes, on their level; where things are goes in the model's layout.\n */\nimport type { Edge, Node, XYPosition } from \"@xyflow/react\";\nimport type {\n Hotspot as ModelHotspot,\n Layout,\n Model,\n Note,\n Relation,\n Resource,\n ResourceType,\n} from \"../model\";\nimport { MESSAGE_TYPES } from \"../model\";\nimport {\n shortId,\n type Hotspot,\n type LevelPlace,\n type Thread,\n} from \"./canvas-doc\";\nimport { createEdge } from \"./edges\";\nimport { ENTITY_SOURCE_HANDLE } from \"./entity-handles\";\nimport { getAbsolutePosition, sortByHierarchy } from \"./grouping\";\nimport { getLayoutPositions } from \"./layout\";\nimport {\n GROUP_TYPES,\n getNodeDefinition,\n getResource,\n isGroupType,\n isWrittenOnCanvas,\n} from \"./node-types\";\nimport { placeNodes, type Link } from \"./placement\";\nimport { ENTITY_TARGET_HANDLE_ID } from \"../index\";\n\n/** Canvas node types for each type of resource (Studio's, which are the visualiser's) */\nconst NODE_TYPE: Record<ResourceType, string> = {\n domain: GROUP_TYPES.domain,\n system: GROUP_TYPES.system,\n service: \"service\",\n event: \"event\",\n command: \"command\",\n query: \"query\",\n channel: \"channel\",\n container: \"data\",\n actor: \"actor\",\n \"external-system\": \"externalSystem\",\n agent: \"agent\",\n view: \"view\",\n entity: \"entity\",\n team: \"team\",\n};\nconst RESOURCE_TYPE: Record<string, ResourceType> = {\n ...Object.fromEntries(\n Object.entries(NODE_TYPE).map(([resource, node]) => [\n node,\n resource as ResourceType,\n ]),\n ),\n // Catalog domains and systems as cards (Studio's catalog adds them; kept if a canvas has them)\n system: \"system\",\n \"context-domain\": \"domain\",\n};\nexport const resourceTypeOf = (nodeType?: string) =>\n RESOURCE_TYPE[nodeType ?? \"\"];\n\nconst LEVEL_NUMBER = { overview: 1, services: 2, messages: 3 } as const;\nconst LEVEL_NAME = { 1: \"overview\", 2: \"services\", 3: \"messages\" } as const;\n\n/** The edge's relations, and the ends they were drawn between (an edge moved to other ends stands for something else) */\ntype EdgeRelations = { relations: Relation[]; ends: string };\nconst endsOf = (edge: Pick<Edge, \"source\" | \"target\">) =>\n `${edge.source}->${edge.target}`;\n\nexport type ModelCanvasContent = {\n nodes: Node[];\n edges: Edge[];\n levelLayouts: Record<1 | 2, Map<string, LevelPlace>>;\n /** Comment threads people left on it */\n threads?: Thread[];\n /** What's flagged on it (by people, or the agent) */\n hotspots?: Hotspot[];\n /** A live room's document as this browser kept it: the canvas starts from that instead (see local-canvas.ts) */\n doc?: Uint8Array;\n};\n\n// Who flagged a hotspot the agent sent without saying\nconst AGENT_AUTHOR = { name: \"Agent\", color: \"#7c3aed\", agent: true };\n\n/** The model's hotspots as the canvas has them: on their resource's node, or at their place */\nconst toCanvasHotspots = (hotspots: ModelHotspot[]): Hotspot[] =>\n hotspots.map((hotspot) => ({\n id: hotspot.id ?? shortId(),\n severity: hotspot.severity ?? \"warning\",\n title: hotspot.title,\n ...(hotspot.description && { description: hotspot.description }),\n ...(hotspot.resource && { nodeId: hotspot.resource }),\n position: hotspot.position ?? { x: 0, y: 0 },\n ...(!hotspot.resource && hotspot.level && { level: hotspot.level }),\n author: hotspot.author ?? AGENT_AUTHOR,\n createdAt: hotspot.createdAt ?? Date.now(),\n }));\n\n/** A resource's node data, as Studio's components for its type create it (and the resource itself, to keep what the canvas doesn't show) */\nexport function resourceNodeData(resource: Resource): Record<string, unknown> {\n const type = NODE_TYPE[resource.type];\n const fields = {\n name: resource.name,\n version: resource.version ?? \"0.0.1\",\n summary: resource.summary ?? \"\",\n owners: resource.owners ?? [],\n };\n const defaults = getNodeDefinition(type)?.createData() ?? {};\n const shared = { resource };\n switch (resource.type) {\n case \"domain\":\n return resource.card\n ? {\n ...shared,\n mode: \"full\",\n navigable: false,\n domain: { id: resource.id, ...fields },\n }\n : {\n ...shared,\n domain: {\n id: resource.id,\n name: resource.name,\n version: fields.version,\n },\n };\n case \"system\":\n return resource.card\n ? {\n ...shared,\n mode: \"full\",\n navigable: false,\n system: { id: resource.id, ...fields },\n }\n : {\n ...shared,\n system: {\n id: resource.id,\n name: resource.name,\n version: fields.version,\n },\n };\n case \"actor\":\n return {\n ...defaults,\n ...shared,\n name: resource.name,\n summary: resource.summary ?? \"\",\n };\n case \"channel\":\n return {\n ...defaults,\n ...shared,\n channel: {\n ...fields,\n protocols: resource.technology ? [resource.technology] : [],\n },\n };\n case \"container\":\n return {\n ...defaults,\n ...shared,\n data: {\n ...fields,\n container_type: resource.containerType ?? \"database\",\n technology: resource.technology,\n },\n };\n case \"entity\":\n return {\n ...defaults,\n ...shared,\n entity: { ...fields, properties: resource.properties ?? [] },\n };\n default: {\n const key = getNodeDefinition(type)?.resourceKey ?? type;\n return {\n ...defaults,\n ...shared,\n [key]: {\n ...((defaults as Record<string, Record<string, unknown>>)[key] ?? {}),\n ...fields,\n },\n };\n }\n }\n}\n\n/** The edges the model's relations are drawn as, between the nodes of the resources they join */\nfunction edgesFor(model: Model, byId: Map<string, Resource>): Edge[] {\n const drawn = new Map<string, Edge & { data: EdgeRelations }>();\n const channelsOf = new Map<string, string[]>();\n model.relations\n .filter((r) => r.kind === \"routes-through\")\n .forEach((r) =>\n channelsOf.set(r.from, [...(channelsOf.get(r.from) ?? []), r.to]),\n );\n const draw = (source: string, target: string, relation: Relation) => {\n const [from, to] = [byId.get(source), byId.get(target)];\n if (!from || !to || source === target) return;\n const key = `${source}->${target}`;\n const fields =\n from.type === \"entity\" || to.type === \"entity\"\n ? `:${relation.fromField ?? \"\"}:${relation.toField ?? \"\"}`\n : \"\";\n const existing = drawn.get(key + fields);\n if (existing) return void existing.data.relations.push(relation);\n // An entity's connections are to and from its properties' rows (or its header, for the whole entity)\n const sourceHandle =\n from.type === \"entity\"\n ? relation.fromField\n ? `${relation.fromField}-source`\n : ENTITY_SOURCE_HANDLE\n : null;\n const targetHandle =\n to.type === \"entity\"\n ? relation.toField\n ? `${relation.toField}-target`\n : ENTITY_TARGET_HANDLE_ID\n : null;\n const edge = createEdge(\n { source, target, sourceHandle, targetHandle },\n NODE_TYPE[from.type],\n NODE_TYPE[to.type],\n );\n drawn.set(key + fields, {\n ...edge,\n id: key + fields,\n // What someone wrote on it (any connection), else EventCatalog's wording\n ...(relation.label && { label: relation.label }),\n data: {\n ...edge.data,\n relations: [relation],\n ends: key,\n ...(relation.label && { customLabel: relation.label }),\n },\n });\n };\n for (const relation of model.relations) {\n switch (relation.kind) {\n case \"receives\": {\n // Through the message's channels, when it has any\n const channels = channelsOf.get(relation.to);\n if (channels?.length)\n channels.forEach((channel) => draw(channel, relation.from, relation));\n else draw(relation.to, relation.from, relation);\n break;\n }\n // A data store is read by a service: drawn from the store\n case \"reads\":\n draw(relation.to, relation.from, relation);\n break;\n default:\n draw(relation.from, relation.to, relation);\n }\n }\n // Guessed by the agent: amber and dotted, as the diagram draws them\n return [...drawn.values()].map((edge) =>\n edge.data.relations.every((r) => r.inferred)\n ? {\n ...edge,\n label: edge.label ? `${edge.label} \\n(inferred)` : \"(inferred)\",\n style: { stroke: \"#d97706\", strokeDasharray: \"2 4\" },\n markerEnd: {\n type: \"arrowclosed\",\n color: \"#d97706\",\n width: 18,\n height: 18,\n },\n }\n : edge,\n );\n}\n\nconst placeOf = (place: { x: number; y: number }) => ({\n x: place.x,\n y: place.y,\n});\n\n/**\n * The model on a canvas: where the model's layout puts things, what's new placed next to what it connects to,\n * and laid out with the visualiser's layout when nothing has a place yet\n */\n/** A resource's canvas node type: domains and systems as containers, or as cards when they're drawn as cards */\nconst nodeTypeOf = (resource: Resource) =>\n resource.card && resource.type === \"domain\"\n ? \"context-domain\"\n : resource.card && resource.type === \"system\"\n ? \"system\"\n : NODE_TYPE[resource.type];\nconst isCardType = (type?: string) =>\n type === \"context-domain\" || type === \"system\";\n\nexport async function modelToCanvas(\n model: Model,\n seed?: { nodes: Node[] },\n): Promise<ModelCanvasContent> {\n const byId = new Map(model.resources.map((r) => [r.id, r]));\n const saved = model.layout?.messages ?? {};\n let nodes: Node[] = sortByHierarchy(\n model.resources.map((resource) => {\n const parent = resource.parent ? byId.get(resource.parent) : undefined;\n const place = saved[resource.id];\n const group =\n !resource.card &&\n (resource.type === \"domain\" || resource.type === \"system\");\n const size = group\n ? place?.width && place.height\n ? { width: place.width, height: place.height }\n : getNodeDefinition(NODE_TYPE[resource.type])?.defaultSize\n : undefined;\n return {\n id: resource.id,\n type: nodeTypeOf(resource),\n position: place ? placeOf(place) : { x: 0, y: 0 },\n data: resourceNodeData(resource),\n ...(size && { width: size.width, height: size.height }),\n ...(parent &&\n !parent.card &&\n (parent.type === \"domain\" || parent.type === \"system\") && {\n parentId: parent.id,\n }),\n // Containers sit behind what's in them and the connections between them\n ...(group && { zIndex: -1 }),\n } satisfies Node;\n }),\n );\n const edges = edgesFor(model, byId);\n\n // Places are relative to the container a node is in: one outside its container wasn't set by the view (e.g. an\n // agent guessed where something new goes, in canvas coordinates), so it's placed as something new is\n const lookup = new Map(nodes.map((node) => [node.id, node]));\n const misplaced = (node: Node) => {\n const parent = node.parentId ? lookup.get(node.parentId) : undefined;\n if (!parent || !saved[node.id]) return false;\n const { x, y } = node.position;\n const slack = 20;\n return (\n x < -slack ||\n y < -slack ||\n (parent.width !== undefined && x > parent.width) ||\n (parent.height !== undefined && y > parent.height)\n );\n };\n const unplaced = nodes\n .filter((node) => !saved[node.id] || misplaced(node))\n .map((node) => node.id);\n const seeded =\n unplaced.length === nodes.length && seed\n ? placesFromSeed(seed.nodes, nodes)\n : undefined;\n if (seeded) {\n // Nothing has a place: where the diagram it was drawn as put things (so the agent's build ends where the canvas starts)\n nodes = nodes.map((node) =>\n seeded.has(node.id) ? { ...node, ...seeded.get(node.id)! } : node,\n );\n } else if (unplaced.length === nodes.length && nodes.length) {\n // Nothing has a place: laid out as the visualiser lays a diagram out\n const layout = await getLayoutPositions(nodes, edges);\n nodes = nodes.map((node) => {\n const laidOut = layout.nodes.get(node.id);\n return laidOut\n ? {\n ...node,\n position: laidOut.position,\n ...(laidOut.size && laidOut.size),\n }\n : node;\n });\n } else if (unplaced.length) {\n // Some new (e.g. the agent added them): next to what they connect to, nothing else moves\n const links: Link[] = edges.map(({ source, target }) => ({\n source,\n target,\n }));\n const places = placeNodes(nodes, unplaced, links);\n // Placed in canvas coordinates: what's in a container is positioned relative to it (a new service in a new domain\n // was drawn as far from its domain as the domain is from the canvas's corner)\n const byNodeId = new Map(nodes.map((node) => [node.id, node]));\n const canvasAt = (node: Node): XYPosition => {\n const placed = places.get(node.id);\n if (placed) return placed;\n const parent = node.parentId ? byNodeId.get(node.parentId) : undefined;\n if (!parent) return node.position;\n const parentAt = canvasAt(parent);\n return {\n x: parentAt.x + node.position.x,\n y: parentAt.y + node.position.y,\n };\n };\n nodes = nodes.map((node) => {\n const placed = places.get(node.id);\n if (!placed) return node;\n const parent = node.parentId ? byNodeId.get(node.parentId) : undefined;\n const parentAt = parent ? canvasAt(parent) : { x: 0, y: 0 };\n return {\n ...node,\n position: { x: placed.x - parentAt.x, y: placed.y - parentAt.y },\n };\n });\n }\n\n return {\n nodes: [...nodes, ...notesToNodes(model.notes ?? [], nodes)],\n edges,\n levelLayouts: {\n 1: new Map(Object.entries(model.layout?.overview ?? {})),\n 2: new Map(Object.entries(model.layout?.services ?? {})),\n },\n threads: (model.comments ?? []) as Thread[],\n hotspots: toCanvasHotspots(model.hotspots ?? []),\n };\n}\n\n/**\n * Where a diagram (the visualiser's graph of the model, with its own ids for domains and systems) puts each resource's\n * node, relative to the container it's in on the canvas, and containers' sizes. Undefined unless it has them all.\n */\nfunction placesFromSeed(seedNodes: Node[], nodes: Node[]) {\n const seedLookup = new Map(seedNodes.map((node) => [node.id, node]));\n const seedOf = (node: Node) =>\n seedLookup.get(node.id) ?? seedLookup.get(`${node.type}-${node.id}`);\n const absolute = new Map<string, XYPosition>();\n for (const node of nodes) {\n const found = seedOf(node);\n if (!found) return undefined;\n absolute.set(node.id, getAbsolutePosition(found, seedLookup));\n }\n return new Map(\n nodes.map((node) => {\n const found = seedOf(node)!;\n const at = absolute.get(node.id)!;\n const parentAt = node.parentId ? absolute.get(node.parentId) : undefined;\n const width =\n typeof found.style?.width === \"number\"\n ? found.style.width\n : found.width;\n const height =\n typeof found.style?.height === \"number\"\n ? found.style.height\n : found.height;\n return [\n node.id,\n {\n position: parentAt\n ? { x: at.x - parentAt.x, y: at.y - parentAt.y }\n : at,\n ...(isGroupType(node.type) && width && height && { width, height }),\n },\n ] as const;\n }),\n );\n}\n\n/** Notes as sticky note (or text) nodes, on their level: put where they were, else beside what they're about */\nfunction notesToNodes(notes: Note[], nodes: Node[]): Node[] {\n const lookup = new Map(nodes.map((node) => [node.id, node]));\n const bottom = nodes.length\n ? Math.max(\n ...nodes.map(\n (node) => getAbsolutePosition(node, lookup).y + (node.height ?? 120),\n ),\n )\n : 0;\n const beside = new Map<string, number>();\n return notes.map((note, index) => {\n const type = note.kind === \"text\" ? \"text\" : \"note\";\n const about = note.resource ? lookup.get(note.resource) : undefined;\n let position: XYPosition;\n if (note.x !== undefined && note.y !== undefined)\n position = { x: note.x, y: note.y };\n else if (about) {\n // To the right of it, stacked when it has several\n const stacked = beside.get(about.id) ?? 0;\n beside.set(about.id, stacked + 1);\n const at = getAbsolutePosition(about, lookup);\n position = {\n x: at.x + (about.width ?? 260) + 40,\n y: at.y + stacked * 200,\n };\n } else position = { x: index * 240, y: bottom + 120 };\n const level = note.level ? LEVEL_NUMBER[note.level] : undefined;\n return {\n id: `note-${index}`,\n type,\n position,\n // Text is as wide as what's written (its size is its font's)\n ...(type === \"note\" && { width: note.width ?? 200 }),\n data: {\n text: note.text,\n ...(type === \"note\" && { color: note.color ?? \"yellow\" }),\n // Studio keeps a note on L3 unless it says otherwise\n ...(level && level !== 3 && { level }),\n ...(note.resource && { resource: note.resource }),\n ...(note.author && { author: note.author }),\n ...(note.createdAt && { createdAt: note.createdAt }),\n ...(note.fontSize && { fontSize: note.fontSize }),\n ...(note.angle && { angle: note.angle }),\n },\n } satisfies Node;\n });\n}\n\n// ---- Back to the model ----\n\nconst PRODUCERS = new Set<ResourceType>([\n \"service\",\n \"agent\",\n \"view\",\n \"actor\",\n \"external-system\",\n]);\n\n/**\n * What a new connection between two nodes means, from their types: sends and receives between services (and the\n * like) and messages, routes through from a message to a channel, writes and reads with data stores, and\n * otherwise a \"connects\" described by the edge's label\n */\nfunction relationsForEdge(\n edge: Edge,\n from: Resource,\n to: Resource,\n routedThrough: (channel: string) => string[],\n): Relation[] {\n const label =\n typeof edge.label === \"string\" && edge.label.trim()\n ? edge.label.replace(/\\s+/g, \" \").trim()\n : undefined;\n if (PRODUCERS.has(from.type) && MESSAGE_TYPES.has(to.type))\n return [{ from: from.id, to: to.id, kind: \"sends\" }];\n if (MESSAGE_TYPES.has(from.type) && PRODUCERS.has(to.type))\n return [{ from: to.id, to: from.id, kind: \"receives\" }];\n if (MESSAGE_TYPES.has(from.type) && to.type === \"channel\")\n return [{ from: from.id, to: to.id, kind: \"routes-through\" }];\n if (from.type === \"channel\" && PRODUCERS.has(to.type)) {\n const messages = routedThrough(from.id);\n if (messages.length)\n return messages.map((message) => ({\n from: to.id,\n to: message,\n kind: \"receives\" as const,\n }));\n }\n if (\n (from.type === \"service\" || from.type === \"agent\") &&\n to.type === \"container\"\n )\n return [{ from: from.id, to: to.id, kind: \"writes\" }];\n if (\n from.type === \"container\" &&\n (to.type === \"service\" || to.type === \"agent\")\n )\n return [{ from: to.id, to: from.id, kind: \"reads\" }];\n return [\n { from: from.id, to: to.id, kind: \"connects\", ...(label && { label }) },\n ];\n}\n\nconst round = (value: number) => Math.round(value);\nconst placeFor = (node: Node) => ({\n x: round(node.position.x),\n y: round(node.position.y),\n ...(isGroupType(node.type) &&\n node.width &&\n node.height && { width: round(node.width), height: round(node.height) }),\n});\nconst placesOf = (\n places: ReadonlyMap<string, LevelPlace>,\n ids: Set<string>,\n) => {\n const kept = [...places].filter(([id]) => ids.has(id));\n return kept.length\n ? Object.fromEntries(\n kept.map(([id, place]) => [\n id,\n {\n x: round(place.x),\n y: round(place.y),\n ...(place.width &&\n place.height && {\n width: round(place.width),\n height: round(place.height),\n }),\n },\n ]),\n )\n : undefined;\n};\n\n/** The canvas as the model: its resources, relations and notes (through what's still on it), and where things are */\nexport function canvasToModel(\n nodes: Node[],\n edges: Edge[],\n levelLayouts: Record<1 | 2, ReadonlyMap<string, LevelPlace>>,\n base: Model,\n threads: Thread[] = [],\n hotspots: Hotspot[] = [],\n): Model {\n const lookup = new Map(nodes.map((node) => [node.id, node]));\n const resourceNodes = nodes.filter(\n (node) => !isWrittenOnCanvas(node.type) && resourceTypeOf(node.type),\n );\n const resources: Resource[] = resourceNodes.map((node) => {\n const type = resourceTypeOf(node.type)!;\n const kept = (node.data.resource as Resource | undefined) ?? undefined;\n const fields = getResource(node.type, node.data);\n const parent = node.parentId && lookup.get(node.parentId);\n const summary = String(fields.summary ?? \"\").trim();\n const version = String(fields.version ?? kept?.version ?? \"\").trim();\n const { parent: _, card: __, ...rest } = kept ?? ({} as Partial<Resource>);\n return {\n ...rest,\n id: node.id,\n type,\n name: String(fields.name ?? kept?.name ?? node.id).trim() || node.id,\n ...(summary ? { summary } : { summary: undefined }),\n ...(version && { version }),\n ...(type === \"entity\" &&\n Array.isArray(fields.properties) && {\n properties: fields.properties as Resource[\"properties\"],\n }),\n // Its kind of data store, as it is on the canvas (a database is the default, so it isn't written)\n ...(type === \"container\" && {\n containerType:\n fields.container_type && fields.container_type !== \"database\"\n ? (fields.container_type as Resource[\"containerType\"])\n : undefined,\n }),\n ...(isCardType(node.type) && { card: true }),\n ...(parent && resourceTypeOf(parent.type) && { parent: parent.id }),\n } as Resource;\n });\n const byId = new Map(resources.map((r) => [r.id, r]));\n\n // Messages through each channel, as the canvas has them now\n const routed = new Map<string, string[]>();\n edges.forEach((edge) => {\n const [from, to] = [byId.get(edge.source), byId.get(edge.target)];\n if (from && to && MESSAGE_TYPES.has(from.type) && to.type === \"channel\")\n routed.set(to.id, [...(routed.get(to.id) ?? []), from.id]);\n });\n const seen = new Set<string>();\n const relations: Relation[] = [];\n for (const edge of edges) {\n const [from, to] = [byId.get(edge.source), byId.get(edge.target)];\n if (!from || !to) continue;\n const kept = edge.data as Partial<EdgeRelations> | undefined;\n // What it was drawn for, while it joins the same ends; a connection made (or moved) here, from what it joins\n const drawnFor =\n kept?.relations && kept.ends === endsOf(edge)\n ? kept.relations.filter((r) => byId.has(r.from) && byId.has(r.to))\n : relationsForEdge(\n edge,\n from,\n to,\n (channel) => routed.get(channel) ?? [],\n );\n // Which of an entity's properties it's joined at, as it's drawn now\n const fieldOf = (handle: string | null | undefined, suffix: string) =>\n handle && handle.endsWith(suffix) && handle !== ENTITY_SOURCE_HANDLE\n ? handle.slice(0, -suffix.length)\n : undefined;\n const atFields = (relation: Relation): Relation => {\n if (\n relation.kind !== \"connects\" ||\n relation.from !== edge.source ||\n (from.type !== \"entity\" && to.type !== \"entity\")\n )\n return relation;\n const { fromField: _f, toField: _t, ...rest } = relation;\n const fromField =\n from.type === \"entity\"\n ? fieldOf(edge.sourceHandle, \"-source\")\n : undefined;\n const toField =\n to.type === \"entity\"\n ? fieldOf(edge.targetHandle, \"-target\")\n : undefined;\n return {\n ...rest,\n ...(fromField && { fromField }),\n ...(toField && { toField }),\n };\n };\n // What's written on it is on what it was drawn for (a connects is described by it; the others say it instead)\n const written = (edge.data as { customLabel?: string } | undefined)\n ?.customLabel;\n const withLabel = (relation: Relation): Relation => {\n if (written) return { ...relation, label: written };\n if (relation.kind === \"connects\") return relation;\n const { label: _, ...rest } = relation;\n return rest;\n };\n for (const relation of drawnFor.map(atFields).map(withLabel)) {\n const key = `${relation.from}|${relation.kind}|${relation.to}|${relation.fromField ?? \"\"}|${relation.toField ?? \"\"}`;\n if (!seen.has(key)) (relations.push(relation), seen.add(key));\n }\n }\n\n const notes: Note[] = nodes\n .filter((node) => isWrittenOnCanvas(node.type))\n .map((node) => {\n const at = getAbsolutePosition(node, lookup);\n const level = (node.data.level as 1 | 2 | undefined) ?? undefined;\n const resource =\n typeof node.data.resource === \"string\" && byId.has(node.data.resource)\n ? node.data.resource\n : undefined;\n return {\n text: String(node.data.text ?? \"\").slice(0, 1000),\n ...(node.type === \"text\" && { kind: \"text\" as const }),\n ...(node.type === \"note\" && node.data.color\n ? { color: node.data.color as Note[\"color\"] }\n : {}),\n ...(resource && { resource }),\n ...(typeof node.data.author === \"string\" && {\n author: node.data.author,\n }),\n ...(typeof node.data.createdAt === \"number\" && {\n createdAt: node.data.createdAt,\n }),\n ...(typeof node.data.fontSize === \"number\" && {\n fontSize: node.data.fontSize,\n }),\n ...(typeof node.data.angle === \"number\" &&\n node.data.angle !== 0 && { angle: node.data.angle }),\n level: LEVEL_NAME[level ?? 3],\n x: round(at.x),\n y: round(at.y),\n ...(node.type === \"note\" &&\n node.width && {\n width: Math.min(800, Math.max(120, round(node.width))),\n }),\n };\n });\n\n // A team connected to something owns it (as EventCatalog's owners): its name is in that resource's owners, while\n // the connection's there (owners that aren't a team on the canvas, e.g. ones the agent found, are kept)\n const teams = resources.filter((r) => r.type === \"team\");\n if (teams.length) {\n const teamNames = new Set(teams.map((team) => team.name));\n const ownedBy = new Map<string, string[]>();\n for (const relation of relations) {\n const team = byId.get(relation.from);\n if (team?.type !== \"team\" || relation.kind !== \"connects\") continue;\n ownedBy.set(relation.to, [\n ...(ownedBy.get(relation.to) ?? []),\n team.name,\n ]);\n }\n for (const resource of resources) {\n if (resource.type === \"team\") continue;\n const owners = [\n ...new Set([\n ...(resource.owners ?? []).filter((owner) => !teamNames.has(owner)),\n ...(ownedBy.get(resource.id) ?? []),\n ]),\n ];\n if (owners.length) resource.owners = owners;\n else delete resource.owners;\n }\n }\n\n const ids = new Set(resources.map((r) => r.id));\n const layout: Layout = {\n messages: Object.fromEntries(\n resourceNodes.map((node) => [node.id, placeFor(node)]),\n ),\n overview: placesOf(levelLayouts[1], ids),\n services: placesOf(levelLayouts[2], ids),\n };\n return {\n title: base.title,\n resources,\n relations,\n ...(notes.length && { notes }),\n ...(threads.length && { comments: threads }),\n // On a resource still on the canvas, else where they are\n ...(hotspots.length && {\n hotspots: hotspots.map(({ nodeId, position, level, ...hotspot }) =>\n nodeId && ids.has(nodeId)\n ? { ...hotspot, resource: nodeId }\n : { ...hotspot, position, ...(level && { level }) },\n ),\n }),\n layout,\n };\n}\n","/**\n * \"Save to file\" and \"Open\": a diagram as a .eventcatalog file (JSON: the model, with its notes, comments and\n * hotspots, and where it was focused), as drawing tools save theirs. The same file in Studio on the web and in\n * EventCatalog's Studio, so a diagram moves between them.\n */\nimport {\n LEVELS,\n Model,\n validateModel,\n type ArchitecturePayload,\n type Level,\n} from \"../model\";\n\nexport const DIAGRAM_FILE_EXTENSION = \".eventcatalog\";\nconst FILE_TYPE = \"eventcatalog-diagram\";\nconst FILE_VERSION = 1;\n// Big enough for any diagram the server accepts (its requests are limited to 1MB)\nconst MAX_FILE_SIZE = 2 * 1024 * 1024;\n\ntype DiagramFile = {\n type: typeof FILE_TYPE;\n version: number;\n source: string;\n model: Model;\n focus?: string;\n level?: Level;\n};\n\nexport const fileNameFor = (title: string, extension: string) =>\n `${\n title\n .replace(/[^\\w\\- ]+/g, \"\")\n .trim()\n .replace(/\\s+/g, \"-\")\n .toLowerCase() || \"diagram\"\n }${extension}`;\n\nexport function toDiagramFile(\n model: Model,\n { focus, level }: { focus?: string; level?: Level } = {},\n): string {\n const file: DiagramFile = {\n type: FILE_TYPE,\n version: FILE_VERSION,\n source: \"https://www.eventcatalog.dev\",\n model,\n focus,\n level,\n };\n return JSON.stringify(file, null, 2);\n}\n\n/** The diagram in a .eventcatalog file (or a bare model, as the agent writes them), or why it can't be opened */\nexport async function readDiagramFile(\n file: File,\n): Promise<\n Pick<ArchitecturePayload, \"model\" | \"focus\" | \"level\"> | { error: string }\n> {\n if (file.size > MAX_FILE_SIZE)\n return { error: `${file.name} is too big to be a diagram.` };\n let json: unknown;\n try {\n json = JSON.parse(await file.text());\n } catch {\n return {\n error: `${file.name} isn't a diagram file: save one with \"Save to file\".`,\n };\n }\n const saved =\n json &&\n typeof json === \"object\" &&\n (json as { type?: unknown }).type === FILE_TYPE\n ? (json as Partial<DiagramFile>)\n : undefined;\n if (saved && (saved.version ?? 0) > FILE_VERSION)\n return {\n error: `${file.name} was saved by a newer version: open it at eventcatalog.dev.`,\n };\n const parsed = Model.safeParse(saved ? saved.model : json);\n if (!parsed.success)\n return {\n error: `${file.name} isn't a diagram file: save one with \"Save to file\".`,\n };\n const { errors } = validateModel(parsed.data);\n if (errors.length)\n return { error: `${file.name} can't be drawn: ${errors[0]}` };\n const focus =\n saved?.focus && parsed.data.resources.some((r) => r.id === saved.focus)\n ? saved.focus\n : undefined;\n const level =\n saved?.level && LEVELS.includes(saved.level) ? saved.level : undefined;\n return { model: parsed.data, focus, level };\n}\n\n/** Downloads a file (text, or base64 for binary files such as images) */\nexport function downloadFile({\n name,\n mimeType,\n text,\n base64,\n}: {\n name: string;\n mimeType: string;\n text?: string;\n base64?: string;\n}) {\n const href =\n base64 !== undefined\n ? `data:${mimeType};base64,${base64}`\n : URL.createObjectURL(new Blob([text ?? \"\"], { type: mimeType }));\n const link = document.createElement(\"a\");\n link.href = href;\n link.download = name;\n link.click();\n if (href.startsWith(\"blob:\"))\n setTimeout(() => URL.revokeObjectURL(href), 1000);\n return true;\n}\n\n/** A name typed for the file, made safe to save, with the extension on the end */\nexport function cleanFileName(name: string, extension: string) {\n // No path characters, and no leading dots (hidden files)\n const cleaned = name\n .replace(/[\\\\/:*?\"<>|\\u0000-\\u001f]+/g, \"\")\n .trim()\n .replace(/^\\.+/, \"\");\n const base = cleaned.toLowerCase().endsWith(extension)\n ? cleaned.slice(0, -extension.length).trim()\n : cleaned;\n return `${base || \"diagram\"}${extension}`;\n}\n\n// The browser's save dialog (File System Access API: Chromium browsers, and not in frames such as chats)\ntype WritableFile = {\n createWritable: () => Promise<{\n write: (data: string) => Promise<void>;\n close: () => Promise<void>;\n }>;\n name: string;\n};\ntype SaveFilePicker = (options: {\n suggestedName: string;\n types: { description: string; accept: Record<string, string[]> }[];\n}) => Promise<WritableFile>;\nexport type SavedFileHandle = WritableFile;\n\nexport const canPickWhereToSave = () => {\n try {\n return (\n typeof (window as unknown as { showSaveFilePicker?: unknown })\n .showSaveFilePicker === \"function\" && window.self === window.top\n );\n } catch {\n return false;\n }\n};\n\n/** Writes to a file picked (or picked before): the handle, undefined when they cancelled */\nexport async function saveToPickedFile(\n text: string,\n {\n suggestedName,\n handle,\n }: { suggestedName: string; handle?: SavedFileHandle },\n) {\n const picker = (window as unknown as { showSaveFilePicker: SaveFilePicker })\n .showSaveFilePicker;\n let file = handle;\n if (!file) {\n try {\n file = await picker({\n suggestedName,\n types: [\n {\n description: \"EventCatalog diagram\",\n accept: { \"application/json\": [DIAGRAM_FILE_EXTENSION] },\n },\n ],\n });\n } catch (error) {\n if ((error as Error)?.name === \"AbortError\") return undefined;\n throw error;\n }\n }\n const writable = await file.createWritable();\n await writable.write(text);\n await writable.close();\n return file;\n}\n\n/** Asks for a .eventcatalog file to open */\nexport function pickDiagramFile(): Promise<File | undefined> {\n return new Promise((resolve) => {\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.accept = `${DIAGRAM_FILE_EXTENSION},application/json,.json`;\n input.onchange = () => resolve(input.files?.[0]);\n input.oncancel = () => resolve(undefined);\n input.click();\n });\n}\n","/**\n * \"Export image…\": the whole canvas (and its sticky notes and text) as a PNG, as the visualiser exports a diagram\n * (its helpers in utils/export-image.ts), with \"Made with EventCatalog\" in its bottom right corner. Each app saves it\n * its own way (downloaded, or through the chat it's in).\n */\nimport { toPng } from \"html-to-image\";\nimport {\n addExportBranding,\n getExportImageDimensions,\n injectExportStyles,\n} from \"../utils/export-image\";\n\nconst PIXEL_RATIO = 2;\n\nconst translateOf = (element: HTMLElement) => {\n const matrix = new DOMMatrix(getComputedStyle(element).transform);\n return { x: matrix.e, y: matrix.f };\n};\n\n/** What's drawn, in the diagram's coordinates: its nodes (React Flow places them with transforms) and notes */\nfunction drawnBounds(viewport: HTMLElement) {\n const rects: { x: number; y: number; width: number; height: number }[] = [];\n viewport\n .querySelectorAll<HTMLElement>(\".react-flow__node\")\n .forEach((node) => {\n const { x, y } = translateOf(node);\n rects.push({ x, y, width: node.offsetWidth, height: node.offsetHeight });\n });\n viewport.querySelectorAll<HTMLElement>(\".studio-note\").forEach((note) => {\n rects.push({\n x: note.offsetLeft,\n y: note.offsetTop,\n width: note.offsetWidth,\n height: note.offsetHeight,\n });\n });\n if (!rects.length) return undefined;\n const left = Math.min(...rects.map((r) => r.x));\n const top = Math.min(...rects.map((r) => r.y));\n return {\n x: left,\n y: top,\n width: Math.max(...rects.map((r) => r.x + r.width)) - left,\n height: Math.max(...rects.map((r) => r.y + r.height)) - top,\n };\n}\n\n/** The canvas in `container` as a PNG (a data URL), or undefined when there's nothing on it */\nexport async function canvasImage(\n container: HTMLElement,\n): Promise<string | undefined> {\n const viewport = container.querySelector<HTMLElement>(\n \".react-flow__viewport\",\n );\n const bounds = viewport && drawnBounds(viewport);\n if (!viewport || !bounds) return undefined;\n const { width, height, viewport: view } = getExportImageDimensions(bounds);\n const removeExportStyles = injectExportStyles(viewport);\n // Without the selection outlines\n container.classList.add(\"ec-exporting\");\n let dataUrl: string;\n try {\n dataUrl = await toPng(viewport, {\n backgroundColor: getComputedStyle(document.body).backgroundColor,\n width,\n height,\n pixelRatio: PIXEL_RATIO,\n style: {\n width: `${width}px`,\n height: `${height}px`,\n transform: `translate(${view.x}px, ${view.y}px) scale(${view.zoom})`,\n },\n });\n } finally {\n removeExportStyles();\n container.classList.remove(\"ec-exporting\");\n }\n return addExportBranding(dataUrl, PIXEL_RATIO);\n}\n","import {\n createContext,\n memo,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n} from \"react\";\nimport {\n Handle,\n NodeResizeControl,\n NodeResizer,\n Position,\n ResizeControlVariant,\n useReactFlow,\n useStoreApi,\n useUpdateNodeInternals,\n type NodeProps,\n type NodeTypes,\n} from \"@xyflow/react\";\nimport { ENTITY_SOURCE_HANDLE } from \"../entity-handles\";\nimport {\n diagramNodeComponents,\n DomainCardNode,\n EntityNode,\n memoNode,\n SystemGroupNode,\n} from \"../../index\";\nimport { TeamNode } from \"./TeamNode\";\nimport { ConnectPlaceholderNode } from \"./ConnectChooser\";\nimport { CONNECT_PLACEHOLDER } from \"../connect-new\";\nimport type { Editing } from \"../presence\";\nimport { GROUP_PADDING } from \"../grouping\";\nimport { getNodeName, getNoteLevel, GROUP_TYPES } from \"../node-types\";\n\n/** How the canvas draws each kind of node: the visualiser's nodes, notes and text written on the canvas, and resizable containers */\n\nexport type UpdateNodeData = (\n id: string,\n updater: (data: Record<string, unknown>) => Record<string, unknown>,\n) => void;\n\n// Notes are edited in place, so their callbacks need to reach the shared design\nexport const UpdateNodeDataContext = createContext<UpdateNodeData>(() => {});\n\n// What's being written on a note or text as it's typed (a live session shows it to the others), and done (null)\n/** Tells a live room what's being changed on a note or text as it changes (nothing: done) */\nexport const EditingContext = createContext<(editing: Editing | null) => void>(\n () => {},\n);\n\n// Which container something dragged would drop into, to highlight it\nexport const DropTargetContext = createContext<string | null>(null);\n\n// Text just put on the canvas with the text tool: written straight away\nexport const StartWritingContext = createContext<string | null>(null);\n\n// The canvas locked: looked at, not changed (nothing written, scaled, turned or resized)\nexport const LockedContext = createContext(false);\n\nconst SystemGroupComponent: NodeTypes[string] = SystemGroupNode;\n\n/** The handles that set a node's width, on either side (its height follows what's written in it) */\nfunction WidthHandles() {\n return (\n <>\n {/* Horizontal only: otherwise React Flow saves the height too, and it stops growing with what's written */}\n <NodeResizeControl\n position=\"left\"\n variant={ResizeControlVariant.Line}\n resizeDirection=\"horizontal\"\n minWidth={80}\n className=\"studio-width-handle\"\n />\n <NodeResizeControl\n position=\"right\"\n variant={ResizeControlVariant.Line}\n resizeDirection=\"horizontal\"\n minWidth={80}\n className=\"studio-width-handle\"\n />\n </>\n );\n}\n\n/**\n * What's written on a note or text, and writing it: Enter starts a new line, Escape or ⌘/Ctrl + Enter (or clicking\n * away) finishes, and it's saved for everyone then\n */\nfunction Writing({\n id,\n text,\n editing,\n onDone,\n placeholder,\n className,\n style,\n growWidth = false,\n}: {\n id: string;\n text: string;\n editing: boolean;\n /** Writing it is done, with what's written */\n onDone: (text: string) => void;\n placeholder: string;\n className: string;\n /** e.g. its font size, for text scaled on the canvas */\n style?: CSSProperties;\n /** The box is as wide as what's written, lines only breaking where they're broken (text, as Excalidraw's) */\n growWidth?: boolean;\n}) {\n const updateNodeData = useContext(UpdateNodeDataContext);\n const liveEdit = useContext(EditingContext);\n // Focused once it's shown: React Flow keeps a new node hidden until it's measured, and hidden fields can't take focus\n const areaRef = useRef<HTMLTextAreaElement | null>(null);\n useEffect(() => {\n if (!editing) return;\n let frame = 0;\n let tries = 0;\n const focus = () => {\n const area = areaRef.current;\n if (!area || document.activeElement === area) return;\n // Without scrolling: the browser would scroll the canvas to it, moving everything on it\n area.focus({ preventScroll: true });\n if (document.activeElement !== area && ++tries < 30)\n frame = requestAnimationFrame(focus);\n };\n focus();\n return () => cancelAnimationFrame(frame);\n }, [editing]);\n // The box grows with what's written (the node's height follows it)\n const fit = (area: HTMLTextAreaElement) => {\n if (growWidth) {\n area.style.width = \"0\";\n area.style.width = `${area.scrollWidth + 2}px`;\n }\n area.style.height = \"auto\";\n area.style.height = `${area.scrollHeight}px`;\n };\n if (!editing)\n return (\n <p className={className} style={style}>\n {text ||\n (placeholder && <span className=\"opacity-50\">{placeholder}</span>)}\n </p>\n );\n return (\n <textarea\n ref={(area) => {\n areaRef.current = area;\n if (area) fit(area);\n }}\n defaultValue={text}\n placeholder={placeholder}\n wrap={growWidth ? \"off\" : undefined}\n onFocus={(event) => event.currentTarget.select()}\n onInput={(event) => {\n fit(event.currentTarget);\n liveEdit({ id, text: event.currentTarget.value });\n }}\n onBlur={(event) => {\n const value = event.currentTarget.value;\n onDone(value);\n if (value !== text)\n updateNodeData(id, (current) => ({ ...current, text: value }));\n // Done (after what's written is saved, so the others don't see it go back in between)\n liveEdit(null);\n }}\n onKeyDown={(event) => {\n if (\n event.key === \"Escape\" ||\n (event.key === \"Enter\" && (event.metaKey || event.ctrlKey))\n )\n event.currentTarget.blur();\n }}\n className={`nodrag nopan nowheel block w-full resize-none overflow-hidden bg-transparent outline-none ${className}`}\n style={style}\n />\n );\n}\n\n/** A sticky note's colours: soft paper colours, readable in light and dark themes (the names are the visualiser's) */\nconst NOTE_COLORS: Record<string, { fill: string; border: string }> = {\n yellow: { fill: \"#fef9c3\", border: \"#fde047\" },\n blue: { fill: \"#dbeafe\", border: \"#93c5fd\" },\n green: { fill: \"#dcfce7\", border: \"#86efac\" },\n pink: { fill: \"#fce7f3\", border: \"#f9a8d4\" },\n purple: { fill: \"#ede9fe\", border: \"#c4b5fd\" },\n gray: { fill: \"#f3f4f6\", border: \"#d1d5db\" },\n};\n\n/**\n * A sticky note: a few lines on paper, about as wide as a card and as tall as what's on it. Double click it to\n * write; when it's selected, its colour can be changed and its width set.\n */\nconst StickyNote = memo(function StickyNote({ id, data, selected }: NodeProps) {\n const updateNodeData = useContext(UpdateNodeDataContext);\n // A note just put on the canvas is written on straight away\n const [editing, setEditing] = useState(\n useContext(StartWritingContext) === id,\n );\n const locked = useContext(LockedContext);\n const colorName =\n typeof data.color === \"string\" && NOTE_COLORS[data.color]\n ? data.color\n : \"yellow\";\n const color = NOTE_COLORS[colorName];\n return (\n <div\n className=\"studio-note\"\n style={{ background: color.fill, borderColor: color.border }}\n onDoubleClick={() => !locked && setEditing(true)}\n >\n {selected && !editing && !locked && (\n <>\n <WidthHandles />\n <div\n className=\"nodrag nopan studio-note-colors\"\n role=\"radiogroup\"\n aria-label=\"Note colour\"\n >\n {Object.entries(NOTE_COLORS).map(([name, { fill, border }]) => (\n <button\n key={name}\n role=\"radio\"\n aria-checked={name === colorName}\n title={name.charAt(0).toUpperCase() + name.slice(1)}\n onClick={() =>\n updateNodeData(id, (current) => ({ ...current, color: name }))\n }\n className=\"studio-note-color\"\n style={{\n background: fill,\n borderColor:\n name === colorName ? \"rgb(var(--ec-page-text))\" : border,\n }}\n />\n ))}\n </div>\n </>\n )}\n <Writing\n id={id}\n text={String(data.text ?? \"\")}\n editing={editing}\n onDone={() => setEditing(false)}\n placeholder=\"\"\n className=\"studio-note-body\"\n />\n {/* The level it's on (it's only shown there), and when it was written */}\n <span className=\"studio-note-level\">\n L{getNoteLevel({ type: \"note\", data })} note\n </span>\n {typeof data.createdAt === \"number\" && (\n <span className=\"studio-note-date\">\n {new Date(data.createdAt).toLocaleDateString(undefined, {\n day: \"numeric\",\n month: \"short\",\n })}\n </span>\n )}\n </div>\n );\n});\n\n/**\n * Text written straight on the canvas (titles, labels, notes to self), as Excalidraw's: as big as what's written,\n * in a box with corners to scale it (its font grows with it) and a handle above to turn it. Double click it to write.\n */\n/** Text's size when it's first written */\nexport const TEXT_FONT_SIZE = 22;\nconst clampFont = (size: number) =>\n Math.round(Math.min(160, Math.max(10, size)));\n/** Turned to between -180 and 180 degrees */\nconst normaliseAngle = (angle: number) =>\n Math.round(((((angle + 180) % 360) + 360) % 360) - 180);\nconst TEXT_CORNERS = [\n \"top-left\",\n \"top-right\",\n \"bottom-left\",\n \"bottom-right\",\n] as const;\n\n/** Follows the pointer until it's let go (for handles that aren't React Flow's) */\nconst followPointer = (\n onMove: (event: PointerEvent) => void,\n onEnd: () => void,\n) => {\n const end = () => {\n window.removeEventListener(\"pointermove\", onMove);\n window.removeEventListener(\"pointerup\", end);\n window.removeEventListener(\"pointercancel\", end);\n onEnd();\n };\n window.addEventListener(\"pointermove\", onMove);\n window.addEventListener(\"pointerup\", end);\n window.addEventListener(\"pointercancel\", end);\n};\n\nconst TextNode = memo(function TextNode({ id, data, selected }: NodeProps) {\n const [editing, setEditing] = useState(\n useContext(StartWritingContext) === id,\n );\n const { deleteElements } = useReactFlow();\n const updateNodeData = useContext(UpdateNodeDataContext);\n const liveEdit = useContext(EditingContext);\n const boxRef = useRef<HTMLDivElement>(null);\n // Scaled and turned live while a handle is dragged, saved when it's let go\n const savedFont =\n typeof data.fontSize === \"number\" ? data.fontSize : TEXT_FONT_SIZE;\n const savedAngle = typeof data.angle === \"number\" ? data.angle : 0;\n const [scaling, setScaling] = useState<number | null>(null);\n const [turning, setTurning] = useState<number | null>(null);\n const fontSize = scaling ?? savedFont;\n const angle = turning ?? savedAngle;\n\n // A corner scales it by how far it's dragged from the opposite corner\n const startScaling =\n (corner: (typeof TEXT_CORNERS)[number]) => (event: React.PointerEvent) => {\n event.stopPropagation();\n event.preventDefault();\n const rect = boxRef.current!.getBoundingClientRect();\n const anchor = {\n x: corner.endsWith(\"left\") ? rect.right : rect.left,\n y: corner.startsWith(\"top\") ? rect.bottom : rect.top,\n };\n const from = Math.max(\n Math.hypot(event.clientX - anchor.x, event.clientY - anchor.y),\n 1,\n );\n let next = savedFont;\n followPointer(\n (move) => {\n const size = clampFont(\n (savedFont *\n Math.hypot(move.clientX - anchor.x, move.clientY - anchor.y)) /\n from,\n );\n if (size === next) return;\n setScaling((next = size));\n liveEdit({ id, fontSize: size });\n },\n () => {\n setScaling(null);\n if (next !== savedFont)\n updateNodeData(id, (current) => ({ ...current, fontSize: next }));\n // (after it's saved, so the others don't see it go back in between)\n liveEdit(null);\n },\n );\n };\n // The handle above turns it about its middle (in steps of 15° with Shift held)\n const startTurning = (event: React.PointerEvent) => {\n event.stopPropagation();\n event.preventDefault();\n const rect = boxRef.current!.getBoundingClientRect();\n const centre = {\n x: rect.left + rect.width / 2,\n y: rect.top + rect.height / 2,\n };\n let next = savedAngle;\n followPointer(\n (move) => {\n const turned =\n (Math.atan2(move.clientY - centre.y, move.clientX - centre.x) * 180) /\n Math.PI +\n 90;\n const to = normaliseAngle(\n move.shiftKey ? Math.round(turned / 15) * 15 : turned,\n );\n if (to === next) return;\n setTurning((next = to));\n liveEdit({ id, angle: to });\n },\n () => {\n setTurning(null);\n if (next !== savedAngle)\n updateNodeData(id, (current) => ({ ...current, angle: next }));\n liveEdit(null);\n },\n );\n };\n\n // Text left empty goes, as Excalidraw's does\n const done = (text: string) => {\n setEditing(false);\n if (!text.trim()) void deleteElements({ nodes: [{ id }] });\n };\n const locked = useContext(LockedContext);\n const framed =\n (selected || scaling !== null || turning !== null) && !editing && !locked;\n return (\n <div\n ref={boxRef}\n className={`studio-text ${framed ? \"is-framed\" : \"\"}`}\n style={angle ? { transform: `rotate(${angle}deg)` } : undefined}\n onDoubleClick={() => !locked && setEditing(true)}\n >\n {framed && (\n <>\n {TEXT_CORNERS.map((corner) => (\n <span\n key={corner}\n className={`nodrag nopan studio-text-corner is-${corner}`}\n onPointerDown={startScaling(corner)}\n />\n ))}\n <span\n className=\"nodrag nopan studio-text-turn\"\n title=\"Rotate (Shift: 15° steps)\"\n onPointerDown={startTurning}\n />\n </>\n )}\n <Writing\n id={id}\n text={String(data.text ?? \"\")}\n editing={editing}\n onDone={done}\n placeholder={editing ? \"\" : \"Double-click to write\"}\n className=\"studio-text-body\"\n style={{ fontSize }}\n growWidth\n />\n </div>\n );\n});\n\n/** A domain inside another one is a subdomain (badged as one, like the visualiser), unless its data says otherwise */\nconst useDomainData = ({\n type,\n data,\n parentId,\n}: Pick<NodeProps, \"type\" | \"data\" | \"parentId\">) =>\n useMemo(() => {\n const isDomain = type === GROUP_TYPES.domain || type === \"context-domain\";\n return isDomain && parentId && data.subdomain === undefined\n ? { ...data, subdomain: true }\n : data;\n }, [type, data, parentId]);\n\n/**\n * An entity as the visualiser draws EventCatalog's (its properties listed). The canvas keeps an entity's fields in\n * data.entity, as it keeps every resource's; the visualiser reads a catalog entry (data.entity.data)\n */\nconst EntityCard = memo(function EntityCard(props: NodeProps) {\n const data = useMemo(\n () => ({ ...props.data, entity: { data: props.data.entity ?? {} } }),\n [props.data],\n );\n return (\n <>\n <EntityNode {...props} data={data} />\n {/* From the entity as a whole (its header): the visualiser's only start at a property's row */}\n <Handle\n type=\"source\"\n position={Position.Right}\n id={ENTITY_SOURCE_HANDLE}\n className=\"studio-entity-source\"\n />\n </>\n );\n});\n\n/** A domain card, badged as a subdomain when it's in another domain */\nconst DomainCard = memo(function DomainCard(props: NodeProps) {\n return <DomainCardNode {...props} data={useDomainData(props)} />;\n});\n\n/**\n * A domain or system as a container: resizable when selected, highlighted when something's dragged over it.\n * Like frames in design tools, it's moved and selected by its header, and dragging inside it draws a selection\n * box (its body lets the pointer through to the canvas: see studio.css).\n */\nconst GroupNode = memo(function GroupNode(props: NodeProps) {\n const isDropTarget = useContext(DropTargetContext) === props.id;\n const locked = useContext(LockedContext);\n const data = useDomainData(props);\n const store = useStoreApi();\n // Its handles (where edges meet its sides) measured again when its size changes: resizing it (NodeResizer) sets its\n // measured size first, so React Flow sees no change when it renders at that size and keeps the handles where the\n // sides were. A size that eases in (fitted to what's in it, or someone else's resize) is measured again by\n // RemeasureHandles once it's done; this one measures mid-transition, which that corrects.\n const updateNodeInternals = useUpdateNodeInternals();\n useEffect(() => {\n updateNodeInternals(props.id);\n }, [updateNodeInternals, props.id, props.width, props.height]);\n // Where what's inside has to stay (with room around it and for the header), in the container's parent's\n // coordinates: found when a resize starts, so it can't be resized smaller than what's in it\n const contents = useRef<{\n left: number;\n top: number;\n right: number;\n bottom: number;\n } | null>(null);\n const onResizeStart = useCallback(() => {\n const { nodeLookup } = store.getState();\n const container = nodeLookup.get(props.id);\n const children = [...nodeLookup.values()].filter(\n (node) => node.parentId === props.id,\n );\n if (!container || children.length === 0) {\n contents.current = null;\n return;\n }\n const { x, y } = container.position;\n const size = (node: (typeof children)[number]) => ({\n width: node.measured.width ?? node.width ?? 0,\n height: node.measured.height ?? node.height ?? 0,\n });\n const own = size(container);\n // A side already closer in than that (e.g. something placed in the padding) can still move out, just not in\n contents.current = {\n left: Math.max(\n x +\n Math.min(...children.map((node) => node.position.x)) -\n GROUP_PADDING.left,\n x,\n ),\n top: Math.max(\n y +\n Math.min(...children.map((node) => node.position.y)) -\n GROUP_PADDING.top,\n y,\n ),\n right: Math.min(\n x +\n Math.max(\n ...children.map((node) => node.position.x + size(node).width),\n ) +\n GROUP_PADDING.right,\n x + own.width,\n ),\n bottom: Math.min(\n y +\n Math.max(\n ...children.map((node) => node.position.y + size(node).height),\n ) +\n GROUP_PADDING.bottom,\n y + own.height,\n ),\n };\n }, [store, props.id]);\n const shouldResize = useCallback(\n (\n _: unknown,\n {\n x,\n y,\n width,\n height,\n }: { x: number; y: number; width: number; height: number },\n ) => {\n const bounds = contents.current;\n return (\n !bounds ||\n (x <= bounds.left &&\n y <= bounds.top &&\n x + width >= bounds.right &&\n y + height >= bounds.bottom)\n );\n },\n [],\n );\n return (\n <div style={{ width: \"100%\", height: \"100%\", position: \"relative\" }}>\n <NodeResizer\n isVisible={props.selected && !locked}\n onResizeStart={onResizeStart}\n shouldResize={shouldResize}\n minWidth={240}\n minHeight={160}\n lineClassName=\"!border-[rgb(var(--ec-accent))]\"\n handleClassName=\"!h-2.5 !w-2.5 !rounded-sm !border-2 !bg-[rgb(var(--ec-card-bg))] !border-[rgb(var(--ec-accent))]\"\n />\n <SystemGroupComponent {...props} data={data} />\n {/* The header (and the badge on its border) */}\n <div className=\"ec-group-grip absolute inset-x-0 -top-3 h-[60px] cursor-grab\" />\n {isDropTarget ? (\n // What's dragged over it goes in it when it's dropped\n <div className=\"ec-drop-target\">\n <span className=\"ec-drop-target-label\">\n Drop to add to{\" \"}\n {getNodeName(props.type, props.data, \"this container\")}\n </span>\n </div>\n ) : (\n props.selected && <div className=\"ec-group-selected\" />\n )}\n </div>\n );\n});\n\nconst components: NodeTypes = {\n // Everything the visualiser draws, drawn the same (so a diagram's levels look as they do there). It types its\n // components' props as nodes (Node<Data>) rather than React Flow's NodeProps, which they're rendered with.\n ...(diagramNodeComponents as unknown as NodeTypes),\n // Written on the canvas\n note: StickyNote,\n text: TextNode,\n // Actors look like the visualiser's actors on its architecture diagrams\n actor: diagramNodeComponents[\"context-actor\"] as NodeTypes[string],\n \"context-domain\": DomainCard,\n // The domain model, and who owns what\n entity: EntityCard,\n team: TeamNode,\n // Domains and systems as containers\n [GROUP_TYPES.domain]: GroupNode,\n [GROUP_TYPES.system]: GroupNode,\n // Where a connection let go of on empty canvas makes something new, until what it is is chosen\n [CONNECT_PLACEHOLDER]: ConnectPlaceholderNode,\n};\n\n// React Flow gives every node its position, which changes on every frame it moves (dragged, in a dragged container,\n// or gliding to a layout): like the visualiser's, nodes render again only when something else changes\nexport const nodeTypes: NodeTypes = Object.fromEntries(\n Object.entries(components).map(([type, component]) => [\n type,\n memoNode(component),\n ]),\n);\n","/**\n * A team: who owns what. Drawn like the visualiser's cards (a coloured border, its kind on a tab over the top edge,\n * its name and summary), in the team colour. Connected to a domain, system or service, it's that resource's owner.\n */\nimport { memo } from \"react\";\nimport { Handle, Position, type NodeProps } from \"@xyflow/react\";\nimport { Users } from \"lucide-react\";\n\ntype TeamData = {\n mode?: string;\n team?: { name?: string; summary?: string; version?: string };\n};\n\nexport const TeamNode = memo(function TeamNode({ data, selected }: NodeProps) {\n const { mode = \"full\", team = {} } = data as TeamData;\n const name = team.name || \"Team\";\n return (\n <div\n className={`relative min-w-44 max-w-60 rounded-xl border-2 border-emerald-500 ${selected ? \"ring-2 ring-emerald-400/60 ring-offset-2\" : \"\"}`}\n style={{\n background: \"rgb(var(--ec-card-bg))\",\n boxShadow: \"0 2px 12px rgba(16, 185, 129, 0.15)\",\n }}\n >\n <Handle type=\"target\" position={Position.Left} />\n <Handle type=\"source\" position={Position.Right} />\n <div className=\"absolute -top-2.5 left-2.5 z-10 flex items-center\">\n <span className=\"inline-flex items-center gap-1 rounded bg-emerald-500 px-1.5 py-0.5 text-[7px] font-bold uppercase tracking-widest text-white shadow-sm\">\n <Users className=\"h-2.5 w-2.5\" strokeWidth={2.5} />\n Team\n </span>\n </div>\n <div className=\"flex items-start gap-2 px-3 pb-2.5 pt-3.5\">\n <span className=\"mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-emerald-500/10 text-emerald-600\">\n <Users className=\"h-3.5 w-3.5\" />\n </span>\n <div className=\"min-w-0\">\n <div\n className=\"truncate text-[13px] font-semibold leading-snug text-[rgb(var(--ec-page-text))]\"\n title={name}\n >\n {name}\n </div>\n {mode === \"full\" && team.summary && (\n <div\n className=\"mt-1 line-clamp-2 text-[9px] leading-relaxed text-[rgb(var(--ec-page-text-muted))]\"\n title={team.summary}\n >\n {team.summary}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n});\n\nexport default TeamNode;\n","/**\n * What a connection let go of on empty canvas makes there: a placeholder where it was let go of (connected to the node\n * it was dragged from), and a list beside it to choose what it is, searched as you type and picked with the arrow\n * keys and Enter (see connect-new.ts).\n */\nimport {\n Fragment,\n memo,\n useEffect,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent,\n} from \"react\";\nimport { Handle, Position, type NodeProps } from \"@xyflow/react\";\nimport { Plus, X } from \"lucide-react\";\nimport {\n CONNECT_PLACEHOLDER_SIZE,\n filterConnectOptions,\n type ConnectOption,\n} from \"../connect-new\";\nimport { NODE_ICONS } from \"./icons\";\n\nexport type ConnectPlaceholderData = {\n /** The option picked out in the list, shown on the placeholder */\n choice?: { key: string; label: string; summary?: string };\n};\n\nconst HIDDEN_HANDLE = {\n opacity: 0,\n pointerEvents: \"none\",\n} as const;\n\n// Drawn as the canvas's nodes are (a card with its kind on a badge on its top edge, its name and summary as a\n// service's), faded and dashed until it's chosen, in the colour of what's picked out in the list (the border and badge\n// take the text colour)\nconst PLACEHOLDER_CLASS =\n \"relative rounded-xl border-2 border-dashed border-current bg-[rgb(var(--ec-card-bg))] px-3 pt-3.5 pb-2.5 opacity-50\";\nconst DEFAULT_COLOUR = \"text-[rgb(var(--ec-accent))]\";\n\n/** What the placeholder shows: what it'll be once chosen, or a new node until then */\nfunction PlaceholderContent({ choice }: ConnectPlaceholderData) {\n const icon = choice ? NODE_ICONS[choice.key] : undefined;\n const Icon = icon?.icon ?? Plus;\n return (\n <>\n <span className=\"absolute -top-2.5 left-2.5 rounded bg-current px-1.5 py-0.5 shadow-sm\">\n <span className=\"flex items-center gap-1 text-[7px] font-bold uppercase tracking-widest text-white\">\n <Icon className=\"h-2.5 w-2.5\" strokeWidth={2.5} />\n {choice?.label ?? \"New\"}\n </span>\n </span>\n <div className=\"truncate text-[13px] font-semibold leading-snug text-[rgb(var(--ec-page-text))]\">\n {choice ? `New ${choice.label}` : \"New node\"}\n </div>\n <div className=\"mt-1.5 truncate text-[9px] leading-relaxed text-[rgb(var(--ec-page-text-muted))]\">\n {choice ? choice.summary : \"Choose what it is from the list\"}\n </div>\n </>\n );\n}\n\n/** Where the new node goes, until what it is is chosen */\nexport const ConnectPlaceholderNode = memo(function ConnectPlaceholderNode({\n data,\n}: NodeProps) {\n const { choice } = data as ConnectPlaceholderData;\n const colour =\n (choice && NODE_ICONS[choice.key]?.className) || DEFAULT_COLOUR;\n return (\n <div\n className={`${PLACEHOLDER_CLASS} ${colour}`}\n style={CONNECT_PLACEHOLDER_SIZE}\n >\n <Handle\n type=\"target\"\n position={Position.Left}\n isConnectable={false}\n style={HIDDEN_HANDLE}\n />\n <PlaceholderContent choice={choice} />\n <Handle\n type=\"source\"\n position={Position.Right}\n isConnectable={false}\n style={HIDDEN_HANDLE}\n />\n </div>\n );\n});\n\nconst LIST_WIDTH = 288;\nconst LIST_HEIGHT = 360;\n\nexport function ConnectChooser({\n options,\n fromName,\n anchor,\n onHighlight,\n onChoose,\n onCancel,\n}: {\n /** What can be made (getConnectOptions), the suggested ones first */\n options: ConnectOption[];\n /** The node the connection was dragged from */\n fromName?: string;\n /** The placeholder on screen: the list goes under it (or above, near the bottom of the screen) */\n anchor: { x: number; y: number; width: number; height: number };\n onHighlight: (option: ConnectOption | undefined) => void;\n onChoose: (option: ConnectOption) => void;\n onCancel: () => void;\n}) {\n const [query, setQuery] = useState(\"\");\n const [index, setIndex] = useState(0);\n // The placeholder says what it'll be once something's picked out (typed, arrowed or pointed at), not straight away\n const [picking, setPicking] = useState(false);\n const shown = useMemo(\n () => filterConnectOptions(options, query),\n [options, query],\n );\n const highlighted = shown[Math.min(index, shown.length - 1)];\n const listRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => setIndex(0), [query]);\n useEffect(\n () => onHighlight(picking ? highlighted : undefined),\n [picking, highlighted?.key],\n );\n useEffect(() => {\n if (!highlighted) return;\n listRef.current\n ?.querySelector(`[data-key=\"${CSS.escape(highlighted.key)}\"]`)\n ?.scrollIntoView({ block: \"nearest\" });\n }, [highlighted?.key]);\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n event.preventDefault();\n event.stopPropagation();\n return onCancel();\n }\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n setPicking(true);\n if (!shown.length) return;\n const step = event.key === \"ArrowDown\" ? 1 : -1;\n setIndex(\n (current) =>\n (Math.min(current, shown.length - 1) + step + shown.length) %\n shown.length,\n );\n }\n if (event.key === \"Enter\" && highlighted) {\n event.preventDefault();\n onChoose(highlighted);\n }\n };\n\n // Kept on screen: under the placeholder, or above it when there's no room below\n const left = Math.min(\n Math.max(anchor.x, 12),\n window.innerWidth - LIST_WIDTH - 12,\n );\n const below = anchor.y + anchor.height + 8;\n const top =\n below + LIST_HEIGHT > window.innerHeight - 12\n ? Math.max(anchor.y - LIST_HEIGHT - 8, 12)\n : below;\n\n const suggested = shown.filter((option) => option.says);\n const others = shown.filter((option) => !option.says);\n const row = (option: ConnectOption) => {\n const { icon: Icon, className } = NODE_ICONS[option.key] ??\n NODE_ICONS[option.type] ?? { icon: Plus, className: \"\" };\n const active = option.key === highlighted?.key;\n return (\n <button\n key={option.key}\n type=\"button\"\n role=\"option\"\n // Focus stays in the search, where the keys work (arrows, Enter, Escape)\n tabIndex={-1}\n onMouseDown={(event) => event.preventDefault()}\n aria-selected={active}\n data-key={option.key}\n onPointerMove={() => {\n setPicking(true);\n if (!active) setIndex(shown.indexOf(option));\n }}\n onClick={() => onChoose(option)}\n className={`flex w-full items-center gap-2.5 rounded-md px-2 py-1.5 text-left ${\n active ? \"bg-[rgb(var(--ec-accent)/0.1)]\" : \"\"\n }`}\n >\n <span className=\"flex h-7 w-7 flex-none items-center justify-center rounded-md bg-[rgb(var(--ec-content-hover))]\">\n <Icon size={15} className={className} />\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-[13px] font-medium leading-tight\">\n {option.label}\n </span>\n <span className=\"block truncate text-[11px] leading-snug text-[rgb(var(--ec-page-text-muted))]\">\n {option.says || option.summary}\n </span>\n </span>\n </button>\n );\n };\n const section = (title: string, list: ConnectOption[]) =>\n list.length > 0 && (\n <Fragment key={title}>\n <p\n role=\"presentation\"\n className=\"px-2 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wider text-[rgb(var(--ec-page-text-muted))]\"\n >\n {title}\n </p>\n {list.map(row)}\n </Fragment>\n );\n\n return (\n <div className=\"fixed inset-0 z-50\" onPointerDown={onCancel}>\n <div\n role=\"dialog\"\n aria-label=\"Connect to something new\"\n onPointerDown={(event) => event.stopPropagation()}\n className=\"absolute flex flex-col rounded-lg border shadow-xl bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))]\"\n style={{ left, top, width: LIST_WIDTH, maxHeight: LIST_HEIGHT }}\n >\n <div className=\"flex flex-none items-center gap-1 border-b border-[rgb(var(--ec-page-border))] p-1.5\">\n <input\n autoFocus\n value={query}\n onChange={(event) => {\n setPicking(true);\n setQuery(event.target.value);\n }}\n onKeyDown={onKeyDown}\n placeholder={fromName ? `Connect ${fromName} to…` : \"Connect to…\"}\n aria-label=\"What to connect to\"\n role=\"combobox\"\n aria-expanded\n aria-controls=\"studio-connect-options\"\n className=\"min-w-0 flex-1 rounded-md bg-transparent px-2 py-1 text-[13px] outline-none placeholder:text-[rgb(var(--ec-page-text-muted))]\"\n />\n <button\n type=\"button\"\n onClick={onCancel}\n aria-label=\"Cancel\"\n className=\"rounded p-1 text-[rgb(var(--ec-icon-color))] hover:bg-[rgb(var(--ec-page-border)/0.5)]\"\n >\n <X size={14} />\n </button>\n </div>\n <div\n ref={listRef}\n id=\"studio-connect-options\"\n role=\"listbox\"\n className=\"min-h-0 flex-1 overflow-y-auto p-1\"\n >\n {shown.length ? (\n <>\n {section(\"Suggested\", suggested)}\n {section(\n suggested.length ? \"Everything else\" : \"Components\",\n others,\n )}\n </>\n ) : (\n <p className=\"px-2 py-3 text-center text-xs text-[rgb(var(--ec-page-text-muted))]\">\n Nothing called “{query}”\n </p>\n )}\n </div>\n </div>\n </div>\n );\n}\n","import {\n createContext,\n memo,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n type PointerEvent as ReactPointerEvent,\n type ReactNode,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n useInternalNode,\n useReactFlow,\n type Node,\n type XYPosition,\n} from \"@xyflow/react\";\nimport { CanvasPortal } from \"../../utils/flow-portals\";\nimport {\n Check,\n GripVertical,\n Maximize2,\n RotateCcw,\n Trash2,\n X,\n} from \"lucide-react\";\nimport { getAbsolutePosition } from \"../grouping\";\nimport type { Author, CommentAnchor, Thread } from \"../canvas-doc\";\nimport { COUNTER_SCALE, useCounterScale } from \"../use-counter-scale\";\nimport { isGroupType, isWrittenOnCanvas } from \"../node-types\";\nimport { STATUS } from \"./status\";\nimport { sendMove, useRemoteMoves, type LiveMoves } from \"../live-moves\";\nimport Picture from \"./Picture\";\nimport { AgentMark } from \"./ClientLogos\";\n\n// Each word's first letter (as people's avatars are everywhere else here), or a single word's first two\nconst initials = (name: string) => {\n const words = name.trim().split(/\\s+/).filter(Boolean);\n return (\n words.length > 1 ? words.map((word) => word[0]).join(\"\") : name.trim()\n )\n .slice(0, 2)\n .toUpperCase();\n};\n\nexport const timeAgo = (timestamp: number) => {\n const seconds = Math.round((Date.now() - timestamp) / 1000);\n if (seconds < 60) return \"just now\";\n const minutes = Math.round(seconds / 60);\n if (minutes < 60) return `${minutes}m ago`;\n const hours = Math.round(minutes / 60);\n if (hours < 24) return `${hours}h ago`;\n return new Date(timestamp).toLocaleDateString();\n};\n\n/** Where a pin sits on the canvas: on its node (so it moves with it), or where it was dropped */\nexport const getAnchorPosition = (\n anchor: CommentAnchor,\n nodesById: Map<string, Node>,\n): XYPosition => {\n const node = anchor.nodeId ? nodesById.get(anchor.nodeId) : undefined;\n if (!node || !anchor.offset) return anchor.position;\n // Nodes in containers are positioned relative to them\n const position = getAbsolutePosition(node, nodesById);\n return { x: position.x + anchor.offset.x, y: position.y + anchor.offset.y };\n};\n\n/** Pinned to a node, a comment keeps its offset from the node so it moves with it */\nexport const anchorAt = (\n position: XYPosition,\n node?: Node,\n nodesById?: Map<string, Node>,\n): CommentAnchor => {\n if (!node) return { position };\n const nodePosition = getAbsolutePosition(\n node,\n nodesById ?? new Map([[node.id, node]]),\n );\n return {\n position,\n nodeId: node.id,\n offset: { x: position.x - nodePosition.x, y: position.y - nodePosition.y },\n };\n};\n\nconst DRAG_THRESHOLD_PX = 4;\n\nconst panelClass =\n \"nowheel nodrag nopan absolute z-40 w-72 rounded-xl border shadow-xl bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))]\";\n\n/** The people in a thread, in the order they joined it (the pin shows the first few, like Figma) */\nconst participantsOf = (thread: Thread): Author[] => {\n const seen = new Map<string, Author>([[thread.author.name, thread.author]]);\n for (const message of thread.messages)\n if (!seen.has(message.author.name))\n seen.set(message.author.name, message.author);\n return [...seen.values()];\n};\nconst MAX_PIN_AVATARS = 3;\n/** How long the pointer rests on a pin before it opens its preview (passing over pins leaves them closed) */\nconst PREVIEW_DELAY_MS = 500;\nconst repliesLabel = (count: number) =>\n count === 1 ? \"1 reply\" : `${count} replies`;\n\nfunction Avatar({\n author,\n muted,\n size = \"h-6 w-6\",\n}: {\n author: Author;\n muted?: boolean;\n size?: string;\n}) {\n return (\n <span\n title={author.name}\n className={`relative flex ${size} shrink-0 items-center justify-center rounded-full text-[10px] font-semibold text-white ring-2 ring-[rgb(var(--ec-card-bg))]`}\n style={{\n backgroundColor: muted\n ? \"rgb(var(--ec-page-text-muted))\"\n : author.color,\n }}\n >\n {author.agent ? (\n <AgentMark name={author.name} size={13} />\n ) : (\n initials(author.name)\n )}\n <Picture\n src={author.picture}\n className={`absolute inset-0 h-full w-full ${muted ? \"opacity-50 grayscale\" : \"\"}`}\n />\n </span>\n );\n}\n\n/**\n * A comment pin, like Figma's: a speech bubble with the people in the thread, that opens into a preview of it\n * (who started it, when, what they said and how many replies) once the pointer rests on it. Click opens the\n * thread, dragging moves it: `onDrag` gets the screen point the pin's tip (its bottom left corner) is over,\n * keeping where on the pin it was grabbed.\n */\nfunction Pin({\n author,\n thread,\n active,\n selected,\n resolved,\n onClick,\n onDrag,\n}: {\n author: Author;\n /** The thread it's for (a new comment being written has none yet) */\n thread?: Thread;\n active?: boolean;\n /** Part of what's selected on the canvas (e.g. after selecting everything) */\n selected?: boolean;\n resolved?: boolean;\n onClick?: () => void;\n onDrag?: (tip: XYPosition, phase: \"move\" | \"end\") => void;\n}) {\n const drag = useRef<{\n start: XYPosition;\n grab: XYPosition;\n moved: boolean;\n } | null>(null);\n const [hovered, setHovered] = useState(false);\n const hoverTimer = useRef<ReturnType<typeof setTimeout>>(undefined);\n useEffect(() => () => clearTimeout(hoverTimer.current), []);\n const [pressed, setPressed] = useState(false);\n const tipOf = (event: { clientX: number; clientY: number }) => ({\n x: event.clientX - drag.current!.grab.x,\n y: event.clientY - drag.current!.grab.y,\n });\n const people = thread ? participantsOf(thread) : [author];\n const [first, ...rest] = thread?.messages ?? [];\n // The preview shows while the pointer is over the pin, not while the thread is open or the pin is dragged\n const expanded = !!thread && !!first && hovered && !active && !pressed;\n\n return (\n <button\n onPointerEnter={() => {\n clearTimeout(hoverTimer.current);\n hoverTimer.current = setTimeout(\n () => setHovered(true),\n PREVIEW_DELAY_MS,\n );\n }}\n onPointerLeave={() => {\n clearTimeout(hoverTimer.current);\n setHovered(false);\n }}\n onPointerDown={(event) => {\n if (event.button !== 0) return;\n // Keeps pointer events coming while the pointer is outside the pin (throws if the pointer has gone)\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {}\n setPressed(true);\n const rect = event.currentTarget.getBoundingClientRect();\n drag.current = {\n start: { x: event.clientX, y: event.clientY },\n grab: {\n x: event.clientX - rect.left,\n y: event.clientY - rect.bottom,\n },\n moved: false,\n };\n }}\n onPointerMove={(event) => {\n const current = drag.current;\n if (!current || !onDrag) return;\n const distance = Math.hypot(\n event.clientX - current.start.x,\n event.clientY - current.start.y,\n );\n if (!current.moved && distance < DRAG_THRESHOLD_PX) return;\n current.moved = true;\n onDrag(tipOf(event), \"move\");\n }}\n onPointerUp={(event) => {\n const current = drag.current;\n setPressed(false);\n if (!current) return;\n if (current.moved) onDrag?.(tipOf(event), \"end\");\n else onClick?.();\n drag.current = null;\n }}\n onPointerCancel={() => {\n drag.current = null;\n setPressed(false);\n }}\n // Keyboard activation (pointer clicks are handled on pointer up)\n onClick={(event) => event.detail === 0 && onClick?.()}\n aria-label={\n thread\n ? `Comment by ${thread.author.name}${rest.length ? `, ${repliesLabel(rest.length)}` : \"\"}`\n : \"New comment\"\n }\n className={`block cursor-grab rounded-[18px] rounded-bl-none border p-1 text-left shadow-lg transition-[box-shadow,transform] active:cursor-grabbing bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))] ${\n active ? \"ring-2 ring-[rgb(var(--ec-accent))]\" : \"\"\n } ${expanded ? \"w-64\" : \"\"}`}\n // Selected: a ring in the theme's button colour (strong in light and dark themes)\n style={\n selected\n ? {\n boxShadow:\n \"0 0 0 2px rgb(var(--ec-card-bg)), 0 0 0 4px rgb(var(--ec-button-bg))\",\n }\n : undefined\n }\n >\n {expanded ? (\n <span className=\"block space-y-1 px-1.5 py-1\">\n <span className=\"flex items-center gap-2\">\n <span className=\"flex -space-x-0.5\">\n {people.slice(0, MAX_PIN_AVATARS).map((person) => (\n <Avatar\n key={person.name}\n author={person}\n muted={resolved}\n size=\"h-5 w-5\"\n />\n ))}\n </span>\n <span className=\"min-w-0 truncate text-xs font-semibold\">\n {thread.author.name}\n </span>\n <span className=\"shrink-0 text-[11px] text-[rgb(var(--ec-page-text-muted))]\">\n {timeAgo(first.createdAt)}\n </span>\n </span>\n <span className=\"line-clamp-3 block whitespace-pre-wrap break-words text-xs\">\n {first.text}\n </span>\n {(rest.length > 0 || resolved) && (\n <span className=\"flex items-center gap-2 text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))]\">\n {rest.length > 0 && <span>{repliesLabel(rest.length)}</span>}\n {resolved && (\n <span\n className={`flex items-center gap-0.5 ${STATUS.success.text}`}\n >\n <Check size={11} /> Resolved\n </span>\n )}\n </span>\n )}\n </span>\n ) : (\n <span className=\"flex -space-x-1\">\n {people.slice(0, MAX_PIN_AVATARS).map((person) => (\n <Avatar key={person.name} author={person} muted={resolved} />\n ))}\n {people.length > MAX_PIN_AVATARS && (\n <span className=\"flex h-6 w-6 items-center justify-center rounded-full text-[10px] font-semibold ring-2 ring-[rgb(var(--ec-card-bg))] bg-[rgb(var(--ec-page-border))]\">\n +{people.length - MAX_PIN_AVATARS}\n </span>\n )}\n </span>\n )}\n </button>\n );\n}\n\nfunction Composer({\n placeholder,\n onSubmit,\n onCancel,\n}: {\n placeholder: string;\n onSubmit: (text: string) => void;\n onCancel?: () => void;\n}) {\n const [text, setText] = useState(\"\");\n const submit = () => {\n if (!text.trim()) return;\n onSubmit(text.trim());\n setText(\"\");\n };\n\n return (\n <div className=\"flex items-end gap-2 p-2\">\n <textarea\n autoFocus\n rows={1}\n value={text}\n placeholder={placeholder}\n onChange={(e) => setText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n submit();\n }\n if (e.key === \"Escape\") onCancel?.();\n }}\n className=\"max-h-32 min-h-[34px] flex-1 resize-none rounded-md border px-2 py-1.5 text-sm bg-[rgb(var(--ec-input-bg))] border-[rgb(var(--ec-input-border))] text-[rgb(var(--ec-input-text))]\"\n />\n <button\n onClick={submit}\n disabled={!text.trim()}\n className=\"rounded-md px-2.5 py-1.5 text-xs font-medium disabled:opacity-40 bg-[rgb(var(--ec-button-bg))] text-[rgb(var(--ec-button-text))]\"\n >\n Post\n </button>\n </div>\n );\n}\n\nfunction IconButton({\n title,\n onClick,\n children,\n}: {\n title: string;\n onClick: () => void;\n children: ReactNode;\n}) {\n return (\n <button\n title={title}\n onClick={onClick}\n className=\"rounded p-1 text-[rgb(var(--ec-icon-color))] hover:bg-[rgb(var(--ec-page-border)/0.5)] hover:text-[rgb(var(--ec-icon-hover))]\"\n >\n {children}\n </button>\n );\n}\n\n/** Room kept between a thread's box and the edges of the canvas */\nconst PANEL_MARGIN_PX = 12;\n/** A thread's box is at most this tall: longer threads scroll (or open bigger, in a dialog) */\nconst PANEL_MAX_HEIGHT_PX = 360;\n/** What drags a thread's box around (its header) */\nconst DragPanelContext = createContext<\n ((event: ReactPointerEvent<HTMLElement>) => void) | null\n>(null);\n\n/**\n * The box a thread (or a new comment) opens in, beside its pin. It opens moved up as far as needed to be fully\n * on the canvas, and can be dragged around by its header to see more of the canvas or of a long thread. Where it's\n * been moved is only here, and goes when it closes. With `onClickOutside`, a click anywhere but the box and its pin\n * closes it (as a popover does), unless there's a reply being written in it.\n */\nfunction FloatingPanel({\n children,\n onClickOutside,\n}: {\n children: ReactNode;\n onClickOutside?: () => void;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n const [offset, setOffset] = useState<XYPosition>({ x: 0, y: 0 });\n const offsetRef = useRef(offset);\n offsetRef.current = offset;\n\n const clickedOutside = useRef(onClickOutside);\n clickedOutside.current = onClickOutside;\n const closesOnClickOutside = !!onClickOutside;\n useEffect(() => {\n if (!closesOnClickOutside) return;\n const onPointerDown = (event: PointerEvent) => {\n const element = ref.current;\n // The box and its pin (the pin toggles it itself)\n const own = element?.parentElement;\n if (\n !element ||\n event.button !== 0 ||\n own?.contains(event.target as globalThis.Node)\n )\n return;\n // A reply half written isn't thrown away\n if (element.querySelector(\"textarea\")?.value.trim()) return;\n clickedOutside.current?.();\n };\n // Capture: the canvas stops some pointer events (panning, dragging nodes) from reaching the document\n document.addEventListener(\"pointerdown\", onPointerDown, true);\n return () =>\n document.removeEventListener(\"pointerdown\", onPointerDown, true);\n }, [closesOnClickOutside]);\n\n // Opened low on the canvas, or grown past the bottom of it (replies): moved up so its bottom (and the reply box)\n // can be seen\n useEffect(() => {\n const element = ref.current;\n if (!element) return;\n const fit = () => {\n const rect = element.getBoundingClientRect();\n const canvas = element\n .closest(\".react-flow\")\n ?.getBoundingClientRect() ?? { top: 0, bottom: window.innerHeight };\n const up = Math.min(\n rect.bottom - (canvas.bottom - PANEL_MARGIN_PX),\n rect.top - (canvas.top + PANEL_MARGIN_PX),\n );\n if (up > 0) setOffset((current) => ({ x: current.x, y: current.y - up }));\n };\n const observer = new ResizeObserver(fit);\n observer.observe(element);\n return () => observer.disconnect();\n }, []);\n\n // Pin and box are counter-scaled with the zoom, so the box moves by as much as the pointer does on screen\n const startDrag = useCallback((event: ReactPointerEvent<HTMLElement>) => {\n if (event.button !== 0 || (event.target as Element).closest(\"button\"))\n return;\n event.preventDefault();\n const element = event.currentTarget;\n element.setPointerCapture(event.pointerId);\n const start = { x: event.clientX, y: event.clientY };\n const from = offsetRef.current;\n const move = (moveEvent: PointerEvent) =>\n setOffset({\n x: from.x + moveEvent.clientX - start.x,\n y: from.y + moveEvent.clientY - start.y,\n });\n const end = () => {\n element.removeEventListener(\"pointermove\", move);\n element.removeEventListener(\"pointerup\", end);\n element.removeEventListener(\"pointercancel\", end);\n };\n element.addEventListener(\"pointermove\", move);\n element.addEventListener(\"pointerup\", end);\n element.addEventListener(\"pointercancel\", end);\n }, []);\n\n return (\n <div\n ref={ref}\n className={`${panelClass} flex flex-col`}\n style={{\n left: `calc(100% + 8px + ${offset.x}px)`,\n top: offset.y,\n maxHeight: PANEL_MAX_HEIGHT_PX,\n }}\n >\n <DragPanelContext.Provider value={startDrag}>\n {children}\n </DragPanelContext.Provider>\n </div>\n );\n}\n\nfunction ThreadPopover({\n thread,\n onReply,\n onResolve,\n onDelete,\n onClose,\n onExpand,\n}: {\n thread: Thread;\n onReply: (text: string) => void;\n onResolve: (resolved: boolean) => void;\n onDelete: () => void;\n onClose: () => void;\n /** Open it bigger, in a dialog (not there when it's already in one) */\n onExpand?: () => void;\n}) {\n const listRef = useRef<HTMLDivElement>(null);\n const startDrag = useContext(DragPanelContext);\n useEffect(() => {\n listRef.current?.scrollTo({ top: listRef.current.scrollHeight });\n }, [thread.messages.length]);\n\n return (\n <>\n <div\n onPointerDown={startDrag ?? undefined}\n title={startDrag ? \"Drag to move\" : undefined}\n className={`flex shrink-0 select-none items-center justify-between border-b px-3 py-2 border-[rgb(var(--ec-page-border))] ${\n startDrag ? \"cursor-move\" : \"\"\n }`}\n >\n <span className=\"flex items-center gap-1 text-xs font-semibold\">\n {/* It can be dragged by its header: the grip says so */}\n {startDrag && (\n <GripVertical\n size={14}\n aria-hidden\n className=\"-ml-1 text-[rgb(var(--ec-page-text-muted))]\"\n />\n )}\n {thread.resolved ? \"Resolved thread\" : \"Thread\"}\n </span>\n <span className=\"flex items-center gap-0.5\">\n <IconButton\n title={thread.resolved ? \"Reopen\" : \"Resolve\"}\n onClick={() => onResolve(!thread.resolved)}\n >\n {thread.resolved ? <RotateCcw size={14} /> : <Check size={14} />}\n </IconButton>\n <IconButton title=\"Delete thread\" onClick={onDelete}>\n <Trash2 size={14} />\n </IconButton>\n {onExpand && (\n <IconButton title=\"Open bigger\" onClick={onExpand}>\n <Maximize2 size={14} />\n </IconButton>\n )}\n <IconButton title=\"Close\" onClick={onClose}>\n <X size={14} />\n </IconButton>\n </span>\n </div>\n <div\n ref={listRef}\n className=\"min-h-0 flex-1 space-y-3 overflow-y-auto px-3 py-3\"\n >\n {thread.messages.map((message) => (\n <div key={message.id} className=\"flex gap-2\">\n <span\n className=\"relative flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-[10px] font-semibold text-white\"\n style={{ backgroundColor: message.author.color }}\n >\n {message.author.agent ? (\n <AgentMark name={message.author.name} size={13} />\n ) : (\n initials(message.author.name)\n )}\n <Picture src={message.author.picture} />\n </span>\n <div className=\"min-w-0\">\n <p className=\"text-xs\">\n <span className=\"font-semibold\">{message.author.name}</span>{\" \"}\n <span className=\"text-[rgb(var(--ec-page-text-muted))]\">\n {timeAgo(message.createdAt)}\n </span>\n </p>\n <p className=\"whitespace-pre-wrap break-words text-sm\">\n {message.text}\n </p>\n </div>\n </div>\n ))}\n </div>\n <div className=\"shrink-0 border-t border-[rgb(var(--ec-page-border))]\">\n <Composer placeholder=\"Reply\" onSubmit={onReply} onCancel={onClose} />\n </div>\n </>\n );\n}\n\n/** A thread opened bigger, in a dialog over the page (for long threads) */\nfunction ThreadDialog({\n thread,\n onReply,\n onResolve,\n onDelete,\n onShrink,\n onClose,\n}: {\n thread: Thread;\n onReply: (text: string) => void;\n onResolve: (resolved: boolean) => void;\n onDelete: () => void;\n /** Back to the box beside its pin */\n onShrink: () => void;\n onClose: () => void;\n}) {\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) =>\n event.key === \"Escape\" && onShrink();\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, [onShrink]);\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4\"\n // It's in the canvas's React tree (a portal), so its events would reach the canvas: they stop here (clicks in\n // the dialog stop at it)\n onClick={(event) => {\n event.stopPropagation();\n onShrink();\n }}\n onPointerDown={(event) => event.stopPropagation()}\n onMouseDown={(event) => event.stopPropagation()}\n onDoubleClick={(event) => event.stopPropagation()}\n onContextMenu={(event) => event.stopPropagation()}\n onWheel={(event) => event.stopPropagation()}\n >\n <div\n role=\"dialog\"\n aria-label=\"Comment thread\"\n onClick={(event) => event.stopPropagation()}\n className=\"flex max-h-[80vh] w-full max-w-xl flex-col rounded-xl border shadow-2xl bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))]\"\n >\n <ThreadPopover\n thread={thread}\n onReply={onReply}\n onResolve={onResolve}\n onDelete={onDelete}\n onClose={onClose}\n />\n </div>\n </div>\n );\n}\n\n/**\n * Where a pin goes on the canvas, following only the node it's on (if it's on one), counter-scaled (by the layer's\n * COUNTER_SCALE, so zooming doesn't re-render it)\n */\nfunction PinAt({\n anchor,\n zIndex,\n children,\n}: {\n anchor: CommentAnchor;\n zIndex: number;\n children: ReactNode;\n}) {\n const node = useInternalNode(anchor.nodeId ?? \"\");\n const origin =\n anchor.nodeId && anchor.offset\n ? node?.internals.positionAbsolute\n : undefined;\n const { x, y } =\n origin && anchor.offset\n ? { x: origin.x + anchor.offset.x, y: origin.y + anchor.offset.y }\n : anchor.position;\n return (\n <div\n className=\"absolute\"\n style={{\n left: x,\n top: y,\n transform: `scale(var(${COUNTER_SCALE}, 1))`,\n transformOrigin: \"0 0\",\n zIndex,\n }}\n >\n {/* The pin's tip (bottom left corner) sits on the anchor point, and it grows up and right as it opens */}\n <div className=\"nopan nodrag nowheel pointer-events-auto absolute bottom-0 left-0\">\n {children}\n </div>\n </div>\n );\n}\n\n/**\n * Comment pins (and the open thread) on the canvas, in its own coordinates (React Flow's viewport portal) so\n * they move with it without re-rendering, counter-scaled to stay the same size on screen. Each pin follows\n * only its own node, so other nodes moving don't re-render them.\n */\nexport const CommentLayer = memo(function CommentLayer({\n threads,\n author,\n openThreadId,\n draft,\n showResolved,\n onOpen,\n onCreate,\n onCancelDraft,\n onReply,\n onResolve,\n onDelete,\n onMove,\n onMoveDraft,\n selectedIds,\n selectionOffset,\n live,\n}: {\n threads: Thread[];\n author: Author;\n openThreadId: string | null;\n /** Threads that are part of what's selected */\n selectedIds: ReadonlySet<string>;\n /** How far what's selected has been dragged: selected pins not on a node move with it */\n selectionOffset: XYPosition | null;\n draft: CommentAnchor | null;\n showResolved: boolean;\n onOpen: (threadId: string | null) => void;\n onCreate: (text: string) => void;\n onCancelDraft: () => void;\n onReply: (threadId: string, text: string) => void;\n onResolve: (threadId: string, resolved: boolean) => void;\n onDelete: (threadId: string) => void;\n onMove: (threadId: string, anchor: CommentAnchor) => void;\n onMoveDraft: (anchor: CommentAnchor) => void;\n /** In a live room: pins the others are dragging move here as they drag, and mine move for them */\n live?: LiveMoves;\n}) {\n const layer = useRef<HTMLDivElement>(null);\n useCounterScale(layer);\n const { screenToFlowPosition, getInternalNode } = useReactFlow();\n // A pin being dragged stays here until it's dropped, then moves for everyone\n const [moving, setMoving] = useState<{\n threadId: string;\n anchor: CommentAnchor;\n } | null>(null);\n const remote = useRemoteMoves(live, \"comment\");\n // The open thread, shown bigger in a dialog\n const [expandedId, setExpandedId] = useState<string | null>(null);\n const expanded =\n expandedId && expandedId === openThreadId\n ? threads.find((thread) => thread.id === expandedId)\n : undefined;\n\n // While dragging, a pin follows the pointer. Dropped on a node it attaches to it (and moves with it),\n // anywhere else it stays on the canvas.\n // Not domains and systems (a comment over one is at that place), nor notes and text: what it's about\n const nodeUnder = (point: XYPosition) => {\n for (const element of document.elementsFromPoint(point.x, point.y)) {\n const id = element.closest(\".react-flow__node\")?.getAttribute(\"data-id\");\n const node = id ? getInternalNode(id) : undefined;\n if (node && !isGroupType(node.type) && !isWrittenOnCanvas(node.type))\n return node;\n }\n return undefined;\n };\n const anchorFor = (tip: XYPosition, phase: \"move\" | \"end\"): CommentAnchor => {\n const position = screenToFlowPosition(tip);\n const node = phase === \"end\" ? nodeUnder(tip) : undefined;\n if (!node) return { position };\n const origin = node.internals.positionAbsolute;\n return {\n position,\n nodeId: node.id,\n offset: { x: position.x - origin.x, y: position.y - origin.y },\n };\n };\n\n const visible = threads.filter(\n (thread) => showResolved || !thread.resolved || thread.id === openThreadId,\n );\n\n return (\n <CanvasPortal>\n {/* Above nodes (selected ones are raised to 1000) and other people's pointers */}\n <div\n ref={layer}\n className=\"absolute left-0 top-0\"\n style={{ zIndex: 2001 }}\n >\n {visible.map((thread) => {\n const isOpen = thread.id === openThreadId;\n return (\n <PinAt\n key={thread.id}\n anchor={\n moving?.threadId === thread.id\n ? moving.anchor\n : remote.has(thread.id)\n ? { position: remote.get(thread.id)! }\n : selectionOffset &&\n !thread.nodeId &&\n selectedIds.has(thread.id)\n ? {\n position: {\n x: thread.position.x + selectionOffset.x,\n y: thread.position.y + selectionOffset.y,\n },\n }\n : thread\n }\n zIndex={isOpen ? 2 : 1}\n >\n <Pin\n author={thread.author}\n thread={thread}\n active={isOpen}\n selected={selectedIds.has(thread.id)}\n resolved={thread.resolved}\n onClick={() => onOpen(isOpen ? null : thread.id)}\n onDrag={(tip, phase) => {\n const anchor = anchorFor(tip, phase);\n if (phase === \"move\") {\n sendMove(live, \"comment\", thread.id, anchor.position);\n return setMoving({ threadId: thread.id, anchor });\n }\n onMove(thread.id, anchor);\n // (after the drop's in the document, so the others don't see it go back in between)\n sendMove(live, \"comment\", thread.id, null);\n setMoving(null);\n }}\n />\n {/* (not while it's open bigger, in the dialog) */}\n {isOpen && expanded?.id !== thread.id && (\n <FloatingPanel onClickOutside={() => onOpen(null)}>\n <ThreadPopover\n thread={thread}\n onReply={(text) => onReply(thread.id, text)}\n onResolve={(resolved) => onResolve(thread.id, resolved)}\n onDelete={() => onDelete(thread.id)}\n onClose={() => onOpen(null)}\n onExpand={() => setExpandedId(thread.id)}\n />\n </FloatingPanel>\n )}\n </PinAt>\n );\n })}\n\n {expanded &&\n createPortal(\n <ThreadDialog\n thread={expanded}\n onReply={(text) => onReply(expanded.id, text)}\n onResolve={(resolved) => onResolve(expanded.id, resolved)}\n onDelete={() => {\n setExpandedId(null);\n onDelete(expanded.id);\n }}\n onShrink={() => setExpandedId(null)}\n onClose={() => {\n setExpandedId(null);\n onOpen(null);\n }}\n />,\n document.body,\n )}\n\n {draft && (\n <PinAt anchor={draft} zIndex={3}>\n <Pin\n author={author}\n active\n onDrag={(tip, phase) => onMoveDraft(anchorFor(tip, phase))}\n />\n <FloatingPanel>\n <Composer\n placeholder=\"Add a comment\"\n onSubmit={onCreate}\n onCancel={onCancelDraft}\n />\n </FloatingPanel>\n </PinAt>\n )}\n </div>\n </CanvasPortal>\n );\n});\n\n/** All threads, for the left panel. Clicking one opens it on the canvas. */\nexport function CommentList({\n threads,\n showResolved,\n onToggleResolved,\n onOpen,\n}: {\n threads: Thread[];\n showResolved: boolean;\n onToggleResolved: () => void;\n onOpen: (thread: Thread) => void;\n}) {\n const shown = threads\n .filter((thread) => showResolved || !thread.resolved)\n .reverse();\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <label className=\"mx-3 mb-2 flex items-center gap-2 text-xs text-[rgb(var(--ec-page-text-muted))]\">\n <input\n type=\"checkbox\"\n checked={showResolved}\n onChange={onToggleResolved}\n />\n Show resolved\n </label>\n <div className=\"min-h-0 flex-1 space-y-1.5 overflow-y-auto px-3 pb-3\">\n {shown.length === 0 && (\n <p className=\"py-6 text-center text-xs text-[rgb(var(--ec-page-text-muted))]\">\n No comments yet. Right click the canvas, or press C, to add one.\n </p>\n )}\n {shown.map((thread) => {\n const [first, ...replies] = thread.messages;\n return (\n <button\n key={thread.id}\n onClick={() => onOpen(thread)}\n className={`w-full space-y-1 rounded-md border px-2.5 py-2 text-left bg-[rgb(var(--ec-page-bg))] border-[rgb(var(--ec-page-border))] hover:border-[rgb(var(--ec-accent))] ${\n thread.resolved ? \"opacity-60\" : \"\"\n }`}\n >\n <p className=\"flex items-center gap-1.5 text-xs\">\n <span\n className=\"h-2 w-2 shrink-0 rounded-full\"\n style={{ backgroundColor: thread.author.color }}\n />\n <span className=\"font-semibold\">{thread.author.name}</span>\n <span className=\"text-[rgb(var(--ec-page-text-muted))]\">\n {timeAgo(thread.createdAt)}\n </span>\n {thread.resolved && (\n <Check\n size={12}\n className={`ml-auto ${STATUS.success.text}`}\n />\n )}\n </p>\n <p className=\"line-clamp-2 text-xs\">{first?.text}</p>\n {replies.length > 0 && (\n <p className=\"text-[11px] text-[rgb(var(--ec-page-text-muted))]\">\n {replies.length} {replies.length === 1 ? \"reply\" : \"replies\"}\n </p>\n )}\n </button>\n );\n })}\n </div>\n </div>\n );\n}\n","import type { CanvasStatus } from \"../canvas-doc\";\n\n/**\n * Status and destructive colours for the canvas, from the theme's badge colours (EventCatalog has no status\n * variables), so they follow light, dark and custom themes. Kept here rather than repeated in each component.\n */\nexport const STATUS = {\n success: {\n text: \"text-[rgb(var(--ec-badge-color-green-text))]\",\n dot: \"bg-[rgb(var(--ec-badge-color-green-text))]\",\n },\n warning: {\n text: \"text-[rgb(var(--ec-badge-color-yellow-text))]\",\n dot: \"bg-[rgb(var(--ec-badge-color-yellow-text))]\",\n },\n danger: {\n text: \"text-[rgb(var(--ec-badge-color-red-text))]\",\n dot: \"bg-[rgb(var(--ec-badge-color-red-text))]\",\n hover: \"hover:bg-[rgb(var(--ec-badge-color-red-background))]\",\n /** A button that deletes something */\n button:\n \"bg-[rgb(var(--ec-badge-color-red-text))] text-white hover:bg-[rgb(var(--ec-badge-color-red-text)/0.85)]\",\n },\n} as const;\n\n/** How each canvas status looks and what it means (from the theme's badge colours) */\nexport const CANVAS_STATUS_LOOK: Record<\n CanvasStatus,\n { label: string; description: string; pill: string; dot: string }\n> = {\n draft: {\n label: \"Draft\",\n description: \"Being worked on\",\n pill: \"bg-[rgb(var(--ec-badge-color-gray-background))] text-[rgb(var(--ec-badge-color-gray-text))] border-[rgb(var(--ec-badge-color-gray-text)/0.25)]\",\n dot: \"bg-[rgb(var(--ec-badge-color-gray-text))]\",\n },\n proposed: {\n label: \"Proposed\",\n description: \"Ready for review\",\n pill: \"bg-[rgb(var(--ec-badge-color-yellow-background))] text-[rgb(var(--ec-badge-color-yellow-text))] border-[rgb(var(--ec-badge-color-yellow-text)/0.3)]\",\n dot: \"bg-[rgb(var(--ec-badge-color-yellow-text))]\",\n },\n accepted: {\n label: \"Accepted\",\n description: \"The agreed design\",\n pill: \"bg-[rgb(var(--ec-badge-color-green-background))] text-[rgb(var(--ec-badge-color-green-text))] border-[rgb(var(--ec-badge-color-green-text)/0.3)]\",\n dot: \"bg-[rgb(var(--ec-badge-color-green-text))]\",\n },\n rejected: {\n label: \"Rejected\",\n description: \"Decided against, kept for the record\",\n pill: \"bg-[rgb(var(--ec-badge-color-red-background))] text-[rgb(var(--ec-badge-color-red-text))] border-[rgb(var(--ec-badge-color-red-text)/0.3)]\",\n dot: \"bg-[rgb(var(--ec-badge-color-red-text))]\",\n },\n};\n","import { useState } from \"react\";\n\n/**\n * Someone's picture from their sign-in provider (SSO), loaded from there. By default it covers their avatar's\n * initials, which show again if it doesn't load (blocked, expired, or no longer there).\n */\nexport default function Picture({\n src,\n className = \"absolute inset-0 h-full w-full\",\n}: {\n src?: string;\n className?: string;\n}) {\n const [failed, setFailed] = useState<string>();\n if (!src || failed === src) return null;\n return (\n <img\n src={src}\n alt=\"\"\n draggable={false}\n // Some providers (e.g. Google) refuse pictures loaded with a referrer from another site\n referrerPolicy=\"no-referrer\"\n onError={() => setFailed(src)}\n className={`rounded-full object-cover ${className}`}\n />\n );\n}\n","/**\n * The AI clients' logos, for the connect dialog's tabs. From Lobe Icons (@lobehub/icons-static-svg, MIT):\n * https://github.com/lobehub/lobe-icons\n */\nimport type { SVGProps } from \"react\";\nimport { Bot } from \"lucide-react\";\n\ntype LogoProps = SVGProps<SVGSVGElement>;\n\nexport const ClaudeLogo = (props: LogoProps) => (\n <svg viewBox=\"0 0 24 24\" aria-hidden {...props}>\n <path\n fill=\"#D97757\"\n d=\"M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z\"\n />\n </svg>\n);\n\nexport const ClaudeCodeLogo = (props: LogoProps) => (\n <svg viewBox=\"0 0 24 24\" aria-hidden {...props}>\n <path\n fill=\"#D97757\"\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M20.998 10.949H24v3.102h-3v3.028h-1.487V20H18v-2.921h-1.487V20H15v-2.921H9V20H7.488v-2.921H6V20H4.487v-2.921H3V14.05H0V10.95h3V5h17.998v5.949zM6 10.949h1.488V8.102H6v2.847zm10.51 0H18V8.102h-1.49v2.847z\"\n />\n </svg>\n);\n\nexport const OpenAILogo = (props: LogoProps) => (\n <svg viewBox=\"0 0 24 24\" aria-hidden {...props}>\n <path\n fill=\"currentColor\"\n d=\"M9.205 8.658v-2.26c0-.19.072-.333.238-.428l4.543-2.616c.619-.357 1.356-.523 2.117-.523 2.854 0 4.662 2.212 4.662 4.566 0 .167 0 .357-.024.547l-4.71-2.759a.797.797 0 00-.856 0l-5.97 3.473zm10.609 8.8V12.06c0-.333-.143-.57-.429-.737l-5.97-3.473 1.95-1.118a.433.433 0 01.476 0l4.543 2.617c1.309.76 2.189 2.378 2.189 3.948 0 1.808-1.07 3.473-2.76 4.163zM7.802 12.703l-1.95-1.142c-.167-.095-.239-.238-.239-.428V5.899c0-2.545 1.95-4.472 4.591-4.472 1 0 1.927.333 2.712.928L8.23 5.067c-.285.166-.428.404-.428.737v6.898zM12 15.128l-2.795-1.57v-3.33L12 8.658l2.795 1.57v3.33L12 15.128zm1.796 7.23c-1 0-1.927-.332-2.712-.927l4.686-2.712c.285-.166.428-.404.428-.737v-6.898l1.974 1.142c.167.095.238.238.238.428v5.233c0 2.545-1.974 4.472-4.614 4.472zm-5.637-5.303l-4.544-2.617c-1.308-.761-2.188-2.378-2.188-3.948A4.482 4.482 0 014.21 6.327v5.423c0 .333.143.571.428.738l5.947 3.449-1.95 1.118a.432.432 0 01-.476 0zm-.262 3.9c-2.688 0-4.662-2.021-4.662-4.519 0-.19.024-.38.047-.57l4.686 2.71c.286.167.571.167.856 0l5.97-3.448v2.26c0 .19-.07.333-.237.428l-4.543 2.616c-.619.357-1.356.523-2.117.523zm5.899 2.83a5.947 5.947 0 005.827-4.756C22.287 18.339 24 15.84 24 13.296c0-1.665-.713-3.282-1.998-4.448.119-.5.19-.999.19-1.498 0-3.401-2.759-5.947-5.946-5.947-.642 0-1.26.095-1.88.31A5.962 5.962 0 0010.205 0a5.947 5.947 0 00-5.827 4.757C1.713 5.447 0 7.945 0 10.49c0 1.666.713 3.283 1.998 4.448-.119.5-.19 1-.19 1.499 0 3.401 2.759 5.946 5.946 5.946.642 0 1.26-.095 1.88-.309a5.96 5.96 0 004.162 1.713z\"\n />\n </svg>\n);\n\nexport const CursorLogo = (props: LogoProps) => (\n <svg viewBox=\"0 0 24 24\" aria-hidden {...props}>\n <path\n fill=\"currentColor\"\n d=\"M22.106 5.68L12.5.135a.998.998 0 00-.998 0L1.893 5.68a.84.84 0 00-.419.726v11.186c0 .3.16.577.42.727l9.607 5.547a.999.999 0 00.998 0l9.608-5.547a.84.84 0 00.42-.727V6.407a.84.84 0 00-.42-.726zm-.603 1.176L12.228 22.92c-.063.108-.228.064-.228-.061V12.34a.59.59 0 00-.295-.51l-9.11-5.26c-.107-.062-.063-.228.062-.228h18.55c.264 0 .428.286.296.514z\"\n />\n </svg>\n);\n\n/**\n * The logo of the company behind an agent, from the name it joined with (agentName on the MCP tools, e.g. \"Claude\n * Code\", \"Codex\", \"Cursor\"), when it's one we know: shown instead of a robot on its avatar, pointer and comments\n */\nexport const agentLogoFor = (name?: string) => {\n const lowered = (name ?? \"\").toLowerCase();\n if (lowered.includes(\"claude code\")) return ClaudeCodeLogo;\n if (/\\b(claude|anthropic)\\b/.test(lowered)) return ClaudeLogo;\n if (/\\b(codex|chatgpt|openai|gpt)/.test(lowered)) return OpenAILogo;\n if (/\\bcursor\\b/.test(lowered)) return CursorLogo;\n return undefined;\n};\n\n/** An agent's mark: its company's logo when it's one we know (agentLogoFor), else a robot */\nexport function AgentMark({\n name,\n size = 14,\n}: {\n name?: string;\n size?: number;\n}) {\n const Logo = agentLogoFor(name);\n // On a light disc, so the logo keeps its colours on the agent's coloured avatar or label\n return Logo ? (\n <span\n className=\"flex flex-none items-center justify-center rounded-full bg-white\"\n style={{ width: size + 4, height: size + 4, color: \"#111827\" }}\n >\n <Logo width={size - 2} height={size - 2} />\n </span>\n ) : (\n <Bot size={size} />\n );\n}\n","/**\n * The canvas's right-click menu: on a node, commenting on it, flagging it, a note beside it, editing its details,\n * copying, duplicating and deleting it (or the selection it's in), and questions for an agent about it (when the\n * view is in a chat that takes them); on the canvas, putting a comment, hotspot or note there, pasting there, and\n * laying the level shown out again. What an app leaves out isn't offered.\n */\nimport {\n memo,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\nimport type { Node, XYPosition } from \"@xyflow/react\";\nimport {\n ClipboardPaste,\n Copy,\n CopyPlus,\n MessageCircle,\n MessageCircleQuestion,\n Pencil,\n SendToBack,\n StickyNote,\n Trash2,\n TriangleAlert,\n} from \"lucide-react\";\nimport { isWrittenOnCanvas } from \"../node-types\";\nimport { STATUS } from \"./status\";\n\nexport type ContextMenuState = {\n x: number;\n y: number;\n flowPosition: XYPosition;\n node?: Node;\n} | null;\n\n/** The least room left between the menu and the window's edges */\nconst EDGE = 8;\n\n/** Something to ask the agent about the node right clicked */\nexport type MenuQuestion = { label: string; onSelect: () => void };\n\nexport const ContextMenu = memo(function ContextMenu({\n menu,\n questions,\n onCopy,\n onDuplicate,\n onPaste,\n onAddNote,\n onAddComment,\n onAddHotspot,\n onEditDetails,\n onReorder,\n onDeleteNode,\n onClose,\n}: {\n menu: ContextMenuState;\n /** For the node right clicked */\n questions?: MenuQuestion[];\n onCopy: () => void;\n onDuplicate: () => void;\n /** Paste what was last copied where the menu was opened, if anything was */\n onPaste?: () => void;\n /** A sticky note where the menu was opened (on the canvas), or beside the node */\n onAddNote: () => void;\n /** A comment pinned where the menu was opened (on the canvas or the node), on L3 */\n onAddComment?: () => void;\n /** A hotspot on the node right clicked (or where the menu was opened), on L3 */\n onAddHotspot?: () => void;\n /** Opens the node's details (not for notes and text, which are written on the canvas) */\n onEditDetails?: () => void;\n /** Lays the level shown out again (the visualiser's layout), from the canvas's menu */\n onReorder?: () => void;\n onDeleteNode: () => void;\n onClose: () => void;\n}) {\n useEffect(() => {\n if (!menu) return;\n const close = (event: Event) => {\n if (event instanceof KeyboardEvent && event.key !== \"Escape\") return;\n onClose();\n };\n window.addEventListener(\"pointerdown\", close);\n window.addEventListener(\"keydown\", close);\n window.addEventListener(\"wheel\", close);\n return () => {\n window.removeEventListener(\"pointerdown\", close);\n window.removeEventListener(\"keydown\", close);\n window.removeEventListener(\"wheel\", close);\n };\n }, [menu, onClose]);\n\n // Kept in the window: opened near its right or bottom edge, it opens to the left of the pointer, or above it.\n // Measured before it's shown (a layout effect), so it never shows cut off first\n const menuRef = useRef<HTMLDivElement>(null);\n const [placed, setPlaced] = useState<{ left: number; top: number } | null>(\n null,\n );\n useLayoutEffect(() => {\n const element = menuRef.current;\n if (!menu || !element) return setPlaced(null);\n const { width, height } = element.getBoundingClientRect();\n const fit = (at: number, size: number, room: number) =>\n at + size <= room - EDGE\n ? at\n : Math.max(EDGE, Math.min(at - size, room - EDGE - size));\n setPlaced({\n left: fit(menu.x, width, window.innerWidth),\n top: fit(menu.y, height, window.innerHeight),\n });\n }, [menu]);\n\n if (!menu) return null;\n\n const itemClass =\n \"flex w-full items-center gap-2 rounded px-2.5 py-1.5 text-left text-xs hover:bg-[rgb(var(--ec-page-border)/0.5)]\";\n const shortcutClass = \"ml-auto text-[rgb(var(--ec-page-text-muted))]\";\n const item = (\n icon: ReactNode,\n label: string,\n onClick: () => void,\n shortcut?: string,\n className = \"\",\n ) => (\n <button className={`${itemClass} ${className}`} onClick={onClick}>\n {icon}\n {label}\n {shortcut && <span className={shortcutClass}>{shortcut}</span>}\n </button>\n );\n const separator = (\n <div className=\"my-1 h-px bg-[rgb(var(--ec-page-border))]\" />\n );\n\n return (\n <div\n // Keep the window pointerdown listener from closing the menu before a click lands\n onPointerDown={(event) => event.stopPropagation()}\n onContextMenu={(event) => event.preventDefault()}\n ref={menuRef}\n className=\"fixed z-50 w-56 overflow-y-auto rounded-lg border p-1 shadow-xl bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))]\"\n style={{\n left: placed?.left ?? menu.x,\n top: placed?.top ?? menu.y,\n maxHeight: `calc(100vh - ${EDGE * 2}px)`,\n visibility: placed ? \"visible\" : \"hidden\",\n }}\n >\n {menu.node && questions?.length ? (\n <>\n {questions.map((question) => (\n <button\n key={question.label}\n className={itemClass}\n onClick={question.onSelect}\n >\n <MessageCircleQuestion size={14} />\n {question.label}\n </button>\n ))}\n {separator}\n </>\n ) : null}\n {menu.node && (\n <>\n {onAddComment &&\n item(<MessageCircle size={14} />, \"Add comment\", onAddComment, \"C\")}\n {onAddHotspot &&\n !isWrittenOnCanvas(menu.node.type) &&\n item(<TriangleAlert size={14} />, \"Add hotspot\", onAddHotspot, \"A\")}\n {!isWrittenOnCanvas(menu.node.type) &&\n item(<StickyNote size={14} />, \"Add a note\", onAddNote)}\n {onEditDetails &&\n !isWrittenOnCanvas(menu.node.type) &&\n item(<Pencil size={14} />, \"Edit details\", onEditDetails)}\n {item(<Copy size={14} />, \"Copy\", onCopy, \"⌘C\")}\n {item(<CopyPlus size={14} />, \"Duplicate\", onDuplicate, \"⌘D\")}\n {separator}\n {item(\n <Trash2 size={14} />,\n \"Delete\",\n onDeleteNode,\n \"⌫\",\n STATUS.danger.text,\n )}\n </>\n )}\n {!menu.node && (\n <>\n {onAddComment &&\n item(<MessageCircle size={14} />, \"Add comment\", onAddComment, \"C\")}\n {onAddHotspot &&\n item(<TriangleAlert size={14} />, \"Add hotspot\", onAddHotspot, \"A\")}\n {item(<StickyNote size={14} />, \"Add a sticky note\", onAddNote, \"N\")}\n {onPaste &&\n item(<ClipboardPaste size={14} />, \"Paste here\", onPaste, \"⌘V\")}\n {onReorder && (\n <>\n {separator}\n {item(<SendToBack size={14} />, \"Reorder diagram\", onReorder)}\n </>\n )}\n </>\n )}\n </div>\n );\n});\n","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type DragEvent,\n} from \"react\";\nimport {\n ReactFlow,\n ReactFlowProvider,\n useStoreApi,\n type Node,\n type XYPosition,\n} from \"@xyflow/react\";\nimport { getNodeSize, isGroupType } from \"../node-types\";\nimport { nodeTypes } from \"./canvas-nodes\";\n\n/**\n * Dragging something from the left panel onto the canvas shows the node it becomes, under the pointer, at the\n * canvas's zoom and where it will land (centred on the pointer, as it's dropped). Drawn here rather than as the\n * browser's drag image, which browsers shrink, fade and put a backing behind.\n */\n\n/** What's dragged: the node it becomes */\nexport type DragPreview = { type: string; data: Record<string, unknown> };\n/** Starts dragging `value` as `dragType`, showing `preview` as what's dragged */\nexport type StartDrag = (\n dragType: string,\n value: string,\n preview: DragPreview,\n) => (event: DragEvent) => void;\n\n// Hides the browser's own drag image (a transparent pixel)\nconst NO_DRAG_IMAGE =\n typeof Image === \"undefined\"\n ? undefined\n : Object.assign(new Image(), {\n src: \"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\",\n });\n\n// Room around the node for the badge on its top edge\nconst MARGIN = 16;\nconst PRO_OPTIONS = { hideAttribution: true };\n\ntype Ghost = { preview: DragPreview; zoom: number; at: XYPosition };\n\n/** The ghost of what's being dragged, and how to start dragging something with one */\nexport function useDragGhost() {\n const store = useStoreApi();\n const [ghost, setGhost] = useState<Ghost | null>(null);\n\n const startDrag = useCallback<StartDrag>(\n (dragType, value, preview) => (event) => {\n event.dataTransfer.setData(dragType, value);\n event.dataTransfer.effectAllowed = \"move\";\n if (NO_DRAG_IMAGE) event.dataTransfer.setDragImage(NO_DRAG_IMAGE, 0, 0);\n setGhost({\n preview,\n zoom: store.getState().transform[2],\n at: { x: event.clientX, y: event.clientY },\n });\n },\n [store],\n );\n\n const element = ghost && (\n <DragGhost ghost={ghost} onEnd={() => setGhost(null)} />\n );\n return { startDrag, ghost: element };\n}\n\nfunction DragGhost({ ghost, onEnd }: { ghost: Ghost; onEnd: () => void }) {\n const ref = useRef<HTMLDivElement>(null);\n const { preview, zoom } = ghost;\n const container = isGroupType(preview.type);\n // The size it's added at (containers are sized; cards are drawn at their own size inside this)\n const size = getNodeSize(preview.type);\n // The node is placed with its middle where it's dropped, at the size it's added at\n const offset = {\n x: (size.width / 2) * zoom + MARGIN,\n y: (size.height / 2) * zoom + MARGIN,\n };\n\n // Follows the pointer (as the browser reports it while dragging) without re-rendering, and goes when it's dropped\n useEffect(() => {\n const move = (x: number, y: number) => {\n if (ref.current)\n ref.current.style.transform = `translate(${x - offset.x}px, ${y - offset.y}px)`;\n };\n move(ghost.at.x, ghost.at.y);\n const onDragOver = (event: globalThis.DragEvent) => {\n if (event.clientX || event.clientY) move(event.clientX, event.clientY);\n };\n document.addEventListener(\"dragover\", onDragOver);\n document.addEventListener(\"drop\", onEnd);\n document.addEventListener(\"dragend\", onEnd);\n return () => {\n document.removeEventListener(\"dragover\", onDragOver);\n document.removeEventListener(\"drop\", onEnd);\n document.removeEventListener(\"dragend\", onEnd);\n };\n }, [ghost]);\n\n const nodes = useMemo<Node[]>(\n () => [\n {\n id: \"drag-ghost\",\n type: preview.type,\n position: { x: 0, y: 0 },\n data: preview.data,\n ...(container && size),\n },\n ],\n [preview, container, size],\n );\n const viewport = useMemo(() => ({ x: MARGIN, y: MARGIN, zoom }), [zoom]);\n\n return (\n <div\n ref={ref}\n aria-hidden\n // Sized here: the visualiser's styles make its class fill the window\n className=\"studio-drag-preview eventcatalog-visualizer pointer-events-none fixed left-0 top-0 z-[100] opacity-70\"\n style={{\n width: size.width * zoom + MARGIN * 2,\n height: size.height * zoom + MARGIN * 2,\n }}\n >\n <ReactFlowProvider>\n <ReactFlow\n nodes={nodes}\n nodeTypes={nodeTypes}\n defaultViewport={viewport}\n proOptions={PRO_OPTIONS}\n nodesDraggable={false}\n nodesConnectable={false}\n elementsSelectable={false}\n panOnDrag={false}\n zoomOnScroll={false}\n zoomOnPinch={false}\n preventScrolling={false}\n />\n </ReactFlowProvider>\n </div>\n );\n}\n","/**\n * Hotspots: what an architect (or the agent) flags on the architecture so people find what matters: risks, single\n * points of failure, known problems, the key parts to understand. Each is critical, a warning or info.\n *\n * On a node, a marker sits on its top right corner with its title (and the node glows in its colour, see\n * studio.css); at a place, the marker's there. On L1 and L2 a node shows the hotspots inside it, to go and see them.\n * In the canvas's own coordinates (React Flow's viewport portal), counter-scaled to stay the same size on screen.\n */\nimport {\n memo,\n useLayoutEffect,\n useRef,\n useState,\n type FormEvent,\n type ReactNode,\n type RefObject,\n} from \"react\";\nimport {\n useInternalNode,\n useReactFlow,\n useStoreApi,\n type XYPosition,\n} from \"@xyflow/react\";\nimport { CanvasPortal } from \"../../utils/flow-portals\";\nimport {\n Info,\n OctagonAlert,\n Pencil,\n Trash2,\n TriangleAlert,\n X,\n type LucideIcon,\n} from \"lucide-react\";\nimport type { Hotspot, HotspotSeverity } from \"../canvas-doc\";\nimport { isWrittenOnCanvas } from \"../node-types\";\nimport { AgentMark } from \"./ClientLogos\";\nimport { timeAgo } from \"./Comments\";\nimport { sendMove, useRemoteMoves, type LiveMoves } from \"../live-moves\";\n\nexport const SEVERITIES: Record<\n HotspotSeverity,\n { label: string; color: string; icon: LucideIcon; rank: number }\n> = {\n critical: {\n label: \"Critical\",\n color: \"#dc2626\",\n icon: OctagonAlert,\n rank: 0,\n },\n warning: { label: \"Warning\", color: \"#d97706\", icon: TriangleAlert, rank: 1 },\n info: { label: \"Info\", color: \"#2563eb\", icon: Info, rank: 2 },\n};\nconst SEVERITY_ORDER: HotspotSeverity[] = [\"critical\", \"warning\", \"info\"];\n\n/** Most important first (then oldest first) */\nexport const bySeverity = (a: Hotspot, b: Hotspot) =>\n SEVERITIES[a.severity].rank - SEVERITIES[b.severity].rank ||\n a.createdAt - b.createdAt;\nexport const topSeverity = (hotspots: Hotspot[]) =>\n [...hotspots].sort(bySeverity)[0]?.severity;\n\n/** Hotspots shown together: on a node (its own, or on L1 and L2 also the ones inside it), or one at a place */\nexport type HotspotSpot = {\n key: string;\n nodeId?: string;\n position?: XYPosition;\n hotspots: Hotspot[];\n inside?: boolean;\n};\n/** A hotspot being added: on a node, or at a place */\nexport type HotspotDraft = {\n nodeId?: string;\n position: XYPosition;\n level?: 1 | 2;\n};\nexport type HotspotFields = {\n severity: HotspotSeverity;\n title: string;\n description?: string;\n};\n\n// Markers keep their size on screen as the canvas zooms in, and shrink with it zoomed out (to half their size at\n// most), so they don't cover what they're about; zoomed well out they're just their icon\nconst MARKER_SCALE = \"--studio-hotspot-scale\";\n// What an open marker's panel is scaled by inside it, so it's always its full size on screen (to be read)\nconst PANEL_SCALE = \"--studio-hotspot-panel-scale\";\nconst MIN_SCREEN_SCALE = 0.5;\nconst ICONS_ONLY_BELOW_ZOOM = 0.6;\n\n/** Keeps MARKER_SCALE (and icons only) on the layer as the canvas zooms, outside React, so markers don't re-render */\nfunction useMarkerScale(ref: RefObject<HTMLElement | null>) {\n const store = useStoreApi();\n useLayoutEffect(() => {\n const apply = (zoom: number) => {\n const element = ref.current;\n if (!element) return;\n // In the canvas's coordinates: zoomed in, 1 / zoom (the same size on screen); zoomed out, the canvas's size\n // (1), until that's under MIN_SCREEN_SCALE on screen\n const scale = zoom >= 1 ? 1 / zoom : Math.max(1, MIN_SCREEN_SCALE / zoom);\n element.style.setProperty(MARKER_SCALE, String(scale));\n element.style.setProperty(PANEL_SCALE, String(1 / zoom / scale));\n element.classList.toggle(\"is-icons-only\", zoom < ICONS_ONLY_BELOW_ZOOM);\n };\n apply(store.getState().transform[2]);\n return store.subscribe((state, previous) => {\n if (state.transform[2] !== previous.transform[2])\n apply(state.transform[2]);\n });\n }, [store, ref]);\n}\n\n/** On its node's top right corner (following only that node), or at its place */\nfunction SpotAt({\n nodeId,\n position,\n zIndex,\n children,\n}: {\n nodeId?: string;\n position?: XYPosition;\n zIndex: number;\n children: ReactNode;\n}) {\n const node = useInternalNode(nodeId ?? \"\");\n let at = position;\n if (nodeId) {\n if (!node) return null;\n const { x, y } = node.internals.positionAbsolute;\n at = { x: x + (node.measured.width ?? node.width ?? 0), y };\n }\n if (!at) return null;\n return (\n <div\n className=\"absolute\"\n style={{\n left: at.x,\n top: at.y,\n transform: `scale(var(${MARKER_SCALE}, 1))`,\n transformOrigin: \"0 0\",\n zIndex,\n }}\n >\n {/* The marker's icon is centred on the corner, its title out to the right */}\n <div className=\"nopan nodrag nowheel pointer-events-auto absolute left-[-14px] top-[-14px]\">\n {children}\n </div>\n </div>\n );\n}\n\nfunction SeverityIcon({\n severity,\n size = 13,\n}: {\n severity: HotspotSeverity;\n size?: number;\n}) {\n const { icon: Icon } = SEVERITIES[severity];\n return <Icon size={size} strokeWidth={2.5} aria-hidden />;\n}\n\n/** Where a hotspot is put: on a node (it moves with it), or at a place */\nexport type HotspotPlace = { nodeId?: string; position: XYPosition };\n\n// How far the pointer moves before a press on a marker is a drag (not a click)\nconst DRAG_THRESHOLD_PX = 4;\n// The marker's icon (where it's anchored) is this far from its top left corner\nconst ICON_CENTRE_PX = 14;\n\n/**\n * The marker: its severity's colour and icon, and its title (or how many there are). Click opens it; dragging it\n * moves it: `onDrag` gets the screen point its icon is over, keeping where on the marker it was grabbed\n */\nfunction Marker({\n spot,\n open,\n selected,\n onClick,\n onDrag,\n}: {\n spot: HotspotSpot;\n open: boolean;\n /** Part of what's selected on the canvas (after selecting everything) */\n selected?: boolean;\n onClick: () => void;\n onDrag?: (point: XYPosition, phase: \"move\" | \"end\") => void;\n}) {\n const drag = useRef<{\n start: XYPosition;\n grab: XYPosition;\n moved: boolean;\n } | null>(null);\n const pointOf = (event: { clientX: number; clientY: number }) => ({\n x: event.clientX - drag.current!.grab.x,\n y: event.clientY - drag.current!.grab.y,\n });\n const sorted = [...spot.hotspots].sort(bySeverity);\n const severity = sorted[0].severity;\n const count = sorted.length;\n const label = spot.inside\n ? `${count} hotspot${count === 1 ? \"\" : \"s\"}`\n : count > 1\n ? `${sorted[0].title} +${count - 1}`\n : sorted[0].title;\n return (\n <button\n type=\"button\"\n aria-expanded={open}\n title={sorted\n .map(\n (hotspot) =>\n `${SEVERITIES[hotspot.severity].label}: ${hotspot.title}`,\n )\n .join(\"\\n\")}\n onKeyDown={(event) =>\n (event.key === \"Enter\" || event.key === \" \") && onClick()\n }\n onPointerDown={(event) => {\n if (event.button !== 0) return;\n // Keeps pointer events coming while the pointer is off the marker (throws if the pointer has gone)\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {}\n const rect = event.currentTarget.getBoundingClientRect();\n drag.current = {\n start: { x: event.clientX, y: event.clientY },\n grab: {\n x: event.clientX - rect.left - ICON_CENTRE_PX * (rect.height / 28),\n y: event.clientY - rect.top - rect.height / 2,\n },\n moved: false,\n };\n }}\n onPointerMove={(event) => {\n const current = drag.current;\n if (!current || !onDrag) return;\n if (\n !current.moved &&\n Math.hypot(\n event.clientX - current.start.x,\n event.clientY - current.start.y,\n ) < DRAG_THRESHOLD_PX\n )\n return;\n current.moved = true;\n onDrag(pointOf(event), \"move\");\n }}\n onPointerUp={(event) => {\n const current = drag.current;\n drag.current = null;\n if (!current) return;\n if (current.moved)\n onDrag?.(\n {\n x: event.clientX - current.grab.x,\n y: event.clientY - current.grab.y,\n },\n \"end\",\n );\n else onClick();\n }}\n onPointerCancel={() => (drag.current = null)}\n className={`studio-hotspot-marker flex h-7 max-w-[240px] items-center gap-1.5 rounded-full pl-1 pr-2.5 text-[11px] font-semibold text-white ${onDrag ? \"cursor-grab active:cursor-grabbing\" : \"\"}`}\n style={{\n background: SEVERITIES[severity].color,\n touchAction: \"none\",\n ...(selected && {\n boxShadow:\n \"0 0 0 2px rgb(var(--ec-card-bg)), 0 0 0 4px rgb(var(--ec-button-bg))\",\n }),\n }}\n >\n <span className=\"flex h-5 w-5 flex-none items-center justify-center rounded-full bg-white/20\">\n <SeverityIcon severity={severity} />\n </span>\n <span className=\"studio-hotspot-label truncate\">{label}</span>\n </button>\n );\n}\n\nconst panelClass =\n \"studio-hotspot-panel absolute left-0 top-[34px] w-80 rounded-xl border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg))] text-[rgb(var(--ec-page-text))] shadow-xl\";\nconst inputClass =\n \"block w-full rounded-md border border-[rgb(var(--ec-input-border))] bg-[rgb(var(--ec-input-bg))] px-2.5 py-1.5 text-sm text-[rgb(var(--ec-input-text))] outline-none focus:border-[rgb(var(--ec-accent))]\";\n\n/** Adding or changing one: how important, what it is, and why */\nfunction HotspotForm({\n initial,\n submitLabel,\n onSubmit,\n onCancel,\n}: {\n initial?: HotspotFields;\n submitLabel: string;\n onSubmit: (fields: HotspotFields) => void;\n onCancel: () => void;\n}) {\n const [severity, setSeverity] = useState<HotspotSeverity>(\n initial?.severity ?? \"warning\",\n );\n const [title, setTitle] = useState(initial?.title ?? \"\");\n const [description, setDescription] = useState(initial?.description ?? \"\");\n const submit = (event?: FormEvent) => {\n event?.preventDefault();\n if (!title.trim()) return;\n onSubmit({\n severity,\n title: title.trim(),\n ...(description.trim() && { description: description.trim() }),\n });\n };\n return (\n <form\n onSubmit={submit}\n onKeyDown={(event) => {\n if (event.key === \"Escape\") {\n event.stopPropagation();\n onCancel();\n }\n }}\n className=\"space-y-2.5 p-3\"\n >\n <div role=\"radiogroup\" aria-label=\"How important\" className=\"flex gap-1\">\n {SEVERITY_ORDER.map((value) => {\n const picked = value === severity;\n return (\n <button\n key={value}\n type=\"button\"\n role=\"radio\"\n aria-checked={picked}\n onClick={() => setSeverity(value)}\n className=\"flex flex-1 items-center justify-center gap-1 rounded-md border px-2 py-1.5 text-xs font-semibold transition-colors\"\n style={\n picked\n ? {\n background: SEVERITIES[value].color,\n borderColor: SEVERITIES[value].color,\n color: \"#fff\",\n }\n : {\n borderColor: \"rgb(var(--ec-page-border))\",\n color: SEVERITIES[value].color,\n }\n }\n >\n <SeverityIcon severity={value} size={12} />\n {SEVERITIES[value].label}\n </button>\n );\n })}\n </div>\n <input\n autoFocus\n value={title}\n maxLength={120}\n onChange={(event) => setTitle(event.target.value)}\n placeholder=\"What should people know? e.g. Single point of failure\"\n className={inputClass}\n />\n <textarea\n value={description}\n maxLength={1000}\n rows={3}\n onChange={(event) => setDescription(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" && (event.metaKey || event.ctrlKey))\n submit();\n }}\n placeholder=\"Why it matters, and what to do about it (optional)\"\n className={`${inputClass} resize-none`}\n />\n <div className=\"flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"rounded-md px-3 py-1.5 text-xs font-medium text-[rgb(var(--ec-page-text-muted))] hover:bg-[rgb(var(--ec-content-hover))]!\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n disabled={!title.trim()}\n className=\"rounded-md bg-[rgb(var(--ec-primary-bg))] px-3 py-1.5 text-xs font-semibold text-[rgb(var(--ec-primary-text))] disabled:opacity-40\"\n >\n {submitLabel}\n </button>\n </div>\n </form>\n );\n}\n\nfunction SeverityTag({ severity }: { severity: HotspotSeverity }) {\n return (\n <span\n className=\"inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide text-white\"\n style={{ background: SEVERITIES[severity].color }}\n >\n <SeverityIcon severity={severity} size={10} />\n {SEVERITIES[severity].label}\n </span>\n );\n}\n\n/** One hotspot as it reads: how important, what, why, and who flagged it */\nfunction HotspotItem({\n hotspot,\n actions,\n}: {\n hotspot: Hotspot;\n actions?: ReactNode;\n}) {\n return (\n <div\n className=\"border-l-[3px] pl-2.5\"\n style={{ borderColor: SEVERITIES[hotspot.severity].color }}\n >\n <div className=\"flex items-center gap-2\">\n <SeverityTag severity={hotspot.severity} />\n <span className=\"flex min-w-0 items-center gap-1 truncate text-[11px] text-[rgb(var(--ec-page-text-muted))]\">\n {hotspot.author.agent && (\n <AgentMark name={hotspot.author.name} size={11} />\n )}\n {hotspot.author.name} · {timeAgo(hotspot.createdAt)}\n </span>\n {actions && (\n <span className=\"ml-auto flex flex-none items-center gap-0.5\">\n {actions}\n </span>\n )}\n </div>\n <p className=\"mt-1.5 text-sm font-semibold leading-snug\">\n {hotspot.title}\n </p>\n {hotspot.description && (\n <p className=\"mt-1 whitespace-pre-wrap text-xs leading-relaxed text-[rgb(var(--ec-page-text-muted))]\">\n {hotspot.description}\n </p>\n )}\n </div>\n );\n}\n\nfunction IconButton({\n label,\n onClick,\n children,\n}: {\n label: string;\n onClick: () => void;\n children: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n title={label}\n aria-label={label}\n onClick={onClick}\n className=\"rounded p-1 text-[rgb(var(--ec-icon-color))] hover:bg-[rgb(var(--ec-page-border)/0.5)] hover:text-[rgb(var(--ec-icon-hover))]\"\n >\n {children}\n </button>\n );\n}\n\n/** The hotspots at a marker, opened: read, changed or removed (or, inside a node on L1 and L2, gone to) */\nfunction SpotPanel({\n spot,\n locked,\n onClose,\n onUpdate,\n onDelete,\n onGo,\n}: {\n spot: HotspotSpot;\n locked: boolean;\n onClose: () => void;\n onUpdate: (id: string, fields: HotspotFields) => void;\n onDelete: (id: string) => void;\n onGo: (hotspot: Hotspot) => void;\n}) {\n const [editing, setEditing] = useState<string | null>(null);\n const sorted = [...spot.hotspots].sort(bySeverity);\n return (\n <div className={panelClass}>\n <div className=\"flex items-center justify-between border-b border-[rgb(var(--ec-page-border))] px-3 py-2\">\n <span className=\"text-xs font-semibold\">\n {sorted.length === 1 ? \"Hotspot\" : `${sorted.length} hotspots`}\n </span>\n <IconButton label=\"Close\" onClick={onClose}>\n <X size={14} />\n </IconButton>\n </div>\n <div className=\"max-h-80 space-y-3 overflow-y-auto p-3\">\n {sorted.map((hotspot) =>\n editing === hotspot.id ? (\n <div key={hotspot.id} className=\"-m-3\">\n <HotspotForm\n initial={hotspot}\n submitLabel=\"Save\"\n onCancel={() => setEditing(null)}\n onSubmit={(fields) => {\n onUpdate(hotspot.id, fields);\n setEditing(null);\n }}\n />\n </div>\n ) : spot.inside ? (\n // Inside a node on L1 or L2: goes to it on L3, where it is\n <button\n key={hotspot.id}\n type=\"button\"\n onClick={() => onGo(hotspot)}\n className=\"block w-full rounded-md text-left hover:bg-[rgb(var(--ec-content-hover))]!\"\n >\n <HotspotItem hotspot={hotspot} />\n </button>\n ) : (\n <HotspotItem\n key={hotspot.id}\n hotspot={hotspot}\n actions={\n !locked && (\n <>\n <IconButton\n label=\"Edit\"\n onClick={() => setEditing(hotspot.id)}\n >\n <Pencil size={13} />\n </IconButton>\n <IconButton\n label=\"Remove\"\n onClick={() => onDelete(hotspot.id)}\n >\n <Trash2 size={13} />\n </IconButton>\n </>\n )\n }\n />\n ),\n )}\n </div>\n {spot.inside && (\n <p className=\"border-t border-[rgb(var(--ec-page-border))] px-3 py-2 text-[11px] text-[rgb(var(--ec-page-text-muted))]\">\n Inside this: click one to go to it.\n </p>\n )}\n </div>\n );\n}\n\nexport const HotspotLayer = memo(function HotspotLayer({\n spots,\n openKey,\n draft,\n locked,\n movable,\n selectedIds,\n onMove,\n onDropTarget,\n onOpen,\n onCreate,\n onCancelDraft,\n onUpdate,\n onDelete,\n onGo,\n live,\n}: {\n spots: HotspotSpot[];\n openKey: string | null;\n draft: HotspotDraft | null;\n locked: boolean;\n /** Markers can be dragged to another node, or a place (on the canvas itself, L3) */\n movable: boolean;\n /** Hotspots that are part of what's selected (after selecting everything) */\n selectedIds: ReadonlySet<string> | null;\n /** Moved: the hotspots at a marker, onto a node or to a place */\n onMove: (ids: string[], to: HotspotPlace) => void;\n /** The node a marker being dragged would go on (and its colour), to light it up; none when it's dropped */\n onDropTarget: (\n target: { nodeId: string; severity: HotspotSeverity } | null,\n ) => void;\n onOpen: (key: string | null) => void;\n onCreate: (fields: HotspotFields) => void;\n onCancelDraft: () => void;\n onUpdate: (id: string, fields: HotspotFields) => void;\n onDelete: (id: string) => void;\n onGo: (hotspot: Hotspot) => void;\n /** In a live room: markers the others are dragging move here as they drag, and mine move for them */\n live?: LiveMoves;\n}) {\n const layer = useRef<HTMLDivElement>(null);\n useMarkerScale(layer);\n const { screenToFlowPosition } = useReactFlow();\n // A marker being dragged follows the pointer here until it's dropped, then moves for everyone\n const [moving, setMoving] = useState<{\n key: string;\n position: XYPosition;\n over?: string;\n } | null>(null);\n // (a marker's known by its first hotspot: the others may group them differently)\n const remote = useRemoteMoves(live, \"hotspot\");\n const remoteAt = (spot: HotspotSpot) => {\n for (const hotspot of spot.hotspots)\n if (remote.has(hotspot.id)) return remote.get(hotspot.id);\n };\n // The node under a point on screen it can go on (not notes or text: they're written on the canvas)\n const nodeUnder = (point: XYPosition) => {\n const element = document\n .elementsFromPoint(point.x, point.y)\n .find((el) => el.closest(\".react-flow__node\"));\n const node = element?.closest(\".react-flow__node\");\n const type = [...(node?.classList ?? [])]\n .find((name) => name.startsWith(\"react-flow__node-\"))\n ?.slice(\"react-flow__node-\".length);\n return node && !isWrittenOnCanvas(type)\n ? (node.getAttribute(\"data-id\") ?? undefined)\n : undefined;\n };\n const dragHandler = (spot: HotspotSpot) =>\n movable && !locked && !spot.inside\n ? (point: XYPosition, phase: \"move\" | \"end\") => {\n const position = screenToFlowPosition(point);\n const over = nodeUnder(point);\n if (phase === \"move\") {\n if (over !== moving?.over)\n onDropTarget(\n over\n ? { nodeId: over, severity: topSeverity(spot.hotspots)! }\n : null,\n );\n sendMove(live, \"hotspot\", spot.hotspots[0].id, position);\n return setMoving({ key: spot.key, position, over });\n }\n setMoving(null);\n onDropTarget(null);\n onMove(\n spot.hotspots.map((hotspot) => hotspot.id),\n over ? { nodeId: over, position } : { position },\n );\n // (after the drop's in the document, so the others don't see it go back in between)\n sendMove(live, \"hotspot\", spot.hotspots[0].id, null);\n }\n : undefined;\n return (\n <CanvasPortal>\n {/* Over the nodes (selected ones are raised to 1000), under comments */}\n <div\n ref={layer}\n className=\"absolute left-0 top-0\"\n style={{ zIndex: 2000 }}\n >\n {spots.map((spot) => {\n const open = spot.key === openKey;\n const remotely = remoteAt(spot);\n const dragged =\n moving?.key === spot.key\n ? moving\n : remotely\n ? { position: remotely }\n : undefined;\n return (\n <SpotAt\n key={spot.key}\n nodeId={dragged ? undefined : spot.nodeId}\n position={dragged ? dragged.position : spot.position}\n zIndex={dragged ? 5 : open ? 3 : 1}\n >\n <Marker\n spot={spot}\n open={open}\n selected={\n !!selectedIds &&\n spot.hotspots.some((hotspot) => selectedIds.has(hotspot.id))\n }\n onClick={() => onOpen(open ? null : spot.key)}\n onDrag={dragHandler(spot)}\n />\n {open && !dragged && (\n <SpotPanel\n spot={spot}\n locked={locked}\n onClose={() => onOpen(null)}\n onUpdate={onUpdate}\n onDelete={onDelete}\n onGo={onGo}\n />\n )}\n </SpotAt>\n );\n })}\n {draft && (\n <SpotAt\n nodeId={draft.nodeId}\n position={draft.nodeId ? undefined : draft.position}\n zIndex={4}\n >\n <span\n className=\"studio-hotspot-marker flex h-7 w-7 items-center justify-center rounded-full text-white\"\n style={{ background: SEVERITIES.warning.color }}\n >\n <SeverityIcon severity=\"warning\" />\n </span>\n <div className={panelClass}>\n <HotspotForm\n submitLabel=\"Add hotspot\"\n onSubmit={onCreate}\n onCancel={onCancelDraft}\n />\n </div>\n </SpotAt>\n )}\n </div>\n </CanvasPortal>\n );\n});\n\n/** All of them, most important first, for the panel at the bottom left: clicking one goes to it */\nexport function HotspotList({\n hotspots,\n nameOf,\n onOpen,\n}: {\n hotspots: Hotspot[];\n nameOf: (nodeId: string) => string | undefined;\n onOpen: (hotspot: Hotspot) => void;\n}) {\n const sorted = [...hotspots].sort(bySeverity);\n if (!sorted.length)\n return (\n <p className=\"px-4 py-6 text-center text-xs leading-relaxed text-[rgb(var(--ec-page-text-muted))]\">\n No hotspots yet. Press A, or right-click a node, to flag what people\n should know: a risk, a problem, or the key part.\n </p>\n );\n return (\n <div className=\"space-y-1.5 p-3\">\n {sorted.map((hotspot) => {\n const on = hotspot.nodeId && nameOf(hotspot.nodeId);\n return (\n <button\n key={hotspot.id}\n type=\"button\"\n onClick={() => onOpen(hotspot)}\n className=\"w-full rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-bg))] px-2.5 py-2 text-left hover:border-[rgb(var(--ec-accent))]!\"\n >\n <HotspotItem hotspot={hotspot} />\n {on && (\n <p className=\"mt-1.5 pl-[13px] text-[11px] text-[rgb(var(--ec-page-text-muted))]\">\n On {on}\n </p>\n )}\n </button>\n );\n })}\n </div>\n );\n}\n","import { memo, type ReactNode } from \"react\";\nimport { useReactFlow, type FitViewOptions } from \"@xyflow/react\";\nimport {\n Hand,\n Lock,\n LockOpen,\n Maximize,\n MessageCircle,\n MessageSquareText,\n MousePointer2,\n Type,\n Redo,\n SendToBack,\n StickyNote,\n TriangleAlert,\n Undo,\n ZoomIn,\n ZoomOut,\n} from \"lucide-react\";\nimport {\n DIAGRAM_FIT_VIEW_OPTIONS,\n Toolbar,\n ToolbarButton,\n ToolbarDivider,\n ZoomLevel,\n} from \"../../index\";\nimport { LEVELS, type Level } from \"../levels\";\nimport type { HotspotSeverity } from \"../canvas-doc\";\nimport { SEVERITIES } from \"./Hotspots\";\n\n// The canvas's bar at the top (lock, select and hand, the levels of detail, notes, text, comments and hotspots),\n// and its controls at the bottom left (zoom, undo, fit and reorder, comments and hotspots). Built from the visualiser's toolbar, so they\n// look and work like a diagram's bar.\n\n// Fitted like the visualiser fits a diagram\nexport const FIT_VIEW_OPTIONS = DIAGRAM_FIT_VIEW_OPTIONS;\n\n/** A tool's icon with its key in the corner, as Excalidraw's tools show theirs */\nfunction WithKey({\n shortcut,\n children,\n}: {\n shortcut: string;\n children: ReactNode;\n}) {\n return (\n <span className=\"relative flex h-8 w-8 items-center justify-center\">\n <span className=\"-translate-x-[3px] -translate-y-[2px]\">{children}</span>\n <span\n aria-hidden\n className=\"absolute bottom-[2px] right-[4px] text-[9px] font-medium leading-none text-[rgb(var(--ec-page-text-muted))] opacity-60\"\n >\n {shortcut}\n </span>\n </span>\n );\n}\n\n/** What to do with the tool picked, under the bar (as Excalidraw says) */\nconst TOOL_HINTS = {\n note: \"Click anywhere to put a sticky note there\",\n text: \"Click anywhere to start typing\",\n comment: \"Click anywhere, or on a node, to comment there\",\n hotspot: \"Click a node, or anywhere, to flag a hotspot there\",\n};\n\n/** The levels of detail: each can always be gone to (one with nothing on it yet is where those things are added) */\nfunction LevelSwitch({\n level,\n onChange,\n unavailable,\n}: {\n level: Level;\n onChange: (level: Level) => void;\n /** Levels this canvas can't show, and why (EventCatalog's Studio: as its diagrams do) */\n unavailable?: Partial<Record<Level, string | undefined>>;\n}) {\n return (\n <div\n role=\"group\"\n aria-label=\"Level of detail\"\n className=\"flex items-center gap-0.5\"\n >\n {LEVELS.map(({ level: value, description }) => (\n <ToolbarButton\n key={value}\n label={`Level ${value}: ${description} (${value})`}\n hint={unavailable?.[value]}\n active={value === level}\n disabled={!!unavailable?.[value]}\n onClick={() => onChange(value)}\n >\n <WithKey shortcut={String(value)}>\n <span className=\"text-xs font-semibold\">L{value}</span>\n </WithKey>\n </ToolbarButton>\n ))}\n </div>\n );\n}\n\nexport default memo(function CanvasControls({\n level,\n onLevelChange,\n unavailableLevels,\n editable,\n locked,\n onToggleLock,\n lockedBy,\n selectMode,\n onSelectMode,\n handMode,\n onHandMode,\n noteMode,\n onToggleNoteMode,\n textMode,\n onToggleTextMode,\n commentMode,\n onToggleCommentMode,\n hotspotMode,\n onToggleHotspotMode,\n extras,\n}: {\n level: Level;\n onLevelChange: (level: Level) => void;\n /** Levels this canvas can't show, and why (greyed out, with the reason) */\n unavailableLevels?: Partial<Record<Level, string | undefined>>;\n /** L3, the canvas itself (comments are there; L1 and L2 are arranged on their own) */\n editable: boolean;\n /** Nothing on the canvas can be changed (until it's unlocked) */\n locked: boolean;\n onToggleLock: () => void;\n /** Who locked it (it's locked for everyone on it) */\n lockedBy?: string | null;\n /** Selecting and moving what's on the canvas (no tool picked) */\n selectMode: boolean;\n onSelectMode: () => void;\n /** The hand: dragging moves around the canvas (nothing on it is picked up) */\n handMode: boolean;\n onHandMode: () => void;\n /** The sticky note tool, on: a click on the canvas puts a note there */\n noteMode: boolean;\n onToggleNoteMode: () => void;\n /** The comment tool, on: a click on the canvas (or a node) pins a comment there */\n commentMode: boolean;\n onToggleCommentMode: () => void;\n /** The hotspot tool, on: a click on a node (or the canvas) flags a hotspot there */\n hotspotMode: boolean;\n onToggleHotspotMode: () => void;\n /** The text tool, on: a click on the canvas writes there */\n textMode: boolean;\n onToggleTextMode: () => void;\n /** More buttons at the end of the bar (e.g. replaying the agent's walkthrough) */\n extras?: ReactNode;\n}) {\n return (\n // At the top, as drawing tools have their tools\n <div className=\"absolute left-1/2 top-3 z-10 -translate-x-1/2\">\n <Toolbar>\n {/* First, as on Excalidraw: locking it, then selecting and moving around */}\n <ToolbarButton\n label={\n locked\n ? `Locked${lockedBy ? ` by ${lockedBy}` : \"\"}: unlock it to change it (for everyone on it)`\n : \"Lock the canvas (it can be looked at, not changed, by everyone on it)\"\n }\n active={locked}\n onClick={onToggleLock}\n >\n {locked ? (\n <Lock className=\"h-4 w-4\" />\n ) : (\n <LockOpen className=\"h-4 w-4\" />\n )}\n </ToolbarButton>\n <ToolbarDivider />\n <ToolbarButton\n label=\"Select (V)\"\n active={selectMode}\n onClick={onSelectMode}\n >\n <WithKey shortcut=\"V\">\n <MousePointer2 className=\"h-4 w-4\" />\n </WithKey>\n </ToolbarButton>\n <ToolbarButton\n label=\"Hand (H): drag to move around\"\n active={handMode}\n onClick={onHandMode}\n >\n <WithKey shortcut=\"H\">\n <Hand className=\"h-4 w-4\" />\n </WithKey>\n </ToolbarButton>\n <ToolbarDivider />\n <LevelSwitch\n level={level}\n onChange={onLevelChange}\n unavailable={unavailableLevels}\n />\n <ToolbarDivider />\n {/* Notes can be added on every level, and are shown on the level they're added on */}\n <ToolbarButton\n label={\n editable\n ? \"Sticky note (N): click where it goes\"\n : `Sticky note (N): on L${level}, where it's clicked`\n }\n active={noteMode}\n disabled={locked}\n hint={locked ? \"The canvas is locked\" : undefined}\n onClick={onToggleNoteMode}\n >\n <WithKey shortcut=\"N\">\n <StickyNote className=\"h-4 w-4 text-yellow-500\" />\n </WithKey>\n </ToolbarButton>\n {/* Excalidraw's text tool: click anywhere and type */}\n <ToolbarButton\n label={\n editable\n ? \"Text (T): click anywhere and type\"\n : `Text (T): on L${level}, where it's clicked`\n }\n active={textMode}\n disabled={locked}\n hint={locked ? \"The canvas is locked\" : undefined}\n onClick={onToggleTextMode}\n >\n <WithKey shortcut=\"T\">\n <Type className=\"h-4 w-4\" />\n </WithKey>\n </ToolbarButton>\n {/* Studio's comments: pinned to the canvas or a node, replied to and resolved */}\n <ToolbarButton\n label=\"Comment (C): click where it goes, or on a node\"\n active={commentMode}\n onClick={onToggleCommentMode}\n >\n <WithKey shortcut=\"C\">\n <MessageCircle className=\"h-4 w-4\" />\n </WithKey>\n </ToolbarButton>\n {/* Hotspots: what people should know about (risks, problems, the key parts), hard to miss */}\n <ToolbarButton\n label=\"Hotspot (A): click a node, or anywhere, to flag it\"\n active={hotspotMode}\n disabled={locked}\n hint={locked ? \"The canvas is locked\" : undefined}\n onClick={onToggleHotspotMode}\n >\n <WithKey shortcut=\"A\">\n <TriangleAlert className=\"h-4 w-4 text-amber-600\" />\n </WithKey>\n </ToolbarButton>\n {extras}\n </Toolbar>\n {(noteMode || textMode || commentMode || hotspotMode) && (\n <p className=\"pointer-events-none mt-2 text-center text-xs text-[rgb(var(--ec-page-text-muted))]\">\n {\n TOOL_HINTS[\n noteMode\n ? \"note\"\n : commentMode\n ? \"comment\"\n : hotspotMode\n ? \"hotspot\"\n : \"text\"\n ]\n }{\" \"}\n ·{\" \"}\n <kbd className=\"rounded border border-[rgb(var(--ec-page-border))] px-1 font-sans text-[11px]\">\n Esc\n </kbd>{\" \"}\n to cancel\n </p>\n )}\n </div>\n );\n});\n\n/** The bottom-left controls, as Excalidraw's: zooming, undo and redo, then fitting it to the view and laying it out again */\nexport const ViewControls = memo(function ViewControls({\n canUndo,\n canRedo,\n onUndo,\n onRedo,\n onReorder,\n reorderLabel,\n locked,\n fitOptions = FIT_VIEW_OPTIONS,\n comments,\n hotspots,\n}: {\n canUndo: boolean;\n canRedo: boolean;\n onUndo: () => void;\n onRedo: () => void;\n /** Lays it out again with the visualiser's layout */\n onReorder: () => void;\n reorderLabel: string;\n locked: boolean;\n /** How the canvas is fitted to the view (clear of what's over it, e.g. the palette) */\n fitOptions?: FitViewOptions;\n /** The comments: how many are open, and showing them all */\n comments?: { open: number; active: boolean; onToggle: () => void };\n /** The hotspots: how many, the most important's severity, and listing them all */\n hotspots?: {\n count: number;\n severity?: HotspotSeverity;\n active: boolean;\n onToggle: () => void;\n };\n}) {\n const { zoomIn, zoomOut, fitView } = useReactFlow();\n return (\n <>\n <Toolbar>\n <ToolbarButton\n label=\"Zoom out\"\n onClick={() => void zoomOut({ duration: 200 })}\n >\n <ZoomOut className=\"h-4 w-4\" />\n </ToolbarButton>\n <ZoomLevel />\n <ToolbarButton\n label=\"Zoom in\"\n onClick={() => void zoomIn({ duration: 200 })}\n >\n <ZoomIn className=\"h-4 w-4\" />\n </ToolbarButton>\n </Toolbar>\n <Toolbar>\n <ToolbarButton\n label=\"Undo (⌘Z)\"\n hint={canUndo ? undefined : \"Nothing to undo\"}\n disabled={!canUndo}\n onClick={onUndo}\n >\n <Undo className=\"h-4 w-4\" />\n </ToolbarButton>\n <ToolbarButton\n label=\"Redo (⇧⌘Z)\"\n hint={canRedo ? undefined : \"Nothing to redo\"}\n disabled={!canRedo}\n onClick={onRedo}\n >\n <Redo className=\"h-4 w-4\" />\n </ToolbarButton>\n </Toolbar>\n <Toolbar>\n <ToolbarButton\n label=\"Fit view (⇧1)\"\n onClick={() => void fitView({ ...fitOptions, duration: 500 })}\n >\n <Maximize className=\"h-4 w-4\" />\n </ToolbarButton>\n <ToolbarButton\n label={reorderLabel}\n hint={locked ? \"The canvas is locked\" : undefined}\n disabled={locked}\n onClick={onReorder}\n >\n <SendToBack className=\"h-4 w-4\" />\n </ToolbarButton>\n </Toolbar>\n {comments && (\n <Toolbar>\n <ToolbarButton\n label={\n comments.open ? `Comments (${comments.open} open)` : \"Comments\"\n }\n active={comments.active}\n onClick={comments.onToggle}\n >\n <span className=\"relative\">\n <MessageSquareText className=\"h-4 w-4\" />\n {comments.open > 0 && (\n <span className=\"absolute -right-2 -top-2 min-w-4 rounded-full bg-[rgb(var(--ec-accent))] px-1 text-center text-[9px] font-semibold leading-4 text-white\">\n {comments.open}\n </span>\n )}\n </span>\n </ToolbarButton>\n {hotspots && (\n <ToolbarButton\n label={\n hotspots.count ? `Hotspots (${hotspots.count})` : \"Hotspots\"\n }\n active={hotspots.active}\n onClick={hotspots.onToggle}\n >\n <span className=\"relative\">\n <TriangleAlert className=\"h-4 w-4\" />\n {hotspots.count > 0 && (\n <span\n className=\"absolute -right-2 -top-2 min-w-4 rounded-full px-1 text-center text-[9px] font-semibold leading-4 text-white\"\n style={{\n background:\n SEVERITIES[hotspots.severity ?? \"warning\"].color,\n }}\n >\n {hotspots.count}\n </span>\n )}\n </span>\n </ToolbarButton>\n )}\n </Toolbar>\n )}\n </>\n );\n});\n","import { useEffect, useState, type ReactElement } from \"react\";\nimport { X } from \"lucide-react\";\n\n/**\n * Asked when a domain or system is put on the canvas: is it a card (connected to what it contains), or a container\n * that what it contains sits inside? Styled like the visualiser's group-by picker (boxes or lanes). One from a catalog\n * can bring what it contains in the catalog inside it (`contents`).\n */\n\nexport type ContainerChoice =\n | { as: \"card\" }\n | { as: \"container\"; withContents?: boolean };\n\nconst plural = (count: number, noun: string) =>\n `${count} ${noun}${count === 1 ? \"\" : \"s\"}`;\n\n// Small pictures of the two ways a domain or system can be on the canvas\nexport const CardPreview = () => (\n <svg viewBox=\"0 0 64 36\" className=\"h-9 w-16\" aria-hidden>\n <rect\n x=\"18\"\n y=\"8\"\n width=\"28\"\n height=\"20\"\n rx=\"4\"\n fill=\"currentColor\"\n fillOpacity=\"0.1\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.5\"\n strokeWidth=\"1.5\"\n />\n <rect\n x=\"23\"\n y=\"13\"\n width=\"14\"\n height=\"3\"\n rx=\"1.5\"\n fill=\"currentColor\"\n fillOpacity=\"0.6\"\n />\n <rect\n x=\"23\"\n y=\"19\"\n width=\"18\"\n height=\"2\"\n rx=\"1\"\n fill=\"currentColor\"\n fillOpacity=\"0.35\"\n />\n <path\n d=\"M46 18h12\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.5\"\n strokeWidth=\"1.5\"\n strokeDasharray=\"2 2\"\n />\n <rect\n x=\"57\"\n y=\"14\"\n width=\"6\"\n height=\"8\"\n rx=\"1.5\"\n fill=\"currentColor\"\n fillOpacity=\"0.4\"\n />\n </svg>\n);\n\nconst ContainerPreview = () => (\n <svg viewBox=\"0 0 64 36\" className=\"h-9 w-16\" aria-hidden>\n <rect\n x=\"4\"\n y=\"2\"\n width=\"56\"\n height=\"32\"\n rx=\"4\"\n fill=\"currentColor\"\n fillOpacity=\"0.08\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.5\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M4 10h56\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.35\"\n strokeWidth=\"1\"\n />\n <rect\n x=\"8\"\n y=\"4.5\"\n width=\"14\"\n height=\"3\"\n rx=\"1.5\"\n fill=\"currentColor\"\n fillOpacity=\"0.6\"\n />\n <rect\n x=\"10\"\n y=\"15\"\n width=\"18\"\n height=\"12\"\n rx=\"2\"\n fill=\"currentColor\"\n fillOpacity=\"0.5\"\n />\n <rect\n x=\"36\"\n y=\"15\"\n width=\"18\"\n height=\"12\"\n rx=\"2\"\n fill=\"currentColor\"\n fillOpacity=\"0.5\"\n />\n </svg>\n);\n\nconst OPTIONS: {\n as: ContainerChoice[\"as\"];\n label: string;\n hint: string;\n Preview: () => ReactElement;\n}[] = [\n {\n as: \"card\",\n label: \"Card\",\n hint: \"Connected to what it contains\",\n Preview: CardPreview,\n },\n {\n as: \"container\",\n label: \"Container\",\n hint: \"What it contains sits inside it\",\n Preview: ContainerPreview,\n },\n];\n\nexport default function ContainerChooser({\n kind,\n name,\n contents,\n position,\n onChoose,\n onCancel,\n}: {\n kind: \"domain\" | \"system\";\n /** Its name, when it has one already (e.g. from a catalog) */\n name?: string;\n /** What it contains in the catalog that isn't on the canvas yet (offered to bring inside it, as a container) */\n contents?: { systems: number; services: number };\n /** Where to show it (screen coordinates) */\n position: { x: number; y: number };\n onChoose: (choice: ContainerChoice) => void;\n onCancel: () => void;\n}) {\n const [withContents, setWithContents] = useState(true);\n const contentsLabel = contents\n ? [\n contents.systems > 0 && plural(contents.systems, \"system\"),\n contents.services > 0 && plural(contents.services, \"service\"),\n ]\n .filter(Boolean)\n .join(\" and \")\n : \"\";\n\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) =>\n event.key === \"Escape\" && onCancel();\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, [onCancel]);\n\n // Kept on screen, next to where it was dropped\n const left = Math.min(\n Math.max(position.x - 160, 12),\n window.innerWidth - 332,\n );\n const top = Math.min(\n Math.max(position.y - 20, 12),\n window.innerHeight - (contentsLabel ? 260 : 200),\n );\n\n return (\n <div className=\"fixed inset-0 z-50\" onPointerDown={onCancel}>\n <div\n role=\"dialog\"\n aria-label={name ? `Add ${name} as` : `Add the ${kind} as`}\n onPointerDown={(event) => event.stopPropagation()}\n className=\"absolute w-80 rounded-lg border p-1.5 shadow-xl bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))]\"\n style={{ left, top }}\n >\n <div className=\"flex items-start justify-between gap-2 px-2 pb-1.5 pt-1\">\n <div className=\"min-w-0\">\n <p className=\"text-[10px] font-semibold uppercase tracking-wider text-[rgb(var(--ec-page-text-muted))]\">\n Add this {kind} as\n </p>\n {name && <p className=\"truncate text-xs font-semibold\">{name}</p>}\n </div>\n <button\n onClick={onCancel}\n aria-label=\"Cancel\"\n className=\"rounded p-0.5 text-[rgb(var(--ec-icon-color))] hover:bg-[rgb(var(--ec-page-border)/0.5)]\"\n >\n <X size={14} />\n </button>\n </div>\n\n <div className=\"grid grid-cols-2 gap-1.5 px-0.5 pb-0.5\">\n {OPTIONS.map(({ as, label, hint, Preview }) => (\n <button\n key={as}\n autoFocus={as === \"container\"}\n onClick={() =>\n onChoose(\n as === \"card\"\n ? { as }\n : { as, withContents: withContents && !!contentsLabel },\n )\n }\n className=\"flex flex-col items-center gap-1 rounded-md border px-2 pb-1.5 pt-2 text-xs outline-none transition-colors border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text-muted))] hover:border-[rgb(var(--ec-accent))] hover:bg-[color-mix(in_srgb,rgb(var(--ec-accent))_8%,transparent)] hover:text-[rgb(var(--ec-accent))] focus-visible:border-[rgb(var(--ec-accent))] focus-visible:text-[rgb(var(--ec-accent))]\"\n >\n <Preview />\n <span className=\"font-semibold\">{label}</span>\n <span className=\"text-center text-[10px] leading-tight text-[rgb(var(--ec-page-text-muted))]\">\n {hint}\n </span>\n </button>\n ))}\n </div>\n\n {contentsLabel && (\n <label className=\"mt-1 flex items-center gap-2 rounded-md px-2 py-1.5 text-[11px] text-[rgb(var(--ec-page-text-muted))]\">\n <input\n type=\"checkbox\"\n checked={withContents}\n onChange={(event) => setWithContents(event.target.checked)}\n />\n As a container, bring its {contentsLabel} inside, with their\n messages and data stores\n </label>\n )}\n </div>\n </div>\n );\n}\n","/**\n * A selected node's Edit button, above its top right corner (Details, when the canvas is locked). It's sized with\n * the canvas, as if it were on it: zoomed out it's small beside a small node, zoomed in it grows with it. Its own\n * component, so only it follows the zoom (not the whole canvas).\n */\nimport { memo } from \"react\";\nimport { NodeToolbar, Position, useStore } from \"@xyflow/react\";\nimport { Info, Pencil } from \"lucide-react\";\n\n// Kept usable when far out, and not huge when far in\nconst MIN_SCALE = 0.4;\nconst MAX_SCALE = 1.6;\nconst OFFSET = 8;\n\nexport default memo(function EditButton({\n nodeId,\n locked,\n onClick,\n}: {\n nodeId: string;\n locked: boolean;\n onClick: () => void;\n}) {\n const zoom = useStore((state) => state.transform[2]);\n const scale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, zoom));\n return (\n <NodeToolbar\n nodeId={nodeId}\n isVisible\n position={Position.Top}\n align=\"end\"\n offset={OFFSET * scale}\n >\n {/* Scaled from its bottom right corner, so it stays on the node's corner */}\n <button\n type=\"button\"\n className=\"studio-edit-button\"\n style={{\n transform: `scale(${scale})`,\n transformOrigin: \"bottom right\",\n }}\n onClick={onClick}\n >\n {locked ? (\n <>\n <Info aria-hidden /> Details\n </>\n ) : (\n <>\n <Pencil aria-hidden /> Edit\n </>\n )}\n </button>\n </NodeToolbar>\n );\n});\n","/**\n * What to put on the canvas, as a drawing tool's palette: a card on the left, under the top left controls, each\n * component a tile to drag onto the canvas (or click, to add it in the middle of what's on screen). Only what the\n * level shows is listed, so what's added stays on it. An app can add tabs beside the components (e.g. EventCatalog's\n * catalog resources and comments), drawn with the same tiles.\n */\nimport {\n memo,\n useCallback,\n useEffect,\n useRef,\n useState,\n type DragEvent,\n type ReactNode,\n} from \"react\";\nimport { ChevronDown, GripVertical, type LucideIcon } from \"lucide-react\";\nimport {\n componentKey,\n GROUP_TYPES,\n isShownOnLevel,\n NODE_CATEGORIES,\n nodeDefinitions,\n} from \"../node-types\";\nimport type { Level } from \"../levels\";\nimport { useDragGhost, type StartDrag } from \"./DragGhost\";\nimport { NODE_ICONS } from \"./icons\";\n\n/** What's dragged from the palette onto the canvas: a component's key (its type, or its kind of data store) */\nexport const COMPONENT_DRAG_TYPE = \"application/eventcatalog-studio\";\n\nconst listedDefinitions = NODE_CATEGORIES.map((category) => ({\n ...category,\n definitions: nodeDefinitions.filter(\n (definition) => definition.category === category.id && !definition.unlisted,\n ),\n}));\n\n// Each component's data, made once, for the node shown while it's dragged. Domains and systems are dragged as the\n// node they'd be as a card (whether they're a card or a container is asked when they're dropped)\nconst cardPreview = (kind: \"domain\" | \"system\") => ({\n type: kind === \"domain\" ? \"context-domain\" : \"system\",\n data: {\n mode: \"full\",\n navigable: false,\n [kind]: {\n name: kind === \"domain\" ? \"New Domain\" : \"New System\",\n version: \"0.0.1\",\n },\n },\n});\nconst componentPreviews = new Map(\n nodeDefinitions.map((definition) => [\n componentKey(definition),\n definition.type === GROUP_TYPES.domain\n ? cardPreview(\"domain\")\n : definition.type === GROUP_TYPES.system\n ? cardPreview(\"system\")\n : { type: definition.type, data: definition.createData() },\n ]),\n);\n\nconst COLLAPSED_KEY = \"eventcatalog-studio-palette-collapsed\";\nconst readCollapsed = () => {\n try {\n return localStorage.getItem(COLLAPSED_KEY) === \"true\";\n } catch {\n return false;\n }\n};\n\n/**\n * A tile in the palette: its icon, its name and what it is, picked up and dragged onto the canvas (or clicked, to\n * add it). Greyed out (`usable` false) where it can't be added, still saying why.\n */\nexport function PaletteItem({\n icon: Icon,\n iconClassName,\n label,\n description,\n usable = true,\n onDragStart,\n onClick,\n title,\n trailing,\n}: {\n icon: LucideIcon;\n iconClassName?: string;\n label: string;\n description?: ReactNode;\n usable?: boolean;\n onDragStart?: (event: DragEvent) => void;\n onClick?: () => void;\n title?: string;\n /** At the end instead of the drag handle (e.g. \"on the canvas\") */\n trailing?: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n draggable={usable && !!onDragStart}\n // (not disabled: it still says why it can't be added)\n aria-disabled={!usable}\n onDragStart={usable ? onDragStart : undefined}\n onClick={usable ? onClick : undefined}\n aria-label={label}\n title={title}\n className={`group flex w-full items-center gap-2.5 rounded-lg border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg))] py-1 pl-1 pr-2 text-left text-[rgb(var(--ec-page-text))] shadow-[0_1px_2px_rgb(0_0_0/0.05)] transition-[transform,box-shadow,border-color] duration-150 ${\n usable\n ? \"cursor-grab hover:-translate-y-px hover:border-[color-mix(in_srgb,rgb(var(--ec-accent))_45%,transparent)]! hover:shadow-[0_4px_12px_rgb(0_0_0/0.08)] active:translate-y-0 active:cursor-grabbing\"\n : \"cursor-not-allowed opacity-40 grayscale\"\n }`}\n >\n <span className=\"flex h-8 w-8 flex-none items-center justify-center rounded-md bg-[rgb(var(--ec-content-hover))]\">\n <Icon size={16} className={iconClassName} />\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-[13px] font-medium leading-tight\">\n {label}\n </span>\n {description && (\n <span className=\"block truncate text-[11px] leading-snug text-[rgb(var(--ec-page-text-muted))]\">\n {description}\n </span>\n )}\n </span>\n {trailing ??\n (usable && onDragStart && (\n // It's picked up and dragged on (a click adds it in the middle): a small handle says so\n <GripVertical\n aria-hidden\n size={14}\n className=\"flex-none text-[rgb(var(--ec-page-text-muted))] opacity-40 transition-opacity group-hover:opacity-80\"\n />\n ))}\n </button>\n );\n}\n\n/** A section of tiles, under a small heading */\nexport function PaletteSection({\n title,\n divided = false,\n children,\n}: {\n title: ReactNode;\n /** A line above it (e.g. what this level doesn't show, at the bottom) */\n divided?: boolean;\n children: ReactNode;\n}) {\n return (\n <section\n className={\n divided ? \"border-t border-[rgb(var(--ec-page-border))] pt-3\" : \"\"\n }\n >\n <h3 className=\"mb-1.5 text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))]\">\n {title}\n </h3>\n <div className=\"space-y-1.5\">{children}</div>\n </section>\n );\n}\n\n/** A tab an app adds beside the components: what it lists, given how to start dragging something onto the canvas */\nexport type PaletteTab = {\n id: string;\n label: string;\n /** A count beside its name (e.g. open comments) */\n badge?: number;\n render: (startDrag: StartDrag) => ReactNode;\n};\n\nconst COMPONENTS_TAB = \"components\";\n\nexport const Palette = memo(function Palette({\n level,\n onAddComponent,\n footer,\n tabs,\n tab,\n onTabChange,\n startCollapsed,\n}: {\n /** The level shown: only what it shows is listed */\n level: Level;\n onAddComponent: (key: string) => void;\n /** At the bottom, under the list (e.g. taking the diagram to EventCatalog) */\n footer?: ReactNode;\n /** More tabs beside the components (the components are the first) */\n tabs?: PaletteTab[];\n /** The tab shown, when the app chooses it (it opens the palette if it's folded away) */\n tab?: string;\n onTabChange?: (tab: string) => void;\n /** Starts folded away, whatever this browser remembers (and doesn't remember it), e.g. in a chat's small view */\n startCollapsed?: boolean;\n}) {\n // What's being dragged onto the canvas, drawn as the node it becomes (see DragGhost)\n const { startDrag, ghost } = useDragGhost();\n // Folded away to see more of the canvas (remembered in this browser)\n const [collapsed, setCollapsed] = useState(\n () => startCollapsed ?? readCollapsed(),\n );\n const remember = (next: boolean) => {\n if (startCollapsed !== undefined) return;\n try {\n localStorage.setItem(COLLAPSED_KEY, String(next));\n } catch {}\n };\n const toggle = useCallback(() => {\n setCollapsed((current) => {\n remember(!current);\n return !current;\n });\n }, []);\n const [ownTab, setOwnTab] = useState(COMPONENTS_TAB);\n const shown =\n tab ??\n (tabs?.some((candidate) => candidate.id === ownTab)\n ? ownTab\n : COMPONENTS_TAB);\n const choose = (next: string) => {\n setOwnTab(next);\n onTabChange?.(next);\n if (collapsed) {\n setCollapsed(false);\n remember(false);\n }\n };\n // Chosen by the app (e.g. the comments from the bottom left controls): shown, opened if it was folded away\n const chosen = useRef(tab);\n useEffect(() => {\n if (tab === chosen.current) return;\n chosen.current = tab;\n if (tab === undefined || !collapsed) return;\n setCollapsed(false);\n remember(false);\n }, [tab]);\n\n // Listed in their categories' order, so the greyed ones keep the same order as the rest\n const unavailable = listedDefinitions.flatMap((category) =>\n category.definitions.filter(\n (definition) => !isShownOnLevel(definition.type, level),\n ),\n );\n\n const tile = (\n definition: (typeof nodeDefinitions)[number],\n usable = true,\n ) => {\n const { label, summary, firstLevel } = definition;\n const key = componentKey(definition);\n const { icon, className } = NODE_ICONS[key] ?? NODE_ICONS[definition.type];\n return (\n <PaletteItem\n key={key}\n icon={icon}\n iconClassName={className}\n label={usable ? label : `${label}: shown from Level ${firstLevel}`}\n description={usable ? summary : `Shown from Level ${firstLevel}`}\n usable={usable}\n onDragStart={startDrag(\n COMPONENT_DRAG_TYPE,\n key,\n componentPreviews.get(key)!,\n )}\n onClick={() => onAddComponent(key)}\n title={\n usable ? `${label}: drag onto the canvas, or click to add` : undefined\n }\n />\n );\n };\n\n const components = (\n <>\n {listedDefinitions.map((category) => {\n const definitions = category.definitions.filter((definition) =>\n isShownOnLevel(definition.type, level),\n );\n if (!definitions.length) return null;\n return (\n <PaletteSection key={category.id} title={category.label}>\n {definitions.map((definition) => tile(definition))}\n </PaletteSection>\n );\n })}\n {/* What this level doesn't show, greyed out at the bottom: they're added on the levels that show them */}\n {unavailable.length > 0 && (\n <PaletteSection title={`Not on Level ${level}`} divided>\n {unavailable.map((definition) => tile(definition, false))}\n </PaletteSection>\n )}\n </>\n );\n const extra = tabs?.find((candidate) => candidate.id === shown);\n const tabButton = (id: string, label: string, badge?: number) => (\n <button\n key={id}\n type=\"button\"\n role=\"tab\"\n aria-selected={shown === id}\n onClick={() => choose(id)}\n className={`flex flex-1 items-center justify-center gap-1 whitespace-nowrap rounded-md px-1.5 py-1 text-xs font-medium ${\n shown === id && !collapsed\n ? \"bg-[rgb(var(--ec-card-bg))] text-[rgb(var(--ec-page-text))] shadow-sm\"\n : \"text-[rgb(var(--ec-page-text-muted))] hover:text-[rgb(var(--ec-page-text))]\"\n }`}\n >\n {label}\n {!!badge && (\n <span className=\"rounded-full bg-[rgb(var(--ec-accent))] px-1.5 text-[10px] leading-4 text-white\">\n {badge}\n </span>\n )}\n </button>\n );\n\n return (\n <div\n // Down to just above the zoom and undo controls (only its header, folded away)\n className={`absolute left-3 top-[62px] z-10 flex w-[264px] flex-col ${collapsed ? \"\" : \"bottom-[68px]\"} rounded-xl border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg))] text-[rgb(var(--ec-page-text))] shadow-[0_8px_24px_rgb(0_0_0/0.08),0_1px_3px_rgb(0_0_0/0.05)]`}\n >\n {tabs?.length ? (\n <div className=\"flex flex-none items-center gap-1 p-2\">\n <div\n role=\"tablist\"\n className=\"flex flex-1 gap-0.5 rounded-lg bg-[rgb(var(--ec-page-border)/0.5)] p-0.5\"\n >\n {tabButton(COMPONENTS_TAB, \"Components\")}\n {tabs.map(({ id, label, badge }) => tabButton(id, label, badge))}\n </div>\n <button\n type=\"button\"\n onClick={toggle}\n aria-expanded={!collapsed}\n aria-label={\n collapsed ? \"Show the palette\" : \"Fold the palette away\"\n }\n className=\"flex-none rounded-md p-1 text-[rgb(var(--ec-page-text-muted))] hover:bg-[rgb(var(--ec-page-border)/0.5)]\"\n >\n <ChevronDown\n aria-hidden\n className={`h-4 w-4 transition-transform ${collapsed ? \"-rotate-90\" : \"\"}`}\n />\n </button>\n </div>\n ) : (\n <button\n type=\"button\"\n onClick={toggle}\n aria-expanded={!collapsed}\n className=\"flex flex-none items-center justify-between rounded-xl px-3.5 py-2.5 text-left text-[13px] font-semibold hover:bg-[rgb(var(--ec-content-hover))]!\"\n >\n {/* What can be added depends on the level shown (what it doesn't show is greyed out below) */}\n <span>Resources</span>\n <ChevronDown\n aria-hidden\n className={`h-4 w-4 text-[rgb(var(--ec-page-text-muted))] transition-transform ${collapsed ? \"-rotate-90\" : \"\"}`}\n />\n </button>\n )}\n {!collapsed && (\n <div className=\"min-h-0 flex-1 space-y-3 overflow-y-auto px-3 pb-3\">\n {extra ? extra.render(startDrag) : components}\n </div>\n )}\n {!collapsed && footer && (\n <div className=\"flex-none border-t border-[rgb(var(--ec-page-border))] px-3 py-2.5\">\n {footer}\n </div>\n )}\n {ghost}\n </div>\n );\n});\n","/**\n * Help: the keyboard shortcuts, as drawing tools list them, in two columns where there's room. Each app shows them in\n * its own dialog, leaving out what it doesn't have (by label).\n */\n\nconst isMac =\n typeof navigator !== \"undefined\" &&\n /Mac|iPhone|iPad/.test(navigator.platform);\nconst MOD = isMac ? \"⌘\" : \"Ctrl\";\n\nexport const SHORTCUTS: { group: string; items: [string, string[]][] }[] = [\n {\n group: \"Tools\",\n items: [\n [\"Select\", [\"V\"]],\n [\"Hand (move around)\", [\"H\"]],\n [\"Sticky note\", [\"N\"]],\n [\"Text\", [\"T\"]],\n [\"Comment\", [\"C\"]],\n [\"Hotspot\", [\"A\"]],\n [\"Level 1 / 2 / 3\", [\"1\", \"2\", \"3\"]],\n [\"Back to selecting\", [\"Esc\"]],\n ],\n },\n {\n group: \"Canvas\",\n items: [\n [\"Select everything\", [MOD, \"A\"]],\n [\"Select several\", [\"⇧\", \"Click\"]],\n [\"Delete what's selected\", [\"Delete\"]],\n [\"Duplicate\", [MOD, \"D\"]],\n [\"Copy / paste\", [MOD, \"C / V\"]],\n [\"Undo / redo\", [MOD, \"Z / ⇧Z\"]],\n [\"Move around\", [\"Scroll\"]],\n [\"Zoom\", [MOD, \"Scroll\"]],\n [\"Fit view\", [\"⇧\", \"1\"]],\n ],\n },\n {\n group: \"Notes and text\",\n items: [\n [\"Write on one\", [\"Double-click\"]],\n [\"Finish writing\", [\"Esc\"]],\n ],\n },\n {\n group: \"Diagram\",\n items: [\n [\"Command palette\", [MOD, \"K\"]],\n [\"Find on canvas\", [MOD, \"F\"]],\n [\"Open a diagram file\", [MOD, \"O\"]],\n [\"Save to file\", [MOD, \"S\"]],\n [\"Export image\", [MOD, \"⇧\", \"E\"]],\n [\"Help\", [\"?\"]],\n ],\n },\n];\n\nexport function ShortcutsList({ omit = [] }: { omit?: string[] }) {\n return (\n <div className=\"grid min-h-0 gap-x-8 gap-y-5 overflow-y-auto px-5 py-4 md:grid-cols-2!\">\n {SHORTCUTS.map(({ group, items }) => ({\n group,\n items: items.filter(([label]) => !omit.includes(label)),\n })).map(({ group, items }) => (\n <section key={group}>\n <h3 className=\"mb-2 text-[11px] font-semibold uppercase tracking-wide text-[rgb(var(--ec-page-text-muted))]\">\n {group}\n </h3>\n <ul className=\"divide-y divide-[rgb(var(--ec-page-border))]\">\n {items.map(([label, keys]) => (\n <li\n key={label}\n className=\"flex items-center justify-between gap-3 py-1.5 text-sm\"\n >\n <span>{label}</span>\n <span className=\"flex gap-1\">\n {keys.map((key) => (\n <kbd\n key={key}\n className=\"min-w-6 rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-content-hover))] px-1.5 py-0.5 text-center font-sans text-xs text-[rgb(var(--ec-page-text-muted))]\"\n >\n {key}\n </kbd>\n ))}\n </span>\n </li>\n ))}\n </ul>\n </section>\n ))}\n </div>\n );\n}\n","/**\n * The canvas with nothing on it (a blank page, or everything deleted), as drawing tools welcome you: the brand, what\n * it's for, and the few things to do from here, drawn on the canvas itself. Tailwind with EventCatalog's theme variables.\n */\nimport { useEffect, useState, type ReactNode } from \"react\";\nimport { CircleHelp, FolderOpen, Plug } from \"lucide-react\";\nimport logoSvg from \"../eventcatalog-logo.svg?raw\";\n\ntype EmptyCanvasProps = {\n /** Opening a .eventcatalog file (not offered when not given, e.g. inside a chat) */\n onOpen?: () => void;\n onHelp: () => void;\n /** How to connect an AI agent to this server (when there's one to connect to) */\n onConnect?: () => void;\n /** The resources panel is on the left, to point to */\n palette?: boolean;\n /** Live sessions can be started (from Share, top right), to point to */\n live?: boolean;\n /** The welcome in the middle (the brand, what it's for, Open, Connect, Help); without it, just the hints */\n welcome?: boolean;\n};\n\n// Hand-drawn, as Excalidraw points at its tools when the canvas is empty\nconst hintText =\n \"font-[Excalifont,Inter,sans-serif] text-[14px] leading-snug text-[color-mix(in_srgb,rgb(var(--ec-page-text))_22%,transparent)]\";\nconst arrow = {\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 1.6,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n} as const;\n\n/** What the tools around the empty canvas are for, each with an arrow to it (on wide enough screens) */\nfunction Hints({ palette, live }: { palette?: boolean; live?: boolean }) {\n return (\n <div aria-hidden className={`hidden md:block! ${hintText}`}>\n {/* To the resources, on the left (low down, clear of the levels hint) */}\n {palette && (\n <div className=\"absolute bottom-[120px] left-[290px] flex items-start gap-1\">\n <svg width=\"56\" height=\"32\" viewBox=\"0 0 70 40\" {...arrow}>\n <path d=\"M66 8 C 45 4, 22 10, 6 26\" />\n <path d=\"M6 26 L15.7 23.4 M6 26 L8.6 16.3\" />\n </svg>\n <p className=\"-mt-0.5 max-w-[160px]\">\n Drag resources onto the canvas, then connect them\n </p>\n </div>\n )}\n {/* To the levels, in the toolbar */}\n <div className=\"absolute left-[calc(50%+6px)] top-[66px] flex -translate-x-1/2 flex-col items-center\">\n <svg width=\"32\" height=\"45\" viewBox=\"0 0 40 56\" {...arrow}>\n <path d=\"M14 54 C 6 38, 10 18, 20 4\" />\n <path d=\"M20 4 L11.8 7.7 M20 4 L19.1 13\" />\n </svg>\n <p className=\"mt-1 whitespace-nowrap\">\n Switch between levels of detail\n </p>\n </div>\n {/* To Share, top right */}\n {live && (\n <div className=\"absolute right-[52px] top-[66px] flex items-end gap-1\">\n <p className=\"mb-[-5px] max-w-[200px] text-right\">\n Start live collaboration with your team or agents\n </p>\n <svg\n width=\"40\"\n height=\"48\"\n viewBox=\"0 0 50 60\"\n className=\"flex-none\"\n {...arrow}\n >\n <path d=\"M6 56 C 30 52, 42 30, 40 4\" />\n <path d=\"M40 4 L36.1 12.1 M40 4 L45.1 11.4\" />\n </svg>\n </div>\n )}\n </div>\n );\n}\n\nconst isMac =\n typeof navigator !== \"undefined\" &&\n /Mac|iPhone|iPad/.test(navigator.platform);\nconst MOD = isMac ? \"Cmd\" : \"Ctrl\";\n\nexport function EmptyCanvas({\n welcome = true,\n onOpen,\n onHelp,\n onConnect,\n palette,\n live,\n}: EmptyCanvasProps) {\n // Something dragged in (a component from the palette): the welcome makes way, so it lands on the canvas. Once it's\n // dropped the canvas is being worked on, so the welcome stays away (e.g. while a domain or system's kind is chosen)\n const [dragging, setDragging] = useState(false);\n const [dropped, setDropped] = useState(false);\n useEffect(() => {\n const start = () => setDragging(true);\n const end = () => setDragging(false);\n const drop = () => {\n setDropped(true);\n setDragging(false);\n };\n document.addEventListener(\"dragstart\", start);\n document.addEventListener(\"dragend\", end);\n document.addEventListener(\"drop\", drop);\n return () => {\n document.removeEventListener(\"dragstart\", start);\n document.removeEventListener(\"dragend\", end);\n document.removeEventListener(\"drop\", drop);\n };\n }, []);\n if (dragging || dropped) return null;\n\n const item = (\n icon: ReactNode,\n label: ReactNode,\n onClick: () => void,\n hint?: ReactNode,\n ) => (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"group flex h-11 w-full items-center gap-3.5 rounded-lg px-3 text-left text-[15px] text-[rgb(var(--ec-page-text-muted))] transition-colors hover:bg-[rgb(var(--ec-content-hover))]! hover:text-[rgb(var(--ec-page-text))]! [&_svg]:h-[18px] [&_svg]:w-[18px] [&_svg]:stroke-[1.75]\"\n >\n <span className=\"flex flex-none\">{icon}</span>\n <span className=\"min-w-0 flex-1 truncate\">{label}</span>\n {hint && <span className=\"flex-none text-[13px] opacity-80\">{hint}</span>}\n </button>\n );\n\n return (\n // On the canvas itself: what's dragged in from the left still lands on it\n <div className=\"pointer-events-none absolute inset-0 z-[5] flex items-center justify-center px-4 pb-16 pt-40\">\n <Hints palette={palette} live={live} />\n {welcome && (\n <div className=\"pointer-events-auto flex w-full max-w-[440px] flex-col items-center\">\n <div className=\"flex items-center gap-3 text-[rgb(var(--ec-page-text))]\">\n <span\n className=\"h-11 w-11 [&_svg]:h-full [&_svg]:w-full\"\n dangerouslySetInnerHTML={{ __html: logoSvg }}\n />\n <span className=\"text-[34px] font-bold tracking-tight\">\n EventCatalog{\" \"}\n <span className=\"font-light text-[rgb(var(--ec-page-text-muted))]\">\n Studio\n </span>\n </span>\n </div>\n <p className=\"mt-5 text-center font-[Excalifont,Inter,sans-serif] text-[22px] leading-snug text-[color-mix(in_srgb,rgb(var(--ec-page-text))_38%,transparent)]\">\n Sketch, design and share architecture with your team and AI agents.\n </p>\n\n <div className=\"mt-10 w-full\">\n {onOpen &&\n item(<FolderOpen aria-hidden />, \"Open\", onOpen, `${MOD}+O`)}\n {onConnect &&\n item(<Plug aria-hidden />, \"Connect to MCP Server\", onConnect)}\n {item(<CircleHelp aria-hidden />, \"Help\", onHelp, \"?\")}\n </div>\n </div>\n )}\n </div>\n );\n}\n","import { memo, useEffect } from \"react\";\nimport {\n useStore,\n useUpdateNodeInternals,\n type ReactFlowState,\n} from \"@xyflow/react\";\n\nconst selectDomNode = (state: ReactFlowState) => state.domNode;\n\n/**\n * Measures a node's handles again once it has finished animating in or resizing. React Flow measures them when the\n * node appears, part way through its pop in (`studio-node-in`, which scales it), and doesn't again while its size\n * stays the same: edges would join a node short of its sides (far short of a container's). Same for a container\n * growing to fit what's in it (its size eases in, `is-container-resize`). One listener for the whole canvas, and one\n * update a frame for everything that finished in it (a container's width and height transitions end separately).\n * Render it inside `<ReactFlow>`.\n */\nexport const RemeasureHandles = memo(function RemeasureHandles() {\n const domNode = useStore(selectDomNode);\n const updateNodeInternals = useUpdateNodeInternals();\n useEffect(() => {\n if (!domNode) return;\n const pending = new Set<string>();\n let frame = 0;\n const flush = () => {\n frame = 0;\n updateNodeInternals([...pending]);\n pending.clear();\n };\n const remeasure = (event: AnimationEvent | TransitionEvent) => {\n const element = event.target as HTMLElement;\n if (!element.classList?.contains(\"react-flow__node\")) return;\n const resized =\n event.type === \"transitionend\"\n ? [\"width\", \"height\"].includes(\n (event as TransitionEvent).propertyName,\n )\n : (event as AnimationEvent).animationName === \"studio-node-in\";\n const id = element.dataset.id;\n if (!resized || !id) return;\n pending.add(id);\n frame ||= requestAnimationFrame(flush);\n };\n domNode.addEventListener(\"animationend\", remeasure);\n domNode.addEventListener(\"transitionend\", remeasure);\n return () => {\n cancelAnimationFrame(frame);\n domNode.removeEventListener(\"animationend\", remeasure);\n domNode.removeEventListener(\"transitionend\", remeasure);\n };\n }, [domNode, updateNodeInternals]);\n return null;\n});\n"],"mappings":"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","names":["getNodeSize","getNodeSize","edge","getNodeSize","row","id","getNodeSize","byId","LEVELS","byId","useEffect","useState","useState","useEffect","byId","placeOf","isCardType","PRODUCERS","memo","useCallback","useEffect","useMemo","useRef","useState","Handle","Position","useReactFlow","useStoreApi","TeamNode","memo","useEffect","useMemo","useRef","useState","Handle","Position","Fragment","jsx","jsxs","memo","ConnectPlaceholderNode","Handle","Position","useState","useMemo","useRef","useEffect","below","Fragment","jsx","jsxs","updateNodeData","useRef","useEffect","memo","StickyNote","useState","TextNode","useReactFlow","useMemo","isDomain","EntityCard","Handle","Position","DomainCard","GroupNode","useStoreApi","useCallback","createContext","memo","useCallback","useContext","useEffect","useRef","useState","useReactFlow","X","useState","jsx","jsx","Fragment","jsx","jsxs","useRef","useState","useEffect","createContext","useCallback","useContext","X","memo","CommentLayer","useReactFlow","memo","useEffect","useLayoutEffect","useRef","useState","StickyNote","Trash2","Fragment","jsx","jsxs","memo","ContextMenu","useEffect","useRef","useState","useLayoutEffect","StickyNote","Trash2","useCallback","useEffect","useMemo","useRef","useState","useStoreApi","jsx","useStoreApi","useState","useCallback","useRef","getNodeSize","useEffect","useMemo","memo","useLayoutEffect","useRef","useState","useInternalNode","useReactFlow","useStoreApi","Pencil","Trash2","TriangleAlert","X","Fragment","jsx","jsxs","TriangleAlert","useStoreApi","useLayoutEffect","useInternalNode","DRAG_THRESHOLD_PX","useRef","panelClass","useState","IconButton","X","Pencil","Trash2","memo","HotspotLayer","useReactFlow","memo","useReactFlow","MessageCircle","SendToBack","StickyNote","TriangleAlert","Fragment","jsx","jsxs","LEVELS","memo","StickyNote","MessageCircle","TriangleAlert","ViewControls","useReactFlow","SendToBack","useEffect","useState","X","jsx","jsxs","memo","Position","Info","Pencil","Fragment","jsx","jsxs","memo","useCallback","useEffect","useRef","useState","GripVertical","Fragment","jsx","jsxs","GripVertical","memo","Palette","useState","useCallback","useRef","useEffect","components","jsx","jsxs","useEffect","useState","jsx","jsxs","isMac","MOD","useState","useEffect","memo","useEffect","useStore","useUpdateNodeInternals","RemeasureHandles"]}
|