@particle-academy/fancy-flow 0.7.0 → 0.9.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 (47) hide show
  1. package/README.md +93 -0
  2. package/dist/{chunk-BCXECQUC.js → chunk-6GGFEZH7.js} +3 -3
  3. package/dist/{chunk-BCXECQUC.js.map → chunk-6GGFEZH7.js.map} +1 -1
  4. package/dist/{chunk-M2XKGQQL.js → chunk-6RHAQ2LP.js} +228 -17
  5. package/dist/chunk-6RHAQ2LP.js.map +1 -0
  6. package/dist/{chunk-WNVBXXOL.js → chunk-CPSOC27D.js} +43 -2
  7. package/dist/chunk-CPSOC27D.js.map +1 -0
  8. package/dist/{chunk-NVULCEDX.js → chunk-HNBO4HP3.js} +8 -4
  9. package/dist/chunk-HNBO4HP3.js.map +1 -0
  10. package/dist/chunk-TITD5W4Y.js +26 -0
  11. package/dist/chunk-TITD5W4Y.js.map +1 -0
  12. package/dist/{chunk-QSSQRQN4.js → chunk-VEI743ZX.js} +3 -3
  13. package/dist/{chunk-QSSQRQN4.js.map → chunk-VEI743ZX.js.map} +1 -1
  14. package/dist/engine.cjs +32 -2
  15. package/dist/engine.cjs.map +1 -1
  16. package/dist/engine.js +3 -1
  17. package/dist/index.cjs +717 -40
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +45 -6
  20. package/dist/index.d.ts +45 -6
  21. package/dist/index.js +415 -23
  22. package/dist/index.js.map +1 -1
  23. package/dist/registry/index.d.cts +111 -4
  24. package/dist/registry/index.d.ts +111 -4
  25. package/dist/registry.cjs +313 -31
  26. package/dist/registry.cjs.map +1 -1
  27. package/dist/registry.js +3 -2
  28. package/dist/runtime.cjs +32 -2
  29. package/dist/runtime.cjs.map +1 -1
  30. package/dist/runtime.js +4 -2
  31. package/dist/schema.cjs +41 -0
  32. package/dist/schema.cjs.map +1 -1
  33. package/dist/schema.js +2 -2
  34. package/dist/styles.css +191 -0
  35. package/dist/styles.css.map +1 -1
  36. package/dist/types-BocBFh6l.d.ts +221 -0
  37. package/dist/types-DKqaUjF_.d.cts +221 -0
  38. package/dist/ux.cjs.map +1 -1
  39. package/dist/ux.d.cts +1 -1
  40. package/dist/ux.d.ts +1 -1
  41. package/dist/ux.js +1 -1
  42. package/package.json +4 -4
  43. package/dist/chunk-M2XKGQQL.js.map +0 -1
  44. package/dist/chunk-NVULCEDX.js.map +0 -1
  45. package/dist/chunk-WNVBXXOL.js.map +0 -1
  46. package/dist/types-C0wdN6QX.d.cts +0 -121
  47. package/dist/types-DnMe9Vsf.d.ts +0 -121
@@ -1,8 +1,115 @@
1
- import { a as NodeKindDefinition } from '../types-C0wdN6QX.cjs';
2
- export { C as ConfigField, b as CredentialConfigField, E as ExpressionConfigField, J as JsonConfigField, N as NodeCategory, c as NumberConfigField, R as RenderBodyContext, S as SelectConfigField, d as SwitchConfigField, T as TextConfigField, e as TextareaConfigField } from '../types-C0wdN6QX.cjs';
1
+ import { a as NodeKindDefinition, P as PortSpec } from '../types-DKqaUjF_.cjs';
2
+ export { C as ConfigField, b as CredentialConfigField, D as DocumentConfigField, E as ExpressionConfigField, J as JsonConfigField, K as KeyValueConfigField, N as NodeCategory, c as NumberConfigField, R as RenderBodyContext, d as RepeaterConfigField, e as RepeaterRowField, S as SelectConfigField, f as SwitchConfigField, T as TextConfigField, g as TextareaConfigField } from '../types-DKqaUjF_.cjs';
3
+ import { F as FlowNode, P as PortDescriptor } from '../types-BS3Gwnkq.cjs';
3
4
  import * as react from 'react';
5
+ import { ReactNode } from 'react';
4
6
  import { NodeProps, NodeTypes } from '@xyflow/react';
5
- import { F as FlowNode } from '../types-BS3Gwnkq.cjs';
7
+
8
+ /**
9
+ * Port resolution — the single place a node's ports are derived, shared by
10
+ * the canvas renderer and the headless runtime.
11
+ *
12
+ * This module is deliberately React-free: `runFlow` (the `/engine` entry)
13
+ * imports it, and the engine bundle must stay free of React.
14
+ *
15
+ * ## Why this is centralized
16
+ *
17
+ * Ports used to be read in two places that disagreed — the canvas consulted
18
+ * `data.outputs ?? kind.outputs`, while the runtime consulted `data.outputs`
19
+ * ONLY and fell back to a single `out` port. A kind that declared branch ports
20
+ * therefore drew correctly and then routed as if it had one output, unless the
21
+ * host remembered to mirror the ports onto every node's `data`. Both callers
22
+ * now go through `resolveNodePorts`, so declared ports and executed ports
23
+ * cannot drift apart.
24
+ */
25
+ /**
26
+ * Resolve a `PortSpec` against a config object.
27
+ *
28
+ * A config-driven spec is author-supplied and runs on every render, so a throw
29
+ * is contained: it degrades to "undeclared" (letting the caller fall back)
30
+ * rather than taking out the canvas or aborting a run mid-flight.
31
+ */
32
+ declare function resolvePortSpec<TConfig>(spec: PortSpec<TConfig> | undefined, config: TConfig): PortDescriptor[] | undefined;
33
+ /** Read the config bag off a node, tolerating the FlowNodeData union. */
34
+ declare function nodeConfig(node: Pick<FlowNode, "data">): Record<string, unknown>;
35
+ /**
36
+ * Resolve a node's effective ports.
37
+ *
38
+ * Precedence: explicit `data.inputs`/`data.outputs` (a per-node host override)
39
+ * beats the kind's declaration. `undefined` means "nothing declared" — the
40
+ * caller applies its own category default.
41
+ */
42
+ declare function resolveNodePorts(node: Pick<FlowNode, "data">, kind?: Pick<NodeKindDefinition<any>, "inputs" | "outputs">): {
43
+ inputs?: PortDescriptor[];
44
+ outputs?: PortDescriptor[];
45
+ };
46
+
47
+ /**
48
+ * Rich user input — the adapter seam.
49
+ *
50
+ * `rich_user_input` pauses a run on a fully authored page (long-form content,
51
+ * required reading + confirmation, multi-section forms) rather than a flat
52
+ * field list. Authoring and rendering that document needs a document model
53
+ * (fancy-cms Stages) and a device frame for the preview (react-fancy's
54
+ * FauxClient) — neither of which fancy-flow depends on.
55
+ *
56
+ * So the host registers them once, and the node lights up:
57
+ *
58
+ * ```tsx
59
+ * import { FauxClient } from "@particle-academy/react-fancy";
60
+ * import { StagesViewer } from "@particle-academy/fancy-cms-ui";
61
+ * import { registerRichInputAdapter } from "@particle-academy/fancy-flow";
62
+ *
63
+ * registerRichInputAdapter({
64
+ * FauxClient,
65
+ * renderDocument: (doc) => <StagesViewer doc={doc} />,
66
+ * });
67
+ * ```
68
+ *
69
+ * Until then the node still registers and still round-trips its config — it
70
+ * just renders an "unavailable" body explaining what to install. Keeping the
71
+ * dependency optional is deliberate: fancy-cms is an early-release beta, and a
72
+ * workflow editor should not hard-require a CMS to draw a canvas.
73
+ */
74
+ type RichInputAdapter = {
75
+ /**
76
+ * react-fancy's `FauxClient` (or any component with the same shape) — a
77
+ * frame that mimics a browser window or device and scales its content down
78
+ * to fit. Used to preview the authored page inside the node card.
79
+ */
80
+ FauxClient?: (props: {
81
+ variant?: "browser" | "device" | "bare";
82
+ children?: ReactNode;
83
+ [key: string]: unknown;
84
+ }) => ReactNode;
85
+ /** Render the stored document read-only, for the in-node preview. */
86
+ renderDocument?: (doc: unknown) => ReactNode;
87
+ /** Editor mounted in the config panel via `renderDocumentField`. */
88
+ renderEditor?: (props: {
89
+ value: unknown;
90
+ onChange: (next: unknown) => void;
91
+ }) => ReactNode;
92
+ };
93
+ /** Install the host's document editor + preview frame. Returns an unregister fn. */
94
+ declare function registerRichInputAdapter(next: RichInputAdapter): () => void;
95
+ /** The registered adapter, or null when the host hasn't wired one. */
96
+ declare function getRichInputAdapter(): RichInputAdapter | null;
97
+ /** True once a host has wired an adapter — i.e. the node is usable. */
98
+ declare function isRichInputEnabled(): boolean;
99
+ /** Subscribe to adapter changes (so nodes re-render when it lands). */
100
+ declare function onRichInputAdapterChanged(fn: () => void): () => void;
101
+ /**
102
+ * RichInputPreview — the node card body. Shows the authored page inside a
103
+ * FauxClient frame so an author can see, at a glance on the canvas, what the
104
+ * person hitting this step will be looking at.
105
+ *
106
+ * Degrades in two steps rather than one: no adapter at all → install hint;
107
+ * adapter but nothing authored yet → an empty frame with the step title. A
108
+ * blank node body would read as "broken" in both cases.
109
+ */
110
+ declare function RichInputPreview({ config }: {
111
+ config: Record<string, unknown>;
112
+ }): react.JSX.Element;
6
113
 
7
114
  /**
8
115
  * registerNodeKind — install a node kind in the global registry. Returns
@@ -50,4 +157,4 @@ declare const BUILTIN_KINDS: NodeKindDefinition[];
50
157
  */
51
158
  declare function buildNodeTypes(): NodeTypes;
52
159
 
53
- export { BUILTIN_KINDS, NodeKindDefinition, RegistryNode, buildNodeTypes, categoryAccent, defaultConfigFor, getNodeKind, listNodeKinds, onNodeKindsChanged, registerBuiltinKinds, registerNodeKind, validateConfig };
160
+ export { BUILTIN_KINDS, NodeKindDefinition, PortSpec, RegistryNode, type RichInputAdapter, RichInputPreview, buildNodeTypes, categoryAccent, defaultConfigFor, getNodeKind, getRichInputAdapter, isRichInputEnabled, listNodeKinds, nodeConfig, onNodeKindsChanged, onRichInputAdapterChanged, registerBuiltinKinds, registerNodeKind, registerRichInputAdapter, resolveNodePorts, resolvePortSpec, validateConfig };
@@ -1,8 +1,115 @@
1
- import { a as NodeKindDefinition } from '../types-DnMe9Vsf.js';
2
- export { C as ConfigField, b as CredentialConfigField, E as ExpressionConfigField, J as JsonConfigField, N as NodeCategory, c as NumberConfigField, R as RenderBodyContext, S as SelectConfigField, d as SwitchConfigField, T as TextConfigField, e as TextareaConfigField } from '../types-DnMe9Vsf.js';
1
+ import { a as NodeKindDefinition, P as PortSpec } from '../types-BocBFh6l.js';
2
+ export { C as ConfigField, b as CredentialConfigField, D as DocumentConfigField, E as ExpressionConfigField, J as JsonConfigField, K as KeyValueConfigField, N as NodeCategory, c as NumberConfigField, R as RenderBodyContext, d as RepeaterConfigField, e as RepeaterRowField, S as SelectConfigField, f as SwitchConfigField, T as TextConfigField, g as TextareaConfigField } from '../types-BocBFh6l.js';
3
+ import { F as FlowNode, P as PortDescriptor } from '../types-BS3Gwnkq.js';
3
4
  import * as react from 'react';
5
+ import { ReactNode } from 'react';
4
6
  import { NodeProps, NodeTypes } from '@xyflow/react';
5
- import { F as FlowNode } from '../types-BS3Gwnkq.js';
7
+
8
+ /**
9
+ * Port resolution — the single place a node's ports are derived, shared by
10
+ * the canvas renderer and the headless runtime.
11
+ *
12
+ * This module is deliberately React-free: `runFlow` (the `/engine` entry)
13
+ * imports it, and the engine bundle must stay free of React.
14
+ *
15
+ * ## Why this is centralized
16
+ *
17
+ * Ports used to be read in two places that disagreed — the canvas consulted
18
+ * `data.outputs ?? kind.outputs`, while the runtime consulted `data.outputs`
19
+ * ONLY and fell back to a single `out` port. A kind that declared branch ports
20
+ * therefore drew correctly and then routed as if it had one output, unless the
21
+ * host remembered to mirror the ports onto every node's `data`. Both callers
22
+ * now go through `resolveNodePorts`, so declared ports and executed ports
23
+ * cannot drift apart.
24
+ */
25
+ /**
26
+ * Resolve a `PortSpec` against a config object.
27
+ *
28
+ * A config-driven spec is author-supplied and runs on every render, so a throw
29
+ * is contained: it degrades to "undeclared" (letting the caller fall back)
30
+ * rather than taking out the canvas or aborting a run mid-flight.
31
+ */
32
+ declare function resolvePortSpec<TConfig>(spec: PortSpec<TConfig> | undefined, config: TConfig): PortDescriptor[] | undefined;
33
+ /** Read the config bag off a node, tolerating the FlowNodeData union. */
34
+ declare function nodeConfig(node: Pick<FlowNode, "data">): Record<string, unknown>;
35
+ /**
36
+ * Resolve a node's effective ports.
37
+ *
38
+ * Precedence: explicit `data.inputs`/`data.outputs` (a per-node host override)
39
+ * beats the kind's declaration. `undefined` means "nothing declared" — the
40
+ * caller applies its own category default.
41
+ */
42
+ declare function resolveNodePorts(node: Pick<FlowNode, "data">, kind?: Pick<NodeKindDefinition<any>, "inputs" | "outputs">): {
43
+ inputs?: PortDescriptor[];
44
+ outputs?: PortDescriptor[];
45
+ };
46
+
47
+ /**
48
+ * Rich user input — the adapter seam.
49
+ *
50
+ * `rich_user_input` pauses a run on a fully authored page (long-form content,
51
+ * required reading + confirmation, multi-section forms) rather than a flat
52
+ * field list. Authoring and rendering that document needs a document model
53
+ * (fancy-cms Stages) and a device frame for the preview (react-fancy's
54
+ * FauxClient) — neither of which fancy-flow depends on.
55
+ *
56
+ * So the host registers them once, and the node lights up:
57
+ *
58
+ * ```tsx
59
+ * import { FauxClient } from "@particle-academy/react-fancy";
60
+ * import { StagesViewer } from "@particle-academy/fancy-cms-ui";
61
+ * import { registerRichInputAdapter } from "@particle-academy/fancy-flow";
62
+ *
63
+ * registerRichInputAdapter({
64
+ * FauxClient,
65
+ * renderDocument: (doc) => <StagesViewer doc={doc} />,
66
+ * });
67
+ * ```
68
+ *
69
+ * Until then the node still registers and still round-trips its config — it
70
+ * just renders an "unavailable" body explaining what to install. Keeping the
71
+ * dependency optional is deliberate: fancy-cms is an early-release beta, and a
72
+ * workflow editor should not hard-require a CMS to draw a canvas.
73
+ */
74
+ type RichInputAdapter = {
75
+ /**
76
+ * react-fancy's `FauxClient` (or any component with the same shape) — a
77
+ * frame that mimics a browser window or device and scales its content down
78
+ * to fit. Used to preview the authored page inside the node card.
79
+ */
80
+ FauxClient?: (props: {
81
+ variant?: "browser" | "device" | "bare";
82
+ children?: ReactNode;
83
+ [key: string]: unknown;
84
+ }) => ReactNode;
85
+ /** Render the stored document read-only, for the in-node preview. */
86
+ renderDocument?: (doc: unknown) => ReactNode;
87
+ /** Editor mounted in the config panel via `renderDocumentField`. */
88
+ renderEditor?: (props: {
89
+ value: unknown;
90
+ onChange: (next: unknown) => void;
91
+ }) => ReactNode;
92
+ };
93
+ /** Install the host's document editor + preview frame. Returns an unregister fn. */
94
+ declare function registerRichInputAdapter(next: RichInputAdapter): () => void;
95
+ /** The registered adapter, or null when the host hasn't wired one. */
96
+ declare function getRichInputAdapter(): RichInputAdapter | null;
97
+ /** True once a host has wired an adapter — i.e. the node is usable. */
98
+ declare function isRichInputEnabled(): boolean;
99
+ /** Subscribe to adapter changes (so nodes re-render when it lands). */
100
+ declare function onRichInputAdapterChanged(fn: () => void): () => void;
101
+ /**
102
+ * RichInputPreview — the node card body. Shows the authored page inside a
103
+ * FauxClient frame so an author can see, at a glance on the canvas, what the
104
+ * person hitting this step will be looking at.
105
+ *
106
+ * Degrades in two steps rather than one: no adapter at all → install hint;
107
+ * adapter but nothing authored yet → an empty frame with the step title. A
108
+ * blank node body would read as "broken" in both cases.
109
+ */
110
+ declare function RichInputPreview({ config }: {
111
+ config: Record<string, unknown>;
112
+ }): react.JSX.Element;
6
113
 
7
114
  /**
8
115
  * registerNodeKind — install a node kind in the global registry. Returns
@@ -50,4 +157,4 @@ declare const BUILTIN_KINDS: NodeKindDefinition[];
50
157
  */
51
158
  declare function buildNodeTypes(): NodeTypes;
52
159
 
53
- export { BUILTIN_KINDS, NodeKindDefinition, RegistryNode, buildNodeTypes, categoryAccent, defaultConfigFor, getNodeKind, listNodeKinds, onNodeKindsChanged, registerBuiltinKinds, registerNodeKind, validateConfig };
160
+ export { BUILTIN_KINDS, NodeKindDefinition, PortSpec, RegistryNode, type RichInputAdapter, RichInputPreview, buildNodeTypes, categoryAccent, defaultConfigFor, getNodeKind, getRichInputAdapter, isRichInputEnabled, listNodeKinds, nodeConfig, onNodeKindsChanged, onRichInputAdapterChanged, registerBuiltinKinds, registerNodeKind, registerRichInputAdapter, resolveNodePorts, resolvePortSpec, validateConfig };