@realflow/react 0.1.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 (74) hide show
  1. package/dist/Background.d.ts +11 -0
  2. package/dist/Background.d.ts.map +1 -0
  3. package/dist/Background.js +27 -0
  4. package/dist/Background.js.map +1 -0
  5. package/dist/Controls.d.ts +14 -0
  6. package/dist/Controls.d.ts.map +1 -0
  7. package/dist/Controls.js +12 -0
  8. package/dist/Controls.js.map +1 -0
  9. package/dist/DefaultNode.d.ts +13 -0
  10. package/dist/DefaultNode.d.ts.map +1 -0
  11. package/dist/DefaultNode.js +30 -0
  12. package/dist/DefaultNode.js.map +1 -0
  13. package/dist/EdgeRenderer.d.ts +7 -0
  14. package/dist/EdgeRenderer.d.ts.map +1 -0
  15. package/dist/EdgeRenderer.js +154 -0
  16. package/dist/EdgeRenderer.js.map +1 -0
  17. package/dist/Handle.d.ts +25 -0
  18. package/dist/Handle.d.ts.map +1 -0
  19. package/dist/Handle.js +83 -0
  20. package/dist/Handle.js.map +1 -0
  21. package/dist/MiniMap.d.ts +15 -0
  22. package/dist/MiniMap.d.ts.map +1 -0
  23. package/dist/MiniMap.js +125 -0
  24. package/dist/MiniMap.js.map +1 -0
  25. package/dist/NodeRenderer.d.ts +13 -0
  26. package/dist/NodeRenderer.d.ts.map +1 -0
  27. package/dist/NodeRenderer.js +194 -0
  28. package/dist/NodeRenderer.js.map +1 -0
  29. package/dist/NodeResizer.d.ts +29 -0
  30. package/dist/NodeResizer.d.ts.map +1 -0
  31. package/dist/NodeResizer.js +120 -0
  32. package/dist/NodeResizer.js.map +1 -0
  33. package/dist/NodeToolbar.d.ts +23 -0
  34. package/dist/NodeToolbar.d.ts.map +1 -0
  35. package/dist/NodeToolbar.js +65 -0
  36. package/dist/NodeToolbar.js.map +1 -0
  37. package/dist/Panel.d.ts +12 -0
  38. package/dist/Panel.d.ts.map +1 -0
  39. package/dist/Panel.js +8 -0
  40. package/dist/Panel.js.map +1 -0
  41. package/dist/ReFlow.d.ts +12 -0
  42. package/dist/ReFlow.d.ts.map +1 -0
  43. package/dist/ReFlow.js +475 -0
  44. package/dist/ReFlow.js.map +1 -0
  45. package/dist/RemoteCursors.d.ts +13 -0
  46. package/dist/RemoteCursors.d.ts.map +1 -0
  47. package/dist/RemoteCursors.js +19 -0
  48. package/dist/RemoteCursors.js.map +1 -0
  49. package/dist/config.d.ts +8 -0
  50. package/dist/config.d.ts.map +1 -0
  51. package/dist/config.js +17 -0
  52. package/dist/config.js.map +1 -0
  53. package/dist/context.d.ts +8 -0
  54. package/dist/context.d.ts.map +1 -0
  55. package/dist/context.js +14 -0
  56. package/dist/context.js.map +1 -0
  57. package/dist/hooks.d.ts +104 -0
  58. package/dist/hooks.d.ts.map +1 -0
  59. package/dist/hooks.js +0 -0
  60. package/dist/hooks.js.map +1 -0
  61. package/dist/index.d.ts +17 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +17 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/measure.d.ts +20 -0
  66. package/dist/measure.d.ts.map +1 -0
  67. package/dist/measure.js +75 -0
  68. package/dist/measure.js.map +1 -0
  69. package/dist/styles.css +642 -0
  70. package/dist/types.d.ts +103 -0
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/types.js +2 -0
  73. package/dist/types.js.map +1 -0
  74. package/package.json +58 -0
@@ -0,0 +1,13 @@
1
+ /** Renders one node (and its children), subscribed only to its own topic. */
2
+ export declare const NodeView: import("react").NamedExoticComponent<{
3
+ id: string;
4
+ }>;
5
+ /** Mounts the visible root nodes (viewport culling built in). */
6
+ export declare const NodesLayer: import("react").NamedExoticComponent<object>;
7
+ export declare const builtinNodeTypes: {
8
+ default: import("react").NamedExoticComponent<import("./types.js").NodeProps<Record<string, unknown>>>;
9
+ input: import("react").NamedExoticComponent<import("./types.js").NodeProps<Record<string, unknown>>>;
10
+ output: import("react").NamedExoticComponent<import("./types.js").NodeProps<Record<string, unknown>>>;
11
+ group: import("react").NamedExoticComponent<import("./types.js").NodeProps<Record<string, unknown>>>;
12
+ };
13
+ //# sourceMappingURL=NodeRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeRenderer.d.ts","sourceRoot":"","sources":["../src/NodeRenderer.tsx"],"names":[],"mappings":"AAWA,6EAA6E;AAC7E,eAAO,MAAM,QAAQ;QAAwC,MAAM;EAuLjE,CAAC;AAUH,iEAAiE;AACjE,eAAO,MAAM,UAAU,8CA0BrB,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;CAK5B,CAAC"}
@@ -0,0 +1,194 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { memo, useEffect, useMemo, useRef } from 'react';
3
+ import { useFlowStore, NodeIdContext } from './context.js';
4
+ import { useConfig } from './config.js';
5
+ import { useFlowSelector } from './hooks.js';
6
+ import { useMeasurer } from './measure.js';
7
+ import { DefaultNode, GroupNode, InputNode, OutputNode } from './DefaultNode.js';
8
+ const NO_DRAG_SELECTOR = '.rf-handle, .rf-nodrag, input, textarea, select, button, a, [contenteditable="true"]';
9
+ /** Renders one node (and its children), subscribed only to its own topic. */
10
+ export const NodeView = memo(function NodeView({ id }) {
11
+ const store = useFlowStore();
12
+ const config = useConfig();
13
+ const node = useFlowSelector([`node:${id}`], () => store.nodes.get(id));
14
+ const contentRef = useRef(null);
15
+ const dragState = useRef(null);
16
+ // Measure real size so edges/minimap/culling stay exact. Nodes with an
17
+ // explicit width AND height skip observation entirely (big win when
18
+ // mounting thousands of fixed-size nodes).
19
+ const measurer = useMeasurer();
20
+ const hasFixedSize = node != null && node.width != null && node.height != null;
21
+ useEffect(() => {
22
+ const el = contentRef.current;
23
+ if (!el || !measurer || hasFixedSize)
24
+ return;
25
+ measurer.observe(el, id);
26
+ return () => measurer.unobserve(el);
27
+ }, [measurer, id, hasFixedSize]);
28
+ const childIds = useChildIds(id);
29
+ if (!node || node.hidden)
30
+ return null;
31
+ const type = node.type ?? 'default';
32
+ const Comp = config.nodeTypes[type] ?? config.nodeTypes.default ?? DefaultNode;
33
+ const onPointerDown = (e) => {
34
+ if (e.button !== 0 || config.readOnly)
35
+ return;
36
+ if (e.target.closest(NO_DRAG_SELECTOR))
37
+ return;
38
+ e.stopPropagation();
39
+ const current = store.getNode(id);
40
+ if (!current || current.selectable === false)
41
+ return;
42
+ // Selection on press (drag keeps the selection group together).
43
+ if (!current.selected) {
44
+ if (e.shiftKey || e.metaKey || e.ctrlKey)
45
+ store.addToSelection([id]);
46
+ else
47
+ store.setSelection([id]);
48
+ }
49
+ if (current.draggable === false)
50
+ return;
51
+ const el = e.currentTarget;
52
+ try {
53
+ el.setPointerCapture(e.pointerId);
54
+ }
55
+ catch {
56
+ /* synthetic events or lost pointers */
57
+ }
58
+ dragState.current = {
59
+ pointerId: e.pointerId,
60
+ startX: e.clientX,
61
+ startY: e.clientY,
62
+ dragging: false,
63
+ raf: null,
64
+ dx: 0,
65
+ dy: 0,
66
+ };
67
+ };
68
+ const onPointerMove = (e) => {
69
+ const s = dragState.current;
70
+ if (!s || e.pointerId !== s.pointerId)
71
+ return;
72
+ const dx = e.clientX - s.startX;
73
+ const dy = e.clientY - s.startY;
74
+ if (!s.dragging) {
75
+ if (Math.hypot(dx, dy) < 3)
76
+ return;
77
+ s.dragging = true;
78
+ const sel = store.getNode(id)?.selected
79
+ ? [...store.selectedNodes]
80
+ : [id];
81
+ store.startDrag(sel);
82
+ }
83
+ const zoom = store.viewport.zoom || 1;
84
+ s.dx = dx / zoom;
85
+ s.dy = dy / zoom;
86
+ if (s.raf == null) {
87
+ s.raf = requestAnimationFrame(() => {
88
+ s.raf = null;
89
+ if (dragState.current === s)
90
+ store.dragBy({ x: s.dx, y: s.dy });
91
+ });
92
+ }
93
+ };
94
+ const onPointerUp = (e) => {
95
+ const s = dragState.current;
96
+ if (!s || e.pointerId !== s.pointerId)
97
+ return;
98
+ dragState.current = null;
99
+ if (s.raf != null)
100
+ cancelAnimationFrame(s.raf);
101
+ try {
102
+ e.currentTarget.releasePointerCapture(e.pointerId);
103
+ }
104
+ catch {
105
+ /* already released */
106
+ }
107
+ if (s.dragging) {
108
+ store.dragBy({ x: s.dx, y: s.dy });
109
+ store.endDrag();
110
+ }
111
+ else if (e.shiftKey || e.metaKey || e.ctrlKey) {
112
+ // Click (no drag) with modifier on an already-selected node: toggle off.
113
+ const current = store.getNode(id);
114
+ if (current?.selected)
115
+ store.toggleSelection(id);
116
+ }
117
+ };
118
+ const onClick = (e) => {
119
+ e.stopPropagation();
120
+ const current = store.getNode(id);
121
+ if (current)
122
+ config.onNodeClick?.(e, current);
123
+ };
124
+ const onDoubleClick = (e) => {
125
+ e.stopPropagation();
126
+ const current = store.getNode(id);
127
+ if (current)
128
+ config.onNodeDoubleClick?.(e, current);
129
+ };
130
+ const onContextMenu = (e) => {
131
+ const current = store.getNode(id);
132
+ if (current && config.onNodeContextMenu) {
133
+ e.stopPropagation();
134
+ config.onNodeContextMenu(e, current);
135
+ }
136
+ };
137
+ const style = {
138
+ transform: `translate(${node.position.x}px, ${node.position.y}px)`,
139
+ zIndex: node.zIndex ?? (node.selected ? 10 : undefined),
140
+ };
141
+ const contentStyle = {
142
+ width: node.width,
143
+ height: node.height,
144
+ ...node.style,
145
+ };
146
+ const label = node.ariaLabel ?? node.data?.label ?? `node ${id}`;
147
+ return (_jsxs("div", { className: `rf-node${node.selected ? ' rf-selected' : ''}${node.draggable === false ? '' : ' rf-draggable'}${node.className ? ` ${node.className}` : ''}`, "data-id": id, "data-type": type, style: style,
148
+ // Accessibility: nodes are focusable and announce themselves. Focusing
149
+ // selects; arrow keys move the selection (handled by the pane).
150
+ tabIndex: config.readOnly ? -1 : 0, role: "button", "aria-label": label, "aria-selected": !!node.selected, "aria-roledescription": "node", onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, onClick: onClick, onDoubleClick: onDoubleClick, onContextMenu: onContextMenu, onFocus: (e) => {
151
+ // Only react to focus on the node itself, not bubbled from children.
152
+ if (e.target !== e.currentTarget)
153
+ return;
154
+ const cur = store.getNode(id);
155
+ if (cur && !cur.selected && cur.selectable !== false)
156
+ store.setSelection([id]);
157
+ }, children: [_jsx("div", { ref: contentRef, className: "rf-node-content", style: contentStyle, children: _jsx(NodeIdContext.Provider, { value: id, children: _jsx(Comp, { id: id, data: node.data, node: node, selected: !!node.selected, dragging: false }) }) }), childIds.map((cid) => (_jsx(NodeView, { id: cid }, cid)))] }));
158
+ });
159
+ /** Reactive list of a node's direct children (stable while unchanged). */
160
+ const useChildIds = (id) => {
161
+ const store = useFlowStore();
162
+ const version = useFlowSelector(['nodes'], () => store.nodesVersion);
163
+ // eslint-disable-next-line react-hooks/exhaustive-deps
164
+ return useMemo(() => store.childrenOf(id), [store, id, version]);
165
+ };
166
+ /** Mounts the visible root nodes (viewport culling built in). */
167
+ export const NodesLayer = memo(function NodesLayer() {
168
+ const store = useFlowStore();
169
+ const cache = useRef({
170
+ roots: new Set(),
171
+ version: -1,
172
+ ids: [],
173
+ });
174
+ const ids = useFlowSelector(['visible', 'nodes'], () => {
175
+ const c = cache.current;
176
+ if (c.roots !== store.visibleRoots || c.version !== store.nodesVersion) {
177
+ const next = [];
178
+ for (const id of store.nodeOrder) {
179
+ if (store.visibleRoots.has(id) && !store.nodes.get(id)?.parentId)
180
+ next.push(id);
181
+ }
182
+ cache.current = { roots: store.visibleRoots, version: store.nodesVersion, ids: next };
183
+ }
184
+ return cache.current.ids;
185
+ });
186
+ return (_jsx("div", { className: "rf-nodes", children: ids.map((id) => (_jsx(NodeView, { id: id }, id))) }));
187
+ });
188
+ export const builtinNodeTypes = {
189
+ default: DefaultNode,
190
+ input: InputNode,
191
+ output: OutputNode,
192
+ group: GroupNode,
193
+ };
194
+ //# sourceMappingURL=NodeRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeRenderer.js","sourceRoot":"","sources":["../src/NodeRenderer.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export interface NodeResizerProps {
2
+ nodeId?: string;
3
+ /** Only render while the node is selected. Default true. */
4
+ isVisible?: boolean;
5
+ minWidth?: number;
6
+ minHeight?: number;
7
+ maxWidth?: number;
8
+ maxHeight?: number;
9
+ /** Preserve aspect ratio while resizing. */
10
+ keepAspectRatio?: boolean;
11
+ color?: string;
12
+ /** Fired continuously during resize. */
13
+ onResize?: (size: {
14
+ width: number;
15
+ height: number;
16
+ }) => void;
17
+ /** Fired once when resizing ends (a single undo entry is recorded). */
18
+ onResizeEnd?: (size: {
19
+ width: number;
20
+ height: number;
21
+ }) => void;
22
+ }
23
+ /**
24
+ * Drag-to-resize handles around a node (8 grips). Updates the node's
25
+ * width/height (and position for top/left grips) live, and records a single
26
+ * undo entry per resize gesture. Counter-scaled so grips stay grabbable.
27
+ */
28
+ export declare const NodeResizer: import("react").NamedExoticComponent<NodeResizerProps>;
29
+ //# sourceMappingURL=NodeResizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeResizer.d.ts","sourceRoot":"","sources":["../src/NodeResizer.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC7D,uEAAuE;IACvE,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACjE;AASD;;;;GAIG;AACH,eAAO,MAAM,WAAW,wDAsItB,CAAC"}
@@ -0,0 +1,120 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { memo, useRef } from 'react';
3
+ import { useFlowStore, useNodeId } from './context.js';
4
+ import { useFlowSelector, useViewport } from './hooks.js';
5
+ const HANDLES = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];
6
+ const CURSOR = {
7
+ nw: 'nwse-resize', n: 'ns-resize', ne: 'nesw-resize', e: 'ew-resize',
8
+ se: 'nwse-resize', s: 'ns-resize', sw: 'nesw-resize', w: 'ew-resize',
9
+ };
10
+ /**
11
+ * Drag-to-resize handles around a node (8 grips). Updates the node's
12
+ * width/height (and position for top/left grips) live, and records a single
13
+ * undo entry per resize gesture. Counter-scaled so grips stay grabbable.
14
+ */
15
+ export const NodeResizer = memo(function NodeResizer({ nodeId, isVisible, minWidth = 40, minHeight = 30, maxWidth = Infinity, maxHeight = Infinity, keepAspectRatio = false, color, onResize, onResizeEnd, }) {
16
+ const store = useFlowStore();
17
+ const ctxId = useNodeId();
18
+ const id = nodeId ?? ctxId;
19
+ const { zoom } = useViewport();
20
+ const node = useFlowSelector([`node:${id}`], () => store.nodes.get(id));
21
+ const drag = useRef(null);
22
+ if (!node || node.hidden)
23
+ return null;
24
+ const show = isVisible ?? !!node.selected;
25
+ if (!show)
26
+ return null;
27
+ const size = store.nodeSize(id);
28
+ const inv = 1 / zoom;
29
+ const onPointerDown = (h) => (e) => {
30
+ if (e.button !== 0)
31
+ return;
32
+ e.stopPropagation();
33
+ e.preventDefault();
34
+ e.currentTarget.setPointerCapture?.(e.pointerId);
35
+ const cur = store.getNode(id);
36
+ const s = store.nodeSize(id);
37
+ drag.current = {
38
+ pointerId: e.pointerId,
39
+ startX: e.clientX,
40
+ startY: e.clientY,
41
+ startW: s.width,
42
+ startH: s.height,
43
+ startPX: cur.position.x,
44
+ startPY: cur.position.y,
45
+ handle: h,
46
+ ratio: s.width / s.height,
47
+ };
48
+ };
49
+ const onPointerMove = (e) => {
50
+ const d = drag.current;
51
+ if (!d || e.pointerId !== d.pointerId)
52
+ return;
53
+ e.stopPropagation();
54
+ const dx = (e.clientX - d.startX) / zoom;
55
+ const dy = (e.clientY - d.startY) / zoom;
56
+ const h = d.handle;
57
+ let w = d.startW;
58
+ let ht = d.startH;
59
+ let px = d.startPX;
60
+ let py = d.startPY;
61
+ const east = h.includes('e');
62
+ const west = h.includes('w');
63
+ const south = h.includes('s');
64
+ const north = h.includes('n');
65
+ if (east)
66
+ w = d.startW + dx;
67
+ if (west)
68
+ w = d.startW - dx;
69
+ if (south)
70
+ ht = d.startH + dy;
71
+ if (north)
72
+ ht = d.startH - dy;
73
+ w = Math.max(minWidth, Math.min(maxWidth, w));
74
+ ht = Math.max(minHeight, Math.min(maxHeight, ht));
75
+ if (keepAspectRatio) {
76
+ if (east || west)
77
+ ht = w / d.ratio;
78
+ else
79
+ w = ht * d.ratio;
80
+ }
81
+ // West/north grips move the origin so the opposite edge stays put.
82
+ if (west)
83
+ px = d.startPX + (d.startW - w);
84
+ if (north)
85
+ py = d.startPY + (d.startH - ht);
86
+ store.updateNode(id, { width: w, height: ht, position: { x: px, y: py } });
87
+ onResize?.({ width: w, height: ht });
88
+ };
89
+ const onPointerUp = (e) => {
90
+ const d = drag.current;
91
+ if (!d || e.pointerId !== d.pointerId)
92
+ return;
93
+ drag.current = null;
94
+ const s = store.nodeSize(id);
95
+ onResizeEnd?.({ width: s.width, height: s.height });
96
+ };
97
+ const style = color ? ({ ['--rf-resizer']: color }) : undefined;
98
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: "rf-resizer-outline", style: style }), HANDLES.map((h) => {
99
+ const pos = { position: 'absolute' };
100
+ if (h.includes('n'))
101
+ pos.top = 0;
102
+ if (h.includes('s'))
103
+ pos.top = size.height;
104
+ if (h.includes('w'))
105
+ pos.left = 0;
106
+ if (h.includes('e'))
107
+ pos.left = size.width;
108
+ if (h === 'n' || h === 's')
109
+ pos.left = size.width / 2;
110
+ if (h === 'e' || h === 'w')
111
+ pos.top = size.height / 2;
112
+ return (_jsx("div", { className: `rf-resizer-handle rf-resizer-${h}`, style: {
113
+ ...pos,
114
+ transform: `translate(-50%, -50%) scale(${inv})`,
115
+ cursor: CURSOR[h],
116
+ ...style,
117
+ }, onPointerDown: onPointerDown(h), onPointerMove: onPointerMove, onPointerUp: onPointerUp, role: "slider", "aria-label": `resize ${h}` }, h));
118
+ })] }));
119
+ });
120
+ //# sourceMappingURL=NodeResizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeResizer.js","sourceRoot":"","sources":["../src/NodeResizer.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { CSSProperties, ReactNode } from 'react';
2
+ import type { Side } from '@realflow/core';
3
+ export interface NodeToolbarProps {
4
+ /** Node to attach to. Defaults to the enclosing node. */
5
+ nodeId?: string;
6
+ /** Which side of the node to float on. Default 'top'. */
7
+ position?: Side;
8
+ /** Only show while the node is selected. Default true. */
9
+ isVisible?: boolean;
10
+ /** Gap between node and toolbar, in screen px. Default 8. */
11
+ offset?: number;
12
+ align?: 'start' | 'center' | 'end';
13
+ className?: string;
14
+ style?: CSSProperties;
15
+ children?: ReactNode;
16
+ }
17
+ /**
18
+ * A floating toolbar anchored to a node. Rendered inside the node but
19
+ * counter-scaled by 1/zoom so it stays a constant, readable size at any zoom
20
+ * level. Shows on selection by default — perfect for per-node actions.
21
+ */
22
+ export declare const NodeToolbar: import("react").NamedExoticComponent<NodeToolbarProps>;
23
+ //# sourceMappingURL=NodeToolbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeToolbar.d.ts","sourceRoot":"","sources":["../src/NodeToolbar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAI3C,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,wDAyEtB,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { memo } from 'react';
3
+ import { useFlowStore, useNodeId } from './context.js';
4
+ import { useFlowSelector, useViewport } from './hooks.js';
5
+ /**
6
+ * A floating toolbar anchored to a node. Rendered inside the node but
7
+ * counter-scaled by 1/zoom so it stays a constant, readable size at any zoom
8
+ * level. Shows on selection by default — perfect for per-node actions.
9
+ */
10
+ export const NodeToolbar = memo(function NodeToolbar({ nodeId, position = 'top', isVisible, offset = 8, align = 'center', className, style, children, }) {
11
+ const store = useFlowStore();
12
+ const ctxId = useNodeId();
13
+ const id = nodeId ?? ctxId;
14
+ const { zoom } = useViewport(); // re-render on zoom to keep counter-scale exact
15
+ const node = useFlowSelector([`node:${id}`], () => store.nodes.get(id));
16
+ if (!node || node.hidden)
17
+ return null;
18
+ const show = isVisible ?? !!node.selected;
19
+ if (!show)
20
+ return null;
21
+ const size = store.nodeSize(id);
22
+ const gap = offset / zoom; // screen px → local units
23
+ const inv = 1 / zoom;
24
+ // Anchor point in node-local coords + which corner of the toolbar pins to it.
25
+ let left = 0;
26
+ let top = 0;
27
+ let tx = '0';
28
+ let ty = '0';
29
+ if (position === 'top' || position === 'bottom') {
30
+ left = align === 'start' ? 0 : align === 'end' ? size.width : size.width / 2;
31
+ tx = align === 'start' ? '0' : align === 'end' ? '-100%' : '-50%';
32
+ if (position === 'top') {
33
+ top = -gap;
34
+ ty = '-100%';
35
+ }
36
+ else {
37
+ top = size.height + gap;
38
+ ty = '0';
39
+ }
40
+ }
41
+ else {
42
+ top = size.height / 2;
43
+ ty = '-50%';
44
+ if (position === 'left') {
45
+ left = -gap;
46
+ tx = '-100%';
47
+ }
48
+ else {
49
+ left = size.width + gap;
50
+ tx = '0';
51
+ }
52
+ }
53
+ return (_jsx("div", { className: `rf-node-toolbar${className ? ` ${className}` : ''}`, style: {
54
+ position: 'absolute',
55
+ left,
56
+ top,
57
+ // Counter-scale so the toolbar is screen-constant size, then pin the
58
+ // correct corner to the anchor.
59
+ transform: `scale(${inv}) translate(${tx}, ${ty})`,
60
+ transformOrigin: `${tx === '-100%' ? '100%' : tx === '-50%' ? '50%' : '0'} ${ty === '-100%' ? '100%' : ty === '-50%' ? '50%' : '0'}`,
61
+ zIndex: 20,
62
+ ...style,
63
+ }, onPointerDown: (e) => e.stopPropagation(), onClick: (e) => e.stopPropagation(), children: children }));
64
+ });
65
+ //# sourceMappingURL=NodeToolbar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeToolbar.js","sourceRoot":"","sources":["../src/NodeToolbar.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { CSSProperties, ReactNode } from 'react';
2
+ export type PanelPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
3
+ export interface PanelProps {
4
+ position?: PanelPosition;
5
+ className?: string;
6
+ style?: CSSProperties;
7
+ children?: ReactNode;
8
+ }
9
+ /** Floating overlay container; swallows pointer events so the pane below
10
+ * doesn't pan/zoom while interacting with it. */
11
+ export declare const Panel: import("react").NamedExoticComponent<PanelProps>;
12
+ //# sourceMappingURL=Panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Panel.d.ts","sourceRoot":"","sources":["../src/Panel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD,MAAM,MAAM,aAAa,GACrB,UAAU,GACV,YAAY,GACZ,WAAW,GACX,aAAa,GACb,eAAe,GACf,cAAc,CAAC;AAEnB,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;kDACkD;AAClD,eAAO,MAAM,KAAK,kDAmBhB,CAAC"}
package/dist/Panel.js ADDED
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { memo } from 'react';
3
+ /** Floating overlay container; swallows pointer events so the pane below
4
+ * doesn't pan/zoom while interacting with it. */
5
+ export const Panel = memo(function Panel({ position = 'top-left', className, style, children, }) {
6
+ return (_jsx("div", { className: `rf-panel rf-panel-${position}${className ? ` ${className}` : ''}`, style: style, onPointerDown: (e) => e.stopPropagation(), onClick: (e) => e.stopPropagation(), onDoubleClick: (e) => e.stopPropagation(), onWheel: (e) => e.stopPropagation(), onContextMenu: (e) => e.stopPropagation(), children: children }));
7
+ });
8
+ //# sourceMappingURL=Panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Panel.js","sourceRoot":"","sources":["../src/Panel.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAkB7B;kDACkD;AAClD,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,KAAK,CAAC,EACvC,QAAQ,GAAG,UAAU,EACrB,SAAS,EACT,KAAK,EACL,QAAQ,GACG;IACX,OAAO,CACL,cACE,SAAS,EAAE,qBAAqB,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAC7E,KAAK,EAAE,KAAK,EACZ,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,EACzC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,EACnC,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,EACzC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,EACnC,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,YAExC,QAAQ,GACL,CACP,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { ReFlowProps } from './types.js';
3
+ /**
4
+ * Standalone provider for using ReFlow hooks outside the <ReFlow> canvas
5
+ * (toolbars, sidebars, inspectors).
6
+ */
7
+ export declare const ReFlowProvider: ({ children }: {
8
+ children: ReactNode;
9
+ }) => React.JSX.Element;
10
+ /** The ReFlow canvas. */
11
+ export declare const ReFlow: import("react").NamedExoticComponent<ReFlowProps>;
12
+ //# sourceMappingURL=ReFlow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReFlow.d.ts","sourceRoot":"","sources":["../src/ReFlow.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAIV,SAAS,EACV,MAAM,OAAO,CAAC;AASf,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,SAAS,CAAC;AAevD;;;GAGG;AACH,eAAO,MAAM,cAAc,GAAI,cAAc;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,KAAG,KAAK,CAAC,GAAG,CAAC,OAGhF,CAAC;AAEF,yBAAyB;AACzB,eAAO,MAAM,MAAM,mDAghBjB,CAAC"}