@particle-academy/fancy-flow 0.45.0 → 0.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/dist/{ConfigFieldRenderer-Dzy4f6rG.d.cts → ConfigFieldRenderer-Cyir8-B8.d.cts} +2 -2
- package/dist/{ConfigFieldRenderer-WqJr-td_.d.ts → ConfigFieldRenderer-iMkZj0VK.d.ts} +2 -2
- package/dist/{FlowViewer-BbbUJe2b.d.cts → FlowViewer-CY3_vHSg.d.cts} +1 -1
- package/dist/{FlowViewer-csuaTL5t.d.ts → FlowViewer-DGW6t-80.d.ts} +1 -1
- package/dist/{capabilities-Brn74URS.d.ts → capabilities-DMUhnyZD.d.ts} +1 -1
- package/dist/{capabilities-CYCeIx6I.d.cts → capabilities-Dmd26aAs.d.cts} +1 -1
- package/dist/chunk-BHM5HGXH.js +79 -0
- package/dist/chunk-BHM5HGXH.js.map +1 -0
- package/dist/chunk-DR3GWVDG.js +196 -0
- package/dist/chunk-DR3GWVDG.js.map +1 -0
- package/dist/{chunk-3BKU4SQZ.js → chunk-ISXRQELT.js} +3 -4
- package/dist/chunk-ISXRQELT.js.map +1 -0
- package/dist/{chunk-OWENS2H5.js → chunk-NDEX655E.js} +1603 -36
- package/dist/chunk-NDEX655E.js.map +1 -0
- package/dist/{chunk-QZTGV3ZL.js → chunk-QVFVL5LQ.js} +3 -3
- package/dist/{chunk-QZTGV3ZL.js.map → chunk-QVFVL5LQ.js.map} +1 -1
- package/dist/{chunk-DHUFUDEX.js → chunk-Z2GRNYR2.js} +7 -6
- package/dist/chunk-Z2GRNYR2.js.map +1 -0
- package/dist/{chunk-A6RFLGWV.js → chunk-ZKJJWBDJ.js} +3 -5
- package/dist/chunk-ZKJJWBDJ.js.map +1 -0
- package/dist/durable/index.d.cts +490 -0
- package/dist/durable/index.d.ts +490 -0
- package/dist/durable.cjs +10991 -0
- package/dist/durable.cjs.map +1 -0
- package/dist/durable.js +552 -0
- package/dist/durable.js.map +1 -0
- package/dist/engine.cjs +10223 -47
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.cts +9 -7
- package/dist/engine.d.ts +9 -7
- package/dist/engine.js +4 -6
- package/dist/engine.js.map +1 -1
- package/dist/fields/react-fancy.d.cts +4 -3
- package/dist/fields/react-fancy.d.ts +4 -3
- package/dist/index.cjs +336 -194
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -10
- package/dist/index.d.ts +12 -10
- package/dist/index.js +15 -93
- package/dist/index.js.map +1 -1
- package/dist/layout/index.d.cts +1 -1
- package/dist/layout/index.d.ts +1 -1
- package/dist/llm/prism.d.cts +2 -2
- package/dist/llm/prism.d.ts +2 -2
- package/dist/llm/vercel-ai.d.cts +2 -2
- package/dist/llm/vercel-ai.d.ts +2 -2
- package/dist/pause-9iT4tCEV.d.cts +96 -0
- package/dist/pause-9iT4tCEV.d.ts +96 -0
- package/dist/registry/index.d.cts +7 -6
- package/dist/registry/index.d.ts +7 -6
- package/dist/{registry-Budds73w.d.cts → registry-Bt55f63_.d.ts} +21 -2
- package/dist/{registry-D0I20HJ3.d.ts → registry-CkcSwmfR.d.cts} +21 -2
- package/dist/registry.cjs +3961 -3821
- package/dist/registry.cjs.map +1 -1
- package/dist/registry.js +3 -6
- package/dist/{run-cohort-CV7EcwGG.d.ts → run-cohort-Cyeny2Uu.d.ts} +3 -34
- package/dist/{run-cohort-DitsaYgS.d.cts → run-cohort-DdPPowJ3.d.cts} +3 -34
- package/dist/run-flow-1KiXhy59.d.cts +55 -0
- package/dist/run-flow-CQvTDBYk.d.ts +55 -0
- package/dist/runtime/index.d.cts +5 -3
- package/dist/runtime/index.d.ts +5 -3
- package/dist/runtime.cjs +1712 -430
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +5 -6
- package/dist/schema/index.d.cts +1 -1
- package/dist/schema/index.d.ts +1 -1
- package/dist/schema.cjs +10369 -24
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.js +4 -3
- package/dist/screens.cjs +1366 -38
- package/dist/screens.cjs.map +1 -1
- package/dist/screens.d.cts +2 -2
- package/dist/screens.d.ts +2 -2
- package/dist/screens.js +5 -8
- package/dist/screens.js.map +1 -1
- package/dist/{types-D6ZSKBly.d.ts → types--S2Kzx7w.d.cts} +3 -97
- package/dist/{types-nQOA8jpk.d.cts → types-ChkCRonF.d.ts} +3 -97
- package/dist/types-Jx1TwehV.d.cts +247 -0
- package/dist/types-Jx1TwehV.d.ts +247 -0
- package/dist/ux.cjs +10363 -2
- package/dist/ux.cjs.map +1 -1
- package/dist/ux.d.cts +3 -2
- package/dist/ux.d.ts +3 -2
- package/dist/ux.js +3 -1
- package/dist/ux.js.map +1 -1
- package/package.json +17 -3
- package/dist/chunk-3BKU4SQZ.js.map +0 -1
- package/dist/chunk-A6RFLGWV.js.map +0 -1
- package/dist/chunk-DHUFUDEX.js.map +0 -1
- package/dist/chunk-OWENS2H5.js.map +0 -1
- package/dist/chunk-PVROYW7C.js +0 -187
- package/dist/chunk-PVROYW7C.js.map +0 -1
- package/dist/chunk-TITD5W4Y.js +0 -26
- package/dist/chunk-TITD5W4Y.js.map +0 -1
- package/dist/chunk-VLATLVGH.js +0 -158
- package/dist/chunk-VLATLVGH.js.map +0 -1
- package/dist/chunk-WBXGZVLB.js +0 -1268
- package/dist/chunk-WBXGZVLB.js.map +0 -1
- package/dist/types-CMSrWVYM.d.cts +0 -109
- package/dist/types-CMSrWVYM.d.ts +0 -109
package/dist/ux.d.cts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { EffectRegistry, DispatchActor } from '@particle-academy/fancy-auto-common';
|
|
2
2
|
export { AutoActivityEvent } from '@particle-academy/fancy-auto-common';
|
|
3
|
-
import { a as NodeCategory, C as ConfigField } from './types
|
|
4
|
-
import { E as ExecutorRegistry } from './types-
|
|
3
|
+
import { a as NodeCategory, C as ConfigField } from './types--S2Kzx7w.cjs';
|
|
4
|
+
import { E as ExecutorRegistry } from './types-Jx1TwehV.cjs';
|
|
5
5
|
import 'react';
|
|
6
6
|
import '@xyflow/react';
|
|
7
|
+
import './pause-9iT4tCEV.cjs';
|
|
7
8
|
|
|
8
9
|
/** Per-effect presentation for the palette node kind that drives it. */
|
|
9
10
|
type UxEffectMeta = {
|
package/dist/ux.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { EffectRegistry, DispatchActor } from '@particle-academy/fancy-auto-common';
|
|
2
2
|
export { AutoActivityEvent } from '@particle-academy/fancy-auto-common';
|
|
3
|
-
import { a as NodeCategory, C as ConfigField } from './types-
|
|
4
|
-
import { E as ExecutorRegistry } from './types-
|
|
3
|
+
import { a as NodeCategory, C as ConfigField } from './types-ChkCRonF.js';
|
|
4
|
+
import { E as ExecutorRegistry } from './types-Jx1TwehV.js';
|
|
5
5
|
import 'react';
|
|
6
6
|
import '@xyflow/react';
|
|
7
|
+
import './pause-9iT4tCEV.js';
|
|
7
8
|
|
|
8
9
|
/** Per-effect presentation for the palette node kind that drives it. */
|
|
9
10
|
type UxEffectMeta = {
|
package/dist/ux.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { registerNodeKind } from './chunk-
|
|
1
|
+
import { registerNodeKind } from './chunk-NDEX655E.js';
|
|
2
|
+
import './chunk-F5RPRB7A.js';
|
|
3
|
+
import './chunk-USL4FMFU.js';
|
|
2
4
|
import { useMemo } from 'react';
|
|
3
5
|
import { createEffectDispatcher } from '@particle-academy/fancy-auto-common';
|
|
4
6
|
|
package/dist/ux.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ux.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/ux.ts"],"names":[],"mappings":";;;;;;AAyEA,IAAM,cAAA,GAAiB,CAAC,IAAA,KAAiB,CAAA,GAAA,EAAM,IAAI,CAAA,CAAA;AAG5C,SAAS,mBAAmB,OAAA,EAA4C;AAC7E,EAAA,MAAM;AAAA,IACJ,OAAA;AAAA,IACA,OAAO,EAAC;AAAA,IACR,KAAA,GAAQ,EAAE,EAAA,EAAI,MAAA,EAAQ,QAAQ,MAAA,EAAO;AAAA,IACrC,OAAA,GAAU;AAAA,GACZ,GAAI,OAAA;AAEJ,EAAA,MAAM,aAAa,sBAAA,CAAuB,OAAA,EAAS,EAAE,KAAA,EAAO,UAAA,EAAY,MAAM,CAAA;AAE9E,EAAA,MAAM,YAA8B,EAAC;AACrC,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,EAAG;AACvC,IAAA,SAAA,CAAU,QAAQ,IAAI,CAAC,IAAI,OAAO,EAAE,MAAK,KAA0B;AACjE,MAAA,MAAM,MAAA,GAAU,IAAA,CAAK,IAAA,EAA2D,MAAA,IAAU,EAAC;AAC3F,MAAA,MAAM,MAAA,GAAS,MAAM,UAAA,CAAW,QAAA,CAAS,MAAM,MAAM,CAAA;AAKrD,MAAA,IAAI,UAAU,OAAO,MAAA,KAAW,aAAa,QAAA,IAAY,MAAA,IAAU,YAAY,MAAA,CAAA,EAAS;AACtF,QAAA,OAAO,MAAA;AAAA,MACT;AACA,MAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,MAAA,EAAO;AAAA,IAChC,CAAA;AAAA,EACF;AAEA,EAAA,MAAM,gBAAgB,MAAM;AAC1B,IAAA,KAAA,MAAW,IAAA,IAAQ,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,EAAG;AACvC,MAAA,MAAM,CAAA,GAAI,IAAA,CAAK,IAAI,CAAA,IAAK,EAAC;AACzB,MAAA,gBAAA,CAAiB;AAAA,QACf,IAAA,EAAM,QAAQ,IAAI,CAAA;AAAA,QAClB,QAAA,EAAU,EAAE,QAAA,IAAY,QAAA;AAAA,QACxB,KAAA,EAAO,EAAE,KAAA,IAAS,IAAA;AAAA,QAClB,WAAA,EAAa,CAAA,CAAE,WAAA,IAAe,CAAA,uBAAA,EAA0B,IAAI,CAAA,CAAA,CAAA;AAAA,QAC5D,IAAA,EAAM,EAAE,IAAA,IAAQ,QAAA;AAAA,QAChB,MAAA,EAAQ,EAAE,MAAA,IAAU,SAAA;AAAA,QACpB,MAAA,EAAQ,CAAC,EAAE,EAAA,EAAI,MAAM,CAAA;AAAA,QACrB,SAAS,EAAC;AAAA,QACV,cAAc,CAAA,CAAE;AAAA,OACjB,CAAA;AAAA,IACH;AAAA,EACF,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,SAAA;AAAA,IACA,UAAU,UAAA,CAAW,QAAA;AAAA,IACrB,aAAa,UAAA,CAAW,KAAA;AAAA,IACxB;AAAA,GACF;AACF;AAMO,SAAS,gBAAgB,OAAA,EAA4C;AAC1E,EAAA,MAAM,MAAM,CAAA,EAAG,MAAA,CAAO,IAAA,CAAK,OAAA,CAAQ,OAAO,CAAA,CAAE,IAAA,EAAK,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,EAAI,OAAA,CAAQ,KAAA,EAAO,MAAM,MAAM,CAAA,CAAA;AAE3F,EAAA,OAAO,QAAQ,MAAM,kBAAA,CAAmB,OAAO,CAAA,EAAG,CAAC,GAAG,CAAC,CAAA;AACzD","file":"ux.js","sourcesContent":["/**\n * FlowRunnerUx — the **flow-driven UX** bridge. The headless counterpart to\n * agent-integrations: where that wires an *agent* to host UI surfaces, this\n * wires a *running flow* to host UX. Both share the same primitives from\n * `@particle-academy/fancy-auto-common` (activity bus, effect dispatch).\n *\n * The host registers named UX effects (toast, navigate, confirm, …); this turns\n * each into a flow executor keyed by a node kind (`ux_<effect>` by default), so\n * dropping a `ux_toast` node into a `<FlowEditor>` and running it fires the\n * host's toast. Every dispatch broadcasts an `AutoActivityEvent` (source:\"flow\")\n * for presence / logging. Human-in-the-loop is free: an effect that returns a\n * Promise (e.g. an approval dialog) pauses the run until the user resolves it.\n *\n * const ux = createFlowRunnerUx({\n * effects: {\n * toast: ({ message }) => toast({ title: message }),\n * navigate:({ to }) => router.visit(to),\n * confirm: ({ prompt }) => new Promise(res => openDialog(prompt, res)), // pauses the run\n * },\n * });\n * ux.registerKinds(); // adds ux_toast / ux_navigate / ux_confirm to the palette\n * <FlowEditor initial={graph} executors={ux.executors} />\n */\nimport { useMemo } from \"react\";\nimport {\n createEffectDispatcher,\n type DispatchActor,\n type EffectRegistry,\n} from \"@particle-academy/fancy-auto-common\";\nimport { registerNodeKind } from \"./registry/registry\";\nimport type { ConfigField, NodeCategory } from \"./registry/types\";\nimport type { ExecutorRegistry, FlowNode } from \"./types\";\n\nexport type { AutoActivityEvent } from \"@particle-academy/fancy-auto-common\";\n\n/** Per-effect presentation for the palette node kind that drives it. */\nexport type UxEffectMeta = {\n /** Palette label. Default: the effect name. */\n label?: string;\n /** One-line palette description. */\n description?: string;\n /** Emoji / glyph for the node header. */\n icon?: string;\n /** Header accent color. */\n accent?: string;\n /** Palette grouping. Default \"output\". */\n category?: NodeCategory;\n /** Config form fields = the effect's params. */\n configSchema?: ConfigField[];\n};\n\nexport type FlowRunnerUxOptions = {\n /** Named host UX effects the flow can invoke. */\n effects: EffectRegistry;\n /** Optional per-effect palette metadata (used by `registerKinds`). */\n meta?: Record<string, UxEffectMeta>;\n /** Identifies the flow run in emitted activity. Default `{ id: \"flow\", source: \"flow\" }`. */\n actor?: DispatchActor;\n /** Map an effect name to its node-kind name. Default `ux_<effect>`. */\n kindFor?: (effectName: string) => string;\n};\n\nexport type FlowRunnerUx = {\n /** Executor registry to hand to `<FlowEditor executors>` or `runFlow`. */\n executors: ExecutorRegistry;\n /** Invoke an effect imperatively (also emits activity). */\n dispatch: <R = unknown>(name: string, params?: unknown) => Promise<R>;\n /** All effect names. */\n effectNames: () => string[];\n /** Register a palette node kind per effect (`ux_<effect>`). Idempotent. */\n registerKinds: () => void;\n};\n\nconst defaultKindFor = (name: string) => `ux_${name}`;\n\n/** Build a FlowRunnerUx from a set of host effects. Framework-agnostic. */\nexport function createFlowRunnerUx(options: FlowRunnerUxOptions): FlowRunnerUx {\n const {\n effects,\n meta = {},\n actor = { id: \"flow\", source: \"flow\" },\n kindFor = defaultKindFor,\n } = options;\n\n const dispatcher = createEffectDispatcher(effects, { actor, targetKind: \"ux\" });\n\n const executors: ExecutorRegistry = {};\n for (const name of Object.keys(effects)) {\n executors[kindFor(name)] = async ({ node }: { node: FlowNode }) => {\n const params = (node.data as { config?: Record<string, unknown> } | undefined)?.config ?? {};\n const result = await dispatcher.dispatch(name, params);\n // A UX effect can drive flow control: if it returns the decision sugar\n // (`{ branch }` or `{ __port }`) — e.g. an interactive \"choose\" effect that\n // awaits a human pick and returns the chosen port — pass it straight\n // through so runFlow routes on it. Otherwise wrap the result for the feed.\n if (result && typeof result === \"object\" && (\"branch\" in result || \"__port\" in result)) {\n return result;\n }\n return { effect: name, result };\n };\n }\n\n const registerKinds = () => {\n for (const name of Object.keys(effects)) {\n const m = meta[name] ?? {};\n registerNodeKind({\n name: kindFor(name),\n category: m.category ?? \"output\",\n label: m.label ?? name,\n description: m.description ?? `Flow-driven UX effect: ${name}.`,\n icon: m.icon ?? \"✨\",\n accent: m.accent ?? \"#8b5cf6\",\n inputs: [{ id: \"in\" }],\n outputs: [],\n configSchema: m.configSchema,\n });\n }\n };\n\n return {\n executors,\n dispatch: dispatcher.dispatch as FlowRunnerUx[\"dispatch\"],\n effectNames: dispatcher.names,\n registerKinds,\n };\n}\n\n/**\n * React hook form — memoizes on the effect-name set + actor id so the returned\n * executors keep a stable identity across renders.\n */\nexport function useFlowRunnerUx(options: FlowRunnerUxOptions): FlowRunnerUx {\n const key = `${Object.keys(options.effects).sort().join(\",\")}|${options.actor?.id ?? \"flow\"}`;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => createFlowRunnerUx(options), [key]);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@particle-academy/fancy-flow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.0",
|
|
4
4
|
"description": "Workflow editor + runner. Six built-in node kits (trigger / action / decision / output / note / subgraph), tokenized theme, topological execution with per-node status. React-flow bundled; consumers npm install fancy-flow and get nothing extra.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -73,6 +73,16 @@
|
|
|
73
73
|
"default": "./dist/engine.cjs"
|
|
74
74
|
}
|
|
75
75
|
},
|
|
76
|
+
"./durable": {
|
|
77
|
+
"import": {
|
|
78
|
+
"types": "./dist/durable/index.d.ts",
|
|
79
|
+
"default": "./dist/durable.js"
|
|
80
|
+
},
|
|
81
|
+
"require": {
|
|
82
|
+
"types": "./dist/durable/index.d.cts",
|
|
83
|
+
"default": "./dist/durable.cjs"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
76
86
|
"./ux": {
|
|
77
87
|
"import": {
|
|
78
88
|
"types": "./dist/ux.d.ts",
|
|
@@ -170,7 +180,7 @@
|
|
|
170
180
|
"devDependencies": {
|
|
171
181
|
"@dagrejs/dagre": "^3.0.0",
|
|
172
182
|
"@particle-academy/fancy-cms-ui": "^0.2.0",
|
|
173
|
-
"@particle-academy/fancy-conformance": "^0.
|
|
183
|
+
"@particle-academy/fancy-conformance": "^0.4.0",
|
|
174
184
|
"@particle-academy/fancy-query": "^0.8.0",
|
|
175
185
|
"@particle-academy/fancy-screens": "^0.4.3",
|
|
176
186
|
"@particle-academy/react-fancy": "^5.17.1",
|
|
@@ -198,7 +208,11 @@
|
|
|
198
208
|
},
|
|
199
209
|
"license": "MIT",
|
|
200
210
|
"sideEffects": [
|
|
201
|
-
"**/*.css"
|
|
211
|
+
"**/*.css",
|
|
212
|
+
"./dist/index.js",
|
|
213
|
+
"./dist/index.cjs",
|
|
214
|
+
"./dist/rich-input.js",
|
|
215
|
+
"./dist/rich-input.cjs"
|
|
202
216
|
],
|
|
203
217
|
"overrides": {
|
|
204
218
|
"esbuild": "^0.28.1"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schema/workflow-schema.ts"],"names":[],"mappings":"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","file":"chunk-3BKU4SQZ.js","sourcesContent":["import type { FlowEdge, FlowGraph, FlowNode, PortDescriptor } from \"../types\";\nimport { defaultConfigFor, getNodeKind, validateConfig } from \"../registry/registry\";\nimport { resolveNodePorts } from \"../registry/ports\";\n\n/** Schema version. Bump on breaking shape changes; add migrations as needed. */\nexport const WORKFLOW_SCHEMA_VERSION = 1 as const;\nexport const WORKFLOW_SCHEMA_URL = \"https://particle.academy/schemas/workflow/v1.json\";\n\nexport type WorkflowSchema = {\n $schema: typeof WORKFLOW_SCHEMA_URL;\n version: typeof WORKFLOW_SCHEMA_VERSION;\n metadata?: WorkflowMetadata;\n graph: {\n nodes: WorkflowSchemaNode[];\n edges: WorkflowSchemaEdge[];\n };\n view?: {\n viewport?: { x: number; y: number; zoom: number };\n };\n};\n\nexport type WorkflowMetadata = {\n id?: string;\n name?: string;\n description?: string;\n createdAt?: number;\n updatedAt?: number;\n author?: string;\n tags?: string[];\n};\n\nexport type WorkflowSchemaNode = {\n id: string;\n /** Registry kind name (e.g. \"memory_store\"). */\n kind: string;\n position: { x: number; y: number };\n label?: string;\n description?: string;\n config?: Record<string, unknown>;\n /**\n * Resolved ports, written on export.\n *\n * A kind may derive its ports from config (`switch_case` cases,\n * `llm_branch` routes), and that derivation is a JavaScript function — a\n * runtime in another language cannot execute it. Without the resolved ports\n * in the document, the PHP twin sees no declared outputs and falls back to a\n * single `out`, so every branch edge in an exported flow silently stops\n * firing. Serializing them keeps the schema self-describing and preserves\n * the cross-runtime guarantee: same JSON in, same routing out.\n *\n * Optional and additive — a hand-written schema may omit them, and each\n * runtime then falls back to its own kind registry.\n */\n inputs?: PortDescriptor[];\n outputs?: PortDescriptor[];\n /**\n * Visual layout — additive + optional. `parentId`/`extent` carry node grouping\n * (swimlanes / containers); `width`/`height` carry an explicit (resized) size;\n * `style` carries inline presentation. A runtime that only walks edges/ports\n * (e.g. the PHP twin) ignores all of these — they exist purely for the canvas,\n * so an older reader that doesn't know them simply drops them.\n */\n parentId?: string;\n extent?: \"parent\" | [[number, number], [number, number]];\n width?: number;\n height?: number;\n style?: Record<string, unknown>;\n};\n\nexport type WorkflowSchemaEdge = {\n id: string;\n source: string;\n target: string;\n sourceHandle?: string;\n targetHandle?: string;\n label?: string;\n};\n\nexport type ImportIssue = {\n level: \"error\" | \"warning\";\n nodeId?: string;\n edgeId?: string;\n message: string;\n};\n\nexport type ImportResult = {\n graph: FlowGraph;\n issues: ImportIssue[];\n /** True when the import produced a usable graph (errors may have been\n * rewritten to warnings via `lenient: true`). */\n ok: boolean;\n};\n\n/** Snapshot the in-memory graph as a portable WorkflowSchema. */\nexport function exportWorkflow(\n graph: FlowGraph,\n metadata?: WorkflowMetadata,\n view?: WorkflowSchema[\"view\"],\n): WorkflowSchema {\n return {\n $schema: WORKFLOW_SCHEMA_URL,\n version: WORKFLOW_SCHEMA_VERSION,\n metadata: metadata ? { ...metadata, updatedAt: Date.now() } : undefined,\n graph: {\n nodes: graph.nodes.map(toSchemaNode),\n edges: graph.edges.map(toSchemaEdge),\n },\n view,\n };\n}\n\nfunction toSchemaNode(n: FlowNode): WorkflowSchemaNode {\n const data: any = n.data ?? {};\n const kindName = data.kind ?? n.type ?? \"custom\";\n // Resolve through the same helper the canvas and runtime use, so a\n // config-driven kind writes its ACTUAL ports into the document instead of\n // leaving another language's runtime to guess at them.\n const ports = resolveNodePorts(n, getNodeKind(kindName) ?? undefined);\n const node = n as any;\n return {\n id: n.id,\n kind: kindName,\n position: { x: n.position.x, y: n.position.y },\n label: data.label,\n description: data.description,\n config: data.config,\n inputs: ports.inputs,\n outputs: ports.outputs,\n // Visual layout — only when explicitly set (never persist auto-`measured`\n // dimensions, which are derived, not authored).\n ...(node.parentId ? { parentId: node.parentId } : {}),\n ...(node.extent ? { extent: node.extent } : {}),\n ...(typeof node.width === \"number\" ? { width: node.width } : {}),\n ...(typeof node.height === \"number\" ? { height: node.height } : {}),\n ...(node.style ? { style: node.style } : {}),\n };\n}\n\nfunction toSchemaEdge(e: FlowEdge): WorkflowSchemaEdge {\n return {\n id: e.id,\n source: e.source,\n target: e.target,\n sourceHandle: e.sourceHandle ?? undefined,\n targetHandle: e.targetHandle ?? undefined,\n label: typeof e.label === \"string\" ? e.label : undefined,\n };\n}\n\nexport type ImportOptions = {\n /** When true, unknown kinds become warnings + a \"custom\" placeholder\n * instead of errors. Default false. */\n lenient?: boolean;\n};\n\n/**\n * Migrate a raw schema object up to the current version. Additive changes need\n * no migration (an older document simply lacks the newer optional fields); this\n * is the seam for a future BREAKING bump — add `case N → N+1` steps here and\n * `importWorkflow` runs them before validating the version.\n */\nexport function migrateSchema(schema: unknown): unknown {\n // v1 is current — nothing to migrate yet.\n return schema;\n}\n\n/**\n * Hydrate a schema into runtime FlowGraph + validate kinds/configs against\n * the registry. Reports issues for unknown kinds, missing required config,\n * and dangling edges.\n */\nexport function importWorkflow(schema: unknown, options: ImportOptions = {}): ImportResult {\n const issues: ImportIssue[] = [];\n const lenient = options.lenient === true;\n schema = migrateSchema(schema);\n\n if (!schema || typeof schema !== \"object\") {\n return { ok: false, graph: { nodes: [], edges: [] }, issues: [{ level: \"error\", message: \"Schema is not an object.\" }] };\n }\n const s = schema as Partial<WorkflowSchema>;\n if (s.version !== WORKFLOW_SCHEMA_VERSION) {\n issues.push({\n level: lenient ? \"warning\" : \"error\",\n message: `Unsupported workflow schema version: ${s.version} (expected ${WORKFLOW_SCHEMA_VERSION})`,\n });\n if (!lenient) return { ok: false, graph: { nodes: [], edges: [] }, issues };\n }\n\n const rawNodes = s.graph?.nodes ?? [];\n const rawEdges = s.graph?.edges ?? [];\n\n const nodes: FlowNode[] = rawNodes.map((n) => {\n const kind = getNodeKind(n.kind);\n if (!kind) {\n issues.push({\n level: lenient ? \"warning\" : \"error\",\n nodeId: n.id,\n message: `Unknown kind \"${n.kind}\" — register it before importing.`,\n });\n }\n const config = n.config ?? (kind ? defaultConfigFor(kind) : {});\n if (kind) {\n for (const iss of validateConfig(kind, config)) {\n issues.push({ level: \"warning\", nodeId: n.id, message: `${iss.key}: ${iss.message}` });\n }\n }\n // Canonicalise on the way in: a document may carry a pre-namespace id, and\n // rewriting it here means the graph converges on the canonical id the next\n // time it is saved, rather than carrying the ambiguous name forever.\n const kindId = kind?.name ?? n.kind;\n return {\n id: n.id,\n type: kindId,\n position: { x: n.position?.x ?? 0, y: n.position?.y ?? 0 },\n // Rehydrate visual layout onto the node's top level (where xyflow reads it).\n ...(n.parentId ? { parentId: n.parentId } : {}),\n ...(n.extent ? { extent: n.extent } : {}),\n ...(typeof n.width === \"number\" ? { width: n.width } : {}),\n ...(typeof n.height === \"number\" ? { height: n.height } : {}),\n ...(n.style ? { style: n.style } : {}),\n data: {\n kind: kindId,\n label: n.label ?? kind?.label ?? n.kind,\n description: n.description,\n config,\n // Carry serialized ports back onto the node so a round-trip is stable\n // and an unknown kind still routes the way the document described.\n ...(n.inputs ? { inputs: n.inputs } : {}),\n ...(n.outputs ? { outputs: n.outputs } : {}),\n } as any,\n };\n });\n\n const nodeIds = new Set(nodes.map((n) => n.id));\n const edges: FlowEdge[] = rawEdges\n .map((e) => {\n if (!nodeIds.has(e.source)) {\n issues.push({ level: \"warning\", edgeId: e.id, message: `Edge source \"${e.source}\" not found.` });\n return null;\n }\n if (!nodeIds.has(e.target)) {\n issues.push({ level: \"warning\", edgeId: e.id, message: `Edge target \"${e.target}\" not found.` });\n return null;\n }\n return {\n id: e.id,\n source: e.source,\n target: e.target,\n sourceHandle: e.sourceHandle,\n targetHandle: e.targetHandle,\n label: e.label,\n } as FlowEdge;\n })\n .filter((e): e is FlowEdge => e !== null);\n\n const ok = issues.every((i) => i.level !== \"error\");\n return { ok, graph: { nodes, edges }, issues };\n}\n\n/** Convenience: serialize a schema as a downloadable JSON Blob. */\nexport function workflowToBlob(schema: WorkflowSchema): Blob {\n return new Blob([JSON.stringify(schema, null, 2)], { type: \"application/json\" });\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtime/use-flow-run.ts","../src/runtime/use-flow-state.ts","../src/runtime/history.ts","../src/runtime/use-flow-history.ts"],"names":["useState","useCallback","useRef"],"mappings":"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","file":"chunk-A6RFLGWV.js","sourcesContent":["import { useCallback, useRef, useState } from \"react\";\nimport { runFlow, type RunOptions, type RunResult } from \"./run-flow\";\nimport { getNodeKind } from \"../registry/registry\";\nimport type {\n ExecutorRegistry,\n FlowGraph,\n NodeRunStatus,\n RunEvent,\n} from \"../types\";\n\nexport type FlowRunFeedEntry = {\n id: string;\n at: number;\n level: \"info\" | \"warn\" | \"error\" | \"status\";\n text: string;\n nodeId?: string;\n detail?: unknown;\n};\n\nexport type UseFlowRunReturn = {\n /** Status keyed by nodeId — drive the UI overlay from this. */\n statuses: Record<string, NodeRunStatus>;\n /** Per-node status text (e.g. error message). */\n statusText: Record<string, string | undefined>;\n /** Latest computed output value per node (for reactive kinds). */\n outputs: Record<string, unknown>;\n /** Live event log (capped to last N). */\n feed: FlowRunFeedEntry[];\n /** Whether a run is currently in progress. */\n running: boolean;\n /** Last run result, or null. */\n lastResult: RunResult | null;\n /** Kick off a run with the provided graph + executors. */\n run: (graph: FlowGraph, executors: ExecutorRegistry, options?: RunOptions) => Promise<RunResult>;\n /** Cancel the current run (if any). */\n cancel: () => void;\n /** Reset all runtime state (statuses, feed, lastResult). */\n reset: () => void;\n};\n\nexport type UseFlowRunOptions = {\n /** Cap the in-memory feed to this many entries. Default 200. */\n maxFeed?: number;\n};\n\n/**\n * useFlowRun — drives `runFlow` + maintains observability state. Pair with\n * `applyStatusesToNodes` (below) before passing nodes to `<FlowCanvas>` so\n * the per-node status badge renders.\n */\nexport function useFlowRun({ maxFeed = 200 }: UseFlowRunOptions = {}): UseFlowRunReturn {\n const [statuses, setStatuses] = useState<Record<string, NodeRunStatus>>({});\n const [statusText, setStatusText] = useState<Record<string, string | undefined>>({});\n const [outputs, setOutputs] = useState<Record<string, unknown>>({});\n const [feed, setFeed] = useState<FlowRunFeedEntry[]>([]);\n const [running, setRunning] = useState(false);\n const [lastResult, setLastResult] = useState<RunResult | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n\n const handleEvent = useCallback(\n (e: RunEvent) => {\n switch (e.type) {\n case \"node-status\":\n setStatuses((s) => ({ ...s, [e.nodeId]: e.status }));\n setStatusText((t) => ({ ...t, [e.nodeId]: e.text }));\n appendFeed({ level: \"status\", text: `${e.nodeId} → ${e.status}${e.text ? ` (${e.text})` : \"\"}`, nodeId: e.nodeId });\n break;\n case \"node-output\":\n setOutputs((o) => ({ ...o, [e.nodeId]: e.value }));\n appendFeed({ level: \"info\", text: `${e.nodeId}.${e.portId} = ${preview(e.value)}`, nodeId: e.nodeId, detail: e.value });\n break;\n case \"log\":\n appendFeed({ level: e.level, text: e.message, nodeId: e.nodeId, detail: e.detail });\n break;\n case \"run-start\":\n appendFeed({ level: \"info\", text: \"▶ run started\" });\n break;\n case \"run-end\":\n appendFeed({ level: e.ok ? \"info\" : \"error\", text: e.ok ? \"✓ run complete\" : \"✗ run failed\" });\n break;\n case \"run-error\":\n appendFeed({ level: \"error\", text: e.error });\n break;\n }\n function appendFeed(partial: Omit<FlowRunFeedEntry, \"id\" | \"at\">) {\n setFeed((f) => {\n const entry: FlowRunFeedEntry = { id: `${Date.now()}_${f.length}`, at: Date.now(), ...partial };\n const next = [...f, entry];\n return next.length > maxFeed ? next.slice(next.length - maxFeed) : next;\n });\n }\n },\n [maxFeed],\n );\n\n const run = useCallback(\n async (graph: FlowGraph, executors: ExecutorRegistry, options: RunOptions = {}) => {\n if (running) {\n return { ok: false, outputs: {}, error: \"another run is already in progress\" } satisfies RunResult;\n }\n const controller = new AbortController();\n abortRef.current = controller;\n // Reset previous statuses for the nodes we're about to run.\n const idleStatuses: Record<string, NodeRunStatus> = {};\n for (const n of graph.nodes) idleStatuses[n.id] = \"idle\";\n setStatuses(idleStatuses);\n setStatusText({});\n setOutputs({});\n setRunning(true);\n try {\n const result = await runFlow(graph, executors, handleEvent, { ...options, signal: controller.signal });\n setLastResult(result);\n return result;\n } finally {\n setRunning(false);\n abortRef.current = null;\n }\n },\n [handleEvent, running],\n );\n\n const cancel = useCallback(() => abortRef.current?.abort(), []);\n\n const reset = useCallback(() => {\n setStatuses({});\n setStatusText({});\n setOutputs({});\n setFeed([]);\n setLastResult(null);\n }, []);\n\n return { statuses, statusText, outputs, feed, running, lastResult, run, cancel, reset };\n}\n\n/**\n * Write each reactive kind's latest run output into its `data.output`, so its\n * card can render the computed value live. Non-reactive kinds are returned\n * untouched. Pair with `applyStatusesToNodes` before rendering.\n */\nexport function applyOutputsToNodes<TNode extends { id: string; type?: string; data: any }>(\n nodes: TNode[],\n outputs: Record<string, unknown>,\n): TNode[] {\n return nodes.map((n) => {\n const kind = getNodeKind((n.data as any)?.kind ?? n.type ?? \"\");\n if (!kind?.reactive || !(n.id in outputs)) return n;\n return { ...n, data: { ...n.data, output: outputs[n.id] } };\n });\n}\n\n/** Merge runtime statuses into nodes for rendering. */\nexport function applyStatusesToNodes<TNode extends { id: string; data: any }>(\n nodes: TNode[],\n statuses: Record<string, NodeRunStatus>,\n statusText: Record<string, string | undefined>,\n): TNode[] {\n return nodes.map((n) => ({\n ...n,\n data: {\n ...n.data,\n status: statuses[n.id] ?? n.data?.status ?? \"idle\",\n statusText: statusText[n.id] ?? n.data?.statusText,\n },\n }));\n}\n\nfunction preview(v: unknown): string {\n try {\n const s = JSON.stringify(v);\n return s && s.length > 60 ? s.slice(0, 57) + \"…\" : (s ?? String(v));\n } catch {\n return String(v);\n }\n}\n","import { useCallback, useState } from \"react\";\nimport {\n addEdge,\n applyEdgeChanges,\n applyNodeChanges,\n type Connection,\n type Edge,\n type EdgeChange,\n type NodeChange,\n} from \"@xyflow/react\";\nimport type { FlowEdge, FlowGraph, FlowNode } from \"../types\";\n\nexport type UseFlowStateReturn = {\n nodes: FlowNode[];\n edges: FlowEdge[];\n setNodes: React.Dispatch<React.SetStateAction<FlowNode[]>>;\n setEdges: React.Dispatch<React.SetStateAction<FlowEdge[]>>;\n /**\n * Replace nodes AND edges atomically in a single commit. Use this for any op\n * that touches both (delete-with-edge-prune, undo/redo restore, setGraph):\n * calling `setNodes` then `setEdges` is NOT atomic in controlled mode (each\n * closes over a stale `value`), so the second write clobbers the first.\n */\n setGraph: (graph: FlowGraph) => void;\n onNodesChange: (changes: NodeChange[]) => void;\n onEdgesChange: (changes: EdgeChange[]) => void;\n onConnect: (connection: Connection) => void;\n /** Snapshot the current graph (suitable for serialization). */\n toGraph: () => FlowGraph;\n};\n\n/**\n * useFlowState — React Flow's standard controlled-state plumbing in one hook.\n * Spread into <FlowCanvas>.\n */\nexport function useFlowState(initial: FlowGraph): UseFlowStateReturn {\n const [nodes, setNodes] = useState<FlowNode[]>(initial.nodes);\n const [edges, setEdges] = useState<FlowEdge[]>(initial.edges);\n\n const onNodesChange = useCallback((changes: NodeChange[]) => {\n setNodes((ns) => applyNodeChanges(changes, ns) as FlowNode[]);\n }, []);\n const onEdgesChange = useCallback((changes: EdgeChange[]) => {\n setEdges((es) => applyEdgeChanges(changes, es));\n }, []);\n const onConnect = useCallback((connection: Connection) => {\n setEdges((es) => addEdge(connection, es) as Edge[]);\n }, []);\n\n const setGraph = useCallback((graph: FlowGraph) => {\n // Two useState writes in one event are batched, so this IS atomic here.\n setNodes(graph.nodes);\n setEdges(graph.edges);\n }, []);\n\n const toGraph = useCallback(() => ({ nodes, edges }), [nodes, edges]);\n\n return { nodes, edges, setNodes, setEdges, setGraph, onNodesChange, onEdgesChange, onConnect, toGraph };\n}\n","import type { FlowGraph } from \"../types\";\n\n/**\n * Undo/redo history — a pure, React-free snapshot controller. The editor pushes\n * a graph snapshot BEFORE each committing mutation; `undo`/`redo` swap snapshots\n * between the past/future stacks. Kept free of React so it can be unit-tested\n * and reused by any host (or a headless driver).\n *\n * Coalescing (collapsing a burst of setState calls from one logical op into a\n * single undo step) is the caller's job — see `useFlowHistory`.\n */\nexport type HistoryController = {\n /** Record `graph` as an undo point. Clears the redo stack (new branch). */\n push: (graph: FlowGraph) => void;\n /** Pop the last undo point; `current` is pushed onto the redo stack. */\n undo: (current: FlowGraph) => FlowGraph | null;\n /** Pop the last redo point; `current` is pushed back onto the undo stack. */\n redo: (current: FlowGraph) => FlowGraph | null;\n canUndo: () => boolean;\n canRedo: () => boolean;\n clear: () => void;\n /** Test/inspection helper — sizes of the two stacks. */\n size: () => { past: number; future: number };\n};\n\nexport function createHistory(limit = 100): HistoryController {\n let past: FlowGraph[] = [];\n let future: FlowGraph[] = [];\n\n return {\n push(graph) {\n past.push(graph);\n if (past.length > limit) past.shift();\n future = [];\n },\n undo(current) {\n const prev = past.pop();\n if (prev === undefined) return null;\n future.push(current);\n return prev;\n },\n redo(current) {\n const next = future.pop();\n if (next === undefined) return null;\n past.push(current);\n return next;\n },\n canUndo: () => past.length > 0,\n canRedo: () => future.length > 0,\n clear() {\n past = [];\n future = [];\n },\n size: () => ({ past: past.length, future: future.length }),\n };\n}\n","import { useCallback, useMemo, useRef, useState } from \"react\";\nimport type { EdgeChange, NodeChange } from \"@xyflow/react\";\nimport type { FlowGraph } from \"../types\";\nimport { createHistory } from \"./history\";\nimport type { UseFlowStateReturn } from \"./use-flow-state\";\n\nexport type UseFlowHistoryReturn = {\n /** The flow sink wrapped so committing mutations snapshot for undo first. */\n flow: UseFlowStateReturn;\n undo: () => void;\n redo: () => void;\n canUndo: boolean;\n canRedo: boolean;\n /** Snapshot the current graph as an undo point (before a programmatic edit). */\n capture: () => void;\n /** Wire to `<FlowCanvas onNodeDragStart>` — snapshots the pre-drag graph. */\n onNodeDragStart: () => void;\n};\n\n/**\n * useFlowHistory — the commit/undo pipeline. Wraps a flow sink (the uncontrolled\n * `useFlowState` hook OR the controlled adapter) so every *committing* mutation\n * records a snapshot first, giving undo/redo without the editor threading\n * history through each call site. This is the single interception point the\n * two-sink architecture otherwise lacks.\n *\n * Granularity: a burst of setState calls from one logical op (e.g. a\n * delete = setNodes+setEdges) is coalesced into ONE undo step; transient\n * interactive changes (drag-move, dimension-measure, selection) are NOT captured\n * — a drag is captured once at `onNodeDragStart` instead.\n */\nexport function useFlowHistory(flow: UseFlowStateReturn): UseFlowHistoryReturn {\n const history = useRef(createHistory()).current;\n const restoring = useRef(false);\n const coalesced = useRef(false);\n const [, bump] = useState(0);\n const rerender = useCallback(() => bump((n) => n + 1), []);\n\n // Latest graph via a ref, so capture never reads a stale snapshot.\n const graphRef = useRef<FlowGraph>({ nodes: flow.nodes, edges: flow.edges });\n graphRef.current = { nodes: flow.nodes, edges: flow.edges };\n\n const capture = useCallback(() => {\n if (restoring.current || coalesced.current) return;\n coalesced.current = true;\n queueMicrotask(() => {\n coalesced.current = false;\n });\n history.push(graphRef.current);\n rerender();\n }, [history, rerender]);\n\n const restore = useCallback(\n (g: FlowGraph | null) => {\n if (!g) return;\n restoring.current = true;\n flow.setGraph(g);\n queueMicrotask(() => {\n restoring.current = false;\n });\n rerender();\n },\n [flow, rerender],\n );\n\n const undo = useCallback(() => restore(history.undo(graphRef.current)), [history, restore]);\n const redo = useCallback(() => restore(history.redo(graphRef.current)), [history, restore]);\n\n const wrapped = useMemo<UseFlowStateReturn>(\n () => ({\n ...flow,\n setNodes: (next) => {\n capture();\n flow.setNodes(next);\n },\n setEdges: (next) => {\n capture();\n flow.setEdges(next);\n },\n setGraph: (g) => {\n capture();\n flow.setGraph(g);\n },\n onNodesChange: (changes: NodeChange[]) => {\n // Only structural removes commit; position/dimensions/select are transient.\n if (!restoring.current && changes.some((c) => c.type === \"remove\")) capture();\n flow.onNodesChange(changes);\n },\n onEdgesChange: (changes: EdgeChange[]) => {\n if (!restoring.current && changes.some((c) => c.type === \"remove\")) capture();\n flow.onEdgesChange(changes);\n },\n onConnect: (conn) => {\n capture();\n flow.onConnect(conn);\n },\n }),\n [flow, capture],\n );\n\n return {\n flow: wrapped,\n undo,\n redo,\n canUndo: history.canUndo(),\n canRedo: history.canRedo(),\n capture,\n onNodeDragStart: capture,\n };\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/nodes/NodeShell.tsx","../src/components/nodes/TriggerNode.tsx","../src/components/nodes/ActionNode.tsx","../src/components/nodes/DecisionNode.tsx","../src/components/nodes/OutputNode.tsx","../src/components/nodes/SubgraphNode.tsx","../src/components/nodes/index.ts","../src/components/FlowEditor/graph-ops.ts","../src/components/canvas/helper-lines.ts","../src/components/canvas/HelperLines.tsx","../src/components/canvas/use-resolved-color-mode.ts","../src/components/canvas/FlowCanvas.tsx","../src/components/FlowViewer/FlowViewer.tsx"],"names":["jsx","memo","jsxs","reconnectEdge","cx","useState","useMemo","index"],"mappings":"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","file":"chunk-DHUFUDEX.js","sourcesContent":["import { type ReactNode, memo } from \"react\";\nimport { Handle, Position, type NodeProps } from \"@xyflow/react\";\nimport type { FlowNode, NodeRunStatus, PortDescriptor } from \"../../types\";\n\nexport type NodeShellProps = {\n /** Required: the xyflow node this is rendering. */\n node: NodeProps<FlowNode>;\n /** Accent color for the title bar / status ring. */\n accent: string;\n /** Tag/label shown to the left of the title (e.g. \"TRIGGER\", \"ACTION\"). */\n tag: string;\n /** Optional icon glyph (single-character string is fine). */\n icon?: ReactNode;\n /** Whether to show input handles on the left. Defaults true. */\n showInputs?: boolean;\n /** Whether to show output handles on the right. Defaults true. */\n showOutputs?: boolean;\n /** Body content under the title bar. */\n children?: ReactNode;\n};\n\n/**\n * Shared chrome for every kit node — title bar, accent border, status ring,\n * port handles. Specific node kinds compose this with their body content.\n */\nfunction NodeShellInner({\n node,\n accent,\n tag,\n icon,\n showInputs = true,\n showOutputs = true,\n children,\n}: NodeShellProps) {\n const data = node.data;\n const status: NodeRunStatus = data.status ?? \"idle\";\n const inputs = data.inputs ?? defaultInputs(showInputs);\n const outputs = data.outputs ?? defaultOutputs(showOutputs);\n\n return (\n <div\n className={[\"ff-node\", `ff-node--status-${status}`, node.selected ? \"ff-node--selected\" : \"\"].filter(Boolean).join(\" \")}\n style={{ borderColor: node.selected ? accent : undefined }}\n >\n <header className=\"ff-node__header\" style={{ background: accent }}>\n <span className=\"ff-node__icon\" aria-hidden>{icon ?? null}</span>\n <span className=\"ff-node__tag\">{tag}</span>\n <span className=\"ff-node__label\">{data.label}</span>\n {status !== \"idle\" && <StatusDot status={status} />}\n </header>\n\n {data.description && <p className=\"ff-node__desc\">{data.description}</p>}\n {children && <div className=\"ff-node__body\">{children}</div>}\n {data.statusText && <p className=\"ff-node__status-text\">{data.statusText}</p>}\n\n {inputs.map((p, i) => (\n <Handle\n key={p.id}\n type=\"target\"\n position={Position.Left}\n id={p.id}\n style={portStyle(i, inputs.length)}\n title={p.label ?? p.id}\n />\n ))}\n {outputs.map((p, i) => (\n <Handle\n key={p.id}\n type=\"source\"\n position={Position.Right}\n id={p.id}\n style={portStyle(i, outputs.length)}\n title={p.label ?? p.id}\n />\n ))}\n </div>\n );\n}\n\nexport const NodeShell = memo(NodeShellInner);\n\nfunction defaultInputs(show: boolean): PortDescriptor[] {\n return show ? [{ id: \"in\" }] : [];\n}\nfunction defaultOutputs(show: boolean): PortDescriptor[] {\n return show ? [{ id: \"out\" }] : [];\n}\n\nfunction portStyle(i: number, total: number): React.CSSProperties {\n if (total <= 1) return {};\n const slot = (100 / (total + 1)) * (i + 1);\n return { top: `${slot}%` };\n}\n\nfunction StatusDot({ status }: { status: NodeRunStatus }) {\n return <span className={`ff-node__dot ff-node__dot--${status}`} aria-label={`status ${status}`} />;\n}\n","import { memo } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { FlowNode } from \"../../types\";\nimport { NodeShell } from \"./NodeShell\";\n\n/** Entry-point node — outputs only, no inputs. */\nfunction TriggerNodeInner(props: NodeProps<FlowNode>) {\n return <NodeShell node={props} accent=\"#10b981\" tag=\"TRIGGER\" icon=\"⚡\" showInputs={false} />;\n}\nexport const TriggerNode = memo(TriggerNodeInner);\n","import { memo } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { FlowNode } from \"../../types\";\nimport { NodeShell } from \"./NodeShell\";\n\n/** General-purpose work node — inputs and outputs. */\nfunction ActionNodeInner(props: NodeProps<FlowNode>) {\n return <NodeShell node={props} accent=\"#3b82f6\" tag=\"ACTION\" icon=\"▸\" />;\n}\nexport const ActionNode = memo(ActionNodeInner);\n","import { memo } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { FlowNode, PortDescriptor } from \"../../types\";\nimport { NodeShell } from \"./NodeShell\";\n\nconst DEFAULT_BRANCHES: PortDescriptor[] = [\n { id: \"true\", label: \"true\" },\n { id: \"false\", label: \"false\" },\n];\n\n/** Branching node — multiple typed outputs, one input. */\nfunction DecisionNodeInner(props: NodeProps<FlowNode>) {\n // If the host hasn't customised outputs, default to a true/false split.\n if (!props.data.outputs) {\n props = { ...props, data: { ...props.data, outputs: DEFAULT_BRANCHES } };\n }\n return <NodeShell node={props} accent=\"#f59e0b\" tag=\"DECISION\" icon=\"◇\" />;\n}\nexport const DecisionNode = memo(DecisionNodeInner);\n","import { memo } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { FlowNode } from \"../../types\";\nimport { NodeShell } from \"./NodeShell\";\n\n/** Terminal node — receives the workflow's final result; no outputs. */\nfunction OutputNodeInner(props: NodeProps<FlowNode>) {\n return <NodeShell node={props} accent=\"#a855f7\" tag=\"OUTPUT\" icon=\"●\" showOutputs={false} />;\n}\nexport const OutputNode = memo(OutputNodeInner);\n","import { memo } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { FlowNode, SubgraphNodeData } from \"../../types\";\nimport { NodeShell } from \"./NodeShell\";\n\n/**\n * SubgraphNode — collapses a group of nodes behind a single facade with\n * inputs and outputs that map to the inner graph's boundary ports. The\n * runtime treats it like an action node: when running, it dispatches to\n * the registered \"subgraph\" executor (host decides expand vs inline).\n *\n * v0.1 just renders the facade. Expand/collapse interactions and inner-\n * graph editing are deferred — host apps can implement those by toggling\n * `data.collapsed` and rendering a nested <FlowCanvas> when expanded.\n */\nfunction SubgraphNodeInner(props: NodeProps<FlowNode>) {\n const data = props.data as SubgraphNodeData;\n const childCount = data.childIds?.length ?? 0;\n return (\n <NodeShell node={props} accent=\"#0ea5e9\" tag=\"SUBGRAPH\" icon=\"❐\">\n <div className=\"ff-subgraph__meta\">\n <span>{childCount} node{childCount === 1 ? \"\" : \"s\"}</span>\n <span>{data.collapsed === false ? \"expanded\" : \"collapsed\"}</span>\n </div>\n </NodeShell>\n );\n}\nexport const SubgraphNode = memo(SubgraphNodeInner);\n","import type { NodeTypes } from \"@xyflow/react\";\nimport { TriggerNode } from \"./TriggerNode\";\nimport { ActionNode } from \"./ActionNode\";\nimport { DecisionNode } from \"./DecisionNode\";\nimport { OutputNode } from \"./OutputNode\";\nimport { NoteNode } from \"./NoteNode\";\nimport { SubgraphNode } from \"./SubgraphNode\";\n\nexport { TriggerNode, ActionNode, DecisionNode, OutputNode, NoteNode, SubgraphNode };\nexport { LaneNode } from \"./LaneNode\";\nexport { NodeShell, type NodeShellProps } from \"./NodeShell\";\n\n/**\n * Default xyflow `nodeTypes` map covering the kit. Spread into your own:\n *\n * <FlowCanvas nodeTypes={{ ...defaultNodeTypes, custom: MyNode }} ... />\n */\nexport const defaultNodeTypes: NodeTypes = {\n trigger: TriggerNode,\n action: ActionNode,\n decision: DecisionNode,\n output: OutputNode,\n note: NoteNode,\n subgraph: SubgraphNode,\n};\n","import { reconnectEdge as xyReconnectEdge, type Connection, type Edge } from \"@xyflow/react\";\nimport type { FlowGraph, FlowNode } from \"../../types\";\n\n/**\n * Remove nodes AND every edge attached to them.\n *\n * Deleting a node without pruning its edges leaves danglers that point at\n * nothing — they survive a round-trip through the schema and blow up the\n * runner, so the two always move together.\n */\nexport function removeNodes(graph: FlowGraph, ids: string[]): FlowGraph {\n if (ids.length === 0) return graph;\n const doomed = new Set(ids);\n\n return {\n nodes: graph.nodes.filter((n) => !doomed.has(n.id)),\n edges: graph.edges.filter((e) => !doomed.has(e.source) && !doomed.has(e.target)),\n };\n}\n\n/** Remove edges by id, leaving nodes untouched. */\nexport function removeEdges(edges: Edge[], ids: string[]): Edge[] {\n if (ids.length === 0) return edges;\n const doomed = new Set(ids);\n\n return edges.filter((e) => !doomed.has(e.id));\n}\n\n/**\n * Set (or clear) an edge's label.\n *\n * An empty/whitespace label is removed rather than stored as `\"\"` — xyflow\n * renders an empty label as an empty chip on the wire, and a blank key would\n * survive export into the workflow schema.\n */\nexport function setEdgeLabel(edges: Edge[], id: string, label: string | undefined): Edge[] {\n const next = label?.trim();\n return edges.map((e) => {\n if (e.id !== id) return e;\n if (!next) {\n const { label: _drop, ...rest } = e;\n return rest as Edge;\n }\n return { ...e, label: next };\n });\n}\n\n/** Copy a node with a fresh id, offset so it doesn't sit exactly on top. */\nexport function duplicateNode(node: FlowNode, id: string, offset = 40): FlowNode {\n return {\n ...node,\n id,\n position: { x: node.position.x + offset, y: node.position.y + offset },\n // Deep copy so the clone's config edits don't mutate the original.\n data: JSON.parse(JSON.stringify(node.data ?? {})),\n } as FlowNode;\n}\n\n/**\n * Clone a set of nodes AND the edges internal to that set, remapping every id.\n * This is the piece `duplicateNode` lacks: a copy/paste (or duplicate-selection)\n * that preserves the wiring *between* the copied nodes. Edges with an endpoint\n * outside the set are dropped (they'd dangle). A `parentId` pointing inside the\n * set is remapped; one pointing outside is detached.\n */\nexport function cloneSubgraph(\n nodes: FlowNode[],\n edges: Edge[],\n opts: { makeId: () => string; offset?: number },\n): { nodes: FlowNode[]; edges: Edge[]; idMap: Map<string, string> } {\n const offset = opts.offset ?? 40;\n const idMap = new Map<string, string>();\n for (const n of nodes) idMap.set(n.id, opts.makeId());\n\n const clonedNodes = nodes.map((n) => {\n const cloned = duplicateNode(n, idMap.get(n.id)!, offset) as any;\n const parentId = (n as any).parentId;\n if (parentId && idMap.has(parentId)) cloned.parentId = idMap.get(parentId);\n else if (parentId) delete cloned.parentId;\n return cloned as FlowNode;\n });\n\n const clonedEdges = edges\n .filter((e) => idMap.has(e.source) && idMap.has(e.target))\n .map((e) => ({ ...e, id: opts.makeId(), source: idMap.get(e.source)!, target: idMap.get(e.target)! }));\n\n return { nodes: clonedNodes, edges: clonedEdges, idMap };\n}\n\n/**\n * Rewire one edge's endpoint(s) — wraps xyflow's `reconnectEdge`. Keeps the\n * edge's id (`shouldReplaceId: false`) so its label and identity survive the\n * rewire instead of being regenerated from the new endpoints.\n */\nexport function reconnectEdge(edges: Edge[], oldEdge: Edge, newConnection: Connection): Edge[] {\n return xyReconnectEdge(oldEdge, newConnection, edges, { shouldReplaceId: false });\n}\n\nexport type AlignEdge = \"left\" | \"hcenter\" | \"right\" | \"top\" | \"vcenter\" | \"bottom\";\n\nconst nodeW = (n: FlowNode): number => (n as any).width ?? (n as any).measured?.width ?? 0;\nconst nodeH = (n: FlowNode): number => (n as any).height ?? (n as any).measured?.height ?? 0;\n\n/** Align a selection to a shared edge/center of its bounding box. */\nexport function alignNodes(nodes: FlowNode[], edge: AlignEdge): FlowNode[] {\n if (nodes.length < 2) return nodes;\n const minL = Math.min(...nodes.map((n) => n.position.x));\n const maxR = Math.max(...nodes.map((n) => n.position.x + nodeW(n)));\n const minT = Math.min(...nodes.map((n) => n.position.y));\n const maxB = Math.max(...nodes.map((n) => n.position.y + nodeH(n)));\n const cx = (minL + maxR) / 2;\n const cy = (minT + maxB) / 2;\n return nodes.map((n) => {\n let { x, y } = n.position;\n if (edge === \"left\") x = minL;\n else if (edge === \"right\") x = maxR - nodeW(n);\n else if (edge === \"hcenter\") x = cx - nodeW(n) / 2;\n else if (edge === \"top\") y = minT;\n else if (edge === \"bottom\") y = maxB - nodeH(n);\n else if (edge === \"vcenter\") y = cy - nodeH(n) / 2;\n return { ...n, position: { x, y } };\n });\n}\n\n/**\n * Order nodes so every parent precedes its children — xyflow misrenders (and\n * warns) when a child appears before its `parentId` in the array. Stable\n * otherwise. Apply at the render boundary once grouping is in play.\n */\nexport function sortNodesParentFirst<T extends { id: string; parentId?: string }>(nodes: T[]): T[] {\n const byId = new Map(nodes.map((n) => [n.id, n] as const));\n const seen = new Set<string>();\n const out: T[] = [];\n const visit = (n: T) => {\n if (seen.has(n.id)) return;\n const pid = (n as any).parentId as string | undefined;\n if (pid && byId.has(pid) && !seen.has(pid)) visit(byId.get(pid)!);\n seen.add(n.id);\n out.push(n);\n };\n for (const n of nodes) visit(n);\n return out;\n}\n\n/** Absolute position of a node, accounting for one level of parent nesting. */\nfunction absolutePosition(node: FlowNode, nodes: FlowNode[]): { x: number; y: number } {\n const pid = (node as any).parentId as string | undefined;\n if (!pid) return node.position;\n const parent = nodes.find((n) => n.id === pid);\n return parent ? { x: node.position.x + parent.position.x, y: node.position.y + parent.position.y } : node.position;\n}\n\n/**\n * Put a node inside a lane/container: set `parentId` + `extent:'parent'` and\n * convert its position to be relative to the lane. Idempotent-safe; a no-op if\n * either id is missing or they're the same node.\n */\nexport function assignToLane(nodes: FlowNode[], nodeId: string, laneId: string): FlowNode[] {\n if (nodeId === laneId) return nodes;\n const node = nodes.find((n) => n.id === nodeId);\n const lane = nodes.find((n) => n.id === laneId);\n if (!node || !lane) return nodes;\n const abs = absolutePosition(node, nodes);\n const laneAbs = absolutePosition(lane, nodes);\n const rel = { x: abs.x - laneAbs.x, y: abs.y - laneAbs.y };\n return nodes.map((n) => (n.id === nodeId ? ({ ...n, parentId: laneId, extent: \"parent\", position: rel } as FlowNode) : n));\n}\n\n/** Take a node out of its lane: drop `parentId`/`extent`, restore absolute position. */\nexport function removeFromLane(nodes: FlowNode[], nodeId: string): FlowNode[] {\n const node = nodes.find((n) => n.id === nodeId);\n if (!node || !(node as any).parentId) return nodes;\n const abs = absolutePosition(node, nodes);\n return nodes.map((n) => {\n if (n.id !== nodeId) return n;\n const { parentId: _p, extent: _e, ...rest } = n as any;\n return { ...rest, position: abs } as FlowNode;\n });\n}\n\n/**\n * Stack lanes into contiguous rows (horizontal) or columns (vertical) — the\n * \"fixed rows/columns\" behavior. `isLane` picks which nodes are lanes; they're\n * ordered by their current cross-axis position and repacked from the first\n * lane's origin. Each lane keeps its own size (independently resizable).\n */\nexport function stackLanes(\n nodes: FlowNode[],\n isLane: (n: FlowNode) => boolean,\n opts: { orientation?: \"horizontal\" | \"vertical\"; gap?: number } = {},\n): FlowNode[] {\n const orientation = opts.orientation ?? \"horizontal\";\n const gap = opts.gap ?? 12;\n const vertical = orientation === \"vertical\";\n const lanes = nodes.filter(isLane).sort((a, b) => (vertical ? a.position.x - b.position.x : a.position.y - b.position.y));\n if (lanes.length === 0) return nodes;\n const originX = lanes[0].position.x;\n const originY = lanes[0].position.y;\n const moves = new Map<string, { x: number; y: number }>();\n let cursor = vertical ? originX : originY;\n for (const lane of lanes) {\n moves.set(lane.id, vertical ? { x: cursor, y: originY } : { x: originX, y: cursor });\n cursor += (vertical ? ((lane as any).width ?? 320) : ((lane as any).height ?? 160)) + gap;\n }\n return nodes.map((n) => (moves.has(n.id) ? { ...n, position: moves.get(n.id)! } : n));\n}\n\n/** Evenly distribute a selection's gaps along an axis (needs 3+ nodes). */\nexport function distributeNodes(nodes: FlowNode[], axis: \"h\" | \"v\"): FlowNode[] {\n if (nodes.length < 3) return nodes;\n const size = (n: FlowNode) => (axis === \"h\" ? nodeW(n) : nodeH(n));\n const coord = (n: FlowNode) => (axis === \"h\" ? n.position.x : n.position.y);\n const sorted = [...nodes].sort((a, b) => coord(a) - coord(b));\n const start = coord(sorted[0]);\n const last = sorted[sorted.length - 1];\n const end = coord(last) + size(last);\n const totalSize = sorted.reduce((s, n) => s + size(n), 0);\n const gap = (end - start - totalSize) / (sorted.length - 1);\n const posById = new Map<string, number>();\n let cursor = start;\n for (const n of sorted) {\n posById.set(n.id, cursor);\n cursor += size(n) + gap;\n }\n return nodes.map((n) => {\n const p = posById.get(n.id)!;\n return { ...n, position: axis === \"h\" ? { ...n.position, x: p } : { ...n.position, y: p } };\n });\n}\n","import type { FlowNode } from \"../../types\";\n\nexport type HelperLineChange = { id: string; position?: { x: number; y: number } };\n\nexport type HelperLinesResult = {\n /** Y of a horizontal guide line (flow coords), if the drag aligns on Y. */\n horizontal?: number;\n /** X of a vertical guide line (flow coords), if the drag aligns on X. */\n vertical?: number;\n /** The snapped position to apply to the dragged node. */\n snapPosition: { x?: number; y?: number };\n};\n\nconst w = (n: FlowNode): number => (n as any).width ?? (n as any).measured?.width ?? 0;\nconst h = (n: FlowNode): number => (n as any).height ?? (n as any).measured?.height ?? 0;\n\n/**\n * Compute alignment guide lines (and a snapped position) for a node being\n * dragged to `change.position`, against the other nodes. Standard \"helper\n * lines\" algorithm: match the dragged node's left/right/top/bottom edges to any\n * other node's edges within `distance`, snapping to the nearest. Pure + testable.\n */\nexport function getHelperLines(change: HelperLineChange, nodes: FlowNode[], distance = 6): HelperLinesResult {\n const result: HelperLinesResult = { snapPosition: { x: undefined, y: undefined } };\n const a = nodes.find((n) => n.id === change.id);\n if (!a || !change.position) return result;\n\n const A = {\n left: change.position.x,\n right: change.position.x + w(a),\n top: change.position.y,\n bottom: change.position.y + h(a),\n width: w(a),\n height: h(a),\n };\n let vDist = distance;\n let hDist = distance;\n\n for (const b of nodes) {\n if (b.id === a.id) continue;\n const B = { left: b.position.x, right: b.position.x + w(b), top: b.position.y, bottom: b.position.y + h(b) };\n\n // Vertical guides (X alignment).\n const ll = Math.abs(A.left - B.left);\n if (ll < vDist) { result.snapPosition.x = B.left; result.vertical = B.left; vDist = ll; }\n const rr = Math.abs(A.right - B.right);\n if (rr < vDist) { result.snapPosition.x = B.right - A.width; result.vertical = B.right; vDist = rr; }\n const lr = Math.abs(A.left - B.right);\n if (lr < vDist) { result.snapPosition.x = B.right; result.vertical = B.right; vDist = lr; }\n const rl = Math.abs(A.right - B.left);\n if (rl < vDist) { result.snapPosition.x = B.left - A.width; result.vertical = B.left; vDist = rl; }\n\n // Horizontal guides (Y alignment).\n const tt = Math.abs(A.top - B.top);\n if (tt < hDist) { result.snapPosition.y = B.top; result.horizontal = B.top; hDist = tt; }\n const bb = Math.abs(A.bottom - B.bottom);\n if (bb < hDist) { result.snapPosition.y = B.bottom - A.height; result.horizontal = B.bottom; hDist = bb; }\n const tb = Math.abs(A.top - B.bottom);\n if (tb < hDist) { result.snapPosition.y = B.bottom; result.horizontal = B.bottom; hDist = tb; }\n const bt = Math.abs(A.bottom - B.top);\n if (bt < hDist) { result.snapPosition.y = B.top - A.height; result.horizontal = B.top; hDist = bt; }\n }\n\n return result;\n}\n","import { ViewportPortal } from \"@xyflow/react\";\n\n/**\n * HelperLines — alignment guides drawn during a drag. Rendered in flow\n * coordinate space (ViewportPortal), so the lines track pan/zoom. Positions come\n * from `getHelperLines`.\n */\nexport function HelperLines({ horizontal, vertical }: { horizontal?: number; vertical?: number }) {\n if (horizontal === undefined && vertical === undefined) return null;\n return (\n <ViewportPortal>\n {vertical !== undefined && (\n <div\n className=\"ff-helper-line\"\n style={{ position: \"absolute\", transform: `translateX(${vertical}px)`, top: -5000, height: 10000, width: 1, pointerEvents: \"none\" }}\n />\n )}\n {horizontal !== undefined && (\n <div\n className=\"ff-helper-line\"\n style={{ position: \"absolute\", transform: `translateY(${horizontal}px)`, left: -5000, width: 10000, height: 1, pointerEvents: \"none\" }}\n />\n )}\n </ViewportPortal>\n );\n}\n","import { useEffect, useState } from \"react\";\n\n/** The resolved mode React Flow and our own `ff-` tokens both understand. */\nexport type FlowColorMode = \"light\" | \"dark\";\n\n/**\n * What a host may PASS. React Flow's own `ColorMode` includes `\"system\"`, and\n * it is meaningful here rather than something to cast away: it means \"follow\n * the environment\", which is the same job `undefined` now does.\n */\nexport type FlowColorModeInput = FlowColorMode | \"system\";\n\n/**\n * Read the app's theme off the document, the way every host in this suite\n * signals it.\n *\n * Checked in the order a host actually sets them: an explicit `data-theme`\n * beats a `.dark` class (a host that writes both, like the showcase, is\n * consistent either way), and only when neither is present does the OS\n * preference decide.\n */\nfunction readDocumentTheme(): FlowColorMode {\n if (typeof document === \"undefined\") return \"light\";\n\n const root = document.documentElement;\n const attr = root.getAttribute(\"data-theme\");\n if (attr === \"dark\" || attr === \"light\") return attr;\n if (root.classList.contains(\"dark\")) return \"dark\";\n\n return typeof window !== \"undefined\" && window.matchMedia?.(\"(prefers-color-scheme: dark)\").matches\n ? \"dark\"\n : \"light\";\n}\n\n/**\n * The colour mode the canvas should actually use.\n *\n * **Why this exists.** `colorMode` used to be passed straight through to React\n * Flow, so a host that did not supply one got React Flow's own default —\n * `light` — no matter what the surrounding app was doing. Our `ff-` styles\n * still looked right, because they hang off an ancestor `.dark`, which is\n * exactly what made the bug hard to see: the nodes we style were fine while\n * React Flow's own layer stayed light underneath. Any node whose kind is not\n * registered falls back to React Flow's default node, and on a dark page that\n * is a white box with unreadable text. Edges, handles, the selection rectangle\n * and the controls were light too.\n *\n * So an unset `colorMode` now means \"follow the app\", not \"light\". Passing one\n * explicitly still wins — a canvas deliberately pinned light on a dark page is\n * a real thing, and this does not take it away.\n *\n * The subscription matters as much as the initial read: a theme toggle changes\n * an attribute on `<html>`, which triggers no React render on its own, so\n * without an observer the canvas would be correct on load and wrong the moment\n * someone flipped the switch.\n */\nexport function useResolvedColorMode(explicit?: FlowColorModeInput): FlowColorMode {\n // Start light on the server and on first paint. Reading the DOM in the\n // initialiser would differ between server and client markup and trip\n // hydration; the effect below corrects it before anything is visible.\n const [resolved, setResolved] = useState<FlowColorMode>(\"light\");\n\n // `\"system\"` is treated exactly like an unset prop: both mean \"follow the\n // environment\", and collapsing them here keeps one resolution path.\n const pinned = explicit === \"light\" || explicit === \"dark\" ? explicit : undefined;\n\n useEffect(() => {\n if (pinned) return;\n if (typeof document === \"undefined\") return;\n\n const sync = () => setResolved(readDocumentTheme());\n sync();\n\n const observer = new MutationObserver(sync);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\", \"data-theme\"],\n });\n\n const media = window.matchMedia?.(\"(prefers-color-scheme: dark)\");\n media?.addEventListener?.(\"change\", sync);\n\n return () => {\n observer.disconnect();\n media?.removeEventListener?.(\"change\", sync);\n };\n }, [pinned]);\n\n return pinned ?? resolved;\n}\n","import {\n type CSSProperties,\n type ReactNode,\n type WheelEvent as ReactWheelEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n ReactFlow,\n Background,\n BackgroundVariant,\n Controls,\n MiniMap,\n type DefaultEdgeOptions,\n type Edge,\n type EdgeTypes,\n type FitViewOptions,\n type NodeTypes,\n type ReactFlowProps,\n} from \"@xyflow/react\";\nimport \"@xyflow/react/dist/style.css\";\nimport { defaultNodeTypes } from \"../nodes\";\nimport { createConnectionValidator, type ConnectionValidatorOptions } from \"../../registry/connection\";\nimport { sortNodesParentFirst } from \"../FlowEditor/graph-ops\";\nimport { getHelperLines } from \"./helper-lines\";\nimport { HelperLines } from \"./HelperLines\";\nimport type { FlowNode } from \"../../types\";\nimport { useResolvedColorMode } from \"./use-resolved-color-mode\";\n\n/**\n * With wheel-zoom off, Shift+wheel still zooms — and must not ALSO scroll the\n * page while it does. React Flow's own `preventScrolling` is all-or-nothing, so\n * the modifier case is handled here: swallow the gesture that zooms, leave the\n * one that doesn't alone.\n *\n * Capture phase, so it lands before React Flow's own wheel handling.\n */\nfunction preventScrollWhileZooming(event: ReactWheelEvent<HTMLDivElement>): void {\n if (event.shiftKey) event.preventDefault();\n}\n\n/**\n * The three React Flow props that together decide what the wheel does.\n *\n * Extracted because they only make sense as a set, and getting the set wrong is\n * invisible in a screenshot: the canvas looks fine and feels broken. This is\n * the unit worth testing — mounting a canvas to assert it would be testing\n * d3-zoom through jsdom.\n *\n * - **on** (default): no modifier needed, and the page never scrolls under a\n * wheel that is zooming.\n * - **off**: zoom moves to Shift+wheel and the bare wheel goes back to the\n * page. `preventScrolling` alone cannot express that — left true it swallows\n * the bare wheel (page frozen, nothing zooms), left false it lets Shift+wheel\n * zoom *and* scroll at once — so the handler covers the modifier case.\n */\nexport function wheelZoomProps(zoomOnWheel: boolean): {\n zoomActivationKeyCode: string | null;\n preventScrolling: boolean;\n onWheelCapture?: (event: ReactWheelEvent<HTMLDivElement>) => void;\n} {\n return zoomOnWheel\n ? { zoomActivationKeyCode: null, preventScrolling: true }\n : {\n zoomActivationKeyCode: \"Shift\",\n preventScrolling: false,\n onWheelCapture: preventScrollWhileZooming,\n };\n}\n\nexport type FlowCanvasProps = Omit<ReactFlowProps<FlowNode, Edge>, \"nodes\" | \"edges\" | \"height\"> & {\n nodes: FlowNode[];\n edges: Edge[];\n /** Background variant. Default: \"dots\". */\n background?: BackgroundVariant | \"none\";\n /** Show pan/zoom/fit controls. Default true. */\n showControls?: boolean;\n /** Show minimap. Default false (turn on for big graphs). */\n showMinimap?: boolean;\n /** Pixel height; FlowCanvas expects a sized container. Default 600. */\n height?: number | string;\n /**\n * Enforce port-type compatibility on new connections. `true` (default) uses\n * the built-in validator: a connection is refused only when both ports\n * declare a concrete, differing `type` (so untyped graphs are unaffected),\n * and self-loops are blocked. Pass options to tune the rule, or `false` to\n * disable. An `isValidConnection` you pass yourself always takes precedence.\n */\n validateConnections?: boolean | ConnectionValidatorOptions;\n /** Show alignment guide lines while dragging, and snap to them. Default off. */\n showHelperLines?: boolean;\n /**\n * A bare mouse wheel over the canvas zooms it. Default **true**.\n *\n * Turn it off for a canvas embedded mid-page, where a reader scrolling past\n * would otherwise get trapped zooming. With it off the wheel scrolls the page\n * and **Shift+wheel** zooms instead.\n *\n * Either way, a wheel gesture that zooms never also scrolls the page — the\n * two happening at once is the thing that makes an embedded canvas feel\n * broken.\n */\n zoomOnWheel?: boolean;\n /** Optional toolbar / palette etc. rendered above the canvas. */\n toolbar?: ReactNode;\n className?: string;\n style?: CSSProperties;\n};\n\nconst DEFAULT_FIT_VIEW: FitViewOptions = { padding: 0.2 };\nconst DEFAULT_EDGE_OPTIONS: DefaultEdgeOptions = {\n type: \"smoothstep\",\n animated: false,\n};\n\n/**\n * FlowCanvas — themed React Flow surface with the kit's nodes registered\n * by default. Pass your own `nodeTypes` to extend; the kit's defaults are\n * merged behind yours.\n *\n * Hosts wire `onNodesChange` / `onEdgesChange` / `onConnect` themselves\n * (xyflow's standard pattern). The surrounding `useFlowState` hook in\n * `runtime/use-flow-state.ts` is a convenience that wires those for you.\n */\nexport function FlowCanvas({\n nodes,\n edges,\n background = BackgroundVariant.Dots,\n showControls = true,\n showMinimap = false,\n height = 600,\n validateConnections = true,\n isValidConnection,\n colorMode,\n showHelperLines = false,\n zoomOnWheel = true,\n onNodesChange,\n toolbar,\n nodeTypes,\n edgeTypes,\n className,\n style,\n ...rest\n}: FlowCanvasProps) {\n const mergedNodeTypes = useMemo<NodeTypes>(\n () => ({ ...defaultNodeTypes, ...(nodeTypes ?? {}) }),\n [nodeTypes],\n );\n\n // Read nodes live through a ref so the validator (built once) always sees the\n // current graph without being rebuilt on every node change.\n const nodesRef = useRef(nodes);\n nodesRef.current = nodes;\n const builtinValidator = useMemo(\n () =>\n validateConnections === false\n ? undefined\n : createConnectionValidator(\n () => nodesRef.current,\n validateConnections === true ? undefined : validateConnections,\n ),\n [validateConnections],\n );\n // A caller-supplied predicate wins; otherwise fall back to port-type validation.\n const resolvedIsValidConnection = isValidConnection ?? builtinValidator;\n\n const mergedEdgeTypes = useMemo<EdgeTypes | undefined>(\n () => (edgeTypes ? { ...edgeTypes } : undefined),\n [edgeTypes],\n );\n\n // xyflow requires a parent node to precede its children in the array; grouping\n // (swimlanes) can produce any order, so normalize it here at the boundary.\n const orderedNodes = useMemo(() => sortNodesParentFirst(nodes), [nodes]);\n\n // Helper lines: on a single-node drag, snap to aligned edges + show guides.\n const [helperLines, setHelperLines] = useState<{ horizontal?: number; vertical?: number }>({});\n const handleNodesChange = useCallback(\n (changes: any[]) => {\n if (showHelperLines) {\n const pos = changes.filter((c) => c.type === \"position\" && c.position);\n if (pos.length === 1 && pos[0].dragging) {\n const lines = getHelperLines(pos[0], nodesRef.current);\n if (lines.snapPosition.x !== undefined) pos[0].position.x = lines.snapPosition.x;\n if (lines.snapPosition.y !== undefined) pos[0].position.y = lines.snapPosition.y;\n setHelperLines({ horizontal: lines.horizontal, vertical: lines.vertical });\n } else {\n setHelperLines({});\n }\n }\n onNodesChange?.(changes as any);\n },\n [showHelperLines, onNodesChange],\n );\n\n /**\n * An unset `colorMode` means \"follow the app\", NOT \"light\".\n *\n * It used to pass straight through to React Flow, whose own default is\n * light — so on a dark page React Flow's layer stayed light underneath our\n * `ff-` styles, which look right because they hang off an ancestor `.dark`.\n * Any node kind without a registered type falls back to React Flow's default\n * node: a white box with unreadable text on a dark canvas. Passing a mode\n * explicitly still wins.\n */\n const resolvedColorMode = useResolvedColorMode(colorMode);\n\n return (\n <div\n className={[\n \"ff-canvas\",\n // colorMode drives BOTH react-flow's chrome (below) and our `ff-` styles\n // via the shared `.dark` class / light opt-out — one theme signal.\n resolvedColorMode === \"dark\" ? \"dark\" : \"\",\n resolvedColorMode === \"light\" ? \"ff-canvas--light\" : \"\",\n className ?? \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n style={{ height, ...style }}\n >\n {toolbar && <div className=\"ff-canvas__toolbar\">{toolbar}</div>}\n <div className=\"ff-canvas__surface\">\n <ReactFlow\n nodes={orderedNodes}\n edges={edges}\n onNodesChange={handleNodesChange}\n colorMode={resolvedColorMode}\n nodeTypes={mergedNodeTypes}\n edgeTypes={mergedEdgeTypes}\n fitView\n fitViewOptions={DEFAULT_FIT_VIEW}\n defaultEdgeOptions={DEFAULT_EDGE_OPTIONS}\n proOptions={{ hideAttribution: true }}\n // Wheel zooms by default; `zoomOnWheel={false}` moves that onto\n // Shift+wheel and gives the bare wheel back to the page. The three\n // props only make sense as a set — see wheelZoomProps.\n {...wheelZoomProps(zoomOnWheel)}\n isValidConnection={resolvedIsValidConnection}\n {...rest}\n >\n {background !== \"none\" && (\n <Background variant={background as BackgroundVariant} gap={20} size={1} color=\"rgba(0,0,0,0.18)\" />\n )}\n {showControls && <Controls className=\"ff-controls\" position=\"bottom-right\" />}\n {showMinimap && <MiniMap className=\"ff-minimap\" pannable zoomable />}\n {showHelperLines && <HelperLines horizontal={helperLines.horizontal} vertical={helperLines.vertical} />}\n </ReactFlow>\n </div>\n </div>\n );\n}\n","import { useMemo, type CSSProperties, type ReactNode } from \"react\";\nimport { FlowCanvas } from \"../canvas\";\nimport { buildNodeTypes } from \"../../registry\";\nimport { categoryAccent, getNodeKind } from \"../../registry/registry\";\nimport type { FlowGraph, FlowNode } from \"../../types\";\n\n/** Outcome of one node in a run, for annotating the graph after the fact. */\nexport type FlowNodeStatus = \"ok\" | \"running\" | \"failed\" | \"skipped\" | \"pending\";\n\nexport interface FlowViewerClassNames {\n root?: string;\n list?: string;\n row?: string;\n rowIndex?: string;\n rowTitle?: string;\n rowDescription?: string;\n rowStatus?: string;\n}\n\nexport interface FlowViewerProps {\n /** The graph to show. */\n graph: FlowGraph;\n /**\n * `canvas` draws the graph. `list` renders the nodes as rows — for a docs\n * page, a narrow column, print, or an audit view, where a pan-zoom surface is\n * the wrong shape and often not usable at all.\n */\n variant?: \"canvas\" | \"list\";\n /** Canvas height. Ignored by `list`. Default 480. */\n height?: number | string;\n /** Canvas minimap. Default false. */\n showMinimap?: boolean;\n /** Canvas pan/zoom/fit controls. Default true. */\n showControls?: boolean;\n /**\n * Per-node run outcome, keyed by node id. Lets the same component serve\n * \"here is the workflow\" and \"here is what happened on Tuesday\".\n */\n statuses?: Record<string, FlowNodeStatus>;\n /** Controlled selection. */\n selectedNodeId?: string | null;\n /** Omit and nothing is clickable — a viewer with no handler is inert. */\n onSelectNode?: (node: FlowNode) => void;\n className?: string;\n classNames?: FlowViewerClassNames;\n style?: CSSProperties;\n /** Rendered when the graph has no nodes. */\n empty?: ReactNode;\n}\n\nconst STATUS_LABEL: Record<FlowNodeStatus, string> = {\n ok: \"ok\",\n running: \"running\",\n failed: \"failed\",\n skipped: \"skipped\",\n pending: \"pending\",\n};\n\n/**\n * FlowViewer — a workflow, read-only.\n *\n * **Read-only by construction, not by configuration.** There is no prop that\n * makes this editable, because a viewer that can be switched into an editor is\n * a viewer somebody eventually switches into an editor by accident. Before this\n * existed the only way to show a flow was `FlowEditor` (the whole editor) or\n * `FlowCanvas` plus four React Flow flags a consumer had to know to pass —\n * assembly, not an affordance, and nothing stopped the next person shipping a\n * fully editable canvas where they wanted a picture.\n *\n * Node titles come from the registry, so `overrideNodeKind()` renames apply\n * here too.\n */\nexport function FlowViewer({\n graph,\n variant = \"canvas\",\n height = 480,\n showMinimap = false,\n showControls = true,\n statuses,\n selectedNodeId = null,\n onSelectNode,\n className,\n classNames = {},\n style,\n empty,\n}: FlowViewerProps) {\n const nodeTypes = useMemo(() => buildNodeTypes(), []);\n\n const rows = useMemo(\n () =>\n graph.nodes.map((node, index) => {\n const kind = getNodeKind(node.data?.kind ?? node.type ?? \"\");\n return {\n node,\n index,\n title: kind?.label ?? node.data?.label ?? node.data?.kind ?? node.id,\n description: kind?.description ?? null,\n accent: kind?.accent ?? categoryAccent(kind?.category ?? \"custom\"),\n status: statuses?.[node.id] ?? null,\n };\n }),\n [graph.nodes, statuses],\n );\n\n if (graph.nodes.length === 0) {\n return (\n <div className={cx(\"ff-viewer ff-viewer--empty\", className, classNames.root)} style={style}>\n {empty ?? <span className=\"ff-viewer__empty\">This flow has no nodes.</span>}\n </div>\n );\n }\n\n if (variant === \"list\") {\n return (\n <div\n className={cx(\"ff-viewer ff-viewer--list\", className, classNames.root)}\n style={style}\n data-flow-viewer=\"list\"\n >\n <ol className={cx(\"ff-viewer__list\", classNames.list)}>\n {rows.map(({ node, index, title, description, accent, status }) => {\n const selected = node.id === selectedNodeId;\n const Row = onSelectNode ? \"button\" : \"div\";\n\n return (\n <li key={node.id}>\n <Row\n {...(onSelectNode\n ? { type: \"button\" as const, onClick: () => onSelectNode(node) }\n : {})}\n className={cx(\n \"ff-viewer__row\",\n selected && \"ff-viewer__row--selected\",\n onSelectNode && \"ff-viewer__row--interactive\",\n classNames.row,\n )}\n data-flow-viewer-node={node.id}\n data-flow-viewer-status={status ?? undefined}\n aria-current={selected || undefined}\n >\n <span\n className={cx(\"ff-viewer__index\", classNames.rowIndex)}\n style={{ backgroundColor: accent }}\n aria-hidden\n >\n {index + 1}\n </span>\n\n <span className=\"ff-viewer__body\">\n <span className={cx(\"ff-viewer__title\", classNames.rowTitle)}>{title}</span>\n {description && (\n <span className={cx(\"ff-viewer__desc\", classNames.rowDescription)}>\n {description}\n </span>\n )}\n </span>\n\n {status && (\n <span\n className={cx(\n \"ff-viewer__status\",\n `ff-viewer__status--${status}`,\n classNames.rowStatus,\n )}\n >\n {STATUS_LABEL[status]}\n </span>\n )}\n </Row>\n </li>\n );\n })}\n </ol>\n </div>\n );\n }\n\n return (\n <div\n className={cx(\"ff-viewer ff-viewer--canvas\", className, classNames.root)}\n style={style}\n data-flow-viewer=\"canvas\"\n >\n <FlowCanvas\n nodes={graph.nodes}\n edges={graph.edges}\n nodeTypes={nodeTypes}\n height={height}\n showControls={showControls}\n showMinimap={showMinimap}\n // The read-only contract. Every mutation path React Flow offers is\n // closed here rather than left to the caller to remember.\n nodesDraggable={false}\n nodesConnectable={false}\n nodesFocusable={Boolean(onSelectNode)}\n edgesFocusable={false}\n elementsSelectable={Boolean(onSelectNode)}\n deleteKeyCode={null}\n selectionKeyCode={null}\n multiSelectionKeyCode={null}\n connectOnClick={false}\n // A canvas embedded mid-page must not trap a reader's scroll.\n zoomOnScroll={false}\n onNodeClick={onSelectNode ? (_, node) => onSelectNode(node as FlowNode) : undefined}\n fitView\n />\n </div>\n );\n}\n\nfunction cx(...parts: Array<string | false | null | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n"]}
|