{
	"$schema": "https://shadcn-svelte.com/schema/registry-item.json",
	"name": "flow",
	"title": "Flow",
	"type": "registry:block",
	"description": "A group of components for building directed flow diagrams with nodes and connectors.",
	"dependencies": [
		"motion-sv",
		"runed"
	],
	"cssVars": {
		"theme": {
			"color-kumo-base": "var(--kumo-base)",
			"color-kumo-fill": "var(--kumo-fill)",
			"color-kumo-hairline": "var(--kumo-hairline)",
			"color-kumo-overlay": "var(--kumo-overlay)",
			"color-kumo-line": "var(--kumo-line)",
			"color-kumo-inactive": "var(--kumo-inactive)",
			"color-kumo-subtle": "var(--kumo-subtle)",
			"text-color-kumo-inactive": "var(--kumo-inactive)",
			"text-color-kumo-subtle": "var(--kumo-subtle)"
		},
		"light": {
			"kumo-base": "#fff",
			"kumo-fill": "oklch(92.2% 0 0)",
			"kumo-hairline": "oklch(93.5% 0 0)",
			"kumo-overlay": "oklch(97.5% 0 0)",
			"kumo-line": "oklch(14.5% 0 0 / 0.1)",
			"kumo-inactive": "oklch(87% 0 0)",
			"kumo-subtle": "oklch(55.6% 0 0)"
		},
		"dark": {
			"kumo-base": "oklch(17% 0 0)",
			"kumo-fill": "oklch(26.9% 0 0)",
			"kumo-hairline": "oklch(26.9% 0 0)",
			"kumo-overlay": "oklch(26.9% 0 0)",
			"kumo-line": "oklch(32% 0 0)",
			"kumo-inactive": "oklch(43.9% 0 0)",
			"kumo-subtle": "oklch(70.8% 0 0)"
		}
	},
	"files": [
		{
			"content": "<script lang=\"ts\">\n\timport type { Snippet } from 'svelte';\n\timport { createRoundedPath } from './connectors';\n\timport type { Connector, Orientation } from './types';\n\timport { cn } from '$UTILS$';\n\n\tinterface Props {\n\t\tconnectors: Connector[];\n\t\tchildren?: Snippet;\n\t\tcornerRadius?: number;\n\t\tmidOffset?: number;\n\t\tarrowheadOffset?: number;\n\t\torientation?: Orientation;\n\t}\n\n\tlet {\n\t\tconnectors,\n\t\tchildren,\n\t\tcornerRadius,\n\t\tmidOffset,\n\t\tarrowheadOffset,\n\t\torientation = 'vertical'\n\t}: Props = $props();\n\n\tconst markerId = $props.id();\n\n\tlet orderedConnectors = $derived(\n\t\t[...connectors].sort((a, b) => {\n\t\t\tif (a.disabled && !b.disabled) return -1;\n\t\t\tif (!a.disabled && b.disabled) return 1;\n\t\t\treturn 0;\n\t\t})\n\t);\n</script>\n\n<svg width=\"100%\" height=\"100%\" aria-hidden=\"true\" class=\"text-kumo-inactive overflow-visible\">\n\t<defs>\n\t\t<marker\n\t\t\tid={markerId}\n\t\t\tmarkerWidth=\"8\"\n\t\t\tmarkerHeight=\"8\"\n\t\t\trefX=\"0\"\n\t\t\trefY=\"4\"\n\t\t\torient=\"auto\"\n\t\t\tmarkerUnits=\"userSpaceOnUse\"\n\t\t>\n\t\t\t<path\n\t\t\t\td=\"M 0,1.5 Q 0,0 1.5,0 Q 3.5,1 5.8,3.2 Q 6.5,4 5.8,4.8 Q 3.5,7 1.5,8 Q 0,8 0,6.5 Z\"\n\t\t\t\tfill=\"currentColor\"\n\t\t\t\tstroke=\"none\"\n\t\t\t/>\n\t\t</marker>\n\t</defs>\n\n\t{#each orderedConnectors as connector, index (`${connector.fromId ?? 'from'}-${connector.toId ?? 'to'}-${index}`)}\n\t\t{let path = $state(createRoundedPath(connector, {\n\t\t\tcornerRadius,\n\t\t\tmidOffset,\n\t\t\tarrowheadOffset,\n\t\t\tisBottom: connector.isBottom,\n\t\t\tsingle: connector.single,\n\t\t\torientation\n\t\t}))}\n\t\t{let pathId =\n\t\t\t$state(connector.fromId && connector.toId\n\t\t\t\t? `${connector.fromId}-${connector.toId}`\n\t\t\t\t: `path-${index}`)}\n\n\t\t<g class={cn(connector.disabled && 'opacity-40')}>\n\t\t\t<path\n\t\t\t\td={path}\n\t\t\t\tfill=\"none\"\n\t\t\t\tstroke=\"currentColor\"\n\t\t\t\tstroke-width=\"2\"\n\t\t\t\tmarker-end={`url(#${markerId})`}\n\t\t\t\tdata-index={index}\n\t\t\t\tdata-testid={pathId}\n\t\t\t/>\n\t\t</g>\n\t{/each}\n\n\t{@render children?.()}\n</svg>\n",
			"type": "registry:component",
			"target": "magic/flow/connectors.svelte"
		},
		{
			"content": "<script lang=\"ts\">\n\timport { untrack, type Snippet } from \"svelte\";\n\timport { watch } from \"runed\";\n\timport { useFlowNodeAnchorContext } from \"./node-context.svelte\";\n\timport { withElementAttachment } from \"./render-props\";\n\n\tinterface FlowAnchorProps {\n\t\ttype?: \"start\" | \"end\";\n\t\tchildren?: Snippet;\n\t\trender?: Snippet<[{ props: Record<string, unknown> }]>;\n\t}\n\n\tlet { type, children, render }: FlowAnchorProps = $props();\n\n\tconst context = useFlowNodeAnchorContext();\n\n\tlet anchorRef = $state<HTMLElement | null>(null);\n\n\tlet renderProps = $derived(\n\t\twithElementAttachment({}, (element: HTMLElement | null) => {\n\t\t\tanchorRef = element;\n\t\t})\n\t);\n\n\twatch([() => anchorRef, () => type], ([currentAnchor, currentType]) => {\n\t\tif (!currentAnchor) return;\n\n\t\tif (currentType === \"start\" || currentType === undefined) {\n\t\t\tuntrack(() => context.registerStartAnchor(currentAnchor));\n\t\t}\n\n\t\tif (currentType === \"end\" || currentType === undefined) {\n\t\t\tuntrack(() => context.registerEndAnchor(currentAnchor));\n\t\t}\n\n\t\treturn () => {\n\t\t\tif (currentType === \"start\" || currentType === undefined) {\n\t\t\t\tcontext.registerStartAnchor(null);\n\t\t\t}\n\n\t\t\tif (currentType === \"end\" || currentType === undefined) {\n\t\t\t\tcontext.registerEndAnchor(null);\n\t\t\t}\n\t\t};\n\t});\n</script>\n\n{#if render}\n\t{@render render({ props: renderProps })}\n{:else}\n\t<div bind:this={anchorRef}>\n\t\t{@render children?.()}\n\t</div>\n{/if}\n",
			"type": "registry:component",
			"target": "magic/flow/flow-anchor.svelte"
		},
		{
			"content": "<script lang=\"ts\">\n\timport { cn } from '$UTILS$.js';\n\timport { onMount, untrack, type Snippet } from 'svelte';\n\timport { watch } from 'runed';\n\timport Connectors from './connectors.svelte';\n\timport {\n\t\tuseDescendantsContext,\n\t\tuseOptionalDescendantsContext,\n\t\tcreateDescendantsState,\n\t\tsetDescendantsContext\n\t} from './descendants.svelte';\n\timport { useDiagramContext } from './diagram-context.svelte';\n\timport type { Connector, NodeData } from './types';\n\n\tinterface Props {\n\t\tchildren?: Snippet;\n\t}\n\n\tlet { children }: Props = $props();\n\n\tconst registrationId = $props.id();\n\tconst diagram = useDiagramContext();\n\tconst parentDescendants = useOptionalDescendantsContext<NodeData>();\n\tconst descendants = setDescendantsContext(createDescendantsState<NodeData>());\n\n\tlet containerRef = $state<HTMLDivElement | null>(null);\n\tlet connectors = $state<Connector[]>([]);\n\n\tlet orientation = $derived(diagram.orientation());\n\tlet align = $derived(diagram.align());\n\tlet firstNode = $derived(descendants.descendants[0]);\n\tlet lastNode = $derived(descendants.descendants[descendants.descendants.length - 1]);\n\tlet startAnchor = $derived(lastNode?.props.start ?? null);\n\tlet endAnchor = $derived(firstNode?.props.end ?? null);\n\tlet nodeData = $derived<NodeData>({\n\t\telement: containerRef,\n\t\tparallel: false,\n\t\tdisabled: false,\n\t\tstart: startAnchor,\n\t\tend: endAnchor\n\t});\n\n\tfunction computeConnectors() {\n\t\tif (!containerRef) {\n\t\t\tconnectors = [];\n\t\t\treturn;\n\t\t}\n\n\t\tconst nodes = descendants.descendants;\n\t\tconst containerRect = containerRef.getBoundingClientRect();\n\t\tconst offsetX = containerRect.left;\n\t\tconst offsetY = containerRect.top;\n\t\tconst edges: Connector[] = [];\n\n\t\tfor (let i = 0; i < nodes.length - 1; i += 1) {\n\t\t\tconst currentNode = nodes[i];\n\t\t\tconst nextNode = nodes[i + 1];\n\n\t\t\tif (currentNode.props.parallel || nextNode.props.parallel) continue;\n\n\t\t\tconst currentRect = currentNode.props.start;\n\t\t\tconst nextRect = nextNode.props.end;\n\n\t\t\tif (!currentRect || !nextRect) continue;\n\n\t\t\tconst connector =\n\t\t\t\torientation === 'vertical'\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tx1: currentRect.left - offsetX + currentRect.width / 2,\n\t\t\t\t\t\t\ty1: currentRect.top - offsetY + currentRect.height,\n\t\t\t\t\t\t\tx2: nextRect.left - offsetX + nextRect.width / 2,\n\t\t\t\t\t\t\ty2: nextRect.top - offsetY\n\t\t\t\t\t\t}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tx1: currentRect.left - offsetX + currentRect.width,\n\t\t\t\t\t\t\ty1: currentRect.top - offsetY + currentRect.height / 2,\n\t\t\t\t\t\t\tx2: nextRect.left - offsetX,\n\t\t\t\t\t\t\ty2: nextRect.top - offsetY + nextRect.height / 2\n\t\t\t\t\t\t};\n\n\t\t\tedges.push({\n\t\t\t\t...connector,\n\t\t\t\tdisabled: currentNode.props.disabled || nextNode.props.disabled,\n\t\t\t\tsingle: true,\n\t\t\t\tfromId: currentNode.id,\n\t\t\t\ttoId: nextNode.id\n\t\t\t});\n\t\t}\n\n\t\tconnectors = edges;\n\t}\n\n\tonMount(() => {\n\t\tif (!parentDescendants) return;\n\t\tconst unregister = parentDescendants.mount(\n\t\t\tuntrack(() => registrationId),\n\t\t\tuntrack(() => nodeData)\n\t\t);\n\t\treturn () => unregister();\n\t});\n\n\twatch(\n\t\t() => nodeData,\n\t\t(nextNodeData) => {\n\t\t\tif (!parentDescendants) return;\n\t\t\tparentDescendants.update(registrationId, nextNodeData);\n\t\t}\n\t);\n\n\twatch([() => descendants.measurementEpoch, () => descendants.descendants, () => orientation, () => align], () => {\n\t\tuntrack(() => computeConnectors());\n\t});\n\n\t$effect(() => {\n\t\tconst onLayoutShift = () => computeConnectors();\n\n\t\twindow.addEventListener('scroll', onLayoutShift, {\n\t\t\tcapture: true,\n\t\t\tpassive: true\n\t\t});\n\t\twindow.addEventListener('resize', onLayoutShift, { passive: true });\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener('scroll', onLayoutShift, { capture: true });\n\t\t\twindow.removeEventListener('resize', onLayoutShift);\n\t\t};\n\t});\n</script>\n\n<div class=\"relative\" bind:this={containerRef}>\n\t<ul\n\t\tclass={cn(\n\t\t\t'ml-0 list-none',\n\t\t\torientation === 'vertical' ? 'grid auto-rows-min gap-16' : 'flex gap-16',\n\t\t\torientation === 'vertical' && (align === 'center' ? 'justify-items-center' : 'justify-items-start'),\n\t\t\torientation === 'horizontal' && (align === 'center' ? 'items-center' : 'items-start')\n\t\t)}\n\t>\n\t\t{@render children?.()}\n\t</ul>\n\n\t<div class=\"pointer-events-none absolute inset-0\">\n\t\t<Connectors {connectors} {orientation} />\n\t</div>\n</div>\n",
			"type": "registry:component",
			"target": "magic/flow/flow-node-list.svelte"
		},
		{
			"content": "<script lang=\"ts\">\n\timport { cn } from '$UTILS$.js';\n\timport { onMount, untrack, type Snippet } from 'svelte';\n\timport { watch } from 'runed';\n\timport { useDescendantsContext } from './descendants.svelte';\n\timport { setFlowNodeAnchorContext } from './node-context.svelte';\n\timport { withElementAttachment } from './render-props';\n\timport { rectEquals, type NodeData, type RectLike } from './types';\n\n\tinterface FlowNodeProps {\n\t\tid?: string;\n\t\tdisabled?: boolean;\n\t\tclass?: string;\n\t\tchildren?: Snippet;\n\t\trender?: Snippet<[{ props: Record<string, unknown> }]>;\n\t}\n\n\tlet { id, disabled = false, class: className, children, render }: FlowNodeProps = $props();\n\n\tconst descendants = useDescendantsContext<NodeData>();\n\tconst generatedId = $props.id();\n\tlet nodeId = $derived(id ?? generatedId);\n\n\tlet nodeRef = $state<HTMLElement | null>(null);\n\tlet startAnchorRef = $state<HTMLElement | null>(null);\n\tlet endAnchorRef = $state<HTMLElement | null>(null);\n\tlet measurements = $state<{\n\t\tstart: RectLike | null;\n\t\tend: RectLike | null;\n\t}>({\n\t\tstart: null,\n\t\tend: null\n\t});\n\n\tlet index = $derived(descendants.getIndex(nodeId));\n\tlet nodeData = $derived<NodeData>({\n\t\telement: nodeRef,\n\t\tparallel: false,\n\t\tdisabled,\n\t\tstart: measurements.start,\n\t\tend: measurements.end\n\t});\n\n\tsetFlowNodeAnchorContext({\n\t\tregisterStartAnchor: (anchor) => {\n\t\t\tstartAnchorRef = anchor;\n\t\t\tremeasure();\n\t\t},\n\t\tregisterEndAnchor: (anchor) => {\n\t\t\tendAnchorRef = anchor;\n\t\t\tremeasure();\n\t\t}\n\t});\n\n\tfunction remeasure() {\n\t\tif (!nodeRef) return;\n\n\t\tconst nodeRect = nodeRef.getBoundingClientRect();\n\t\tconst startRect = startAnchorRef?.getBoundingClientRect() ?? nodeRect;\n\t\tconst endRect = endAnchorRef?.getBoundingClientRect() ?? nodeRect;\n\n\t\tif (rectEquals(measurements.start, startRect) && rectEquals(measurements.end, endRect)) {\n\t\t\treturn;\n\t\t}\n\n\t\tmeasurements = {\n\t\t\tstart: startRect,\n\t\t\tend: endRect\n\t\t};\n\t}\n\n\tlet renderProps = $derived(\n\t\twithElementAttachment(\n\t\t\t{\n\t\t\t\tclass: className,\n\t\t\t\tstyle: 'cursor: default;',\n\t\t\t\t'data-node-index': index,\n\t\t\t\t'data-node-id': nodeId,\n\t\t\t\t'data-testid': nodeId\n\t\t\t},\n\t\t\t(element: HTMLElement | null) => {\n\t\t\t\tnodeRef = element;\n\t\t\t}\n\t\t)\n\t);\n\n\tonMount(() => {\n\t\tconst unregister = descendants.mount(\n\t\t\tuntrack(() => nodeId),\n\t\t\tuntrack(() => nodeData)\n\t\t);\n\t\treturn () => unregister();\n\t});\n\n\twatch([() => nodeId, () => nodeData], ([nextId, nextData], previous) => {\n\t\tconst previousId = previous?.[0];\n\n\t\tif (previousId && previousId !== nextId) {\n\t\t\tdescendants.unmount(previousId);\n\t\t\tdescendants.mount(nextId, nextData);\n\t\t\treturn;\n\t\t}\n\n\t\tdescendants.update(nextId, nextData);\n\t});\n\n\t$effect(() => {\n\t\tif (!nodeRef) return;\n\n\t\tconst onResize = () => {\n\t\t\tremeasure();\n\t\t\tdescendants.notifySizeChange();\n\t\t};\n\n\t\tconst observer = new ResizeObserver(onResize);\n\t\tobserver.observe(nodeRef);\n\n\t\treturn () => observer.disconnect();\n\t});\n\n\twatch(\n\t\t() => descendants.measurementEpoch,\n\t\t() => {\n\t\t\tuntrack(() => remeasure());\n\t\t}\n\t);\n\n\t$effect(() => {\n\t\tconst onLayoutShift = () => {\n\t\t\tremeasure();\n\t\t\tdescendants.notifySizeChange();\n\t\t};\n\n\t\twindow.addEventListener('scroll', onLayoutShift, {\n\t\t\tcapture: true,\n\t\t\tpassive: true\n\t\t});\n\t\twindow.addEventListener('resize', onLayoutShift, { passive: true });\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener('scroll', onLayoutShift, { capture: true });\n\t\t\twindow.removeEventListener('resize', onLayoutShift);\n\t\t};\n\t});\n</script>\n\n{#if render}\n\t{@render render({ props: renderProps })}\n{:else}\n\t<li\n\t\tbind:this={nodeRef}\n\t\tclass={cn('bg-kumo-base text-sm ring-kumo-line rounded-md px-3 py-2 shadow ring', className)}\n\t\tstyle=\"cursor: default;\"\n\t\tdata-node-index={index}\n\t\tdata-node-id={nodeId}\n\t\tdata-testid={nodeId}\n\t>\n\t\t{@render children?.()}\n\t</li>\n{/if}\n",
			"type": "registry:component",
			"target": "magic/flow/flow-node.svelte"
		},
		{
			"content": "<script lang=\"ts\">\n\timport { cn } from \"$UTILS$.js\";\n\timport { onMount, untrack, type Snippet } from \"svelte\";\n\timport { watch } from \"runed\";\n\timport Connectors from \"./connectors.svelte\";\n\timport { createDescendantsState, setDescendantsContext, useDescendantsContext } from \"./descendants.svelte\";\n\timport { useDiagramContext } from \"./diagram-context.svelte\";\n\timport type { Connector, NodeData, ParallelAlign, RectLike } from \"./types\";\n\n\ttype LinksResult = {\n\t\tconnectors: Connector[];\n\t\tjunctions: {\n\t\t\tstart?: { x: number; y: number };\n\t\t\tend?: { x: number; y: number };\n\t\t};\n\t\tcontainerRect: DOMRect;\n\t};\n\n\tinterface FlowParallelProps {\n\t\talign?: ParallelAlign;\n\t\tclass?: string;\n\t\tchildren?: Snippet;\n\t}\n\n\tconst FLAT_THRESHOLD = 2;\n\n\tlet { align = \"start\", class: className, children }: FlowParallelProps = $props();\n\n\tconst registrationId = $props.id();\n\tconst diagram = useDiagramContext();\n\tconst parentDescendants = useDescendantsContext<NodeData>();\n\tconst descendants = setDescendantsContext(createDescendantsState<NodeData>());\n\n\tlet containerRef = $state<HTMLDivElement | null>(null);\n\tlet contentRef = $state<HTMLUListElement | null>(null);\n\tlet measurements = $state<DOMRect | null>(null);\n\tlet links = $state<LinksResult | null>(null);\n\n\tlet orientation = $derived(diagram.orientation());\n\tlet diagramAlign = $derived(diagram.align());\n\tlet junctionMarker = $derived(diagram.junctionMarker());\n\tlet useSquareJunctions = $derived(junctionMarker === \"square\");\n\tlet firstBranch = $derived(descendants.descendants[0]);\n\tlet startAnchor = $derived<RectLike | null>(firstBranch?.props.start ?? measurements);\n\tlet endAnchor = $derived<RectLike | null>(firstBranch?.props.end ?? measurements);\n\tlet nodeData = $derived<NodeData>({\n\t\telement: containerRef,\n\t\tparallel: true,\n\t\tstart: startAnchor,\n\t\tend: endAnchor,\n\t});\n\tlet index = $derived(parentDescendants.getIndex(registrationId));\n\tlet previousNode = $derived(parentDescendants.getPrevious(registrationId));\n\tlet nextNode = $derived(parentDescendants.getNext(registrationId));\n\tlet previousIsParallel = $derived(previousNode?.props.parallel === true);\n\n\tfunction getStartAndEndPoints({\n\t\tcontainer,\n\t\tprevious,\n\t\tnext,\n\t\torientation,\n\t}: {\n\t\tcontainer: RectLike;\n\t\tprevious: RectLike | null;\n\t\tnext: RectLike | null;\n\t\torientation: \"horizontal\" | \"vertical\";\n\t}) {\n\t\tif (orientation === \"vertical\") {\n\t\t\tconst startX = previous\n\t\t\t\t? previous.left - container.left + previous.width / 2\n\t\t\t\t: container.width / 2;\n\t\t\tconst endX = next ? next.left - container.left + next.width / 2 : container.width / 2;\n\n\t\t\treturn {\n\t\t\t\tstart: {\n\t\t\t\t\tx: startX,\n\t\t\t\t\ty: 0,\n\t\t\t\t},\n\t\t\t\tend: {\n\t\t\t\t\tx: endX,\n\t\t\t\t\ty: container.height,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tlet start = {\n\t\t\tx: 0,\n\t\t\ty: container.height / 2,\n\t\t};\n\t\tlet end = {\n\t\t\tx: container.width,\n\t\t\ty: container.height / 2,\n\t\t};\n\n\t\tif (previous) {\n\t\t\tstart.y = previous.top - container.top + previous.height / 2;\n\t\t}\n\n\t\tif (next) {\n\t\t\tend.y = next.top - container.top + next.height / 2;\n\t\t}\n\n\t\treturn { start, end };\n\t}\n\n\tfunction remeasure() {\n\t\tif (!contentRef) return;\n\n\t\tconst rect = contentRef.getBoundingClientRect();\n\t\tconst current = measurements;\n\n\t\tif (\n\t\t\tcurrent &&\n\t\t\tcurrent.x === rect.x &&\n\t\t\tcurrent.y === rect.y &&\n\t\t\tcurrent.top === rect.top &&\n\t\t\tcurrent.left === rect.left &&\n\t\t\tcurrent.right === rect.right &&\n\t\t\tcurrent.bottom === rect.bottom &&\n\t\t\tcurrent.width === rect.width &&\n\t\t\tcurrent.height === rect.height\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tmeasurements = rect;\n\t}\n\n\tfunction computeLinks() {\n\t\tif (!containerRef) {\n\t\t\tlinks = null;\n\t\t\treturn;\n\t\t}\n\n\t\tconst containerRect = containerRef.getBoundingClientRect();\n\t\tconst previousNodeRect = previousNode?.props.start ?? null;\n\t\tconst nextNodeRect = nextNode?.props.end ?? null;\n\t\tconst { start, end } = getStartAndEndPoints({\n\t\t\tcontainer: containerRect,\n\t\t\tprevious: previousNodeRect,\n\t\t\tnext: nextNodeRect,\n\t\t\torientation,\n\t\t});\n\n\t\tconst incomingBranchPoints: Array<{ y: number }> = [];\n\t\tconst outgoingBranchPoints: Array<{ y: number }> = [];\n\n\t\tfor (const descendant of descendants.descendants) {\n\t\t\tconst endAnchorRect = descendant.props.end;\n\t\t\tconst startAnchorRect = descendant.props.start;\n\n\t\t\tif (previousNodeRect && endAnchorRect) {\n\t\t\t\tconst anchorCenter =\n\t\t\t\t\torientation === \"horizontal\"\n\t\t\t\t\t\t? endAnchorRect.top - containerRect.top + endAnchorRect.height / 2\n\t\t\t\t\t\t: endAnchorRect.left - containerRect.left + endAnchorRect.width / 2;\n\n\t\t\t\tincomingBranchPoints.push({ y: anchorCenter });\n\t\t\t}\n\n\t\t\tif (nextNodeRect && startAnchorRect) {\n\t\t\t\tconst anchorCenter =\n\t\t\t\t\torientation === \"horizontal\"\n\t\t\t\t\t\t? startAnchorRect.top - containerRect.top + startAnchorRect.height / 2\n\t\t\t\t\t\t: startAnchorRect.left - containerRect.left + startAnchorRect.width / 2;\n\n\t\t\t\toutgoingBranchPoints.push({ y: anchorCenter });\n\t\t\t}\n\t\t}\n\n\t\tconst hasIncomingJunction = (() => {\n\t\t\tif (incomingBranchPoints.length <= 1) return false;\n\n\t\t\tconst hasAbove = incomingBranchPoints.some((point) => point.y < start.y - FLAT_THRESHOLD);\n\t\t\tconst hasBelow = incomingBranchPoints.some((point) => point.y > start.y + FLAT_THRESHOLD);\n\t\t\tconst hasInline = incomingBranchPoints.some(\n\t\t\t\t(point) => Math.abs(point.y - start.y) <= FLAT_THRESHOLD\n\t\t\t);\n\n\t\t\treturn [hasAbove, hasBelow, hasInline].filter(Boolean).length > 1;\n\t\t})();\n\n\t\tconst hasOutgoingJunction = (() => {\n\t\t\tif (outgoingBranchPoints.length <= 1) return false;\n\n\t\t\tconst hasAbove = outgoingBranchPoints.some((point) => point.y < end.y - FLAT_THRESHOLD);\n\t\t\tconst hasBelow = outgoingBranchPoints.some((point) => point.y > end.y + FLAT_THRESHOLD);\n\t\t\tconst hasInline = outgoingBranchPoints.some(\n\t\t\t\t(point) => Math.abs(point.y - end.y) <= FLAT_THRESHOLD\n\t\t\t);\n\n\t\t\treturn [hasAbove, hasBelow, hasInline].filter(Boolean).length > 1;\n\t\t})();\n\n\t\tconst branchConnectors = descendants.descendants.flatMap((descendant) => {\n\t\t\tconst connectors: Connector[] = [];\n\t\t\tconst endAnchorRect = descendant.props.end;\n\t\t\tconst startAnchorRect = descendant.props.start;\n\t\t\tconst isDescendantDisabled = descendant.props.disabled;\n\n\t\t\tif (previousNodeRect && endAnchorRect) {\n\t\t\t\tlet branchStart: { x: number; y: number };\n\n\t\t\t\tif (orientation === \"vertical\") {\n\t\t\t\t\tconst anchorCenter =\n\t\t\t\t\t\tendAnchorRect.left - containerRect.left + endAnchorRect.width / 2;\n\n\t\t\t\t\tbranchStart = {\n\t\t\t\t\t\tx: anchorCenter,\n\t\t\t\t\t\ty: endAnchorRect.top - containerRect.top,\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\tconst anchorCenter =\n\t\t\t\t\t\tendAnchorRect.top - containerRect.top + endAnchorRect.height / 2;\n\n\t\t\t\t\tbranchStart = {\n\t\t\t\t\t\tx: endAnchorRect.left - containerRect.left,\n\t\t\t\t\t\ty: anchorCenter,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconnectors.push({\n\t\t\t\t\tx1: start.x,\n\t\t\t\t\ty1: start.y,\n\t\t\t\t\tx2: branchStart.x,\n\t\t\t\t\ty2: branchStart.y,\n\t\t\t\t\tisBottom: false,\n\t\t\t\t\tdisabled: previousNode?.props.disabled || isDescendantDisabled,\n\t\t\t\t\tsingle: useSquareJunctions ? !hasIncomingJunction : true,\n\t\t\t\t\tfromId: previousNode?.id,\n\t\t\t\t\ttoId: descendant.id,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (nextNodeRect && startAnchorRect) {\n\t\t\t\tlet branchEnd: { x: number; y: number };\n\n\t\t\t\tif (orientation === \"vertical\") {\n\t\t\t\t\tconst anchorCenter =\n\t\t\t\t\t\tstartAnchorRect.left - containerRect.left + startAnchorRect.width / 2;\n\n\t\t\t\t\tbranchEnd = {\n\t\t\t\t\t\tx: anchorCenter,\n\t\t\t\t\t\ty: startAnchorRect.bottom - containerRect.top,\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\tconst anchorCenter =\n\t\t\t\t\t\tstartAnchorRect.top - containerRect.top + startAnchorRect.height / 2;\n\n\t\t\t\t\tbranchEnd = {\n\t\t\t\t\t\tx: startAnchorRect.right - containerRect.left,\n\t\t\t\t\t\ty: anchorCenter,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconnectors.push({\n\t\t\t\t\tx1: branchEnd.x,\n\t\t\t\t\ty1: branchEnd.y,\n\t\t\t\t\tx2: end.x,\n\t\t\t\t\ty2: end.y,\n\t\t\t\t\tisBottom: true,\n\t\t\t\t\tdisabled: isDescendantDisabled || nextNode?.props.disabled,\n\t\t\t\t\tsingle: useSquareJunctions ? !hasOutgoingJunction : true,\n\t\t\t\t\tfromId: descendant.id,\n\t\t\t\t\ttoId: nextNode?.id,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn connectors;\n\t\t});\n\n\t\tlinks = {\n\t\t\tconnectors: branchConnectors,\n\t\t\tjunctions: {\n\t\t\t\tstart:\n\t\t\t\t\tuseSquareJunctions && previousNodeRect && hasIncomingJunction\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tx: orientation === \"vertical\" ? start.x : start.x + 32,\n\t\t\t\t\t\t\t\ty: orientation === \"vertical\" ? start.y + 32 : start.y,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined,\n\t\t\t\tend:\n\t\t\t\t\tuseSquareJunctions && nextNodeRect && hasOutgoingJunction\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tx: orientation === \"vertical\" ? end.x : end.x - 32,\n\t\t\t\t\t\t\t\ty: orientation === \"vertical\" ? end.y - 32 : end.y,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined,\n\t\t\t},\n\t\t\tcontainerRect,\n\t\t};\n\t}\n\n\tonMount(() => {\n\t\tconst unregister = parentDescendants.mount(\n\t\t\tuntrack(() => registrationId),\n\t\t\tuntrack(() => nodeData)\n\t\t);\n\t\treturn () => unregister();\n\t});\n\n\twatch([() => registrationId, () => nodeData], ([nextId, nextNodeData], previous) => {\n\t\tconst previousId = previous?.[0];\n\n\t\tif (previousId && previousId !== nextId) {\n\t\t\tparentDescendants.unmount(previousId);\n\t\t\tparentDescendants.mount(nextId, nextNodeData);\n\t\t\treturn;\n\t\t}\n\n\t\tparentDescendants.update(nextId, nextNodeData);\n\t});\n\n\t$effect(() => {\n\t\tif (!contentRef) return;\n\n\t\tconst onResize = () => {\n\t\t\tremeasure();\n\t\t\tparentDescendants.notifySizeChange();\n\t\t};\n\n\t\tconst observer = new ResizeObserver(onResize);\n\t\tobserver.observe(contentRef);\n\n\t\treturn () => observer.disconnect();\n\t});\n\n\twatch(() => parentDescendants.measurementEpoch, () => {\n\t\tuntrack(() => remeasure());\n\t});\n\n\t$effect(() => {\n\t\tconst onLayoutShift = () => {\n\t\t\tremeasure();\n\t\t\tparentDescendants.notifySizeChange();\n\t\t};\n\n\t\twindow.addEventListener(\"scroll\", onLayoutShift, {\n\t\t\tcapture: true,\n\t\t\tpassive: true,\n\t\t});\n\t\twindow.addEventListener(\"resize\", onLayoutShift, { passive: true });\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener(\"scroll\", onLayoutShift, { capture: true });\n\t\t\twindow.removeEventListener(\"resize\", onLayoutShift);\n\t\t};\n\t});\n\n\twatch(\n\t\t[\n\t\t\t() => descendants.measurementEpoch,\n\t\t\t() => descendants.descendants,\n\t\t\t() => parentDescendants.measurementEpoch,\n\t\t\t() => previousNode,\n\t\t\t() => nextNode,\n\t\t\t() => diagramAlign,\n\t\t],\n\t\t() => {\n\t\t\tuntrack(() => computeLinks());\n\t\t}\n\t);\n\n\t$effect(() => {\n\t\tconst onLayoutShift = () => computeLinks();\n\n\t\twindow.addEventListener(\"scroll\", onLayoutShift, {\n\t\t\tcapture: true,\n\t\t\tpassive: true,\n\t\t});\n\t\twindow.addEventListener(\"resize\", onLayoutShift, { passive: true });\n\n\t\treturn () => {\n\t\t\twindow.removeEventListener(\"scroll\", onLayoutShift, { capture: true });\n\t\t\twindow.removeEventListener(\"resize\", onLayoutShift);\n\t\t};\n\t});\n</script>\n\n<div\n\tbind:this={containerRef}\n\tclass={cn(\n\t\t\"relative isolate\",\n\t\torientation === \"horizontal\" ? \"px-16 -mr-16\" : \"py-16 -mb-16\",\n\t\torientation === \"horizontal\"\n\t\t\t? previousIsParallel\n\t\t\t\t? \"-ml-3\"\n\t\t\t\t: \"-ml-16\"\n\t\t\t: previousIsParallel\n\t\t\t\t? \"-mt-3\"\n\t\t\t\t: \"-mt-16\",\n\t\tclassName\n\t)}\n\tdata-node-index={index}\n>\n\t<div class=\"pointer-events-none absolute inset-0 z-1\">\n\t\t{#if links}\n\t\t\t<Connectors connectors={links.connectors} {orientation}>\n\t\t\t\t{#if junctionMarker === \"square\" && links.junctions.start}\n\t\t\t\t\t<g transform={`translate(${links.junctions.start.x} ${links.junctions.start.y})`}>\n\t\t\t\t\t\t<rect x=\"-3\" y=\"-3\" width=\"6\" height=\"6\" fill=\"currentColor\" rx=\"1\" />\n\t\t\t\t\t</g>\n\t\t\t\t{/if}\n\n\t\t\t\t{#if junctionMarker === \"square\" && links.junctions.end}\n\t\t\t\t\t<g transform={`translate(${links.junctions.end.x} ${links.junctions.end.y})`}>\n\t\t\t\t\t\t<rect x=\"-3\" y=\"-3\" width=\"6\" height=\"6\" fill=\"currentColor\" rx=\"1\" />\n\t\t\t\t\t</g>\n\t\t\t\t{/if}\n\t\t\t</Connectors>\n\t\t{/if}\n\t</div>\n\n\t<ul\n\t\tbind:this={contentRef}\n\t\tclass={cn(\n\t\t\t\"flex list-none gap-5\",\n\t\t\talign === \"start\" ? \"items-start\" : \"items-end\",\n\t\t\torientation === \"horizontal\"\n\t\t\t\t? \"ml-0 flex-col\"\n\t\t\t\t: diagramAlign === \"center\"\n\t\t\t\t\t? \"mx-auto w-fit gap-5\"\n\t\t\t\t\t: \"mr-auto w-fit gap-5\"\n\t\t)}\n\t>\n\t\t{@render children?.()}\n\t</ul>\n</div>\n",
			"type": "registry:component",
			"target": "magic/flow/flow-parallel.svelte"
		},
		{
			"content": "<script lang=\"ts\">\n\timport { motion, useMotionTemplate, useMotionValue, useTransform, type PanInfo } from \"motion-sv\";\n\timport type { Snippet } from \"svelte\";\n\timport { cn } from \"$UTILS$.js\";\n\timport FlowNodeList from \"./flow-node-list.svelte\";\n\timport { setDiagramContext } from \"./diagram-context.svelte\";\n\timport type { Align, JunctionMarker, Orientation } from \"./types\";\n\n\tconst DEFAULT_PADDING = {\n\t\tx: 16,\n\t\ty: 64,\n\t};\n\n\tinterface FlowRootProps {\n\t\torientation?: Orientation;\n\t\talign?: Align;\n\t\tjunctionMarker?: JunctionMarker;\n\t\tcanvas?: boolean;\n\t\tpadding?: { x?: number; y?: number };\n\t\tonOverflowChange?: (overflow: { x: boolean; y: boolean }) => void;\n\t\tclass?: string;\n\t\tchildren?: Snippet;\n\t}\n\n\ttype Bounds = {\n\t\tx: number;\n\t\ty: number;\n\t};\n\n\ttype Dimensions = {\n\t\tviewportWidth: number;\n\t\tviewportHeight: number;\n\t\tcontentWidth: number;\n\t\tcontentHeight: number;\n\t};\n\n\tconst MIN_SCROLLBAR_THUMB_SIZE = 10;\n\n\tlet {\n\t\torientation = \"horizontal\",\n\t\talign = \"start\",\n\t\tjunctionMarker = \"square\",\n\t\tcanvas = true,\n\t\tpadding,\n\t\tonOverflowChange,\n\t\tclass: className,\n\t\tchildren,\n\t}: FlowRootProps = $props();\n\n\tlet wrapperRef = $state<HTMLDivElement | null>(null);\n\tlet contentRef = $state<HTMLDivElement | null>(null);\n\tlet bounds = $state<Bounds | null>(null);\n\tlet dimensions = $state<Dimensions | null>(null);\n\tlet isPanning = $state(false);\n\tlet canPan = $state(false);\n\n\tlet x = useMotionValue(0);\n\tlet y = useMotionValue(0);\n\n\tlet paddingX = $derived(padding?.x ?? DEFAULT_PADDING.x);\n\tlet paddingY = $derived(padding?.y ?? DEFAULT_PADDING.y);\n\tlet canScrollX = $derived(Boolean(bounds && bounds.x < 0));\n\tlet canScrollY = $derived(Boolean(bounds && bounds.y < 0));\n\tlet scrollThumbWidth = $derived(\n\t\tdimensions && dimensions.contentWidth > 0 && dimensions.viewportWidth > 0\n\t\t\t? Math.max(\n\t\t\t\t\tMIN_SCROLLBAR_THUMB_SIZE,\n\t\t\t\t\t(dimensions.viewportWidth / dimensions.contentWidth) * 100\n\t\t\t\t)\n\t\t\t: 0\n\t);\n\tlet scrollThumbHeight = $derived(\n\t\tdimensions && dimensions.contentHeight > 0 && dimensions.viewportHeight > 0\n\t\t\t? Math.max(\n\t\t\t\t\tMIN_SCROLLBAR_THUMB_SIZE,\n\t\t\t\t\t(dimensions.viewportHeight / dimensions.contentHeight) * 100\n\t\t\t\t)\n\t\t\t: 0\n\t);\n\n\tsetDiagramContext({\n\t\torientation: () => orientation,\n\t\talign: () => align,\n\t\tjunctionMarker: () => junctionMarker,\n\t\tx,\n\t\ty,\n\t\twrapper: () => wrapperRef,\n\t});\n\n\tfunction isEventFromNode(target: EventTarget | null) {\n\t\treturn target instanceof Element && target.closest(\"[data-node-id]\") !== null;\n\t}\n\n\tfunction clamp(value: number, min: number, max: number) {\n\t\treturn Math.max(min, Math.min(max, value));\n\t}\n\n\tfunction measureBounds() {\n\t\tif (!wrapperRef || !contentRef) return;\n\n\t\tconst wrapper = wrapperRef.getBoundingClientRect();\n\t\tconst content = contentRef.getBoundingClientRect();\n\t\tconst availableWidth = wrapper.width - paddingX * 2;\n\t\tconst availableHeight = wrapper.height - paddingY * 2;\n\n\t\tbounds = {\n\t\t\tx: Math.min(0, availableWidth - content.width),\n\t\t\ty: Math.min(0, availableHeight - content.height),\n\t\t};\n\n\t\tdimensions = {\n\t\t\tviewportWidth: availableWidth,\n\t\t\tviewportHeight: availableHeight,\n\t\t\tcontentWidth: content.width,\n\t\t\tcontentHeight: content.height,\n\t\t};\n\n\t\tconst hasXOverflow = content.width > availableWidth;\n\t\tconst hasYOverflow = content.height > availableHeight;\n\n\t\tcanPan = hasXOverflow || hasYOverflow;\n\t\tonOverflowChange?.({ x: hasXOverflow, y: hasYOverflow });\n\t}\n\n\tfunction handlePanStart(event: PointerEvent) {\n\t\tif (!canvas || isEventFromNode(event.target)) return;\n\t\tisPanning = true;\n\t\tdocument.body.style.cursor = \"grabbing\";\n\t\tdocument.body.style.userSelect = \"none\";\n\t}\n\n\tfunction handlePan(_event: PointerEvent, info: PanInfo) {\n\t\tif (!canvas || !bounds || !isPanning) return;\n\t\tx.set(clamp(x.get() + info.delta.x, bounds.x, 0));\n\t\ty.set(clamp(y.get() + info.delta.y, bounds.y, 0));\n\t}\n\n\tfunction handlePanEnd() {\n\t\tif (!canvas || !isPanning) return;\n\t\tisPanning = false;\n\t\tdocument.body.style.cursor = \"\";\n\t\tdocument.body.style.userSelect = \"\";\n\t}\n\n\tlet scrollbarXPercent = useTransform(() => {\n\t\tconst maxOffset = bounds?.x ?? 0;\n\t\tif (!maxOffset) return 0;\n\t\tconst maxThumbTravel = 100 - scrollThumbWidth;\n\t\treturn clamp((-x.get() / Math.abs(maxOffset)) * maxThumbTravel, 0, maxThumbTravel);\n\t});\n\n\tconst scrollbarYPercent = useTransform(() => {\n\t\tconst maxOffset = bounds?.y ?? 0;\n\t\tif (!maxOffset) return 0;\n\t\tconst maxThumbTravel = 100 - scrollThumbHeight;\n\t\treturn clamp((-y.get() / Math.abs(maxOffset)) * maxThumbTravel, 0, maxThumbTravel);\n\t});\n\n\tlet scrollLeft = useMotionTemplate`${scrollbarXPercent}%`;\n\tlet scrollTop = useMotionTemplate`${scrollbarYPercent}%`;\n\n\t$effect(() => {\n\t\tif (!canvas || !wrapperRef || !contentRef) return;\n\n\t\tmeasureBounds();\n\n\t\tconst resizeObserver = new ResizeObserver(() => measureBounds());\n\t\tresizeObserver.observe(wrapperRef);\n\t\tresizeObserver.observe(contentRef);\n\n\t\treturn () => resizeObserver.disconnect();\n\t});\n\n\t$effect(() => {\n\t\tif (!canvas || !bounds) return;\n\n\t\tif (x.get() < bounds.x) x.set(bounds.x);\n\t\tif (y.get() < bounds.y) y.set(bounds.y);\n\t});\n\n\t$effect(() => {\n\t\tif (!canvas) return;\n\n\t\treturn () => {\n\t\t\tdocument.body.style.cursor = \"\";\n\t\t\tdocument.body.style.userSelect = \"\";\n\t\t};\n\t});\n\n\t$effect(() => {\n\t\tif (!canvas || !wrapperRef) return;\n\n\t\tconst handleWheel = (event: WheelEvent) => {\n\t\t\tif (!bounds) return;\n\n\t\t\tconst allowX = bounds.x < 0;\n\t\t\tconst allowY = bounds.y < 0;\n\n\t\t\tif (!allowX && !allowY) return;\n\n\t\t\tevent.preventDefault();\n\n\t\t\tif (allowY) {\n\t\t\t\ty.set(clamp(y.get() - event.deltaY, bounds.y, 0));\n\t\t\t}\n\n\t\t\tif (allowX) {\n\t\t\t\tx.set(clamp(x.get() - event.deltaX, bounds.x, 0));\n\t\t\t}\n\t\t};\n\n\t\twrapperRef.addEventListener(\"wheel\", handleWheel, { passive: false });\n\n\t\treturn () => wrapperRef?.removeEventListener(\"wheel\", handleWheel);\n\t});\n</script>\n\n{#if canvas}\n\t<motion.div\n\t\tbind:ref={wrapperRef}\n\t\tclass={cn(\"relative isolate grow overflow-hidden group\", className)}\n\t\tstyle={{\n\t\t\tpaddingTop: `${paddingY}px`,\n\t\t\tpaddingBottom: `${paddingY}px`,\n\t\t\tpaddingLeft: `${paddingX}px`,\n\t\t\tpaddingRight: `${paddingX}px`,\n\t\t\tcursor: canPan && !isPanning ? \"grab\" : undefined,\n\t\t}}\n\t\tonPanStart={handlePanStart}\n\t\tonPan={handlePan}\n\t\tonPanEnd={handlePanEnd}\n\t>\n\t\t<motion.div\n\t\t\tbind:ref={contentRef}\n\t\t\tdata-testid=\"flow-contents\"\n\t\t\tclass=\"mx-auto w-max\"\n\t\t\tstyle={{ x, y }}\n\t\t>\n\t\t\t<FlowNodeList>\n\t\t\t\t{@render children?.()}\n\t\t\t</FlowNodeList>\n\t\t</motion.div>\n\n\t\t{#if canScrollY}\n\t\t\t<div class=\"absolute top-1 right-1 bottom-1 w-1.5 rounded-full bg-kumo-hairline/50 opacity-0 group-hover:opacity-100\">\n\t\t\t\t<motion.div\n\t\t\t\t\tclass=\"absolute w-full rounded-full bg-kumo-fill\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\theight: `${scrollThumbHeight}%`,\n\t\t\t\t\t\ttop: scrollTop,\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t{/if}\n\n\t\t{#if canScrollX}\n\t\t\t<div class=\"absolute right-1 bottom-1 left-1 h-1.5 rounded-full bg-kumo-hairline/50 opacity-0 group-hover:opacity-100\">\n\t\t\t\t<motion.div\n\t\t\t\t\tclass=\"absolute h-full rounded-full bg-kumo-fill\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\twidth: `${scrollThumbWidth}%`,\n\t\t\t\t\t\tleft: scrollLeft,\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t{/if}\n\t</motion.div>\n{:else}\n\t<div bind:this={wrapperRef} class={className}>\n\t\t<div bind:this={contentRef}>\n\t\t\t<FlowNodeList>\n\t\t\t\t{@render children?.()}\n\t\t\t</FlowNodeList>\n\t\t</div>\n\t</div>\n{/if}\n",
			"type": "registry:component",
			"target": "magic/flow/flow-root.svelte"
		},
		{
			"content": "import type { Connector, Orientation } from \"./types\";\n\ntype PathProps = Partial<{\n\tcornerRadius: number;\n\tmidOffset: number;\n\tarrowheadOffset: number;\n\tisBottom: boolean;\n\tsingle: boolean;\n\torientation: Orientation;\n}>;\n\nconst FLAT_THRESHOLD = 2;\n\nexport function createRoundedPath(\n\t{ x1, y1, x2, y2 }: Connector,\n\t{\n\t\tcornerRadius: maxCornerRadius = 8,\n\t\tmidOffset = 32,\n\t\tarrowheadOffset = 8,\n\t\tisBottom = false,\n\t\tsingle = false,\n\t\torientation = \"vertical\",\n\t}: PathProps = {}\n) {\n\tconst cornerRadius = Math.min(\n\t\tmaxCornerRadius,\n\t\tMath.abs(orientation === \"horizontal\" ? (y2 - y1) / 2 : (x2 - x1) / 2)\n\t);\n\n\tif (orientation === \"horizontal\") {\n\t\tif (Math.abs(y2 - y1) <= FLAT_THRESHOLD) {\n\t\t\treturn `M ${x1} ${y1} L ${x2 - arrowheadOffset} ${y2}`;\n\t\t}\n\n\t\tconst verticalX = single || isBottom ? x2 - midOffset : x1 + midOffset;\n\t\tconst isGoingRight = x2 > x1;\n\t\tconst horizontalSign = isGoingRight ? 1 : -1;\n\t\tconst isGoingDown = y2 > y1;\n\t\tconst verticalSign = isGoingDown ? 1 : -1;\n\n\t\tconst firstHorizontalEnd = verticalX - horizontalSign * cornerRadius;\n\t\tconst verticalStart = y1 + verticalSign * cornerRadius;\n\t\tconst verticalEnd = y2 - verticalSign * cornerRadius;\n\t\tconst secondHorizontalStart = verticalX + horizontalSign * cornerRadius;\n\t\tconst pathEndX = x2 - horizontalSign * arrowheadOffset;\n\n\t\tconst bottomCurveCommands = [\n\t\t\t`L ${firstHorizontalEnd} ${y1}`,\n\t\t\t`Q ${verticalX} ${y1} ${verticalX} ${verticalStart}`,\n\t\t\tsingle\n\t\t\t\t? `L ${verticalX} ${verticalEnd} Q ${verticalX} ${y2} ${secondHorizontalStart} ${y2}`\n\t\t\t\t: `L ${verticalX} ${y2}`,\n\t\t];\n\n\t\tconst topCurveCommands = [\n\t\t\tsingle\n\t\t\t\t? `L ${firstHorizontalEnd} ${y1} Q ${verticalX} ${y1} ${verticalX} ${verticalStart}`\n\t\t\t\t: `L ${verticalX} ${y1}`,\n\t\t\t`L ${verticalX} ${verticalEnd}`,\n\t\t\t`Q ${verticalX} ${y2} ${secondHorizontalStart} ${y2}`,\n\t\t];\n\n\t\treturn [\n\t\t\t`M ${x1} ${y1}`,\n\t\t\t...(isBottom ? bottomCurveCommands : topCurveCommands),\n\t\t\t`L ${pathEndX} ${y2}`,\n\t\t].join(\" \");\n\t}\n\n\tif (Math.abs(x2 - x1) <= FLAT_THRESHOLD) {\n\t\treturn `M ${x1} ${y1} L ${x2} ${y2 - arrowheadOffset}`;\n\t}\n\n\tconst horizontalY = single || isBottom ? y2 - midOffset : y1 + midOffset;\n\tconst isGoingRight = x2 > x1;\n\tconst horizontalSign = isGoingRight ? 1 : -1;\n\tconst isGoingDown = y2 > y1;\n\tconst verticalSign = isGoingDown ? 1 : -1;\n\n\tconst firstVerticalEnd = horizontalY - cornerRadius;\n\tconst horizontalStart = x1 + horizontalSign * cornerRadius;\n\tconst horizontalEnd = x2 - horizontalSign * cornerRadius;\n\tconst secondVerticalStart = horizontalY + cornerRadius;\n\tconst pathEndY = y2 - verticalSign * arrowheadOffset;\n\n\tconst bottomCurveCommands = [\n\t\t`L ${x1} ${firstVerticalEnd}`,\n\t\t`Q ${x1} ${horizontalY} ${horizontalStart} ${horizontalY}`,\n\t\tsingle\n\t\t\t? `L ${horizontalEnd} ${horizontalY} Q ${x2} ${horizontalY} ${x2} ${secondVerticalStart}`\n\t\t\t: `L ${x2} ${horizontalY}`,\n\t];\n\n\tconst topCurveCommands = [\n\t\tsingle\n\t\t\t? `L ${x1} ${firstVerticalEnd} Q ${x1} ${horizontalY} ${horizontalStart} ${horizontalY}`\n\t\t\t: `L ${x1} ${horizontalY}`,\n\t\t`L ${horizontalEnd} ${horizontalY}`,\n\t\t`Q ${x2} ${horizontalY} ${x2} ${secondVerticalStart}`,\n\t];\n\n\treturn [\n\t\t`M ${x1} ${y1}`,\n\t\t...(isBottom ? bottomCurveCommands : topCurveCommands),\n\t\t`L ${x2} ${pathEndY}`,\n\t].join(\" \");\n}\n",
			"type": "registry:file",
			"target": "magic/flow/connectors.ts"
		},
		{
			"content": "import { getContext, setContext } from \"svelte\";\n\ntype DescendantBase = {\n\telement?: Element | null;\n};\n\nexport type DescendantInfo<T extends DescendantBase = DescendantBase> = {\n\tid: string;\n\tprops: T;\n\torder: number;\n};\n\nfunction compareDocumentOrder(a: Element | null | undefined, b: Element | null | undefined) {\n\tif (!a || !b || a === b || !a.isConnected || !b.isConnected) return null;\n\n\tconst position = a.compareDocumentPosition(b);\n\n\tif (position & Node.DOCUMENT_POSITION_FOLLOWING) return -1;\n\tif (position & Node.DOCUMENT_POSITION_PRECEDING) return 1;\n\n\treturn null;\n}\n\nexport class DescendantsState<T extends DescendantBase> {\n\tdescendants = $state<DescendantInfo<T>[]>([]);\n\tmeasurementEpoch = $state(0);\n\n\t#descendants = new Map<string, DescendantInfo<T>>();\n\t#order = 0;\n\n\tmount(id: string, props: T) {\n\t\tif (!this.#descendants.has(id)) {\n\t\t\tthis.#descendants.set(id, { id, props, order: this.#order++ });\n\t\t\tthis.#sync();\n\t\t\tthis.measurementEpoch += 1;\n\t\t} else {\n\t\t\tthis.update(id, props);\n\t\t}\n\n\t\treturn () => this.unmount(id);\n\t}\n\n\tupdate(id: string, props: T) {\n\t\tconst existing = this.#descendants.get(id);\n\n\t\tif (!existing) {\n\t\t\tthis.#descendants.set(id, { id, props, order: this.#order++ });\n\t\t\tthis.#sync();\n\t\t\tthis.measurementEpoch += 1;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#descendants.set(id, { ...existing, props });\n\t\tthis.#sync();\n\t}\n\n\tunmount(id: string) {\n\t\tif (!this.#descendants.delete(id)) return;\n\n\t\tthis.#sync();\n\t\tthis.measurementEpoch += 1;\n\t}\n\n\tnotifySizeChange = () => {\n\t\tthis.measurementEpoch += 1;\n\t};\n\n\tgetIndex(id: string) {\n\t\treturn this.descendants.findIndex((descendant) => descendant.id === id);\n\t}\n\n\tgetPrevious(id: string) {\n\t\tconst index = this.getIndex(id);\n\t\tif (index <= 0) return undefined;\n\t\treturn this.descendants[index - 1];\n\t}\n\n\tgetNext(id: string) {\n\t\tconst index = this.getIndex(id);\n\t\tif (index < 0 || index >= this.descendants.length - 1) return undefined;\n\t\treturn this.descendants[index + 1];\n\t}\n\n\t#sync() {\n\t\tthis.descendants = Array.from(this.#descendants.values()).sort((a, b) => {\n\t\t\tconst byElement = compareDocumentOrder(a.props.element, b.props.element);\n\t\t\tif (byElement !== null) return byElement;\n\t\t\treturn a.order - b.order;\n\t\t});\n\t}\n}\n\nconst DESCENDANTS_CONTEXT_KEY = Symbol(\"flow-descendants\");\n\nexport function createDescendantsState<T extends DescendantBase>() {\n\treturn new DescendantsState<T>();\n}\n\nexport function setDescendantsContext<T extends DescendantBase>(value: DescendantsState<T>) {\n\tsetContext(DESCENDANTS_CONTEXT_KEY, value);\n\treturn value;\n}\n\nexport function useDescendantsContext<T extends DescendantBase>() {\n\tconst context = getContext<DescendantsState<T> | undefined>(DESCENDANTS_CONTEXT_KEY);\n\n\tif (!context) {\n\t\tthrow new Error(\"Flow descendants context is missing\");\n\t}\n\n\treturn context;\n}\n\nexport function useOptionalDescendantsContext<T extends DescendantBase>() {\n\treturn getContext<DescendantsState<T> | undefined>(DESCENDANTS_CONTEXT_KEY);\n}\n",
			"type": "registry:file",
			"target": "magic/flow/descendants.svelte.ts"
		},
		{
			"content": "import type { MotionValue } from \"motion-sv\";\nimport { getContext, setContext } from \"svelte\";\nimport type { Align, JunctionMarker, Orientation } from \"./types\";\n\nexport type DiagramContextValue = {\n\torientation: () => Orientation;\n\talign: () => Align;\n\tjunctionMarker: () => JunctionMarker;\n\tx: MotionValue<number>;\n\ty: MotionValue<number>;\n\twrapper: () => HTMLDivElement | null;\n};\n\nconst DIAGRAM_CONTEXT_KEY = Symbol(\"flow-diagram\");\n\nexport function setDiagramContext(value: DiagramContextValue) {\n\tsetContext(DIAGRAM_CONTEXT_KEY, value);\n\treturn value;\n}\n\nexport function useDiagramContext() {\n\tconst context = getContext<DiagramContextValue | undefined>(DIAGRAM_CONTEXT_KEY);\n\n\tif (!context) {\n\t\tthrow new Error(\"Flow diagram context is missing\");\n\t}\n\n\treturn context;\n}\n",
			"type": "registry:file",
			"target": "magic/flow/diagram-context.svelte.ts"
		},
		{
			"content": "import Root from \"./flow-root.svelte\";\nimport Node from \"./flow-node.svelte\";\nimport Parallel from \"./flow-parallel.svelte\";\nimport Anchor from \"./flow-anchor.svelte\";\nimport List from \"./flow-node-list.svelte\";\n\nexport {\n\tRoot,\n\tNode,\n\tParallel,\n\tList,\n\tAnchor,\n\t//\n\tRoot as Flow,\n\tNode as FlowNode,\n\tParallel as FlowParallel,\n\tList as FlowNodeList,\n\tAnchor as FlowAnchor,\n};\n\nexport type { Align, Connector, JunctionMarker, NodeData, Orientation, ParallelAlign, RectLike } from \"./types\";\n",
			"type": "registry:file",
			"target": "magic/flow/index.ts"
		},
		{
			"content": "import { getContext, setContext } from \"svelte\";\n\nexport type FlowNodeAnchorContextValue = {\n\tregisterStartAnchor: (ref: HTMLElement | null) => void;\n\tregisterEndAnchor: (ref: HTMLElement | null) => void;\n};\n\nconst FLOW_NODE_CONTEXT_KEY = Symbol(\"flow-node-anchor\");\n\nexport function setFlowNodeAnchorContext(value: FlowNodeAnchorContextValue) {\n\tsetContext(FLOW_NODE_CONTEXT_KEY, value);\n\treturn value;\n}\n\nexport function useFlowNodeAnchorContext() {\n\tconst context = getContext<FlowNodeAnchorContextValue | undefined>(FLOW_NODE_CONTEXT_KEY);\n\n\tif (!context) {\n\t\tthrow new Error(\"Flow.Anchor must be used within Flow.Node\");\n\t}\n\n\treturn context;\n}\n",
			"type": "registry:file",
			"target": "magic/flow/node-context.svelte.ts"
		},
		{
			"content": "import { createAttachmentKey } from \"svelte/attachments\";\n\nexport function withElementAttachment<T extends HTMLElement, P extends Record<string, unknown>>(\n\tprops: P,\n\tsetter: (element: T | null) => void\n) {\n\tconst key = createAttachmentKey();\n\n\treturn {\n\t\t...props,\n\t\t[key]: (element: T) => {\n\t\t\tsetter(element);\n\t\t\treturn () => setter(null);\n\t\t},\n\t} as P;\n}\n",
			"type": "registry:file",
			"target": "magic/flow/render-props.ts"
		},
		{
			"content": "export type Orientation = \"horizontal\" | \"vertical\";\n\nexport type Align = \"start\" | \"center\";\n\nexport type ParallelAlign = \"start\" | \"end\";\n\nexport type JunctionMarker = \"none\" | \"square\";\n\nexport type RectLike = {\n\tx: number;\n\ty: number;\n\ttop: number;\n\tleft: number;\n\tright: number;\n\tbottom: number;\n\twidth: number;\n\theight: number;\n};\n\nexport type NodeData = {\n\telement?: Element | null;\n\tparallel?: boolean;\n\tdisabled?: boolean;\n\tstart?: RectLike | null;\n\tend?: RectLike | null;\n};\n\nexport type Connector = {\n\tx1: number;\n\ty1: number;\n\tx2: number;\n\ty2: number;\n\tisBottom?: boolean;\n\tdisabled?: boolean;\n\tsingle?: boolean;\n\tfromId?: string;\n\ttoId?: string;\n};\n\nexport function rectEquals(a: RectLike | null | undefined, b: RectLike | null | undefined): boolean {\n\tif (a === b) return true;\n\tif (!a || !b) return false;\n\n\treturn (\n\t\ta.x === b.x &&\n\t\ta.y === b.y &&\n\t\ta.top === b.top &&\n\t\ta.left === b.left &&\n\t\ta.right === b.right &&\n\t\ta.bottom === b.bottom &&\n\t\ta.width === b.width &&\n\t\ta.height === b.height\n\t);\n}\n",
			"type": "registry:file",
			"target": "magic/flow/types.ts"
		}
	]
}