@particle-academy/fancy-flow 0.53.0 → 0.55.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.
Files changed (59) hide show
  1. package/dist/{ConfigFieldRenderer-Bc9Txnql.d.cts → HumanPrompt-CPl-Spmp.d.cts} +75 -1
  2. package/dist/{ConfigFieldRenderer-Bt3RGT7Z.d.ts → HumanPrompt-DlJSFi3F.d.ts} +75 -1
  3. package/dist/{chunk-CIBW5ATA.js → chunk-22OJOD4X.js} +7 -3
  4. package/dist/chunk-22OJOD4X.js.map +1 -0
  5. package/dist/{chunk-VWANLNL5.js → chunk-E3AGYTHP.js} +3 -3
  6. package/dist/{chunk-VWANLNL5.js.map → chunk-E3AGYTHP.js.map} +1 -1
  7. package/dist/{chunk-FTGVVKWX.js → chunk-HMEI2LFU.js} +4 -4
  8. package/dist/{chunk-FTGVVKWX.js.map → chunk-HMEI2LFU.js.map} +1 -1
  9. package/dist/{chunk-WCFRKXH5.js → chunk-KP4TBF3A.js} +3 -3
  10. package/dist/{chunk-WCFRKXH5.js.map → chunk-KP4TBF3A.js.map} +1 -1
  11. package/dist/{chunk-FG3C7LIG.js → chunk-L4QAAGLV.js} +3 -3
  12. package/dist/{chunk-FG3C7LIG.js.map → chunk-L4QAAGLV.js.map} +1 -1
  13. package/dist/{chunk-FH6MWLKD.js → chunk-YVLOLS25.js} +3 -3
  14. package/dist/{chunk-FH6MWLKD.js.map → chunk-YVLOLS25.js.map} +1 -1
  15. package/dist/durable/index.d.cts +1 -1
  16. package/dist/durable/index.d.ts +1 -1
  17. package/dist/durable.cjs +5 -1
  18. package/dist/durable.cjs.map +1 -1
  19. package/dist/durable.js +1 -1
  20. package/dist/engine.cjs +5 -1
  21. package/dist/engine.cjs.map +1 -1
  22. package/dist/engine.d.cts +2 -2
  23. package/dist/engine.d.ts +2 -2
  24. package/dist/engine.js +3 -3
  25. package/dist/fields/react-fancy.cjs +66 -0
  26. package/dist/fields/react-fancy.cjs.map +1 -1
  27. package/dist/fields/react-fancy.d.cts +35 -2
  28. package/dist/fields/react-fancy.d.ts +35 -2
  29. package/dist/fields/react-fancy.js +67 -2
  30. package/dist/fields/react-fancy.js.map +1 -1
  31. package/dist/index.cjs +34 -10
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +15 -4
  34. package/dist/index.d.ts +15 -4
  35. package/dist/index.js +40 -20
  36. package/dist/index.js.map +1 -1
  37. package/dist/registry.cjs +5 -1
  38. package/dist/registry.cjs.map +1 -1
  39. package/dist/registry.js +2 -2
  40. package/dist/{run-cohort-BPIOpE8A.d.ts → run-cohort-C1nRh_mi.d.ts} +1 -1
  41. package/dist/{run-cohort-r-L8dMED.d.cts → run-cohort-CBRAUj-z.d.cts} +1 -1
  42. package/dist/{run-flow-COdAOFg2.d.cts → run-flow-2XsHBwpd.d.cts} +31 -0
  43. package/dist/{run-flow-DJ7KYT6E.d.ts → run-flow-D7AOCcfE.d.ts} +31 -0
  44. package/dist/runtime/index.d.cts +3 -3
  45. package/dist/runtime/index.d.ts +3 -3
  46. package/dist/runtime.cjs +5 -1
  47. package/dist/runtime.cjs.map +1 -1
  48. package/dist/runtime.js +3 -3
  49. package/dist/schema.cjs +5 -1
  50. package/dist/schema.cjs.map +1 -1
  51. package/dist/schema.js +2 -2
  52. package/dist/screens.cjs +5 -1
  53. package/dist/screens.cjs.map +1 -1
  54. package/dist/screens.js +4 -4
  55. package/dist/ux.cjs +5 -1
  56. package/dist/ux.cjs.map +1 -1
  57. package/dist/ux.js +1 -1
  58. package/package.json +2 -2
  59. package/dist/chunk-CIBW5ATA.js.map +0 -1
package/dist/engine.d.cts CHANGED
@@ -1,7 +1,7 @@
1
- export { R as RunOptions, a as RunResult, r as runFlow } from './run-flow-COdAOFg2.cjs';
1
+ export { R as RunOptions, a as RunResult, r as runFlow } from './run-flow-2XsHBwpd.cjs';
2
2
  import { F as FlowGraph, R as RunEvent, N as NodeExecutor } from './types-JFYjPJAG.cjs';
3
3
  export { A as ActionNodeData, B as BaseNodeData, D as DecisionNodeData, E as ExecutorRegistry, d as FlowEdge, a as FlowNode, e as FlowNodeData, f as FlowNodeKind, g as NodeRunStatus, h as NoteNodeData, O as OutputNodeData, P as PortDescriptor, b as RunIdentity, c as RunIdentityJson, S as SubgraphNodeData, T as TriggerNodeData, i as escapeSegment } from './types-JFYjPJAG.cjs';
4
- export { C as CohortGuard, a as CohortOptions, b as CohortPolicy, c as CohortResult, r as runCohort } from './run-cohort-r-L8dMED.cjs';
4
+ export { C as CohortGuard, a as CohortOptions, b as CohortPolicy, c as CohortResult, r as runCohort } from './run-cohort-CBRAUj-z.cjs';
5
5
  export { d as defaultConfigFor, g as getNodeKind, k as kindIds, l as listNodeKinds, r as registerNodeKind, a as resolveKindId, v as validateConfig } from './registry-C6TMfiD_.cjs';
6
6
  export { b as CapabilityRequirement, C as ConfigField, M as ManifestProblem, c as ManifestValidation, d as NODE_MANIFEST_SCHEMA_VERSION, a as NodeCategory, N as NodeKindDefinition, e as NodePackageManifest, f as NodeRuntimeId, g as NodeRuntimeSpec, O as OutputField, h as OutputShape, P as PortSpec, S as SideEffects, i as checkCapabilities, j as checkRuntimeSupport, s as satisfiesRange, v as validateNodeManifest } from './types-3sPauVRT.cjs';
7
7
  import { P as PauseAwaiting } from './pause-9iT4tCEV.cjs';
package/dist/engine.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- export { R as RunOptions, a as RunResult, r as runFlow } from './run-flow-DJ7KYT6E.js';
1
+ export { R as RunOptions, a as RunResult, r as runFlow } from './run-flow-D7AOCcfE.js';
2
2
  import { F as FlowGraph, R as RunEvent, N as NodeExecutor } from './types-JFYjPJAG.js';
3
3
  export { A as ActionNodeData, B as BaseNodeData, D as DecisionNodeData, E as ExecutorRegistry, d as FlowEdge, a as FlowNode, e as FlowNodeData, f as FlowNodeKind, g as NodeRunStatus, h as NoteNodeData, O as OutputNodeData, P as PortDescriptor, b as RunIdentity, c as RunIdentityJson, S as SubgraphNodeData, T as TriggerNodeData, i as escapeSegment } from './types-JFYjPJAG.js';
4
- export { C as CohortGuard, a as CohortOptions, b as CohortPolicy, c as CohortResult, r as runCohort } from './run-cohort-BPIOpE8A.js';
4
+ export { C as CohortGuard, a as CohortOptions, b as CohortPolicy, c as CohortResult, r as runCohort } from './run-cohort-C1nRh_mi.js';
5
5
  export { d as defaultConfigFor, g as getNodeKind, k as kindIds, l as listNodeKinds, r as registerNodeKind, a as resolveKindId, v as validateConfig } from './registry-3RkSYrMi.js';
6
6
  export { b as CapabilityRequirement, C as ConfigField, M as ManifestProblem, c as ManifestValidation, d as NODE_MANIFEST_SCHEMA_VERSION, a as NodeCategory, N as NodeKindDefinition, e as NodePackageManifest, f as NodeRuntimeId, g as NodeRuntimeSpec, O as OutputField, h as OutputShape, P as PortSpec, S as SideEffects, i as checkCapabilities, j as checkRuntimeSupport, s as satisfiesRange, v as validateNodeManifest } from './types-s643U1Hi.js';
7
7
  import { P as PauseAwaiting } from './pause-9iT4tCEV.js';
package/dist/engine.js CHANGED
@@ -1,8 +1,8 @@
1
- export { runCohort } from './chunk-WCFRKXH5.js';
1
+ export { runCohort } from './chunk-KP4TBF3A.js';
2
2
  import { decodePause } from './chunk-UEOE6B52.js';
3
3
  export { LEGACY_PAUSE_PREFIXES, PAUSE_PREFIX, decodePause, encodePause, isPause, pauseForHuman } from './chunk-UEOE6B52.js';
4
- import { runFlow, getNodeKind, resolveNodePorts } from './chunk-CIBW5ATA.js';
5
- export { RunIdentity, defaultConfigFor, escapeSegment, getNodeKind, kindIds, listNodeKinds, registerNodeKind, resolveKindId, runFlow, validateConfig } from './chunk-CIBW5ATA.js';
4
+ import { runFlow, getNodeKind, resolveNodePorts } from './chunk-22OJOD4X.js';
5
+ export { RunIdentity, defaultConfigFor, escapeSegment, getNodeKind, kindIds, listNodeKinds, registerNodeKind, resolveKindId, runFlow, validateConfig } from './chunk-22OJOD4X.js';
6
6
  import './chunk-F5RPRB7A.js';
7
7
  import { isResolutionFailure, registerLlmClient, registerWorkflowResolver } from './chunk-USL4FMFU.js';
8
8
 
@@ -33,7 +33,73 @@ var jsonFieldRenderer = ({
33
33
  var reactFancyFieldRenderers = {
34
34
  json: jsonFieldRenderer
35
35
  };
36
+ var humanFieldRenderers = {
37
+ text: ({ field, id, value, onChange, autoFocusRef }) => /* @__PURE__ */ jsxRuntime.jsx(
38
+ reactFancy.Input,
39
+ {
40
+ id,
41
+ "data-ff-field": field.key,
42
+ ref: autoFocusRef,
43
+ placeholder: field.placeholder,
44
+ value: String(value ?? ""),
45
+ onValueChange: onChange
46
+ }
47
+ ),
48
+ textarea: ({ field, id, value, onChange, autoFocusRef }) => /* @__PURE__ */ jsxRuntime.jsx(
49
+ reactFancy.Textarea,
50
+ {
51
+ id,
52
+ "data-ff-field": field.key,
53
+ ref: autoFocusRef,
54
+ placeholder: field.placeholder,
55
+ rows: 3,
56
+ value: String(value ?? ""),
57
+ onValueChange: onChange
58
+ }
59
+ ),
60
+ number: ({ field, id, value, onChange, autoFocusRef }) => /* @__PURE__ */ jsxRuntime.jsx(
61
+ reactFancy.Input,
62
+ {
63
+ id,
64
+ "data-ff-field": field.key,
65
+ ref: autoFocusRef,
66
+ type: "number",
67
+ placeholder: field.placeholder,
68
+ value: String(value ?? ""),
69
+ onValueChange: (v) => onChange(v === "" ? "" : Number(v))
70
+ }
71
+ ),
72
+ select: ({ field, id, value, onChange }) => /* @__PURE__ */ jsxRuntime.jsx(
73
+ reactFancy.Select,
74
+ {
75
+ id,
76
+ "data-ff-field": field.key,
77
+ list: (field.options ?? []).map((o) => ({ value: o.value, label: o.label })),
78
+ value: String(value ?? ""),
79
+ onValueChange: onChange
80
+ }
81
+ ),
82
+ switch: ({ field, id, value, onChange }) => /* @__PURE__ */ jsxRuntime.jsx(
83
+ reactFancy.Switch,
84
+ {
85
+ id,
86
+ "data-ff-field": field.key,
87
+ checked: !!value,
88
+ onCheckedChange: onChange
89
+ }
90
+ ),
91
+ date: ({ field, id, value, onChange }) => /* @__PURE__ */ jsxRuntime.jsx(
92
+ reactFancy.DatePicker,
93
+ {
94
+ id,
95
+ "data-ff-field": field.key,
96
+ value: String(value ?? ""),
97
+ onValueChange: onChange
98
+ }
99
+ )
100
+ };
36
101
 
102
+ exports.humanFieldRenderers = humanFieldRenderers;
37
103
  exports.jsonFieldRenderer = jsonFieldRenderer;
38
104
  exports.reactFancyFieldRenderers = reactFancyFieldRenderers;
39
105
  //# sourceMappingURL=react-fancy.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/fields/react-fancy.tsx"],"names":["jsx","JsonEditor"],"mappings":";;;;;;AA6CO,IAAM,oBAAyC,CAAC;AAAA,EACrD,KAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,KAAgC;AAC9B,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,MAAA,EAAQ,OAAO,IAAA;AAElC,EAAA;AAAA;AAAA;AAAA;AAAA,oBAIEA,cAAA;AAAA,MAACC,qBAAA;AAAA,MAAA;AAAA,QAIC,EAAA;AAAA,QACA,iBAAe,KAAA,CAAM,GAAA;AAAA,QACrB,KAAA,EAAQ,SAAS,EAAC;AAAA,QAClB,QAAA,EAAU,CAAC,IAAA,KAAoB,QAAA,CAAS,IAAI,CAAA;AAAA,QAI5C,QAAQ,KAAA,CAAM,MAAA;AAAA,QACd,IAAA,EAAK,MAAA;AAAA,QACL,IAAA,EAAK,IAAA;AAAA,QACL,WAAW,KAAA,CAAM;AAAA;AAAA;AACnB;AAEJ;AAKO,IAAM,wBAAA,GAAgE;AAAA,EAC3E,IAAA,EAAM;AACR","file":"react-fancy.cjs","sourcesContent":["/**\n * `@particle-academy/fancy-flow/fields/react-fancy` — richer config fields for\n * hosts that already run react-fancy.\n *\n * ```tsx\n * import { reactFancyFieldRenderers } from \"@particle-academy/fancy-flow/fields/react-fancy\";\n *\n * <FlowEditor … fieldRenderers={reactFancyFieldRenderers} />\n * ```\n *\n * ## Why an opt-in subpath rather than the panel itself\n *\n * fancy-flow themes every surface through a `--ff-*` custom-property layer that\n * a host overrides on `.ff-editor`. react-fancy's primitives are hardcoded\n * Tailwind palette classes and read no custom properties — so building them\n * into the panel would trade the theming contract for a nicer widget, which is\n * the trade `panel-labels.test.tsx` already decided against.\n *\n * Making it a subpath keeps both: react-fancy stays an OPTIONAL peer, a\n * standalone install pays nothing, and a Tailwind host opts in with one prop.\n * Same shape as `/llm/vercel-ai` and `/rich-input`.\n *\n * ## What it currently covers\n *\n * Just `json`, because that is the only built-in whose fallback is a raw\n * textarea. The others are already purpose-built controls; replacing them would\n * be churn. This is a map, so a host can spread it and add their own:\n *\n * ```tsx\n * fieldRenderers={{ ...reactFancyFieldRenderers, \"trigger-filters\": myRenderer }}\n * ```\n */\nimport { JsonEditor, type JsonValue } from \"@particle-academy/react-fancy\";\nimport type {\n ConfigFieldRenderContext,\n ConfigFieldRenderFn,\n} from \"../components/NodeConfigPanel/ConfigFieldRenderer\";\n\n/**\n * Render a `json` config field as a react-fancy `JsonEditor`.\n *\n * Returns `null` for every other field type — the seam treats `null` as \"not\n * mine\", so this can be handed over wholesale without claiming controls it has\n * no business replacing.\n */\nexport const jsonFieldRenderer: ConfigFieldRenderFn = ({\n field,\n value,\n onChange,\n id,\n}: ConfigFieldRenderContext) => {\n if (field.type !== \"json\") return null;\n\n return (\n // JSX rather than `createElement` for one concrete reason: `data-*` props\n // are special-cased by JSX but hit excess-property checking in a\n // `createElement` object literal, so the agent handle would not typecheck.\n <JsonEditor\n // The panel's `<label htmlFor>` points at this id, and the Human+\n // contract wants a stable handle an agent can target without guessing at\n // the DOM. Both reach the editor's root element via its rest spread.\n id={id}\n data-ff-field={field.key}\n value={(value ?? {}) as JsonValue}\n onChange={(next: JsonValue) => onChange(next)}\n // `keyMap` is what makes this more than a prettier textarea: it declares\n // a type per path, which picks the control and reports contradictions. A\n // string by design, so it survives an MCP round-trip.\n keyMap={field.keyMap}\n mode=\"edit\"\n size=\"sm\"\n rootLabel={field.label}\n />\n );\n};\n\n/**\n * The full renderer map. Spread it to add your own types alongside.\n */\nexport const reactFancyFieldRenderers: Record<string, ConfigFieldRenderFn> = {\n json: jsonFieldRenderer,\n};\n"]}
1
+ {"version":3,"sources":["../../src/fields/react-fancy.tsx"],"names":["jsx","JsonEditor","Input","Textarea","Select","Switch","DatePicker"],"mappings":"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","file":"react-fancy.cjs","sourcesContent":["/**\n * `@particle-academy/fancy-flow/fields/react-fancy` — richer config fields for\n * hosts that already run react-fancy.\n *\n * ```tsx\n * import { reactFancyFieldRenderers } from \"@particle-academy/fancy-flow/fields/react-fancy\";\n *\n * <FlowEditor … fieldRenderers={reactFancyFieldRenderers} />\n * ```\n *\n * ## Why an opt-in subpath rather than the panel itself\n *\n * fancy-flow themes every surface through a `--ff-*` custom-property layer that\n * a host overrides on `.ff-editor`. react-fancy's primitives are hardcoded\n * Tailwind palette classes and read no custom properties — so building them\n * into the panel would trade the theming contract for a nicer widget, which is\n * the trade `panel-labels.test.tsx` already decided against.\n *\n * Making it a subpath keeps both: react-fancy stays an OPTIONAL peer, a\n * standalone install pays nothing, and a Tailwind host opts in with one prop.\n * Same shape as `/llm/vercel-ai` and `/rich-input`.\n *\n * ## What it currently covers\n *\n * Just `json`, because that is the only built-in whose fallback is a raw\n * textarea. The others are already purpose-built controls; replacing them would\n * be churn. This is a map, so a host can spread it and add their own:\n *\n * ```tsx\n * fieldRenderers={{ ...reactFancyFieldRenderers, \"trigger-filters\": myRenderer }}\n * ```\n */\nimport {\n DatePicker,\n Input,\n JsonEditor,\n Select,\n Switch,\n Textarea,\n type JsonValue,\n} from \"@particle-academy/react-fancy\";\nimport type {\n ConfigFieldRenderContext,\n ConfigFieldRenderFn,\n} from \"../components/NodeConfigPanel/ConfigFieldRenderer\";\nimport type { HumanFieldRenderers } from \"../components/FlowEditor/HumanPrompt\";\n\n/**\n * Render a `json` config field as a react-fancy `JsonEditor`.\n *\n * Returns `null` for every other field type — the seam treats `null` as \"not\n * mine\", so this can be handed over wholesale without claiming controls it has\n * no business replacing.\n */\nexport const jsonFieldRenderer: ConfigFieldRenderFn = ({\n field,\n value,\n onChange,\n id,\n}: ConfigFieldRenderContext) => {\n if (field.type !== \"json\") return null;\n\n return (\n // JSX rather than `createElement` for one concrete reason: `data-*` props\n // are special-cased by JSX but hit excess-property checking in a\n // `createElement` object literal, so the agent handle would not typecheck.\n <JsonEditor\n // The panel's `<label htmlFor>` points at this id, and the Human+\n // contract wants a stable handle an agent can target without guessing at\n // the DOM. Both reach the editor's root element via its rest spread.\n id={id}\n data-ff-field={field.key}\n value={(value ?? {}) as JsonValue}\n onChange={(next: JsonValue) => onChange(next)}\n // `keyMap` is what makes this more than a prettier textarea: it declares\n // a type per path, which picks the control and reports contradictions. A\n // string by design, so it survives an MCP round-trip.\n keyMap={field.keyMap}\n mode=\"edit\"\n size=\"sm\"\n rootLabel={field.label}\n />\n );\n};\n\n/**\n * The full renderer map. Spread it to add your own types alongside.\n */\nexport const reactFancyFieldRenderers: Record<string, ConfigFieldRenderFn> = {\n json: jsonFieldRenderer,\n};\n\n/* ------------------------------------------------------------------------- *\n * Pause-form controls\n * ------------------------------------------------------------------------- */\n\n/**\n * react-fancy controls for the `user_input` / `human_approval` pause form.\n *\n * ```tsx\n * import { humanFieldRenderers } from \"@particle-academy/fancy-flow/fields/react-fancy\";\n *\n * <FlowEditor … humanFieldRenderers={humanFieldRenderers} />\n * ```\n *\n * ## Why this is opt-in rather than the default\n *\n * Rule 2 of the suite says our surfaces compose react-fancy rather than\n * hand-rolling what a primitive already covers, and the pause form's built-ins\n * are native elements. That is not a gap in the kit — react-fancy has every\n * primitive needed — it is a PACKAGING constraint: react-fancy is an OPTIONAL\n * peer, `HumanPrompt` ships in the main entry, and importing it there would\n * make a standalone `npm install @particle-academy/fancy-flow` fail to resolve\n * at import time while bypassing the `--ff-*` token layer hosts theme\n * `.ff-editor` with.\n *\n * This map is how a host that HAS react-fancy gets the Fancy controls anyway,\n * with one prop and no cost to anyone else. Same shape and same reasoning as\n * `reactFancyFieldRenderers` above.\n *\n * ## What it covers, and what it deliberately does not\n *\n * `datetime` is absent: react-fancy's `DatePicker` is date-only, so claiming\n * the type here would render a control that silently drops the time half of a\n * value the field promised to collect. It falls through to the built-in\n * `<input type=\"datetime-local\">`, which does collect it. An honest gap beats a\n * control that looks right and loses data.\n */\nexport const humanFieldRenderers: HumanFieldRenderers = {\n text: ({ field, id, value, onChange, autoFocusRef }) => (\n <Input\n id={id}\n data-ff-field={field.key}\n ref={autoFocusRef as React.RefObject<HTMLInputElement> | undefined}\n placeholder={field.placeholder}\n value={String(value ?? \"\")}\n onValueChange={onChange}\n />\n ),\n\n textarea: ({ field, id, value, onChange, autoFocusRef }) => (\n <Textarea\n id={id}\n data-ff-field={field.key}\n ref={autoFocusRef as React.RefObject<HTMLTextAreaElement> | undefined}\n placeholder={field.placeholder}\n rows={3}\n value={String(value ?? \"\")}\n onValueChange={onChange}\n />\n ),\n\n number: ({ field, id, value, onChange, autoFocusRef }) => (\n <Input\n id={id}\n data-ff-field={field.key}\n ref={autoFocusRef as React.RefObject<HTMLInputElement> | undefined}\n type=\"number\"\n placeholder={field.placeholder}\n value={String(value ?? \"\")}\n // The built-in resolves a number field to a NUMBER, so this must too --\n // the value here is what resumes the paused run, and handing the next\n // node \"41\" where it resolved 41 before is a silent type change that no\n // test downstream would attribute to a renderer swap.\n onValueChange={(v) => onChange(v === \"\" ? \"\" : Number(v))}\n />\n ),\n\n select: ({ field, id, value, onChange }) => (\n <Select\n id={id}\n data-ff-field={field.key}\n list={(field.options ?? []).map((o) => ({ value: o.value, label: o.label }))}\n value={String(value ?? \"\")}\n onValueChange={onChange}\n />\n ),\n\n switch: ({ field, id, value, onChange }) => (\n <Switch\n id={id}\n data-ff-field={field.key}\n checked={!!value}\n onCheckedChange={onChange}\n />\n ),\n\n date: ({ field, id, value, onChange }) => (\n <DatePicker\n id={id}\n data-ff-field={field.key}\n value={String(value ?? \"\")}\n onValueChange={onChange}\n />\n ),\n};\n\n/*\n * `time` and `datetime` are ABSENT on purpose, and for different reasons.\n *\n * `datetime`: react-fancy's `DatePicker` is date-only. Claiming the type here\n * would render a control that silently drops the time half of a value the field\n * promised to collect.\n *\n * `time`: `TimePicker` accepts NO `id` and no `data-*` passthrough --\n * `TimePickerProps` is a closed interface of nine props, none of them an\n * identifier. It therefore cannot satisfy the two handles every control in this\n * form owes: the `id` its `<label htmlFor>` points at, and the `data-ff-field`\n * an agent drives the surface by. Wrapping it in a handle-bearing div would put\n * the label on a non-focusable element, which is worse than not claiming it.\n *\n * Both fall through to the built-in `<input type=\"time\">` /\n * `<input type=\"datetime-local\">`, which do carry the handles and do collect\n * the whole value. An honest gap beats a control that looks right and loses\n * either data or its handle.\n *\n * The `TimePicker` half is a react-fancy FINDING rather than a fancy-flow\n * limitation -- per the suite's second rule, a missing primitive capability is\n * filed against the kit rather than routed around locally.\n */\n"]}
@@ -1,4 +1,4 @@
1
- import { C as ConfigFieldRenderFn } from '../ConfigFieldRenderer-Bc9Txnql.cjs';
1
+ import { H as HumanFieldRenderers, C as ConfigFieldRenderFn } from '../HumanPrompt-CPl-Spmp.cjs';
2
2
  import 'react';
3
3
  import '../types-JFYjPJAG.cjs';
4
4
  import '@xyflow/react';
@@ -17,5 +17,38 @@ declare const jsonFieldRenderer: ConfigFieldRenderFn;
17
17
  * The full renderer map. Spread it to add your own types alongside.
18
18
  */
19
19
  declare const reactFancyFieldRenderers: Record<string, ConfigFieldRenderFn>;
20
+ /**
21
+ * react-fancy controls for the `user_input` / `human_approval` pause form.
22
+ *
23
+ * ```tsx
24
+ * import { humanFieldRenderers } from "@particle-academy/fancy-flow/fields/react-fancy";
25
+ *
26
+ * <FlowEditor … humanFieldRenderers={humanFieldRenderers} />
27
+ * ```
28
+ *
29
+ * ## Why this is opt-in rather than the default
30
+ *
31
+ * Rule 2 of the suite says our surfaces compose react-fancy rather than
32
+ * hand-rolling what a primitive already covers, and the pause form's built-ins
33
+ * are native elements. That is not a gap in the kit — react-fancy has every
34
+ * primitive needed — it is a PACKAGING constraint: react-fancy is an OPTIONAL
35
+ * peer, `HumanPrompt` ships in the main entry, and importing it there would
36
+ * make a standalone `npm install @particle-academy/fancy-flow` fail to resolve
37
+ * at import time while bypassing the `--ff-*` token layer hosts theme
38
+ * `.ff-editor` with.
39
+ *
40
+ * This map is how a host that HAS react-fancy gets the Fancy controls anyway,
41
+ * with one prop and no cost to anyone else. Same shape and same reasoning as
42
+ * `reactFancyFieldRenderers` above.
43
+ *
44
+ * ## What it covers, and what it deliberately does not
45
+ *
46
+ * `datetime` is absent: react-fancy's `DatePicker` is date-only, so claiming
47
+ * the type here would render a control that silently drops the time half of a
48
+ * value the field promised to collect. It falls through to the built-in
49
+ * `<input type="datetime-local">`, which does collect it. An honest gap beats a
50
+ * control that looks right and loses data.
51
+ */
52
+ declare const humanFieldRenderers: HumanFieldRenderers;
20
53
 
21
- export { jsonFieldRenderer, reactFancyFieldRenderers };
54
+ export { humanFieldRenderers, jsonFieldRenderer, reactFancyFieldRenderers };
@@ -1,4 +1,4 @@
1
- import { C as ConfigFieldRenderFn } from '../ConfigFieldRenderer-Bt3RGT7Z.js';
1
+ import { H as HumanFieldRenderers, C as ConfigFieldRenderFn } from '../HumanPrompt-DlJSFi3F.js';
2
2
  import 'react';
3
3
  import '../types-JFYjPJAG.js';
4
4
  import '@xyflow/react';
@@ -17,5 +17,38 @@ declare const jsonFieldRenderer: ConfigFieldRenderFn;
17
17
  * The full renderer map. Spread it to add your own types alongside.
18
18
  */
19
19
  declare const reactFancyFieldRenderers: Record<string, ConfigFieldRenderFn>;
20
+ /**
21
+ * react-fancy controls for the `user_input` / `human_approval` pause form.
22
+ *
23
+ * ```tsx
24
+ * import { humanFieldRenderers } from "@particle-academy/fancy-flow/fields/react-fancy";
25
+ *
26
+ * <FlowEditor … humanFieldRenderers={humanFieldRenderers} />
27
+ * ```
28
+ *
29
+ * ## Why this is opt-in rather than the default
30
+ *
31
+ * Rule 2 of the suite says our surfaces compose react-fancy rather than
32
+ * hand-rolling what a primitive already covers, and the pause form's built-ins
33
+ * are native elements. That is not a gap in the kit — react-fancy has every
34
+ * primitive needed — it is a PACKAGING constraint: react-fancy is an OPTIONAL
35
+ * peer, `HumanPrompt` ships in the main entry, and importing it there would
36
+ * make a standalone `npm install @particle-academy/fancy-flow` fail to resolve
37
+ * at import time while bypassing the `--ff-*` token layer hosts theme
38
+ * `.ff-editor` with.
39
+ *
40
+ * This map is how a host that HAS react-fancy gets the Fancy controls anyway,
41
+ * with one prop and no cost to anyone else. Same shape and same reasoning as
42
+ * `reactFancyFieldRenderers` above.
43
+ *
44
+ * ## What it covers, and what it deliberately does not
45
+ *
46
+ * `datetime` is absent: react-fancy's `DatePicker` is date-only, so claiming
47
+ * the type here would render a control that silently drops the time half of a
48
+ * value the field promised to collect. It falls through to the built-in
49
+ * `<input type="datetime-local">`, which does collect it. An honest gap beats a
50
+ * control that looks right and loses data.
51
+ */
52
+ declare const humanFieldRenderers: HumanFieldRenderers;
20
53
 
21
- export { jsonFieldRenderer, reactFancyFieldRenderers };
54
+ export { humanFieldRenderers, jsonFieldRenderer, reactFancyFieldRenderers };
@@ -1,4 +1,4 @@
1
- import { JsonEditor } from '@particle-academy/react-fancy';
1
+ import { JsonEditor, DatePicker, Switch, Select, Input, Textarea } from '@particle-academy/react-fancy';
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
 
4
4
  // src/fields/react-fancy.tsx
@@ -31,7 +31,72 @@ var jsonFieldRenderer = ({
31
31
  var reactFancyFieldRenderers = {
32
32
  json: jsonFieldRenderer
33
33
  };
34
+ var humanFieldRenderers = {
35
+ text: ({ field, id, value, onChange, autoFocusRef }) => /* @__PURE__ */ jsx(
36
+ Input,
37
+ {
38
+ id,
39
+ "data-ff-field": field.key,
40
+ ref: autoFocusRef,
41
+ placeholder: field.placeholder,
42
+ value: String(value ?? ""),
43
+ onValueChange: onChange
44
+ }
45
+ ),
46
+ textarea: ({ field, id, value, onChange, autoFocusRef }) => /* @__PURE__ */ jsx(
47
+ Textarea,
48
+ {
49
+ id,
50
+ "data-ff-field": field.key,
51
+ ref: autoFocusRef,
52
+ placeholder: field.placeholder,
53
+ rows: 3,
54
+ value: String(value ?? ""),
55
+ onValueChange: onChange
56
+ }
57
+ ),
58
+ number: ({ field, id, value, onChange, autoFocusRef }) => /* @__PURE__ */ jsx(
59
+ Input,
60
+ {
61
+ id,
62
+ "data-ff-field": field.key,
63
+ ref: autoFocusRef,
64
+ type: "number",
65
+ placeholder: field.placeholder,
66
+ value: String(value ?? ""),
67
+ onValueChange: (v) => onChange(v === "" ? "" : Number(v))
68
+ }
69
+ ),
70
+ select: ({ field, id, value, onChange }) => /* @__PURE__ */ jsx(
71
+ Select,
72
+ {
73
+ id,
74
+ "data-ff-field": field.key,
75
+ list: (field.options ?? []).map((o) => ({ value: o.value, label: o.label })),
76
+ value: String(value ?? ""),
77
+ onValueChange: onChange
78
+ }
79
+ ),
80
+ switch: ({ field, id, value, onChange }) => /* @__PURE__ */ jsx(
81
+ Switch,
82
+ {
83
+ id,
84
+ "data-ff-field": field.key,
85
+ checked: !!value,
86
+ onCheckedChange: onChange
87
+ }
88
+ ),
89
+ date: ({ field, id, value, onChange }) => /* @__PURE__ */ jsx(
90
+ DatePicker,
91
+ {
92
+ id,
93
+ "data-ff-field": field.key,
94
+ value: String(value ?? ""),
95
+ onValueChange: onChange
96
+ }
97
+ )
98
+ };
34
99
 
35
- export { jsonFieldRenderer, reactFancyFieldRenderers };
100
+ export { humanFieldRenderers, jsonFieldRenderer, reactFancyFieldRenderers };
36
101
  //# sourceMappingURL=react-fancy.js.map
37
102
  //# sourceMappingURL=react-fancy.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/fields/react-fancy.tsx"],"names":[],"mappings":";;;;AA6CO,IAAM,oBAAyC,CAAC;AAAA,EACrD,KAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,KAAgC;AAC9B,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,MAAA,EAAQ,OAAO,IAAA;AAElC,EAAA;AAAA;AAAA;AAAA;AAAA,oBAIE,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QAIC,EAAA;AAAA,QACA,iBAAe,KAAA,CAAM,GAAA;AAAA,QACrB,KAAA,EAAQ,SAAS,EAAC;AAAA,QAClB,QAAA,EAAU,CAAC,IAAA,KAAoB,QAAA,CAAS,IAAI,CAAA;AAAA,QAI5C,QAAQ,KAAA,CAAM,MAAA;AAAA,QACd,IAAA,EAAK,MAAA;AAAA,QACL,IAAA,EAAK,IAAA;AAAA,QACL,WAAW,KAAA,CAAM;AAAA;AAAA;AACnB;AAEJ;AAKO,IAAM,wBAAA,GAAgE;AAAA,EAC3E,IAAA,EAAM;AACR","file":"react-fancy.js","sourcesContent":["/**\n * `@particle-academy/fancy-flow/fields/react-fancy` — richer config fields for\n * hosts that already run react-fancy.\n *\n * ```tsx\n * import { reactFancyFieldRenderers } from \"@particle-academy/fancy-flow/fields/react-fancy\";\n *\n * <FlowEditor … fieldRenderers={reactFancyFieldRenderers} />\n * ```\n *\n * ## Why an opt-in subpath rather than the panel itself\n *\n * fancy-flow themes every surface through a `--ff-*` custom-property layer that\n * a host overrides on `.ff-editor`. react-fancy's primitives are hardcoded\n * Tailwind palette classes and read no custom properties — so building them\n * into the panel would trade the theming contract for a nicer widget, which is\n * the trade `panel-labels.test.tsx` already decided against.\n *\n * Making it a subpath keeps both: react-fancy stays an OPTIONAL peer, a\n * standalone install pays nothing, and a Tailwind host opts in with one prop.\n * Same shape as `/llm/vercel-ai` and `/rich-input`.\n *\n * ## What it currently covers\n *\n * Just `json`, because that is the only built-in whose fallback is a raw\n * textarea. The others are already purpose-built controls; replacing them would\n * be churn. This is a map, so a host can spread it and add their own:\n *\n * ```tsx\n * fieldRenderers={{ ...reactFancyFieldRenderers, \"trigger-filters\": myRenderer }}\n * ```\n */\nimport { JsonEditor, type JsonValue } from \"@particle-academy/react-fancy\";\nimport type {\n ConfigFieldRenderContext,\n ConfigFieldRenderFn,\n} from \"../components/NodeConfigPanel/ConfigFieldRenderer\";\n\n/**\n * Render a `json` config field as a react-fancy `JsonEditor`.\n *\n * Returns `null` for every other field type — the seam treats `null` as \"not\n * mine\", so this can be handed over wholesale without claiming controls it has\n * no business replacing.\n */\nexport const jsonFieldRenderer: ConfigFieldRenderFn = ({\n field,\n value,\n onChange,\n id,\n}: ConfigFieldRenderContext) => {\n if (field.type !== \"json\") return null;\n\n return (\n // JSX rather than `createElement` for one concrete reason: `data-*` props\n // are special-cased by JSX but hit excess-property checking in a\n // `createElement` object literal, so the agent handle would not typecheck.\n <JsonEditor\n // The panel's `<label htmlFor>` points at this id, and the Human+\n // contract wants a stable handle an agent can target without guessing at\n // the DOM. Both reach the editor's root element via its rest spread.\n id={id}\n data-ff-field={field.key}\n value={(value ?? {}) as JsonValue}\n onChange={(next: JsonValue) => onChange(next)}\n // `keyMap` is what makes this more than a prettier textarea: it declares\n // a type per path, which picks the control and reports contradictions. A\n // string by design, so it survives an MCP round-trip.\n keyMap={field.keyMap}\n mode=\"edit\"\n size=\"sm\"\n rootLabel={field.label}\n />\n );\n};\n\n/**\n * The full renderer map. Spread it to add your own types alongside.\n */\nexport const reactFancyFieldRenderers: Record<string, ConfigFieldRenderFn> = {\n json: jsonFieldRenderer,\n};\n"]}
1
+ {"version":3,"sources":["../../src/fields/react-fancy.tsx"],"names":[],"mappings":"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","file":"react-fancy.js","sourcesContent":["/**\n * `@particle-academy/fancy-flow/fields/react-fancy` — richer config fields for\n * hosts that already run react-fancy.\n *\n * ```tsx\n * import { reactFancyFieldRenderers } from \"@particle-academy/fancy-flow/fields/react-fancy\";\n *\n * <FlowEditor … fieldRenderers={reactFancyFieldRenderers} />\n * ```\n *\n * ## Why an opt-in subpath rather than the panel itself\n *\n * fancy-flow themes every surface through a `--ff-*` custom-property layer that\n * a host overrides on `.ff-editor`. react-fancy's primitives are hardcoded\n * Tailwind palette classes and read no custom properties — so building them\n * into the panel would trade the theming contract for a nicer widget, which is\n * the trade `panel-labels.test.tsx` already decided against.\n *\n * Making it a subpath keeps both: react-fancy stays an OPTIONAL peer, a\n * standalone install pays nothing, and a Tailwind host opts in with one prop.\n * Same shape as `/llm/vercel-ai` and `/rich-input`.\n *\n * ## What it currently covers\n *\n * Just `json`, because that is the only built-in whose fallback is a raw\n * textarea. The others are already purpose-built controls; replacing them would\n * be churn. This is a map, so a host can spread it and add their own:\n *\n * ```tsx\n * fieldRenderers={{ ...reactFancyFieldRenderers, \"trigger-filters\": myRenderer }}\n * ```\n */\nimport {\n DatePicker,\n Input,\n JsonEditor,\n Select,\n Switch,\n Textarea,\n type JsonValue,\n} from \"@particle-academy/react-fancy\";\nimport type {\n ConfigFieldRenderContext,\n ConfigFieldRenderFn,\n} from \"../components/NodeConfigPanel/ConfigFieldRenderer\";\nimport type { HumanFieldRenderers } from \"../components/FlowEditor/HumanPrompt\";\n\n/**\n * Render a `json` config field as a react-fancy `JsonEditor`.\n *\n * Returns `null` for every other field type — the seam treats `null` as \"not\n * mine\", so this can be handed over wholesale without claiming controls it has\n * no business replacing.\n */\nexport const jsonFieldRenderer: ConfigFieldRenderFn = ({\n field,\n value,\n onChange,\n id,\n}: ConfigFieldRenderContext) => {\n if (field.type !== \"json\") return null;\n\n return (\n // JSX rather than `createElement` for one concrete reason: `data-*` props\n // are special-cased by JSX but hit excess-property checking in a\n // `createElement` object literal, so the agent handle would not typecheck.\n <JsonEditor\n // The panel's `<label htmlFor>` points at this id, and the Human+\n // contract wants a stable handle an agent can target without guessing at\n // the DOM. Both reach the editor's root element via its rest spread.\n id={id}\n data-ff-field={field.key}\n value={(value ?? {}) as JsonValue}\n onChange={(next: JsonValue) => onChange(next)}\n // `keyMap` is what makes this more than a prettier textarea: it declares\n // a type per path, which picks the control and reports contradictions. A\n // string by design, so it survives an MCP round-trip.\n keyMap={field.keyMap}\n mode=\"edit\"\n size=\"sm\"\n rootLabel={field.label}\n />\n );\n};\n\n/**\n * The full renderer map. Spread it to add your own types alongside.\n */\nexport const reactFancyFieldRenderers: Record<string, ConfigFieldRenderFn> = {\n json: jsonFieldRenderer,\n};\n\n/* ------------------------------------------------------------------------- *\n * Pause-form controls\n * ------------------------------------------------------------------------- */\n\n/**\n * react-fancy controls for the `user_input` / `human_approval` pause form.\n *\n * ```tsx\n * import { humanFieldRenderers } from \"@particle-academy/fancy-flow/fields/react-fancy\";\n *\n * <FlowEditor … humanFieldRenderers={humanFieldRenderers} />\n * ```\n *\n * ## Why this is opt-in rather than the default\n *\n * Rule 2 of the suite says our surfaces compose react-fancy rather than\n * hand-rolling what a primitive already covers, and the pause form's built-ins\n * are native elements. That is not a gap in the kit — react-fancy has every\n * primitive needed — it is a PACKAGING constraint: react-fancy is an OPTIONAL\n * peer, `HumanPrompt` ships in the main entry, and importing it there would\n * make a standalone `npm install @particle-academy/fancy-flow` fail to resolve\n * at import time while bypassing the `--ff-*` token layer hosts theme\n * `.ff-editor` with.\n *\n * This map is how a host that HAS react-fancy gets the Fancy controls anyway,\n * with one prop and no cost to anyone else. Same shape and same reasoning as\n * `reactFancyFieldRenderers` above.\n *\n * ## What it covers, and what it deliberately does not\n *\n * `datetime` is absent: react-fancy's `DatePicker` is date-only, so claiming\n * the type here would render a control that silently drops the time half of a\n * value the field promised to collect. It falls through to the built-in\n * `<input type=\"datetime-local\">`, which does collect it. An honest gap beats a\n * control that looks right and loses data.\n */\nexport const humanFieldRenderers: HumanFieldRenderers = {\n text: ({ field, id, value, onChange, autoFocusRef }) => (\n <Input\n id={id}\n data-ff-field={field.key}\n ref={autoFocusRef as React.RefObject<HTMLInputElement> | undefined}\n placeholder={field.placeholder}\n value={String(value ?? \"\")}\n onValueChange={onChange}\n />\n ),\n\n textarea: ({ field, id, value, onChange, autoFocusRef }) => (\n <Textarea\n id={id}\n data-ff-field={field.key}\n ref={autoFocusRef as React.RefObject<HTMLTextAreaElement> | undefined}\n placeholder={field.placeholder}\n rows={3}\n value={String(value ?? \"\")}\n onValueChange={onChange}\n />\n ),\n\n number: ({ field, id, value, onChange, autoFocusRef }) => (\n <Input\n id={id}\n data-ff-field={field.key}\n ref={autoFocusRef as React.RefObject<HTMLInputElement> | undefined}\n type=\"number\"\n placeholder={field.placeholder}\n value={String(value ?? \"\")}\n // The built-in resolves a number field to a NUMBER, so this must too --\n // the value here is what resumes the paused run, and handing the next\n // node \"41\" where it resolved 41 before is a silent type change that no\n // test downstream would attribute to a renderer swap.\n onValueChange={(v) => onChange(v === \"\" ? \"\" : Number(v))}\n />\n ),\n\n select: ({ field, id, value, onChange }) => (\n <Select\n id={id}\n data-ff-field={field.key}\n list={(field.options ?? []).map((o) => ({ value: o.value, label: o.label }))}\n value={String(value ?? \"\")}\n onValueChange={onChange}\n />\n ),\n\n switch: ({ field, id, value, onChange }) => (\n <Switch\n id={id}\n data-ff-field={field.key}\n checked={!!value}\n onCheckedChange={onChange}\n />\n ),\n\n date: ({ field, id, value, onChange }) => (\n <DatePicker\n id={id}\n data-ff-field={field.key}\n value={String(value ?? \"\")}\n onValueChange={onChange}\n />\n ),\n};\n\n/*\n * `time` and `datetime` are ABSENT on purpose, and for different reasons.\n *\n * `datetime`: react-fancy's `DatePicker` is date-only. Claiming the type here\n * would render a control that silently drops the time half of a value the field\n * promised to collect.\n *\n * `time`: `TimePicker` accepts NO `id` and no `data-*` passthrough --\n * `TimePickerProps` is a closed interface of nine props, none of them an\n * identifier. It therefore cannot satisfy the two handles every control in this\n * form owes: the `id` its `<label htmlFor>` points at, and the `data-ff-field`\n * an agent drives the surface by. Wrapping it in a handle-bearing div would put\n * the label on a non-focusable element, which is worse than not claiming it.\n *\n * Both fall through to the built-in `<input type=\"time\">` /\n * `<input type=\"datetime-local\">`, which do carry the handles and do collect\n * the whole value. An honest gap beats a control that looks right and loses\n * either data or its handle.\n *\n * The `TimePicker` half is a react-fancy FINDING rather than a fancy-flow\n * limitation -- per the suite's second rule, a missing primitive capability is\n * filed against the kit rather than routed around locally.\n */\n"]}
package/dist/index.cjs CHANGED
@@ -11251,7 +11251,7 @@ function resolveWorkflowProps(declared, passed) {
11251
11251
  // src/runtime/run-flow.ts
11252
11252
  async function runFlow(graph, executors, onEvent = () => {
11253
11253
  }, options = {}) {
11254
- const { signal, initialInputs = {}, timeoutMs, depth = 0, resumeOutputs = {} } = options;
11254
+ const { signal, initialInputs = {}, timeoutMs, depth = 0, resumeOutputs = {}, entryNodes } = options;
11255
11255
  const run = options.run === void 0 ? void 0 : RunIdentity.from(options.run);
11256
11256
  const outputs = {};
11257
11257
  const portValues = /* @__PURE__ */ new Map();
@@ -11290,6 +11290,10 @@ async function runFlow(graph, executors, onEvent = () => {
11290
11290
  continue;
11291
11291
  }
11292
11292
  const incoming = incomingByNode.get(node.id) ?? [];
11293
+ if (incoming.length === 0 && entryNodes !== void 0 && !entryNodes.includes(node.id)) {
11294
+ onEvent({ type: "node-status", nodeId: node.id, status: "idle", text: "skipped" });
11295
+ continue;
11296
+ }
11293
11297
  if (incoming.length > 0) {
11294
11298
  const anyActive = incoming.some((e) => portValues.has(`${e.source}:${e.sourceHandle ?? "out"}`));
11295
11299
  if (!anyActive) {
@@ -14696,7 +14700,11 @@ function initialValues(fields) {
14696
14700
  }
14697
14701
  return v2;
14698
14702
  }
14699
- function HumanPrompt({ request, onCancel }) {
14703
+ function HumanPrompt({
14704
+ request,
14705
+ onCancel,
14706
+ fieldRenderers
14707
+ }) {
14700
14708
  const firstRef = ReactExports.useRef(null);
14701
14709
  ReactExports.useEffect(() => {
14702
14710
  firstRef.current?.focus();
@@ -14708,7 +14716,7 @@ function HumanPrompt({ request, onCancel }) {
14708
14716
  }, [onCancel]);
14709
14717
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ff-prompt-overlay", role: "dialog", "aria-modal": "true", "aria-label": request.title, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ff-prompt", onClick: (e) => e.stopPropagation(), children: [
14710
14718
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ff-prompt__title", children: request.title }),
14711
- request.kind === "approval" ? /* @__PURE__ */ jsxRuntime.jsx(ApprovalBody, { request, onCancel }) : /* @__PURE__ */ jsxRuntime.jsx(InputBody, { request, onCancel, firstRef })
14719
+ request.kind === "approval" ? /* @__PURE__ */ jsxRuntime.jsx(ApprovalBody, { request, onCancel }) : /* @__PURE__ */ jsxRuntime.jsx(InputBody, { request, onCancel, firstRef, fieldRenderers })
14712
14720
  ] }) });
14713
14721
  }
14714
14722
  function ApprovalBody({ request, onCancel }) {
@@ -14724,7 +14732,8 @@ function ApprovalBody({ request, onCancel }) {
14724
14732
  function InputBody({
14725
14733
  request,
14726
14734
  onCancel,
14727
- firstRef
14735
+ firstRef,
14736
+ fieldRenderers
14728
14737
  }) {
14729
14738
  const [values, setValues] = ReactExports.useState(() => initialValues(request.fields));
14730
14739
  const set3 = (k2, v2) => setValues((prev) => ({ ...prev, [k2]: v2 }));
@@ -14760,7 +14769,8 @@ function InputBody({
14760
14769
  id: fieldId(f.key),
14761
14770
  value: values[f.key],
14762
14771
  onChange: (v2) => set3(f.key, v2),
14763
- autoFocusRef: i === 0 ? firstRef : void 0
14772
+ autoFocusRef: i === 0 ? firstRef : void 0,
14773
+ renderers: fieldRenderers
14764
14774
  }
14765
14775
  )
14766
14776
  ] }, f.key)) }),
@@ -14777,8 +14787,14 @@ function FieldControl({
14777
14787
  id: id2,
14778
14788
  value,
14779
14789
  onChange,
14780
- autoFocusRef
14790
+ autoFocusRef,
14791
+ renderers
14781
14792
  }) {
14793
+ const override = renderers?.[field.type ?? "text"];
14794
+ if (override) {
14795
+ const rendered = override({ field, id: id2, value, onChange, autoFocusRef });
14796
+ if (rendered !== null && rendered !== void 0) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: rendered });
14797
+ }
14782
14798
  const handle = { id: id2, "data-ff-field": field.key };
14783
14799
  if (field.type === "textarea") {
14784
14800
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -14866,6 +14882,7 @@ function FlowEditorInner({
14866
14882
  onDelete,
14867
14883
  onEdgeDelete,
14868
14884
  confirmDelete,
14885
+ humanFieldRenderers,
14869
14886
  apiRef
14870
14887
  }) {
14871
14888
  const internal = useFlowState(initial);
@@ -15402,10 +15419,17 @@ function FlowEditorInner({
15402
15419
  }
15403
15420
  ),
15404
15421
  showFeed && (slots.feed ? slots.feed(api) : /* @__PURE__ */ jsxRuntime.jsx(FlowRunFeed, { entries: runner.feed, running: api.running, className: "ff-editor__feed" })),
15405
- prompt && /* @__PURE__ */ jsxRuntime.jsx(HumanPrompt, { request: prompt, onCancel: () => {
15406
- setPrompt(null);
15407
- runner.cancel();
15408
- } })
15422
+ prompt && /* @__PURE__ */ jsxRuntime.jsx(
15423
+ HumanPrompt,
15424
+ {
15425
+ request: prompt,
15426
+ onCancel: () => {
15427
+ setPrompt(null);
15428
+ runner.cancel();
15429
+ },
15430
+ fieldRenderers: humanFieldRenderers
15431
+ }
15432
+ )
15409
15433
  ] }),
15410
15434
  showPanel && (slots.panel ? slots.panel(api) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ff-editor__panel-wrap", children: [
15411
15435
  /* @__PURE__ */ jsxRuntime.jsx(