@statelyai/flow-react 0.4.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.
@@ -0,0 +1,306 @@
1
+ import * as react10 from "react";
2
+ import { CSSProperties, HTMLAttributes, ReactNode, RefObject } from "react";
3
+ import { AnchorSpec, ConnectionEndedEvent, CreateFlowOptions, EdgePathData, FlowColorMode, FlowController, FlowEdge, FlowGraph, FlowInputMode, FlowNode, FlowProfile, FlowStoreContext, LayoutRequestedEvent, Point, Rect, Viewport, VisualPort } from "@statelyai/flow";
4
+ import { ResolvedFlowColorMode } from "@statelyai/flow-dom";
5
+
6
+ //#region src/createFlowInstance.d.ts
7
+ type FlowSelector<T> = (context: FlowStoreContext) => T;
8
+ type FlowSelectorEquality<T> = (current: T, next: T) => boolean;
9
+ type FlowStoreListener<T = unknown> = {
10
+ selector: FlowSelector<T>;
11
+ onChange: (value: T, previousValue: T, context: FlowStoreContext) => void;
12
+ isEqual?: FlowSelectorEquality<T>;
13
+ fireImmediately?: boolean;
14
+ };
15
+ type FlowEventListeners = {
16
+ connectionEnded?: (event: ConnectionEndedEvent) => void;
17
+ layoutRequested?: (event: LayoutRequestedEvent) => void;
18
+ };
19
+ type FlowInstanceSettings = Omit<CreateFlowOptions, "graph">;
20
+ type CreateFlowInstanceOptions = {
21
+ graph: FlowGraph;
22
+ settings?: FlowInstanceSettings;
23
+ listeners?: FlowStoreListener[];
24
+ events?: FlowEventListeners;
25
+ };
26
+ type FlowInstance = FlowController & {
27
+ getSnapshot(): FlowStoreContext;
28
+ /**
29
+ * Convert window client coordinates (e.g. `event.clientX/Y` from drops or
30
+ * window-level listeners) to canvas coordinates, accounting for the
31
+ * attached container's position. Unlike `screenToCanvas`, which expects
32
+ * container-relative pixels.
33
+ */
34
+ clientToCanvas(point: Point): Point;
35
+ listen<T>(selector: FlowSelector<T>, listener: FlowStoreListener<T>["onChange"], options?: {
36
+ isEqual?: FlowSelectorEquality<T>;
37
+ fireImmediately?: boolean;
38
+ }): () => void;
39
+ };
40
+ declare function createFlowInstance(options: CreateFlowInstanceOptions): FlowInstance;
41
+ //#endregion
42
+ //#region src/FlowInstanceContext.d.ts
43
+ declare function FlowInstanceProvider(props: {
44
+ flow: FlowInstance;
45
+ children: ReactNode;
46
+ }): react10.JSX.Element;
47
+ declare function useFlowInstance(): FlowInstance;
48
+ declare function useOptionalFlowInstance(): FlowInstance | null;
49
+ //#endregion
50
+ //#region src/hooks.d.ts
51
+ type UseCreateFlowInstanceOptions = CreateFlowInstanceOptions;
52
+ type UseFlowOptions = UseCreateFlowInstanceOptions;
53
+ declare function useFlow(options: UseFlowOptions): FlowInstance;
54
+ declare function useCreateFlowInstance(options: UseCreateFlowInstanceOptions): FlowInstance;
55
+ declare function useFlowSelector<T>(selector: FlowSelector<T>, options?: {
56
+ flow?: FlowInstance;
57
+ isEqual?: FlowSelectorEquality<T>;
58
+ }): T;
59
+ declare function useFlowContext(): FlowStoreContext;
60
+ /**
61
+ * Like `useFlowSelector`, but subscribed through the entity-change notifier:
62
+ * the selector re-runs only when the entity with `id` may have changed, not
63
+ * on every store transition. This is what makes thousands of mounted entity
64
+ * views affordable — see BENCHMARK.md.
65
+ */
66
+ declare function useFlowEntity<T>(id: string, selector: FlowSelector<T>, options?: {
67
+ flow?: FlowInstance;
68
+ isEqual?: FlowSelectorEquality<T>;
69
+ }): T;
70
+ declare function useFlowValue<T>(selector: FlowSelector<T>, isEqual?: FlowSelectorEquality<T>): T;
71
+ type DerivedEntityFields = {
72
+ selected: boolean;
73
+ focused: boolean;
74
+ hovered: boolean;
75
+ props: HTMLAttributes<HTMLElement> & Record<`data-${string}`, string>;
76
+ };
77
+ type FlowNodeBinding<TData = any> = FlowNode<TData> & DerivedEntityFields;
78
+ type FlowEdgeBinding<TEdgeData = any, TLabelData = any> = FlowEdge<TEdgeData, TLabelData> & DerivedEntityFields & {
79
+ pathData: ReturnType<FlowInstance['getAllEdgePaths']> extends Map<string, infer TPath> ? TPath | null : never;
80
+ };
81
+ type FlowPortBinding = VisualPort & DerivedEntityFields & {
82
+ id: string;
83
+ nodeId: string;
84
+ portName: string;
85
+ };
86
+ type EntitySelector<TValue, TSelected> = (value: TValue, context: FlowStoreContext) => TSelected;
87
+ declare function useFlowNode<TData = any>(id: string): FlowNodeBinding<TData>;
88
+ declare function useFlowNode<TData = any, TSelected = unknown>(id: string, selector: EntitySelector<FlowNode<TData>, TSelected>, isEqual?: FlowSelectorEquality<TSelected>): TSelected;
89
+ declare function useFlowEdge<TEdgeData = any, TLabelData = any>(id: string): FlowEdgeBinding<TEdgeData, TLabelData>;
90
+ declare function useFlowEdge<TEdgeData = any, TLabelData = any, TSelected = unknown>(id: string, selector: EntitySelector<FlowEdge<TEdgeData, TLabelData>, TSelected>, isEqual?: FlowSelectorEquality<TSelected>): TSelected;
91
+ declare function useFlowPort(id: string): FlowPortBinding;
92
+ declare function useFlowPort<TSelected>(id: string, selector: EntitySelector<FlowPortBinding, TSelected>, isEqual?: FlowSelectorEquality<TSelected>): TSelected;
93
+ declare function useFlowViewport(): Viewport;
94
+ declare function useFlowMeasurement(id: string): Rect | null;
95
+ //#endregion
96
+ //#region src/useFlowInput.d.ts
97
+ type UseFlowInputOptions = {
98
+ /**
99
+ * Input modes, or a resolver from store context. Defaults to the store
100
+ * profile's input modes (when a profile is given) and otherwise to the
101
+ * core default set, which follows the store's `context.mode`
102
+ * (interactive / readonly). Initial-only: changes after mount are ignored —
103
+ * swap behavior at runtime via `flow.trigger.setMode(...)` or a
104
+ * context-aware resolver.
105
+ */
106
+ modes?: FlowInputMode[] | ((context: FlowStoreContext) => FlowInputMode[]);
107
+ /** Store profile whose per-mode `input.modes` drive the runtime. */
108
+ profile?: FlowProfile;
109
+ };
110
+ /**
111
+ * Bind a container element to the core input runtime: all pointer, wheel,
112
+ * and keyboard gestures inside the container are recognized by input modes
113
+ * and applied to the flow store. This replaces hand-written gesture handlers.
114
+ */
115
+ declare function useFlowInput(flow: FlowInstance, containerRef: RefObject<HTMLElement | null>, options?: UseFlowInputOptions): void;
116
+ //#endregion
117
+ //#region src/StatelyFlow.d.ts
118
+ type RenderNodeProps<TNodeData = unknown> = {
119
+ flow: FlowInstance;
120
+ node: FlowNode<TNodeData>;
121
+ bounds: Rect;
122
+ selected: boolean;
123
+ dragging: boolean;
124
+ hovered: boolean;
125
+ highlights: ReadonlyArray<{
126
+ kind: string;
127
+ meta: unknown;
128
+ }>;
129
+ };
130
+ type RenderEdgeProps<TEdgeData = unknown> = {
131
+ flow: FlowInstance;
132
+ edge: FlowEdge<TEdgeData>;
133
+ pathData: EdgePathData;
134
+ selected: boolean;
135
+ hovered: boolean;
136
+ highlights: ReadonlyArray<{
137
+ kind: string;
138
+ meta: unknown;
139
+ }>;
140
+ };
141
+ type StatelyFlowProps<TNodeData = unknown, TEdgeData = unknown> = {
142
+ flow?: FlowInstance;
143
+ graph: FlowGraph<TNodeData, TEdgeData>;
144
+ settings?: FlowInstanceSettings;
145
+ listeners?: FlowStoreListener[];
146
+ events?: FlowEventListeners;
147
+ renderNode?: (props: RenderNodeProps<TNodeData>) => ReactNode;
148
+ renderEdge?: (props: RenderEdgeProps<TEdgeData>) => ReactNode;
149
+ /**
150
+ * Only mount nodes/edges that intersect the viewport (plus an overscan
151
+ * margin). Recommended for large graphs.
152
+ */
153
+ onlyRenderVisible?: boolean;
154
+ /**
155
+ * Override the input modes driving gestures (initial-only). Defaults to
156
+ * the store profile's input modes when `settings.store.profile` is set,
157
+ * otherwise to the core defaults. Example — custom connection validity:
158
+ *
159
+ * ```tsx
160
+ * inputModes={[
161
+ * ...defaultInputModes.filter((mode) => mode.id !== "connect"),
162
+ * connectMode({ isValid: myValidity }),
163
+ * ]}
164
+ * ```
165
+ */
166
+ inputModes?: FlowInputMode[] | ((context: FlowStoreContext) => FlowInputMode[]);
167
+ className?: string;
168
+ style?: CSSProperties;
169
+ background?: ReactNode;
170
+ children?: ReactNode;
171
+ };
172
+ declare function StatelyFlow<TNodeData = unknown, TEdgeData = unknown>(props: StatelyFlowProps<TNodeData, TEdgeData>): react10.JSX.Element;
173
+ //#endregion
174
+ //#region src/FlowToolbar.d.ts
175
+ /** Border-box size of an element, kept current via ResizeObserver. */
176
+ declare function useMeasuredSize<T extends HTMLElement>(deps?: ReadonlyArray<unknown>): readonly [(node: T | null) => void, {
177
+ width: number;
178
+ height: number;
179
+ }];
180
+ type UseFlowToolbarOptions = {
181
+ /**
182
+ * Which entities to anchor to. Defaults to the current selection — so one
183
+ * toolbar implementation covers nodes, edges, and multi-selections.
184
+ */
185
+ ids?: string[];
186
+ /** Gap between the anchor and the toolbar (default 10). */
187
+ offset?: number;
188
+ /** Minimum gap from the container edges (default 8). */
189
+ padding?: number;
190
+ };
191
+ type FlowToolbarState = {
192
+ /** Attach to the toolbar element (measures it). */
193
+ setRef: (node: HTMLDivElement | null) => void;
194
+ /** Positioning style for the toolbar element. */
195
+ style: CSSProperties;
196
+ /** False when nothing is anchored (render nothing). */
197
+ visible: boolean;
198
+ /** The resolved screen-space anchor, when visible. */
199
+ anchor: Rect | null;
200
+ /** Which side of the anchor the toolbar sits on. */
201
+ side: "top" | "bottom";
202
+ };
203
+ declare function useFlowToolbar(options?: UseFlowToolbarOptions): FlowToolbarState;
204
+ type FlowToolbarProps = UseFlowToolbarOptions & {
205
+ children: ReactNode;
206
+ className?: string;
207
+ style?: CSSProperties;
208
+ };
209
+ /**
210
+ * Unstyled positioned toolbar anchored to the selection (or explicit `ids`).
211
+ * Marked `data-flow-interactive`, so its contents receive pointer events
212
+ * unopposed by canvas gestures.
213
+ */
214
+ declare function FlowToolbar(props: FlowToolbarProps): react10.JSX.Element | null;
215
+ //#endregion
216
+ //#region src/MiniMap.d.ts
217
+ type MiniMapProps = {
218
+ width?: number;
219
+ height?: number;
220
+ /** Padding around content as a fraction of its size (default 0.1). */
221
+ padding?: number;
222
+ className?: string;
223
+ style?: CSSProperties;
224
+ /** Render one node marker; defaults to a plain `<rect>`. */
225
+ renderNode?: (node: FlowNode, rect: Rect) => ReactNode;
226
+ };
227
+ /**
228
+ * Overview map. Deliberately thin: all math lives in core
229
+ * (`getMinimapProjection`, `viewportCenteredOn`) and every interaction is a
230
+ * plain store trigger — this component is exactly what you would write in
231
+ * userland, kept here as a convenience.
232
+ */
233
+ declare function MiniMap(props: MiniMapProps): react10.JSX.Element;
234
+ //#endregion
235
+ //#region src/Controls.d.ts
236
+ type ControlsProps = {
237
+ className?: string;
238
+ style?: CSSProperties;
239
+ /** Extra buttons appended after the built-ins. */
240
+ children?: ReactNode;
241
+ };
242
+ /**
243
+ * Zoom/fit toolbar. Deliberately thin: every button is one store trigger
244
+ * (`zoomBy`, `fitView`) — replicate or extend it freely in userland.
245
+ */
246
+ declare function Controls(props: ControlsProps): react10.JSX.Element;
247
+ //#endregion
248
+ //#region src/EntityAnchor.d.ts
249
+ type EntityAnchorProps = {
250
+ bounds: Rect;
251
+ anchor: AnchorSpec;
252
+ inverseScale?: boolean;
253
+ className?: string;
254
+ style?: CSSProperties;
255
+ children: ReactNode;
256
+ };
257
+ declare function EntityAnchor(props: EntityAnchorProps): react10.JSX.Element;
258
+ //#endregion
259
+ //#region src/Port.d.ts
260
+ type PortProps = {
261
+ name: string;
262
+ /**
263
+ * Whether the DOM element reports its bounds back to the graph (default
264
+ * true). Ports are unidirectional, one way or the other:
265
+ *
266
+ * - DOM-owned (default): position the element with your own CSS (offsets,
267
+ * percentages, flex…) — NEVER from `port.x`/`port.y` — and the graph's
268
+ * port geometry follows the DOM.
269
+ * - Graph-owned (`measured={false}`): position the element FROM
270
+ * `port.x`/`port.y` (layout results, "virtual" ports) and nothing is
271
+ * written back.
272
+ *
273
+ * Mixing the two (positioning from `port.x` while measuring) creates a
274
+ * feedback loop and runs away.
275
+ */
276
+ measured?: boolean;
277
+ className?: string;
278
+ style?: CSSProperties;
279
+ children?: ReactNode;
280
+ };
281
+ /**
282
+ * A connection port. Purely declarative: it renders the
283
+ * `data-flow-port-name`/`data-flow-node-id` attributes that the input
284
+ * runtime's `connectMode` recognizes, and reports its measured bounds to the
285
+ * store. The connection gesture itself (start/move/validate/end) lives in
286
+ * core — customize it by swapping `connectMode({ isValid })` in the
287
+ * `inputModes` prop of `StatelyFlow` (or your own `useFlowInput` call), and
288
+ * observe results via `flow.on("connectionEnded", …)` or the store's
289
+ * `connection` state.
290
+ */
291
+ declare function Port(props: PortProps): react10.JSX.Element;
292
+ //#endregion
293
+ //#region src/ColorMode.d.ts
294
+ type FlowColorModeScopeProps = {
295
+ children: ReactNode;
296
+ className?: string;
297
+ style?: CSSProperties;
298
+ };
299
+ declare function FlowColorModeScope(props: FlowColorModeScopeProps): react10.JSX.Element;
300
+ declare function useFlowColorMode(): {
301
+ colorMode: FlowColorMode;
302
+ resolvedColorMode: ResolvedFlowColorMode;
303
+ };
304
+ declare function useApplyFlowColorMode(element: HTMLElement | null): void;
305
+ //#endregion
306
+ export { Controls, type ControlsProps, type CreateFlowInstanceOptions, EntityAnchor, type EntityAnchorProps, FlowColorModeScope, type FlowColorModeScopeProps, type FlowEdgeBinding, type FlowEventListeners, type FlowInstance, FlowInstanceProvider, type FlowInstanceSettings, type FlowNodeBinding, type FlowPortBinding, type FlowSelector, type FlowSelectorEquality, type FlowStoreListener, FlowToolbar, type FlowToolbarProps, type FlowToolbarState, MiniMap, type MiniMapProps, Port, type PortProps, type RenderEdgeProps, type RenderNodeProps, StatelyFlow, type StatelyFlowProps, type UseCreateFlowInstanceOptions, type UseFlowInputOptions, type UseFlowOptions, type UseFlowToolbarOptions, createFlowInstance, useApplyFlowColorMode, useCreateFlowInstance, useFlow, useFlowColorMode, useFlowContext, useFlowEdge, useFlowEntity, useFlowInput, useFlowInstance, useFlowMeasurement, useFlowNode, useFlowPort, useFlowSelector, useFlowToolbar, useFlowValue, useFlowViewport, useMeasuredSize, useOptionalFlowInstance };