@particle-academy/fancy-flow 0.38.0 → 0.40.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/dist/index.d.cts CHANGED
@@ -347,47 +347,23 @@ declare function paletteDropHandlers(onDrop: (kindName: string, evt: React.DragE
347
347
  onDrop: (e: React.DragEvent) => void;
348
348
  };
349
349
 
350
- type NodeConfigPanelProps = {
351
- /** Currently-selected node — pass null to render the empty state. */
352
- node: FlowNode | null;
353
- /** Called when the user edits the node label, description, or config. */
354
- onChange: (next: FlowNode) => void;
355
- /**
356
- * Called when the user deletes the node from the panel. When provided, the
357
- * panel renders a "Delete node" button while a node is selected — so the
358
- * delete affordance lives WITH the panel (a dev composing their own editor
359
- * gets it for free), rather than in a host toolbar it has to re-implement.
360
- */
361
- onDelete?: (node: FlowNode) => void;
362
- /** Label for the delete button. Default "Delete node". */
363
- deleteLabel?: string;
364
- /** Optional header content (e.g. close button). */
365
- header?: ReactNode;
366
- /** Optional credential picker hook — host renders the picker. */
367
- renderCredentialField?: (props: {
368
- credentialType: string;
369
- value: unknown;
370
- onChange: (next: unknown) => void;
371
- }) => ReactNode;
372
- /**
373
- * Optional document editor hook — host renders the editor for `document`
374
- * fields. Lets rich authored content live in node config without fancy-flow
375
- * taking on a document model.
376
- */
377
- renderDocumentField?: (props: {
378
- documentType?: string;
379
- value: unknown;
380
- onChange: (next: unknown) => void;
381
- }) => ReactNode;
382
- className?: string;
383
- style?: React.CSSProperties;
350
+ /** What a host renderer is handed. */
351
+ type ConfigFieldRenderContext = {
352
+ field: ConfigField;
353
+ value: unknown;
354
+ onChange: (next: unknown) => void;
355
+ /** The id the panel's `<label>` points at. Put it on your control. */
356
+ id?: string;
384
357
  };
385
358
  /**
386
- * NodeConfigPanel schema-driven form for the selected node. Defers to
387
- * `kind.renderPanel` if the kind opts out of the auto-form.
359
+ * Render one field. Return `null` to fall back to the package's own rendering,
360
+ * so a host can claim a type conditionally instead of reimplementing every case.
361
+ *
362
+ * Named `...Fn` because `ConfigFieldRenderer` is already the component this
363
+ * module exports; two things with one name in a public API is a paper cut a
364
+ * consumer pays for, not us.
388
365
  */
389
- declare function NodeConfigPanel({ node, onChange, onDelete, deleteLabel, header, renderCredentialField, renderDocumentField, className, style, }: NodeConfigPanelProps): react.JSX.Element;
390
-
366
+ type ConfigFieldRenderFn = (ctx: ConfigFieldRenderContext) => ReactNode;
391
367
  type ConfigFieldRendererProps = {
392
368
  field: ConfigField;
393
369
  value: unknown;
@@ -420,6 +396,22 @@ type ConfigFieldRendererProps = {
420
396
  value: unknown;
421
397
  onChange: (next: unknown) => void;
422
398
  }) => ReactNode;
399
+ /**
400
+ * Host renderers keyed by field `type`.
401
+ *
402
+ * The generic form of `renderDocumentField` / `renderCredentialField`: those
403
+ * cover two types the package deliberately does not interpret, this covers
404
+ * any type at all — including one the package has never heard of.
405
+ *
406
+ * Without it, a richer field had to be rendered OUTSIDE the panel, so that
407
+ * node's config stopped living where every other field does. An unknown type
408
+ * also fell through to `default:` and rendered nothing, so the schema said the
409
+ * field existed and the panel showed empty space.
410
+ *
411
+ * Consulted BEFORE the built-in switch, so a host can also replace a built-in
412
+ * (react-fancy inputs, say) through the same seam rather than a second one.
413
+ */
414
+ fieldRenderers?: Record<string, ConfigFieldRenderFn>;
423
415
  };
424
416
  /**
425
417
  * ConfigFieldRenderer — dispatches to the right input element per field type.
@@ -432,7 +424,50 @@ type ConfigFieldRendererProps = {
432
424
  * Each control carries the caller's `id` and a `data-ff-field` handle keyed by
433
425
  * the field, so a label can point at it and an agent can find it by name.
434
426
  */
435
- declare function ConfigFieldRenderer({ field, value, onChange, id, renderCredentialField, renderDocumentField, }: ConfigFieldRendererProps): react.JSX.Element | null;
427
+ declare function ConfigFieldRenderer({ field, value, onChange, id, renderCredentialField, renderDocumentField, fieldRenderers, }: ConfigFieldRendererProps): react.JSX.Element | null;
428
+
429
+ type NodeConfigPanelProps = {
430
+ /** Currently-selected node — pass null to render the empty state. */
431
+ node: FlowNode | null;
432
+ /** Called when the user edits the node label, description, or config. */
433
+ onChange: (next: FlowNode) => void;
434
+ /**
435
+ * Called when the user deletes the node from the panel. When provided, the
436
+ * panel renders a "Delete node" button while a node is selected — so the
437
+ * delete affordance lives WITH the panel (a dev composing their own editor
438
+ * gets it for free), rather than in a host toolbar it has to re-implement.
439
+ */
440
+ onDelete?: (node: FlowNode) => void;
441
+ /** Label for the delete button. Default "Delete node". */
442
+ deleteLabel?: string;
443
+ /** Optional header content (e.g. close button). */
444
+ header?: ReactNode;
445
+ /** Optional credential picker hook — host renders the picker. */
446
+ renderCredentialField?: (props: {
447
+ credentialType: string;
448
+ value: unknown;
449
+ onChange: (next: unknown) => void;
450
+ }) => ReactNode;
451
+ /**
452
+ * Optional document editor hook — host renders the editor for `document`
453
+ * fields. Lets rich authored content live in node config without fancy-flow
454
+ * taking on a document model.
455
+ */
456
+ /** Host renderers keyed by field `type`. See {@link ConfigFieldRenderer}. */
457
+ fieldRenderers?: Record<string, ConfigFieldRenderFn>;
458
+ renderDocumentField?: (props: {
459
+ documentType?: string;
460
+ value: unknown;
461
+ onChange: (next: unknown) => void;
462
+ }) => ReactNode;
463
+ className?: string;
464
+ style?: React.CSSProperties;
465
+ };
466
+ /**
467
+ * NodeConfigPanel — schema-driven form for the selected node. Defers to
468
+ * `kind.renderPanel` if the kind opts out of the auto-form.
469
+ */
470
+ declare function NodeConfigPanel({ node, onChange, onDelete, deleteLabel, header, renderCredentialField, renderDocumentField, fieldRenderers, className, style, }: NodeConfigPanelProps): react.JSX.Element;
436
471
 
437
472
  /** Entry-point node — outputs only, no inputs. */
438
473
  declare function TriggerNodeInner(props: NodeProps<FlowNode>): react.JSX.Element;
@@ -580,4 +615,72 @@ type FlowRunFeedProps = {
580
615
  */
581
616
  declare function FlowRunFeed({ entries, showHeader, title, running, className, style }: FlowRunFeedProps): react.JSX.Element;
582
617
 
583
- export { ActionNode, type AlignEdge, AutoLayoutOptions, ConfigField, ConfigFieldRenderer, type ConfigFieldRendererProps, ConnectionValidatorOptions, DecisionNode, ExecutorRegistry, FlowCanvas, type FlowCanvasProps, FlowEditor, type FlowEditorAction, type FlowEditorApi, type FlowEditorBuiltins, type FlowEditorProps, type FlowEditorSlots, FlowGraph, FlowNode, type FlowNodeRenderProps, FlowRunControls, type FlowRunControlsProps, FlowRunFeed, FlowRunFeedEntry, type FlowRunFeedProps, LaneNode, NodeCategory, NodeConfigPanel, type NodeConfigPanelProps, NodeKindDefinition, NodePalette, type NodePaletteProps, NodePort, type NodePortProps, type NodePortSide, type NodePortType, NodeRunStatus, NodeShell, type NodeShellProps, NoteNode, OutputNode, SubgraphNode, TriggerNode, WorkflowMetadata, WorkflowSchema, alignNodes, cloneSubgraph, defaultNodeTypes, defineNode, distributeNodes, paletteDropHandlers, reconnectEdge, useFlowEditor, useFlowEditorOptional };
618
+ /**
619
+ * The fancy-flow Live Contract — the run / job stream shape.
620
+ *
621
+ * Pure data, with `LiveContract` imported as a TYPE, so this adds no dependency.
622
+ * `FancyFlow\Laravel\LiveContract` declares the identical list and both sides
623
+ * assert parity.
624
+ *
625
+ * ## What makes this shape different
626
+ *
627
+ * A run emits far more than it stores. `NodeStatusChanged` and `NodeOutput`
628
+ * fire per node, many times a second on a wide graph — and a node's log line is
629
+ * not a cache entry, it is a **stream**. So the contract covers the run's
630
+ * DURABLE state (does this run exist, has it finished, is it waiting on a
631
+ * person) and deliberately leaves per-node chatter to `useFancyStream`, the
632
+ * same split the whiteboard makes between its document and its cursors.
633
+ *
634
+ * Get that wrong and a 40-node run invalidates the run list forty times while
635
+ * it executes, each one a re-fetch that tells the UI nothing it did not already
636
+ * learn from the stream.
637
+ *
638
+ * ## `awaiting` is the one that matters
639
+ *
640
+ * A run parking on a human step is the event a host most needs to react to —
641
+ * it is when a form has to appear in front of somebody. It gets its own event
642
+ * rather than folding into `updated`, so a host can subscribe to just that.
643
+ *
644
+ * ## Broadcast status, stated plainly
645
+ *
646
+ * `fancy-flow-php` currently dispatches these as **in-process Laravel events**;
647
+ * none of them implement `ShouldBroadcast` yet. This contract is therefore the
648
+ * agreed vocabulary rather than a description of traffic already on the wire: a
649
+ * host that wants live runs today re-broadcasts these under these names. Making
650
+ * the PHP events broadcast natively is a separate change, because it turns on
651
+ * websocket traffic for every consumer.
652
+ */
653
+ declare const flowLive: {
654
+ readonly namespace: "flow";
655
+ readonly events: readonly [{
656
+ readonly event: "flow.run.created";
657
+ readonly keys: readonly [readonly ["flow", "runs"]];
658
+ }, {
659
+ readonly event: "flow.run.updated";
660
+ readonly keys: readonly [readonly ["flow", "runs"]];
661
+ }, {
662
+ readonly event: "flow.run.completed";
663
+ readonly keys: readonly [readonly ["flow", "runs"]];
664
+ }, {
665
+ readonly event: "flow.run.awaiting";
666
+ readonly keys: readonly [readonly ["flow", "runs"]];
667
+ readonly note: "A run parking on a human step — the moment a form has to appear in front of somebody. Its own event so a host can subscribe to just that, rather than filtering every update.";
668
+ }, {
669
+ readonly event: "flow.run.failed";
670
+ readonly keys: readonly [readonly ["flow", "runs"]];
671
+ readonly note: "Not one of the standard verbs: a failed run is a terminal state a host renders differently from a completed one, so collapsing the two would lose the distinction.";
672
+ }];
673
+ };
674
+ /**
675
+ * Per-run keys, for a host showing a single run rather than the list.
676
+ *
677
+ * The contract declares prefixes because it is static data and a run id is not
678
+ * known until runtime. TanStack matches by prefix, so `["flow", "runs"]` still
679
+ * invalidates `["flow", "runs", runId]`.
680
+ */
681
+ declare const flowKeys: {
682
+ readonly runs: () => readonly ["flow", "runs"];
683
+ readonly run: (runId: string) => readonly ["flow", "runs", string];
684
+ };
685
+
686
+ export { ActionNode, type AlignEdge, AutoLayoutOptions, ConfigField, type ConfigFieldRenderContext, type ConfigFieldRenderFn, ConfigFieldRenderer, type ConfigFieldRendererProps, ConnectionValidatorOptions, DecisionNode, ExecutorRegistry, FlowCanvas, type FlowCanvasProps, FlowEditor, type FlowEditorAction, type FlowEditorApi, type FlowEditorBuiltins, type FlowEditorProps, type FlowEditorSlots, FlowGraph, FlowNode, type FlowNodeRenderProps, FlowRunControls, type FlowRunControlsProps, FlowRunFeed, FlowRunFeedEntry, type FlowRunFeedProps, LaneNode, NodeCategory, NodeConfigPanel, type NodeConfigPanelProps, NodeKindDefinition, NodePalette, type NodePaletteProps, NodePort, type NodePortProps, type NodePortSide, type NodePortType, NodeRunStatus, NodeShell, type NodeShellProps, NoteNode, OutputNode, SubgraphNode, TriggerNode, WorkflowMetadata, WorkflowSchema, alignNodes, cloneSubgraph, defaultNodeTypes, defineNode, distributeNodes, flowKeys, flowLive, paletteDropHandlers, reconnectEdge, useFlowEditor, useFlowEditorOptional };
package/dist/index.d.ts CHANGED
@@ -347,47 +347,23 @@ declare function paletteDropHandlers(onDrop: (kindName: string, evt: React.DragE
347
347
  onDrop: (e: React.DragEvent) => void;
348
348
  };
349
349
 
350
- type NodeConfigPanelProps = {
351
- /** Currently-selected node — pass null to render the empty state. */
352
- node: FlowNode | null;
353
- /** Called when the user edits the node label, description, or config. */
354
- onChange: (next: FlowNode) => void;
355
- /**
356
- * Called when the user deletes the node from the panel. When provided, the
357
- * panel renders a "Delete node" button while a node is selected — so the
358
- * delete affordance lives WITH the panel (a dev composing their own editor
359
- * gets it for free), rather than in a host toolbar it has to re-implement.
360
- */
361
- onDelete?: (node: FlowNode) => void;
362
- /** Label for the delete button. Default "Delete node". */
363
- deleteLabel?: string;
364
- /** Optional header content (e.g. close button). */
365
- header?: ReactNode;
366
- /** Optional credential picker hook — host renders the picker. */
367
- renderCredentialField?: (props: {
368
- credentialType: string;
369
- value: unknown;
370
- onChange: (next: unknown) => void;
371
- }) => ReactNode;
372
- /**
373
- * Optional document editor hook — host renders the editor for `document`
374
- * fields. Lets rich authored content live in node config without fancy-flow
375
- * taking on a document model.
376
- */
377
- renderDocumentField?: (props: {
378
- documentType?: string;
379
- value: unknown;
380
- onChange: (next: unknown) => void;
381
- }) => ReactNode;
382
- className?: string;
383
- style?: React.CSSProperties;
350
+ /** What a host renderer is handed. */
351
+ type ConfigFieldRenderContext = {
352
+ field: ConfigField;
353
+ value: unknown;
354
+ onChange: (next: unknown) => void;
355
+ /** The id the panel's `<label>` points at. Put it on your control. */
356
+ id?: string;
384
357
  };
385
358
  /**
386
- * NodeConfigPanel schema-driven form for the selected node. Defers to
387
- * `kind.renderPanel` if the kind opts out of the auto-form.
359
+ * Render one field. Return `null` to fall back to the package's own rendering,
360
+ * so a host can claim a type conditionally instead of reimplementing every case.
361
+ *
362
+ * Named `...Fn` because `ConfigFieldRenderer` is already the component this
363
+ * module exports; two things with one name in a public API is a paper cut a
364
+ * consumer pays for, not us.
388
365
  */
389
- declare function NodeConfigPanel({ node, onChange, onDelete, deleteLabel, header, renderCredentialField, renderDocumentField, className, style, }: NodeConfigPanelProps): react.JSX.Element;
390
-
366
+ type ConfigFieldRenderFn = (ctx: ConfigFieldRenderContext) => ReactNode;
391
367
  type ConfigFieldRendererProps = {
392
368
  field: ConfigField;
393
369
  value: unknown;
@@ -420,6 +396,22 @@ type ConfigFieldRendererProps = {
420
396
  value: unknown;
421
397
  onChange: (next: unknown) => void;
422
398
  }) => ReactNode;
399
+ /**
400
+ * Host renderers keyed by field `type`.
401
+ *
402
+ * The generic form of `renderDocumentField` / `renderCredentialField`: those
403
+ * cover two types the package deliberately does not interpret, this covers
404
+ * any type at all — including one the package has never heard of.
405
+ *
406
+ * Without it, a richer field had to be rendered OUTSIDE the panel, so that
407
+ * node's config stopped living where every other field does. An unknown type
408
+ * also fell through to `default:` and rendered nothing, so the schema said the
409
+ * field existed and the panel showed empty space.
410
+ *
411
+ * Consulted BEFORE the built-in switch, so a host can also replace a built-in
412
+ * (react-fancy inputs, say) through the same seam rather than a second one.
413
+ */
414
+ fieldRenderers?: Record<string, ConfigFieldRenderFn>;
423
415
  };
424
416
  /**
425
417
  * ConfigFieldRenderer — dispatches to the right input element per field type.
@@ -432,7 +424,50 @@ type ConfigFieldRendererProps = {
432
424
  * Each control carries the caller's `id` and a `data-ff-field` handle keyed by
433
425
  * the field, so a label can point at it and an agent can find it by name.
434
426
  */
435
- declare function ConfigFieldRenderer({ field, value, onChange, id, renderCredentialField, renderDocumentField, }: ConfigFieldRendererProps): react.JSX.Element | null;
427
+ declare function ConfigFieldRenderer({ field, value, onChange, id, renderCredentialField, renderDocumentField, fieldRenderers, }: ConfigFieldRendererProps): react.JSX.Element | null;
428
+
429
+ type NodeConfigPanelProps = {
430
+ /** Currently-selected node — pass null to render the empty state. */
431
+ node: FlowNode | null;
432
+ /** Called when the user edits the node label, description, or config. */
433
+ onChange: (next: FlowNode) => void;
434
+ /**
435
+ * Called when the user deletes the node from the panel. When provided, the
436
+ * panel renders a "Delete node" button while a node is selected — so the
437
+ * delete affordance lives WITH the panel (a dev composing their own editor
438
+ * gets it for free), rather than in a host toolbar it has to re-implement.
439
+ */
440
+ onDelete?: (node: FlowNode) => void;
441
+ /** Label for the delete button. Default "Delete node". */
442
+ deleteLabel?: string;
443
+ /** Optional header content (e.g. close button). */
444
+ header?: ReactNode;
445
+ /** Optional credential picker hook — host renders the picker. */
446
+ renderCredentialField?: (props: {
447
+ credentialType: string;
448
+ value: unknown;
449
+ onChange: (next: unknown) => void;
450
+ }) => ReactNode;
451
+ /**
452
+ * Optional document editor hook — host renders the editor for `document`
453
+ * fields. Lets rich authored content live in node config without fancy-flow
454
+ * taking on a document model.
455
+ */
456
+ /** Host renderers keyed by field `type`. See {@link ConfigFieldRenderer}. */
457
+ fieldRenderers?: Record<string, ConfigFieldRenderFn>;
458
+ renderDocumentField?: (props: {
459
+ documentType?: string;
460
+ value: unknown;
461
+ onChange: (next: unknown) => void;
462
+ }) => ReactNode;
463
+ className?: string;
464
+ style?: React.CSSProperties;
465
+ };
466
+ /**
467
+ * NodeConfigPanel — schema-driven form for the selected node. Defers to
468
+ * `kind.renderPanel` if the kind opts out of the auto-form.
469
+ */
470
+ declare function NodeConfigPanel({ node, onChange, onDelete, deleteLabel, header, renderCredentialField, renderDocumentField, fieldRenderers, className, style, }: NodeConfigPanelProps): react.JSX.Element;
436
471
 
437
472
  /** Entry-point node — outputs only, no inputs. */
438
473
  declare function TriggerNodeInner(props: NodeProps<FlowNode>): react.JSX.Element;
@@ -580,4 +615,72 @@ type FlowRunFeedProps = {
580
615
  */
581
616
  declare function FlowRunFeed({ entries, showHeader, title, running, className, style }: FlowRunFeedProps): react.JSX.Element;
582
617
 
583
- export { ActionNode, type AlignEdge, AutoLayoutOptions, ConfigField, ConfigFieldRenderer, type ConfigFieldRendererProps, ConnectionValidatorOptions, DecisionNode, ExecutorRegistry, FlowCanvas, type FlowCanvasProps, FlowEditor, type FlowEditorAction, type FlowEditorApi, type FlowEditorBuiltins, type FlowEditorProps, type FlowEditorSlots, FlowGraph, FlowNode, type FlowNodeRenderProps, FlowRunControls, type FlowRunControlsProps, FlowRunFeed, FlowRunFeedEntry, type FlowRunFeedProps, LaneNode, NodeCategory, NodeConfigPanel, type NodeConfigPanelProps, NodeKindDefinition, NodePalette, type NodePaletteProps, NodePort, type NodePortProps, type NodePortSide, type NodePortType, NodeRunStatus, NodeShell, type NodeShellProps, NoteNode, OutputNode, SubgraphNode, TriggerNode, WorkflowMetadata, WorkflowSchema, alignNodes, cloneSubgraph, defaultNodeTypes, defineNode, distributeNodes, paletteDropHandlers, reconnectEdge, useFlowEditor, useFlowEditorOptional };
618
+ /**
619
+ * The fancy-flow Live Contract — the run / job stream shape.
620
+ *
621
+ * Pure data, with `LiveContract` imported as a TYPE, so this adds no dependency.
622
+ * `FancyFlow\Laravel\LiveContract` declares the identical list and both sides
623
+ * assert parity.
624
+ *
625
+ * ## What makes this shape different
626
+ *
627
+ * A run emits far more than it stores. `NodeStatusChanged` and `NodeOutput`
628
+ * fire per node, many times a second on a wide graph — and a node's log line is
629
+ * not a cache entry, it is a **stream**. So the contract covers the run's
630
+ * DURABLE state (does this run exist, has it finished, is it waiting on a
631
+ * person) and deliberately leaves per-node chatter to `useFancyStream`, the
632
+ * same split the whiteboard makes between its document and its cursors.
633
+ *
634
+ * Get that wrong and a 40-node run invalidates the run list forty times while
635
+ * it executes, each one a re-fetch that tells the UI nothing it did not already
636
+ * learn from the stream.
637
+ *
638
+ * ## `awaiting` is the one that matters
639
+ *
640
+ * A run parking on a human step is the event a host most needs to react to —
641
+ * it is when a form has to appear in front of somebody. It gets its own event
642
+ * rather than folding into `updated`, so a host can subscribe to just that.
643
+ *
644
+ * ## Broadcast status, stated plainly
645
+ *
646
+ * `fancy-flow-php` currently dispatches these as **in-process Laravel events**;
647
+ * none of them implement `ShouldBroadcast` yet. This contract is therefore the
648
+ * agreed vocabulary rather than a description of traffic already on the wire: a
649
+ * host that wants live runs today re-broadcasts these under these names. Making
650
+ * the PHP events broadcast natively is a separate change, because it turns on
651
+ * websocket traffic for every consumer.
652
+ */
653
+ declare const flowLive: {
654
+ readonly namespace: "flow";
655
+ readonly events: readonly [{
656
+ readonly event: "flow.run.created";
657
+ readonly keys: readonly [readonly ["flow", "runs"]];
658
+ }, {
659
+ readonly event: "flow.run.updated";
660
+ readonly keys: readonly [readonly ["flow", "runs"]];
661
+ }, {
662
+ readonly event: "flow.run.completed";
663
+ readonly keys: readonly [readonly ["flow", "runs"]];
664
+ }, {
665
+ readonly event: "flow.run.awaiting";
666
+ readonly keys: readonly [readonly ["flow", "runs"]];
667
+ readonly note: "A run parking on a human step — the moment a form has to appear in front of somebody. Its own event so a host can subscribe to just that, rather than filtering every update.";
668
+ }, {
669
+ readonly event: "flow.run.failed";
670
+ readonly keys: readonly [readonly ["flow", "runs"]];
671
+ readonly note: "Not one of the standard verbs: a failed run is a terminal state a host renders differently from a completed one, so collapsing the two would lose the distinction.";
672
+ }];
673
+ };
674
+ /**
675
+ * Per-run keys, for a host showing a single run rather than the list.
676
+ *
677
+ * The contract declares prefixes because it is static data and a run id is not
678
+ * known until runtime. TanStack matches by prefix, so `["flow", "runs"]` still
679
+ * invalidates `["flow", "runs", runId]`.
680
+ */
681
+ declare const flowKeys: {
682
+ readonly runs: () => readonly ["flow", "runs"];
683
+ readonly run: (runId: string) => readonly ["flow", "runs", string];
684
+ };
685
+
686
+ export { ActionNode, type AlignEdge, AutoLayoutOptions, ConfigField, type ConfigFieldRenderContext, type ConfigFieldRenderFn, ConfigFieldRenderer, type ConfigFieldRendererProps, ConnectionValidatorOptions, DecisionNode, ExecutorRegistry, FlowCanvas, type FlowCanvasProps, FlowEditor, type FlowEditorAction, type FlowEditorApi, type FlowEditorBuiltins, type FlowEditorProps, type FlowEditorSlots, FlowGraph, FlowNode, type FlowNodeRenderProps, FlowRunControls, type FlowRunControlsProps, FlowRunFeed, FlowRunFeedEntry, type FlowRunFeedProps, LaneNode, NodeCategory, NodeConfigPanel, type NodeConfigPanelProps, NodeKindDefinition, NodePalette, type NodePaletteProps, NodePort, type NodePortProps, type NodePortSide, type NodePortType, NodeRunStatus, NodeShell, type NodeShellProps, NoteNode, OutputNode, SubgraphNode, TriggerNode, WorkflowMetadata, WorkflowSchema, alignNodes, cloneSubgraph, defaultNodeTypes, defineNode, distributeNodes, flowKeys, flowLive, paletteDropHandlers, reconnectEdge, useFlowEditor, useFlowEditorOptional };
package/dist/index.js CHANGED
@@ -115,9 +115,15 @@ function ConfigFieldRenderer({
115
115
  onChange,
116
116
  id,
117
117
  renderCredentialField,
118
- renderDocumentField
118
+ renderDocumentField,
119
+ fieldRenderers
119
120
  }) {
120
121
  const handle = { id, "data-ff-field": field.key };
122
+ const custom = fieldRenderers?.[field.type];
123
+ if (custom) {
124
+ const rendered = custom({ field, value, onChange, id });
125
+ if (rendered !== null && rendered !== void 0) return /* @__PURE__ */ jsx(Fragment, { children: rendered });
126
+ }
121
127
  switch (field.type) {
122
128
  case "text": {
123
129
  if (field.choices?.length) {
@@ -225,7 +231,8 @@ function ConfigFieldRenderer({
225
231
  value,
226
232
  onChange,
227
233
  renderCredentialField,
228
- renderDocumentField
234
+ renderDocumentField,
235
+ fieldRenderers
229
236
  }
230
237
  );
231
238
  case "keyvalue":
@@ -278,7 +285,8 @@ function RepeaterField({
278
285
  value,
279
286
  onChange,
280
287
  renderCredentialField,
281
- renderDocumentField
288
+ renderDocumentField,
289
+ fieldRenderers
282
290
  }) {
283
291
  const rows = Array.isArray(value) ? value : [];
284
292
  const max = field.maxItems ?? Infinity;
@@ -360,7 +368,8 @@ function RepeaterField({
360
368
  value: row[sub.key],
361
369
  onChange: (cell) => setCell(i, sub.key, cell),
362
370
  renderCredentialField,
363
- renderDocumentField
371
+ renderDocumentField,
372
+ fieldRenderers
364
373
  }
365
374
  )
366
375
  ] }, sub.key))
@@ -492,6 +501,7 @@ function NodeConfigPanel({
492
501
  header,
493
502
  renderCredentialField,
494
503
  renderDocumentField,
504
+ fieldRenderers,
495
505
  className,
496
506
  style
497
507
  }) {
@@ -596,7 +606,8 @@ function NodeConfigPanel({
596
606
  value: config[field.key],
597
607
  onChange: (v) => setConfigValue(field.key, v),
598
608
  renderCredentialField,
599
- renderDocumentField: documentField
609
+ renderDocumentField: documentField,
610
+ fieldRenderers
600
611
  }
601
612
  )
602
613
  ] }, field.key))
@@ -1506,9 +1517,33 @@ function NodePort({ side, type, id, style, title, className }) {
1506
1517
  );
1507
1518
  }
1508
1519
 
1520
+ // src/live.ts
1521
+ var flowLive = {
1522
+ namespace: "flow",
1523
+ events: [
1524
+ { event: "flow.run.created", keys: [["flow", "runs"]] },
1525
+ { event: "flow.run.updated", keys: [["flow", "runs"]] },
1526
+ { event: "flow.run.completed", keys: [["flow", "runs"]] },
1527
+ {
1528
+ event: "flow.run.awaiting",
1529
+ keys: [["flow", "runs"]],
1530
+ note: "A run parking on a human step \u2014 the moment a form has to appear in front of somebody. Its own event so a host can subscribe to just that, rather than filtering every update."
1531
+ },
1532
+ {
1533
+ event: "flow.run.failed",
1534
+ keys: [["flow", "runs"]],
1535
+ note: "Not one of the standard verbs: a failed run is a terminal state a host renders differently from a completed one, so collapsing the two would lose the distinction."
1536
+ }
1537
+ ]
1538
+ };
1539
+ var flowKeys = {
1540
+ runs: () => ["flow", "runs"],
1541
+ run: (runId) => ["flow", "runs", runId]
1542
+ };
1543
+
1509
1544
  // src/index.ts
1510
1545
  registerBuiltinKinds();
1511
1546
 
1512
- export { ConfigFieldRenderer, FlowEditor, FlowRunControls, FlowRunFeed, NodeConfigPanel, NodePalette, NodePort, defineNode, paletteDropHandlers };
1547
+ export { ConfigFieldRenderer, FlowEditor, FlowRunControls, FlowRunFeed, NodeConfigPanel, NodePalette, NodePort, defineNode, flowKeys, flowLive, paletteDropHandlers };
1513
1548
  //# sourceMappingURL=index.js.map
1514
1549
  //# sourceMappingURL=index.js.map