@barefootjs/xyflow 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 (58) hide show
  1. package/README.md +117 -0
  2. package/dist/classes.d.ts +31 -0
  3. package/dist/classes.d.ts.map +1 -0
  4. package/dist/compat.d.ts +67 -0
  5. package/dist/compat.d.ts.map +1 -0
  6. package/dist/connection.d.ts +20 -0
  7. package/dist/connection.d.ts.map +1 -0
  8. package/dist/constants.d.ts +4 -0
  9. package/dist/constants.d.ts.map +1 -0
  10. package/dist/context.d.ts +7 -0
  11. package/dist/context.d.ts.map +1 -0
  12. package/dist/edge-path.d.ts +14 -0
  13. package/dist/edge-path.d.ts.map +1 -0
  14. package/dist/flow-subsystems.d.ts +28 -0
  15. package/dist/flow-subsystems.d.ts.map +1 -0
  16. package/dist/hooks.d.ts +34 -0
  17. package/dist/hooks.d.ts.map +1 -0
  18. package/dist/index.d.ts +19 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +6572 -0
  21. package/dist/node-resizer.d.ts +52 -0
  22. package/dist/node-resizer.d.ts.map +1 -0
  23. package/dist/node-type-dispatch.d.ts +34 -0
  24. package/dist/node-type-dispatch.d.ts.map +1 -0
  25. package/dist/selection.d.ts +32 -0
  26. package/dist/selection.d.ts.map +1 -0
  27. package/dist/store.d.ts +8 -0
  28. package/dist/store.d.ts.map +1 -0
  29. package/dist/types.d.ts +214 -0
  30. package/dist/types.d.ts.map +1 -0
  31. package/dist/utils.d.ts +6 -0
  32. package/dist/utils.d.ts.map +1 -0
  33. package/dist/xyflow.browser.min.js +95 -0
  34. package/dist/xyflow.browser.min.js.map +129 -0
  35. package/package.json +58 -0
  36. package/src/__tests__/clamp-drag-position.test.ts +111 -0
  37. package/src/__tests__/compat.test.ts +157 -0
  38. package/src/__tests__/host-element-store.test.ts +33 -0
  39. package/src/__tests__/jsx-smoke.test.ts +33 -0
  40. package/src/__tests__/jsx-smoke.tsx +23 -0
  41. package/src/__tests__/node-type-dispatch.test.ts +104 -0
  42. package/src/__tests__/store.test.ts +399 -0
  43. package/src/__tests__/tsconfig.json +23 -0
  44. package/src/classes.ts +41 -0
  45. package/src/compat.ts +237 -0
  46. package/src/connection.ts +459 -0
  47. package/src/constants.ts +8 -0
  48. package/src/context.ts +8 -0
  49. package/src/edge-path.ts +89 -0
  50. package/src/flow-subsystems.ts +506 -0
  51. package/src/hooks.ts +72 -0
  52. package/src/index.ts +134 -0
  53. package/src/node-resizer.ts +276 -0
  54. package/src/node-type-dispatch.ts +46 -0
  55. package/src/selection.ts +407 -0
  56. package/src/store.ts +526 -0
  57. package/src/types.ts +329 -0
  58. package/src/utils.ts +13 -0
package/src/types.ts ADDED
@@ -0,0 +1,329 @@
1
+ import type {
2
+ NodeBase,
3
+ EdgeBase,
4
+ InternalNodeBase,
5
+ Viewport,
6
+ NodeLookup,
7
+ ParentLookup,
8
+ EdgeLookup,
9
+ ConnectionLookup,
10
+ CoordinateExtent,
11
+ SnapGrid,
12
+ NodeOrigin,
13
+ Transform,
14
+ PanZoomInstance,
15
+ XYPosition,
16
+ FitViewOptionsBase,
17
+ OnConnect,
18
+ OnConnectStart,
19
+ OnConnectEnd,
20
+ IsValidConnection,
21
+ NodeDragItem,
22
+ ConnectionMode,
23
+ Connection,
24
+ } from '@xyflow/system'
25
+ import type { Signal, Memo } from '@barefootjs/client'
26
+ import type { ComponentDef } from '@barefootjs/client/runtime'
27
+
28
+ export type FitViewOptions = FitViewOptionsBase
29
+
30
+ export type {
31
+ NodeBase,
32
+ EdgeBase,
33
+ InternalNodeBase,
34
+ Viewport,
35
+ NodeLookup,
36
+ ParentLookup,
37
+ EdgeLookup,
38
+ ConnectionLookup,
39
+ CoordinateExtent,
40
+ SnapGrid,
41
+ NodeOrigin,
42
+ Transform,
43
+ PanZoomInstance,
44
+ XYPosition,
45
+ OnConnect,
46
+ OnConnectStart,
47
+ OnConnectEnd,
48
+ IsValidConnection,
49
+ NodeDragItem,
50
+ ConnectionMode,
51
+ Connection,
52
+ }
53
+
54
+ /**
55
+ * Callback fired when an edge is reconnected to a new handle.
56
+ */
57
+ export type OnReconnect<EdgeType extends EdgeBase = EdgeBase> = (
58
+ oldEdge: EdgeType,
59
+ newConnection: Connection,
60
+ ) => void
61
+
62
+ /**
63
+ * Options for creating a flow store.
64
+ */
65
+ export type FlowStoreOptions<
66
+ NodeType extends NodeBase = NodeBase,
67
+ EdgeType extends EdgeBase = EdgeBase,
68
+ > = {
69
+ nodes?: NodeType[]
70
+ edges?: EdgeType[]
71
+ defaultViewport?: Viewport
72
+ minZoom?: number
73
+ maxZoom?: number
74
+ nodeOrigin?: NodeOrigin
75
+ nodeExtent?: CoordinateExtent
76
+ snapToGrid?: boolean
77
+ snapGrid?: SnapGrid
78
+ fitView?: boolean
79
+ fitViewOptions?: FitViewOptions
80
+
81
+ // Custom component types
82
+ nodeTypes?: Record<string, ComponentDef | ((props: NodeComponentProps<NodeType>) => void)>
83
+ edgeTypes?: Record<string, ComponentDef | ((props: EdgeComponentProps<EdgeType>) => void)>
84
+
85
+ // Edge reconnection
86
+ edgesReconnectable?: boolean
87
+ onReconnect?: OnReconnect<EdgeType>
88
+
89
+ // Connection callbacks
90
+ onConnect?: OnConnect
91
+ onConnectStart?: OnConnectStart
92
+ onConnectEnd?: OnConnectEnd
93
+ isValidConnection?: IsValidConnection
94
+
95
+ // Lifecycle callbacks
96
+ onInit?: (store: FlowStore<NodeType, EdgeType>) => void
97
+ onNodeDragStart?: (event: MouseEvent, node: NodeType, nodes: NodeType[]) => void
98
+ onNodeDragStop?: (event: MouseEvent, node: NodeType, nodes: NodeType[]) => void
99
+ onMoveEnd?: (event: MouseEvent | TouchEvent | null, viewport: Viewport) => void
100
+ onPaneClick?: (event: MouseEvent) => void
101
+ onPaneMouseMove?: (event: MouseEvent) => void
102
+ onNodesDelete?: (nodes: NodeType[]) => void
103
+ onEdgesDelete?: (edges: EdgeType[]) => void
104
+
105
+ // Interactivity config
106
+ panOnDrag?: boolean
107
+ panOnScroll?: boolean
108
+ zoomOnScroll?: boolean
109
+ zoomOnDoubleClick?: boolean
110
+ zoomActivationKeyCode?: string | null
111
+ nodesDraggable?: boolean
112
+ nodesConnectable?: boolean
113
+ elementsSelectable?: boolean
114
+ deleteKeyCode?: string[] | null
115
+ selectionKeyCode?: string | null
116
+ connectionLineStyle?: Record<string, string>
117
+ defaultEdgeOptions?: Partial<EdgeBase>
118
+ elevateNodesOnSelect?: boolean
119
+ reconnectRadius?: number
120
+ }
121
+
122
+ /**
123
+ * The reactive flow store — all state exposed as signal getters.
124
+ */
125
+ export type FlowStore<
126
+ NodeType extends NodeBase = NodeBase,
127
+ EdgeType extends EdgeBase = EdgeBase,
128
+ > = {
129
+ // Reactive state (signal getters)
130
+ nodes: Signal<NodeType[]>[0]
131
+ edges: Signal<EdgeType[]>[0]
132
+ viewport: Signal<Viewport>[0]
133
+ width: Signal<number>[0]
134
+ height: Signal<number>[0]
135
+ dragging: Signal<boolean>[0]
136
+ nodesInitialized: Memo<boolean>
137
+
138
+ // Lookups (signal getters)
139
+ nodeLookup: Signal<NodeLookup<InternalNodeBase<NodeType>>>[0]
140
+ parentLookup: Signal<ParentLookup<InternalNodeBase<NodeType>>>[0]
141
+ edgeLookup: Signal<EdgeLookup<EdgeType>>[0]
142
+ connectionLookup: Signal<ConnectionLookup>[0]
143
+
144
+ /**
145
+ * Fine-grained per-node subscription. Returns the current internal
146
+ * entry for the given id, and tracks it for reactivity — the
147
+ * surrounding effect / memo will re-run only when **this** node's
148
+ * entry changes (data, selected, position via setNodes, or in-place
149
+ * drag updates), not on changes to sibling nodes.
150
+ *
151
+ * Use this in per-node consumers (data / selected / position
152
+ * observers). For iteration-style consumers that walk all nodes,
153
+ * keep using `nodeLookup()`.
154
+ */
155
+ nodeSignal: (id: string) => InternalNodeBase<NodeType> | undefined
156
+
157
+ // Lightweight position change counter — subscribers re-run without
158
+ // triggering the full adoptUserNodes pipeline.
159
+ positionEpoch: Signal<number>[0]
160
+ triggerPositionUpdate: () => void
161
+
162
+ // Internal refs
163
+ panZoom: Signal<PanZoomInstance | null>[0]
164
+ domNode: Signal<HTMLElement | null>[0]
165
+
166
+ // Setters
167
+ setNodes: Signal<NodeType[]>[1]
168
+ setEdges: Signal<EdgeType[]>[1]
169
+ setViewport: Signal<Viewport>[1]
170
+ setWidth: Signal<number>[1]
171
+ setHeight: Signal<number>[1]
172
+
173
+ // Selection state
174
+ multiSelectionActive: Signal<boolean>[0]
175
+
176
+ // Interactivity — when false, nodes cannot be dragged/connected/deleted
177
+ nodesDraggable: Signal<boolean>[0]
178
+ setNodesDraggable: Signal<boolean>[1]
179
+
180
+ // Actions
181
+ fitView: (options?: FitViewOptions) => void
182
+ updateNodePositions: (
183
+ dragItems: Map<string, NodeDragItem | InternalNodeBase<NodeType>>,
184
+ dragging?: boolean,
185
+ ) => void
186
+ unselectNodesAndEdges: (params?: {
187
+ nodes?: NodeType[]
188
+ edges?: EdgeType[]
189
+ }) => void
190
+ panByDelta: (delta: XYPosition) => Promise<boolean>
191
+ addEdge: (edge: EdgeType) => void
192
+ deleteElements: (params: {
193
+ nodes?: NodeType[]
194
+ edges?: EdgeType[]
195
+ }) => void
196
+
197
+ // Configuration
198
+ minZoom: number
199
+ maxZoom: number
200
+ nodeOrigin: NodeOrigin
201
+ nodeExtent: CoordinateExtent
202
+ snapToGrid: boolean
203
+ snapGrid: SnapGrid
204
+
205
+ // Viewport transform as [tx, ty, scale]
206
+ getTransform: () => Transform
207
+
208
+ // Custom component types
209
+ nodeTypes?: Record<string, ComponentDef | ((props: NodeComponentProps<NodeType>) => void)>
210
+ edgeTypes?: Record<string, ComponentDef | ((props: EdgeComponentProps<EdgeType>) => void)>
211
+
212
+ // Edge reconnection
213
+ edgesReconnectable: boolean
214
+ onReconnect?: OnReconnect<EdgeType>
215
+
216
+ // Connection callbacks
217
+ onConnect?: OnConnect
218
+ onConnectStart?: OnConnectStart
219
+ onConnectEnd?: OnConnectEnd
220
+ isValidConnection?: IsValidConnection
221
+
222
+ // Lifecycle callbacks
223
+ onInit?: (store: FlowStore<NodeType, EdgeType>) => void
224
+ onNodeDragStart?: (event: MouseEvent, node: NodeType, nodes: NodeType[]) => void
225
+ onNodeDragStop?: (event: MouseEvent, node: NodeType, nodes: NodeType[]) => void
226
+ onMoveEnd?: (event: MouseEvent | TouchEvent | null, viewport: Viewport) => void
227
+ onPaneClick?: (event: MouseEvent) => void
228
+ onPaneMouseMove?: (event: MouseEvent) => void
229
+ onNodesDelete?: (nodes: NodeType[]) => void
230
+ onEdgesDelete?: (edges: EdgeType[]) => void
231
+
232
+ // Interactivity (reactive signals)
233
+ nodesConnectable: Signal<boolean>[0]
234
+ setNodesConnectable: Signal<boolean>[1]
235
+ elementsSelectable: Signal<boolean>[0]
236
+ setElementsSelectable: Signal<boolean>[1]
237
+ panOnDrag: Signal<boolean>[0]
238
+ setPanOnDrag: Signal<boolean>[1]
239
+ panOnScroll: Signal<boolean>[0]
240
+ setPanOnScroll: Signal<boolean>[1]
241
+ zoomOnScroll: Signal<boolean>[0]
242
+ setZoomOnScroll: Signal<boolean>[1]
243
+
244
+ // Static config
245
+ deleteKeyCode: string[] | null
246
+ selectionKeyCode: string | null
247
+ connectionLineStyle?: Record<string, string>
248
+ defaultEdgeOptions?: Partial<EdgeBase>
249
+ elevateNodesOnSelect: boolean
250
+ reconnectRadius: number
251
+ }
252
+
253
+ /**
254
+ * Internal setters exposed by createFlowStore but not part of the public API.
255
+ * Used only by initFlow during initialization.
256
+ */
257
+ export type InternalFlowStore<
258
+ NodeType extends NodeBase = NodeBase,
259
+ EdgeType extends EdgeBase = EdgeBase,
260
+ > = FlowStore<NodeType, EdgeType> & {
261
+ setDragging: Signal<boolean>[1]
262
+ setPanZoom: Signal<PanZoomInstance | null>[1]
263
+ setDomNode: Signal<HTMLElement | null>[1]
264
+ setMultiSelectionActive: Signal<boolean>[1]
265
+ updatePanZoomConfig: () => void
266
+ }
267
+
268
+ /**
269
+ * Props passed to custom node components.
270
+ */
271
+ export type NodeComponentProps<NodeType extends NodeBase = NodeBase> = {
272
+ id: string
273
+ data: NodeType['data']
274
+ type: string
275
+ /**
276
+ * Reactive getter for this node's selected state. Call inside a
277
+ * createEffect to observe selection changes at runtime — reading it once
278
+ * at mount time only yields the initial value.
279
+ */
280
+ selected: () => boolean
281
+ dragging: boolean
282
+ positionAbsoluteX: number
283
+ positionAbsoluteY: number
284
+ width?: number
285
+ height?: number
286
+ isConnectable: boolean
287
+ }
288
+
289
+ /**
290
+ * Props passed to custom edge components.
291
+ */
292
+ export type EdgeComponentProps<EdgeType extends EdgeBase = EdgeBase> = {
293
+ id: string
294
+ source: string
295
+ target: string
296
+ sourceX: number
297
+ sourceY: number
298
+ targetX: number
299
+ targetY: number
300
+ sourcePosition: string
301
+ targetPosition: string
302
+ data: EdgeType['data']
303
+ selected: boolean
304
+ animated: boolean
305
+ label?: string
306
+ /** SVG group element to render custom edge content into */
307
+ svgGroup: SVGGElement
308
+ }
309
+
310
+ /**
311
+ * Selection mode for rectangle selection.
312
+ * - 'partial': selects nodes that partially overlap the rectangle (default)
313
+ * - 'full': only selects nodes fully contained in the rectangle
314
+ */
315
+ export type SelectionMode = 'partial' | 'full'
316
+
317
+ /**
318
+ * Props for the Flow init function.
319
+ */
320
+ export type FlowProps<
321
+ NodeType extends NodeBase = NodeBase,
322
+ EdgeType extends EdgeBase = EdgeBase,
323
+ > = FlowStoreOptions<NodeType, EdgeType> & {
324
+ class?: string
325
+ /** When true, dragging on empty pane starts selection without Shift key */
326
+ selectionOnDrag?: boolean
327
+ /** Selection mode: 'partial' (default) or 'full' */
328
+ selectionMode?: SelectionMode
329
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Apply position styling to an absolutely-positioned container element.
3
+ * Parses a position string like 'top-left' or 'bottom-right'.
4
+ */
5
+ export function applyPositionStyle(
6
+ el: HTMLElement,
7
+ position: string,
8
+ offset = '10px',
9
+ ): void {
10
+ const [vertical, horizontal] = position.split('-')
11
+ el.style[vertical as 'top' | 'bottom'] = offset
12
+ el.style[horizontal as 'left' | 'right'] = offset
13
+ }