@particle-academy/fancy-flow 0.40.3 → 0.41.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/ConfigFieldRenderer-4xK9hzvd.d.cts +84 -0
- package/dist/ConfigFieldRenderer-D2TejNY1.d.ts +84 -0
- package/dist/{chunk-5UCWY7G3.js → chunk-WOO4B7M5.js} +37 -6
- package/dist/chunk-WOO4B7M5.js.map +1 -0
- package/dist/engine.d.cts +3 -3
- package/dist/engine.d.ts +3 -3
- package/dist/fields/react-fancy.cjs +40 -0
- package/dist/fields/react-fancy.cjs.map +1 -0
- package/dist/fields/react-fancy.d.cts +20 -0
- package/dist/fields/react-fancy.d.ts +20 -0
- package/dist/fields/react-fancy.js +37 -0
- package/dist/fields/react-fancy.js.map +1 -0
- package/dist/index.cjs +105 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -127
- package/dist/index.d.ts +64 -127
- package/dist/index.js +73 -26
- package/dist/index.js.map +1 -1
- package/dist/registry/index.d.cts +3 -3
- package/dist/registry/index.d.ts +3 -3
- package/dist/{registry-BADFn97n.d.cts → registry-BNyT66SS.d.cts} +1 -1
- package/dist/{registry-DYbFLEcW.d.ts → registry-CS7kjMto.d.ts} +1 -1
- package/dist/screens.cjs +34 -3
- package/dist/screens.cjs.map +1 -1
- package/dist/screens.js +2 -2
- package/dist/styles.css +6 -1
- package/dist/styles.css.map +1 -1
- package/dist/{types-D6lsIGoe.d.ts → types-Cf75IbxY.d.ts} +13 -0
- package/dist/{types-D8Dezh9v.d.cts → types-cAdD1Og2.d.cts} +13 -0
- package/dist/ux.d.cts +1 -1
- package/dist/ux.d.ts +1 -1
- package/package.json +12 -2
- package/dist/chunk-5UCWY7G3.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ReactNode, CSSProperties, ComponentType } from 'react';
|
|
2
|
+
import { ReactNode, CSSProperties, ComponentProps, ComponentType } from 'react';
|
|
3
3
|
import { ReactFlowProps, Edge, BackgroundVariant, Connection, NodeProps, NodeTypes } from '@xyflow/react';
|
|
4
4
|
import { ConnectionValidatorOptions } from './registry/index.cjs';
|
|
5
5
|
export { ANY_PORT_TYPE, BUILTIN_KINDS, PortCompatibility, RegistryNode, RichInputAdapter, RichInputPreview, buildNodeTypes, createConnectionValidator, defaultPortCompatibility, getRichInputAdapter, isRichInputEnabled, onRichInputAdapterChanged, registerBuiltinKinds, registerRichInputAdapter, resolveNodePorts, resolvePortSpec } from './registry/index.cjs';
|
|
6
6
|
import { b as FlowNode, F as FlowGraph, e as NodeRunStatus, E as ExecutorRegistry } from './types-sOmpCitB.cjs';
|
|
7
7
|
export { A as ActionNodeData, B as BaseNodeData, D as DecisionNodeData, a as FlowEdge, c as FlowNodeData, d as FlowNodeKind, N as NodeExecutor, f as NoteNodeData, O as OutputNodeData, P as PortDescriptor, R as RunEvent, S as SubgraphNodeData, T as TriggerNodeData } from './types-sOmpCitB.cjs';
|
|
8
|
+
import { C as ConfigFieldRenderFn } from './ConfigFieldRenderer-4xK9hzvd.cjs';
|
|
9
|
+
export { a as ConfigFieldRenderContext, b as ConfigFieldRenderer, c as ConfigFieldRendererProps } from './ConfigFieldRenderer-4xK9hzvd.cjs';
|
|
8
10
|
import { WorkflowSchema, WorkflowMetadata } from './schema/index.cjs';
|
|
9
11
|
export { ImportIssue, ImportOptions, ImportResult, WORKFLOW_SCHEMA_URL, WORKFLOW_SCHEMA_VERSION, WorkflowSchemaEdge, WorkflowSchemaNode, exportWorkflow, importWorkflow, migrateSchema, workflowToBlob } from './schema/index.cjs';
|
|
10
12
|
import { AutoLayoutOptions } from './layout/index.cjs';
|
|
11
13
|
export { AutoLayoutDirection } from './layout/index.cjs';
|
|
12
|
-
import { c as NodeCategory, d as NodeKindDefinition
|
|
13
|
-
export { D as DocumentConfigField, K as KeyValueConfigField, L as LEGACY_PAUSE_PREFIXES, h as PAUSE_PREFIX, P as PauseAwaiting, i as PauseSignal, j as PortSpec, R as RenderBodyContext, t as RepeaterConfigField, u as RepeaterRowField, m as decodePause, n as encodePause, o as isPause, p as pauseForHuman } from './types-
|
|
14
|
+
import { c as NodeCategory, d as NodeKindDefinition } from './types-cAdD1Og2.cjs';
|
|
15
|
+
export { a as ConfigField, D as DocumentConfigField, K as KeyValueConfigField, L as LEGACY_PAUSE_PREFIXES, h as PAUSE_PREFIX, P as PauseAwaiting, i as PauseSignal, j as PortSpec, R as RenderBodyContext, t as RepeaterConfigField, u as RepeaterRowField, m as decodePause, n as encodePause, o as isPause, p as pauseForHuman } from './types-cAdD1Og2.cjs';
|
|
14
16
|
export { F as FlowNodeStatus, a as FlowViewer, b as FlowViewerClassNames, c as FlowViewerProps } from './FlowViewer-nLqo7s2E.cjs';
|
|
15
17
|
import { FlowRunFeedEntry } from './runtime/index.cjs';
|
|
16
18
|
export { HistoryController, UseFlowHistoryReturn, UseFlowRunOptions, UseFlowRunReturn, UseFlowStateReturn, applyOutputsToNodes, applyStatusesToNodes, createHistory, useFlowHistory, useFlowRun, useFlowState } from './runtime/index.cjs';
|
|
17
19
|
export { C as CohortGuard, a as CohortOptions, b as CohortPolicy, c as CohortResult, R as RunOptions, d as RunResult, r as runCohort, e as runFlow } from './run-cohort-Bjv2ZU6g.cjs';
|
|
18
|
-
export { N as NodeKindPresentation, c as categoryAccent, b as clearNodeKindOverrides, d as defaultConfigFor, g as getNodeKind, l as listNodeKinds, o as onNodeKindsChanged, e as overrideNodeKind, r as registerNodeKind, v as validateConfig } from './registry-
|
|
20
|
+
export { N as NodeKindPresentation, c as categoryAccent, b as clearNodeKindOverrides, d as defaultConfigFor, g as getNodeKind, l as listNodeKinds, o as onNodeKindsChanged, e as overrideNodeKind, r as registerNodeKind, v as validateConfig } from './registry-BNyT66SS.cjs';
|
|
19
21
|
import './capabilities-BtJQTbnw.cjs';
|
|
20
22
|
|
|
21
23
|
type FlowCanvasProps = Omit<ReactFlowProps<FlowNode, Edge>, "nodes" | "edges" | "height"> & {
|
|
@@ -67,6 +69,49 @@ type FlowCanvasProps = Omit<ReactFlowProps<FlowNode, Edge>, "nodes" | "edges" |
|
|
|
67
69
|
*/
|
|
68
70
|
declare function FlowCanvas({ nodes, edges, background, showControls, showMinimap, height, validateConnections, isValidConnection, colorMode, showHelperLines, zoomOnWheel, onNodesChange, toolbar, nodeTypes, edgeTypes, className, style, ...rest }: FlowCanvasProps): react.JSX.Element;
|
|
69
71
|
|
|
72
|
+
type NodeConfigPanelProps = {
|
|
73
|
+
/** Currently-selected node — pass null to render the empty state. */
|
|
74
|
+
node: FlowNode | null;
|
|
75
|
+
/** Called when the user edits the node label, description, or config. */
|
|
76
|
+
onChange: (next: FlowNode) => void;
|
|
77
|
+
/**
|
|
78
|
+
* Called when the user deletes the node from the panel. When provided, the
|
|
79
|
+
* panel renders a "Delete node" button while a node is selected — so the
|
|
80
|
+
* delete affordance lives WITH the panel (a dev composing their own editor
|
|
81
|
+
* gets it for free), rather than in a host toolbar it has to re-implement.
|
|
82
|
+
*/
|
|
83
|
+
onDelete?: (node: FlowNode) => void;
|
|
84
|
+
/** Label for the delete button. Default "Delete node". */
|
|
85
|
+
deleteLabel?: string;
|
|
86
|
+
/** Optional header content (e.g. close button). */
|
|
87
|
+
header?: ReactNode;
|
|
88
|
+
/** Optional credential picker hook — host renders the picker. */
|
|
89
|
+
renderCredentialField?: (props: {
|
|
90
|
+
credentialType: string;
|
|
91
|
+
value: unknown;
|
|
92
|
+
onChange: (next: unknown) => void;
|
|
93
|
+
}) => ReactNode;
|
|
94
|
+
/**
|
|
95
|
+
* Optional document editor hook — host renders the editor for `document`
|
|
96
|
+
* fields. Lets rich authored content live in node config without fancy-flow
|
|
97
|
+
* taking on a document model.
|
|
98
|
+
*/
|
|
99
|
+
/** Host renderers keyed by field `type`. See {@link ConfigFieldRenderer}. */
|
|
100
|
+
fieldRenderers?: Record<string, ConfigFieldRenderFn>;
|
|
101
|
+
renderDocumentField?: (props: {
|
|
102
|
+
documentType?: string;
|
|
103
|
+
value: unknown;
|
|
104
|
+
onChange: (next: unknown) => void;
|
|
105
|
+
}) => ReactNode;
|
|
106
|
+
className?: string;
|
|
107
|
+
style?: React.CSSProperties;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* NodeConfigPanel — schema-driven form for the selected node. Defers to
|
|
111
|
+
* `kind.renderPanel` if the kind opts out of the auto-form.
|
|
112
|
+
*/
|
|
113
|
+
declare function NodeConfigPanel({ node, onChange, onDelete, deleteLabel, header, renderCredentialField, renderDocumentField, fieldRenderers, className, style, }: NodeConfigPanelProps): react.JSX.Element;
|
|
114
|
+
|
|
70
115
|
/**
|
|
71
116
|
* Clone a set of nodes AND the edges internal to that set, remapping every id.
|
|
72
117
|
* This is the piece `duplicateNode` lacks: a copy/paste (or duplicate-selection)
|
|
@@ -273,6 +318,20 @@ type FlowEditorProps = {
|
|
|
273
318
|
showPalette?: boolean;
|
|
274
319
|
/** Show the config panel sidebar. Default true. */
|
|
275
320
|
showPanel?: boolean;
|
|
321
|
+
/**
|
|
322
|
+
* Host renderers for config-field types, keyed by `type`, handed straight to
|
|
323
|
+
* `NodeConfigPanel`.
|
|
324
|
+
*
|
|
325
|
+
* Use it to claim a type the package renders plainly — the built-in `json`
|
|
326
|
+
* field is a bare textarea, and
|
|
327
|
+
* `@particle-academy/fancy-flow/fields/react-fancy` swaps it for a real typed
|
|
328
|
+
* editor — or to supply one the package has never heard of.
|
|
329
|
+
*
|
|
330
|
+
* This forwarding is the whole point: the seam existed on `NodeConfigPanel`
|
|
331
|
+
* and had no route through `FlowEditor`, so reaching it meant abandoning the
|
|
332
|
+
* editor and composing one by hand.
|
|
333
|
+
*/
|
|
334
|
+
fieldRenderers?: ComponentProps<typeof NodeConfigPanel>["fieldRenderers"];
|
|
276
335
|
/** Show run feed below the canvas. Default true. */
|
|
277
336
|
showFeed?: boolean;
|
|
278
337
|
/** Total editor height. Default 720. */
|
|
@@ -347,128 +406,6 @@ declare function paletteDropHandlers(onDrop: (kindName: string, evt: React.DragE
|
|
|
347
406
|
onDrop: (e: React.DragEvent) => void;
|
|
348
407
|
};
|
|
349
408
|
|
|
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;
|
|
357
|
-
};
|
|
358
|
-
/**
|
|
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.
|
|
365
|
-
*/
|
|
366
|
-
type ConfigFieldRenderFn = (ctx: ConfigFieldRenderContext) => ReactNode;
|
|
367
|
-
type ConfigFieldRendererProps = {
|
|
368
|
-
field: ConfigField;
|
|
369
|
-
value: unknown;
|
|
370
|
-
onChange: (value: unknown) => void;
|
|
371
|
-
/**
|
|
372
|
-
* DOM id for the control this renders.
|
|
373
|
-
*
|
|
374
|
-
* Supplied by the caller rather than generated here so the panel's `<label>`
|
|
375
|
-
* can point at it — a label beside a control is not a label attached to one.
|
|
376
|
-
* Also the agent-facing handle: the Human+ contract asks that every
|
|
377
|
-
* interactive element have a stable identity so an agent targets it instead
|
|
378
|
-
* of guessing at the DOM, and until this existed nothing in the editor had
|
|
379
|
-
* one.
|
|
380
|
-
*/
|
|
381
|
-
id?: string;
|
|
382
|
-
renderCredentialField?: (props: {
|
|
383
|
-
credentialType: string;
|
|
384
|
-
value: unknown;
|
|
385
|
-
onChange: (next: unknown) => void;
|
|
386
|
-
}) => ReactNode;
|
|
387
|
-
/**
|
|
388
|
-
* Editor for `document` fields. fancy-flow stores the document but never
|
|
389
|
-
* interprets it — the host owns the editing surface, exactly as it does for
|
|
390
|
-
* `credential`. This is the seam for rich human-input steps (authored pages,
|
|
391
|
-
* required reading, multi-section forms) without the package depending on
|
|
392
|
-
* any particular document model.
|
|
393
|
-
*/
|
|
394
|
-
renderDocumentField?: (props: {
|
|
395
|
-
documentType?: string;
|
|
396
|
-
value: unknown;
|
|
397
|
-
onChange: (next: unknown) => void;
|
|
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>;
|
|
415
|
-
};
|
|
416
|
-
/**
|
|
417
|
-
* ConfigFieldRenderer — dispatches to the right input element per field type.
|
|
418
|
-
*
|
|
419
|
-
* Plain HTML inputs styled via the package's CSS so the package stays
|
|
420
|
-
* standalone (no react-fancy import required) and every surface stays themeable
|
|
421
|
-
* through the `--ff-*` token layer. Hosts that want react-fancy form components
|
|
422
|
-
* can supply their own field renderers via the kind's `renderPanel`.
|
|
423
|
-
*
|
|
424
|
-
* Each control carries the caller's `id` and a `data-ff-field` handle keyed by
|
|
425
|
-
* the field, so a label can point at it and an agent can find it by name.
|
|
426
|
-
*/
|
|
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;
|
|
471
|
-
|
|
472
409
|
/** Entry-point node — outputs only, no inputs. */
|
|
473
410
|
declare function TriggerNodeInner(props: NodeProps<FlowNode>): react.JSX.Element;
|
|
474
411
|
declare const TriggerNode: react.MemoExoticComponent<typeof TriggerNodeInner>;
|
|
@@ -683,4 +620,4 @@ declare const flowKeys: {
|
|
|
683
620
|
readonly run: (runId: string) => readonly ["flow", "runs", string];
|
|
684
621
|
};
|
|
685
622
|
|
|
686
|
-
export { ActionNode, type AlignEdge, AutoLayoutOptions,
|
|
623
|
+
export { ActionNode, type AlignEdge, AutoLayoutOptions, ConfigFieldRenderFn, 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
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ReactNode, CSSProperties, ComponentType } from 'react';
|
|
2
|
+
import { ReactNode, CSSProperties, ComponentProps, ComponentType } from 'react';
|
|
3
3
|
import { ReactFlowProps, Edge, BackgroundVariant, Connection, NodeProps, NodeTypes } from '@xyflow/react';
|
|
4
4
|
import { ConnectionValidatorOptions } from './registry/index.js';
|
|
5
5
|
export { ANY_PORT_TYPE, BUILTIN_KINDS, PortCompatibility, RegistryNode, RichInputAdapter, RichInputPreview, buildNodeTypes, createConnectionValidator, defaultPortCompatibility, getRichInputAdapter, isRichInputEnabled, onRichInputAdapterChanged, registerBuiltinKinds, registerRichInputAdapter, resolveNodePorts, resolvePortSpec } from './registry/index.js';
|
|
6
6
|
import { b as FlowNode, F as FlowGraph, e as NodeRunStatus, E as ExecutorRegistry } from './types-sOmpCitB.js';
|
|
7
7
|
export { A as ActionNodeData, B as BaseNodeData, D as DecisionNodeData, a as FlowEdge, c as FlowNodeData, d as FlowNodeKind, N as NodeExecutor, f as NoteNodeData, O as OutputNodeData, P as PortDescriptor, R as RunEvent, S as SubgraphNodeData, T as TriggerNodeData } from './types-sOmpCitB.js';
|
|
8
|
+
import { C as ConfigFieldRenderFn } from './ConfigFieldRenderer-D2TejNY1.js';
|
|
9
|
+
export { a as ConfigFieldRenderContext, b as ConfigFieldRenderer, c as ConfigFieldRendererProps } from './ConfigFieldRenderer-D2TejNY1.js';
|
|
8
10
|
import { WorkflowSchema, WorkflowMetadata } from './schema/index.js';
|
|
9
11
|
export { ImportIssue, ImportOptions, ImportResult, WORKFLOW_SCHEMA_URL, WORKFLOW_SCHEMA_VERSION, WorkflowSchemaEdge, WorkflowSchemaNode, exportWorkflow, importWorkflow, migrateSchema, workflowToBlob } from './schema/index.js';
|
|
10
12
|
import { AutoLayoutOptions } from './layout/index.js';
|
|
11
13
|
export { AutoLayoutDirection } from './layout/index.js';
|
|
12
|
-
import { c as NodeCategory, d as NodeKindDefinition
|
|
13
|
-
export { D as DocumentConfigField, K as KeyValueConfigField, L as LEGACY_PAUSE_PREFIXES, h as PAUSE_PREFIX, P as PauseAwaiting, i as PauseSignal, j as PortSpec, R as RenderBodyContext, t as RepeaterConfigField, u as RepeaterRowField, m as decodePause, n as encodePause, o as isPause, p as pauseForHuman } from './types-
|
|
14
|
+
import { c as NodeCategory, d as NodeKindDefinition } from './types-Cf75IbxY.js';
|
|
15
|
+
export { a as ConfigField, D as DocumentConfigField, K as KeyValueConfigField, L as LEGACY_PAUSE_PREFIXES, h as PAUSE_PREFIX, P as PauseAwaiting, i as PauseSignal, j as PortSpec, R as RenderBodyContext, t as RepeaterConfigField, u as RepeaterRowField, m as decodePause, n as encodePause, o as isPause, p as pauseForHuman } from './types-Cf75IbxY.js';
|
|
14
16
|
export { F as FlowNodeStatus, a as FlowViewer, b as FlowViewerClassNames, c as FlowViewerProps } from './FlowViewer-C4QAVgWv.js';
|
|
15
17
|
import { FlowRunFeedEntry } from './runtime/index.js';
|
|
16
18
|
export { HistoryController, UseFlowHistoryReturn, UseFlowRunOptions, UseFlowRunReturn, UseFlowStateReturn, applyOutputsToNodes, applyStatusesToNodes, createHistory, useFlowHistory, useFlowRun, useFlowState } from './runtime/index.js';
|
|
17
19
|
export { C as CohortGuard, a as CohortOptions, b as CohortPolicy, c as CohortResult, R as RunOptions, d as RunResult, r as runCohort, e as runFlow } from './run-cohort-BnP6ErHi.js';
|
|
18
|
-
export { N as NodeKindPresentation, c as categoryAccent, b as clearNodeKindOverrides, d as defaultConfigFor, g as getNodeKind, l as listNodeKinds, o as onNodeKindsChanged, e as overrideNodeKind, r as registerNodeKind, v as validateConfig } from './registry-
|
|
20
|
+
export { N as NodeKindPresentation, c as categoryAccent, b as clearNodeKindOverrides, d as defaultConfigFor, g as getNodeKind, l as listNodeKinds, o as onNodeKindsChanged, e as overrideNodeKind, r as registerNodeKind, v as validateConfig } from './registry-CS7kjMto.js';
|
|
19
21
|
import './capabilities-CkhKj_U_.js';
|
|
20
22
|
|
|
21
23
|
type FlowCanvasProps = Omit<ReactFlowProps<FlowNode, Edge>, "nodes" | "edges" | "height"> & {
|
|
@@ -67,6 +69,49 @@ type FlowCanvasProps = Omit<ReactFlowProps<FlowNode, Edge>, "nodes" | "edges" |
|
|
|
67
69
|
*/
|
|
68
70
|
declare function FlowCanvas({ nodes, edges, background, showControls, showMinimap, height, validateConnections, isValidConnection, colorMode, showHelperLines, zoomOnWheel, onNodesChange, toolbar, nodeTypes, edgeTypes, className, style, ...rest }: FlowCanvasProps): react.JSX.Element;
|
|
69
71
|
|
|
72
|
+
type NodeConfigPanelProps = {
|
|
73
|
+
/** Currently-selected node — pass null to render the empty state. */
|
|
74
|
+
node: FlowNode | null;
|
|
75
|
+
/** Called when the user edits the node label, description, or config. */
|
|
76
|
+
onChange: (next: FlowNode) => void;
|
|
77
|
+
/**
|
|
78
|
+
* Called when the user deletes the node from the panel. When provided, the
|
|
79
|
+
* panel renders a "Delete node" button while a node is selected — so the
|
|
80
|
+
* delete affordance lives WITH the panel (a dev composing their own editor
|
|
81
|
+
* gets it for free), rather than in a host toolbar it has to re-implement.
|
|
82
|
+
*/
|
|
83
|
+
onDelete?: (node: FlowNode) => void;
|
|
84
|
+
/** Label for the delete button. Default "Delete node". */
|
|
85
|
+
deleteLabel?: string;
|
|
86
|
+
/** Optional header content (e.g. close button). */
|
|
87
|
+
header?: ReactNode;
|
|
88
|
+
/** Optional credential picker hook — host renders the picker. */
|
|
89
|
+
renderCredentialField?: (props: {
|
|
90
|
+
credentialType: string;
|
|
91
|
+
value: unknown;
|
|
92
|
+
onChange: (next: unknown) => void;
|
|
93
|
+
}) => ReactNode;
|
|
94
|
+
/**
|
|
95
|
+
* Optional document editor hook — host renders the editor for `document`
|
|
96
|
+
* fields. Lets rich authored content live in node config without fancy-flow
|
|
97
|
+
* taking on a document model.
|
|
98
|
+
*/
|
|
99
|
+
/** Host renderers keyed by field `type`. See {@link ConfigFieldRenderer}. */
|
|
100
|
+
fieldRenderers?: Record<string, ConfigFieldRenderFn>;
|
|
101
|
+
renderDocumentField?: (props: {
|
|
102
|
+
documentType?: string;
|
|
103
|
+
value: unknown;
|
|
104
|
+
onChange: (next: unknown) => void;
|
|
105
|
+
}) => ReactNode;
|
|
106
|
+
className?: string;
|
|
107
|
+
style?: React.CSSProperties;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* NodeConfigPanel — schema-driven form for the selected node. Defers to
|
|
111
|
+
* `kind.renderPanel` if the kind opts out of the auto-form.
|
|
112
|
+
*/
|
|
113
|
+
declare function NodeConfigPanel({ node, onChange, onDelete, deleteLabel, header, renderCredentialField, renderDocumentField, fieldRenderers, className, style, }: NodeConfigPanelProps): react.JSX.Element;
|
|
114
|
+
|
|
70
115
|
/**
|
|
71
116
|
* Clone a set of nodes AND the edges internal to that set, remapping every id.
|
|
72
117
|
* This is the piece `duplicateNode` lacks: a copy/paste (or duplicate-selection)
|
|
@@ -273,6 +318,20 @@ type FlowEditorProps = {
|
|
|
273
318
|
showPalette?: boolean;
|
|
274
319
|
/** Show the config panel sidebar. Default true. */
|
|
275
320
|
showPanel?: boolean;
|
|
321
|
+
/**
|
|
322
|
+
* Host renderers for config-field types, keyed by `type`, handed straight to
|
|
323
|
+
* `NodeConfigPanel`.
|
|
324
|
+
*
|
|
325
|
+
* Use it to claim a type the package renders plainly — the built-in `json`
|
|
326
|
+
* field is a bare textarea, and
|
|
327
|
+
* `@particle-academy/fancy-flow/fields/react-fancy` swaps it for a real typed
|
|
328
|
+
* editor — or to supply one the package has never heard of.
|
|
329
|
+
*
|
|
330
|
+
* This forwarding is the whole point: the seam existed on `NodeConfigPanel`
|
|
331
|
+
* and had no route through `FlowEditor`, so reaching it meant abandoning the
|
|
332
|
+
* editor and composing one by hand.
|
|
333
|
+
*/
|
|
334
|
+
fieldRenderers?: ComponentProps<typeof NodeConfigPanel>["fieldRenderers"];
|
|
276
335
|
/** Show run feed below the canvas. Default true. */
|
|
277
336
|
showFeed?: boolean;
|
|
278
337
|
/** Total editor height. Default 720. */
|
|
@@ -347,128 +406,6 @@ declare function paletteDropHandlers(onDrop: (kindName: string, evt: React.DragE
|
|
|
347
406
|
onDrop: (e: React.DragEvent) => void;
|
|
348
407
|
};
|
|
349
408
|
|
|
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;
|
|
357
|
-
};
|
|
358
|
-
/**
|
|
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.
|
|
365
|
-
*/
|
|
366
|
-
type ConfigFieldRenderFn = (ctx: ConfigFieldRenderContext) => ReactNode;
|
|
367
|
-
type ConfigFieldRendererProps = {
|
|
368
|
-
field: ConfigField;
|
|
369
|
-
value: unknown;
|
|
370
|
-
onChange: (value: unknown) => void;
|
|
371
|
-
/**
|
|
372
|
-
* DOM id for the control this renders.
|
|
373
|
-
*
|
|
374
|
-
* Supplied by the caller rather than generated here so the panel's `<label>`
|
|
375
|
-
* can point at it — a label beside a control is not a label attached to one.
|
|
376
|
-
* Also the agent-facing handle: the Human+ contract asks that every
|
|
377
|
-
* interactive element have a stable identity so an agent targets it instead
|
|
378
|
-
* of guessing at the DOM, and until this existed nothing in the editor had
|
|
379
|
-
* one.
|
|
380
|
-
*/
|
|
381
|
-
id?: string;
|
|
382
|
-
renderCredentialField?: (props: {
|
|
383
|
-
credentialType: string;
|
|
384
|
-
value: unknown;
|
|
385
|
-
onChange: (next: unknown) => void;
|
|
386
|
-
}) => ReactNode;
|
|
387
|
-
/**
|
|
388
|
-
* Editor for `document` fields. fancy-flow stores the document but never
|
|
389
|
-
* interprets it — the host owns the editing surface, exactly as it does for
|
|
390
|
-
* `credential`. This is the seam for rich human-input steps (authored pages,
|
|
391
|
-
* required reading, multi-section forms) without the package depending on
|
|
392
|
-
* any particular document model.
|
|
393
|
-
*/
|
|
394
|
-
renderDocumentField?: (props: {
|
|
395
|
-
documentType?: string;
|
|
396
|
-
value: unknown;
|
|
397
|
-
onChange: (next: unknown) => void;
|
|
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>;
|
|
415
|
-
};
|
|
416
|
-
/**
|
|
417
|
-
* ConfigFieldRenderer — dispatches to the right input element per field type.
|
|
418
|
-
*
|
|
419
|
-
* Plain HTML inputs styled via the package's CSS so the package stays
|
|
420
|
-
* standalone (no react-fancy import required) and every surface stays themeable
|
|
421
|
-
* through the `--ff-*` token layer. Hosts that want react-fancy form components
|
|
422
|
-
* can supply their own field renderers via the kind's `renderPanel`.
|
|
423
|
-
*
|
|
424
|
-
* Each control carries the caller's `id` and a `data-ff-field` handle keyed by
|
|
425
|
-
* the field, so a label can point at it and an agent can find it by name.
|
|
426
|
-
*/
|
|
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;
|
|
471
|
-
|
|
472
409
|
/** Entry-point node — outputs only, no inputs. */
|
|
473
410
|
declare function TriggerNodeInner(props: NodeProps<FlowNode>): react.JSX.Element;
|
|
474
411
|
declare const TriggerNode: react.MemoExoticComponent<typeof TriggerNodeInner>;
|
|
@@ -683,4 +620,4 @@ declare const flowKeys: {
|
|
|
683
620
|
readonly run: (runId: string) => readonly ["flow", "runs", string];
|
|
684
621
|
};
|
|
685
622
|
|
|
686
|
-
export { ActionNode, type AlignEdge, AutoLayoutOptions,
|
|
623
|
+
export { ActionNode, type AlignEdge, AutoLayoutOptions, ConfigFieldRenderFn, 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
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { removeNodes, removeEdges, cloneSubgraph, alignNodes, distributeNodes, reconnectEdge, assignToLane, removeFromLane, duplicateNode, setEdgeLabel, FlowCanvas } from './chunk-
|
|
2
|
-
export { ActionNode, DecisionNode, FlowCanvas, FlowViewer, NodeShell, OutputNode, SubgraphNode, TriggerNode, alignNodes, cloneSubgraph, defaultNodeTypes, distributeNodes, reconnectEdge } from './chunk-
|
|
1
|
+
import { removeNodes, removeEdges, cloneSubgraph, alignNodes, distributeNodes, reconnectEdge, assignToLane, removeFromLane, duplicateNode, setEdgeLabel, FlowCanvas } from './chunk-WOO4B7M5.js';
|
|
2
|
+
export { ActionNode, DecisionNode, FlowCanvas, FlowViewer, NodeShell, OutputNode, SubgraphNode, TriggerNode, alignNodes, cloneSubgraph, defaultNodeTypes, distributeNodes, reconnectEdge } from './chunk-WOO4B7M5.js';
|
|
3
3
|
import { useFlowState, useFlowRun, useFlowHistory, applyOutputsToNodes, applyStatusesToNodes } from './chunk-A6RFLGWV.js';
|
|
4
4
|
export { applyOutputsToNodes, applyStatusesToNodes, createHistory, useFlowHistory, useFlowRun, useFlowState } from './chunk-A6RFLGWV.js';
|
|
5
5
|
export { runCohort } from './chunk-QZTGV3ZL.js';
|
|
@@ -195,7 +195,7 @@ function ConfigFieldRenderer({
|
|
|
195
195
|
}
|
|
196
196
|
);
|
|
197
197
|
case "json":
|
|
198
|
-
return /* @__PURE__ */ jsx(JsonField, { value, onChange, rows: field.rows });
|
|
198
|
+
return /* @__PURE__ */ jsx(JsonField, { value, onChange, rows: field.rows, handle });
|
|
199
199
|
case "expression":
|
|
200
200
|
return /* @__PURE__ */ jsx(
|
|
201
201
|
"textarea",
|
|
@@ -227,6 +227,7 @@ function ConfigFieldRenderer({
|
|
|
227
227
|
return /* @__PURE__ */ jsx(
|
|
228
228
|
RepeaterField,
|
|
229
229
|
{
|
|
230
|
+
id,
|
|
230
231
|
field,
|
|
231
232
|
value,
|
|
232
233
|
onChange,
|
|
@@ -236,7 +237,7 @@ function ConfigFieldRenderer({
|
|
|
236
237
|
}
|
|
237
238
|
);
|
|
238
239
|
case "keyvalue":
|
|
239
|
-
return /* @__PURE__ */ jsx(KeyValueField, { field, value, onChange });
|
|
240
|
+
return /* @__PURE__ */ jsx(KeyValueField, { id, field, value, onChange });
|
|
240
241
|
case "document":
|
|
241
242
|
if (renderDocumentField) {
|
|
242
243
|
return /* @__PURE__ */ jsx(Fragment, { children: renderDocumentField({ documentType: field.documentType, value, onChange }) });
|
|
@@ -281,6 +282,7 @@ function ChoiceField({
|
|
|
281
282
|
);
|
|
282
283
|
}
|
|
283
284
|
function RepeaterField({
|
|
285
|
+
id,
|
|
284
286
|
field,
|
|
285
287
|
value,
|
|
286
288
|
onChange,
|
|
@@ -315,7 +317,7 @@ function RepeaterField({
|
|
|
315
317
|
if (typeof raw === "number" || typeof raw === "boolean") return String(raw);
|
|
316
318
|
return `Item ${i + 1}`;
|
|
317
319
|
};
|
|
318
|
-
return /* @__PURE__ */ jsxs("div", { className: "ff-repeater", "data-ff-repeater": field.key, children: [
|
|
320
|
+
return /* @__PURE__ */ jsxs("div", { id, role: "group", className: "ff-repeater", "data-ff-repeater": field.key, "data-ff-field": field.key, children: [
|
|
319
321
|
rows.length === 0 && /* @__PURE__ */ jsx("p", { className: "ff-repeater__empty", children: "None yet." }),
|
|
320
322
|
rows.map((row, i) => /* @__PURE__ */ jsxs("div", { className: "ff-repeater__row", "data-ff-repeater-row": i, children: [
|
|
321
323
|
/* @__PURE__ */ jsxs("div", { className: "ff-repeater__row-head", children: [
|
|
@@ -390,6 +392,7 @@ function RepeaterField({
|
|
|
390
392
|
] });
|
|
391
393
|
}
|
|
392
394
|
function KeyValueField({
|
|
395
|
+
id,
|
|
393
396
|
field,
|
|
394
397
|
value,
|
|
395
398
|
onChange
|
|
@@ -408,7 +411,7 @@ function KeyValueField({
|
|
|
408
411
|
const setVal = (i, val) => commit(entries.map(([k, v], idx) => idx === i ? [k, val] : [k, v]));
|
|
409
412
|
const remove = (i) => commit(entries.filter((_, idx) => idx !== i));
|
|
410
413
|
const add = () => commit([...entries, ["", ""]]);
|
|
411
|
-
return /* @__PURE__ */ jsxs("div", { className: "ff-keyvalue", "data-ff-keyvalue": field.key, children: [
|
|
414
|
+
return /* @__PURE__ */ jsxs("div", { id, role: "group", className: "ff-keyvalue", "data-ff-keyvalue": field.key, "data-ff-field": field.key, children: [
|
|
412
415
|
entries.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ff-keyvalue__head", children: [
|
|
413
416
|
/* @__PURE__ */ jsx("span", { children: field.keyLabel ?? "Key" }),
|
|
414
417
|
/* @__PURE__ */ jsx("span", { children: field.valueLabel ?? "Value" }),
|
|
@@ -464,34 +467,76 @@ function KeyValueField({
|
|
|
464
467
|
] })
|
|
465
468
|
] });
|
|
466
469
|
}
|
|
467
|
-
function JsonField({
|
|
468
|
-
|
|
470
|
+
function JsonField({
|
|
471
|
+
value,
|
|
472
|
+
onChange,
|
|
473
|
+
rows,
|
|
474
|
+
handle
|
|
475
|
+
}) {
|
|
476
|
+
const serialized = useMemo(() => {
|
|
469
477
|
try {
|
|
470
478
|
return value === void 0 ? "" : JSON.stringify(value, null, 2);
|
|
471
479
|
} catch {
|
|
472
480
|
return "";
|
|
473
481
|
}
|
|
474
482
|
}, [value]);
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
483
|
+
const [text, setText] = useState(serialized);
|
|
484
|
+
const [error, setError] = useState(null);
|
|
485
|
+
const [touched, setTouched] = useState(false);
|
|
486
|
+
const lastProps = useRef(serialized);
|
|
487
|
+
const committed = useRef(null);
|
|
488
|
+
if (serialized !== lastProps.current) {
|
|
489
|
+
lastProps.current = serialized;
|
|
490
|
+
if (serialized !== committed.current) {
|
|
491
|
+
setText(serialized);
|
|
492
|
+
setError(null);
|
|
493
|
+
setTouched(false);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
const commit = (next) => {
|
|
497
|
+
const trimmed = next.trim();
|
|
498
|
+
if (trimmed === "") {
|
|
499
|
+
committed.current = "";
|
|
500
|
+
onChange(void 0);
|
|
501
|
+
return null;
|
|
502
|
+
}
|
|
503
|
+
try {
|
|
504
|
+
const parsed = JSON.parse(trimmed);
|
|
505
|
+
committed.current = JSON.stringify(parsed, null, 2);
|
|
506
|
+
onChange(parsed);
|
|
507
|
+
return null;
|
|
508
|
+
} catch (e) {
|
|
509
|
+
return e instanceof Error ? e.message : "Invalid JSON";
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
const errorId = handle.id ? `${handle.id}-error` : void 0;
|
|
513
|
+
const showError = touched && error !== null;
|
|
514
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
515
|
+
/* @__PURE__ */ jsx(
|
|
516
|
+
"textarea",
|
|
517
|
+
{
|
|
518
|
+
...handle,
|
|
519
|
+
className: "ff-panel__input ff-panel__input--json",
|
|
520
|
+
rows: rows ?? 6,
|
|
521
|
+
value: text,
|
|
522
|
+
spellCheck: false,
|
|
523
|
+
"aria-invalid": showError || void 0,
|
|
524
|
+
"aria-describedby": showError ? errorId : void 0,
|
|
525
|
+
onChange: (e) => {
|
|
526
|
+
setText(e.target.value);
|
|
527
|
+
setError(commit(e.target.value));
|
|
528
|
+
},
|
|
529
|
+
onBlur: (e) => {
|
|
530
|
+
setTouched(true);
|
|
531
|
+
setError(commit(e.target.value));
|
|
491
532
|
}
|
|
492
533
|
}
|
|
493
|
-
|
|
494
|
-
|
|
534
|
+
),
|
|
535
|
+
showError && /* @__PURE__ */ jsxs("p", { className: "ff-panel__issue ff-panel__issue--field", id: errorId, role: "alert", children: [
|
|
536
|
+
"\u26A0 ",
|
|
537
|
+
error
|
|
538
|
+
] })
|
|
539
|
+
] });
|
|
495
540
|
}
|
|
496
541
|
function NodeConfigPanel({
|
|
497
542
|
node,
|
|
@@ -810,6 +855,7 @@ function FlowEditorInner({
|
|
|
810
855
|
metadata,
|
|
811
856
|
showPalette = true,
|
|
812
857
|
showPanel = true,
|
|
858
|
+
fieldRenderers,
|
|
813
859
|
showFeed = true,
|
|
814
860
|
extraToolbar,
|
|
815
861
|
actions = [],
|
|
@@ -1369,6 +1415,7 @@ function FlowEditorInner({
|
|
|
1369
1415
|
className: "ff-editor__panel",
|
|
1370
1416
|
node: api.selected,
|
|
1371
1417
|
onChange: api.updateNode,
|
|
1418
|
+
fieldRenderers,
|
|
1372
1419
|
onDelete: builtins.delete === false ? void 0 : (n) => api.deleteNodes([n.id])
|
|
1373
1420
|
}
|
|
1374
1421
|
),
|