panelui-native 0.63.0 → 0.66.1
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/README.md +5 -0
- package/lib/module/components/badge/index.js +1 -1
- package/lib/module/components/badge/index.js.map +1 -1
- package/lib/module/components/bar-chart/index.js +39 -2
- package/lib/module/components/bar-chart/index.js.map +1 -1
- package/lib/module/components/bottom-sheet/index.js +2 -2
- package/lib/module/components/bottom-sheet/index.js.map +1 -1
- package/lib/module/components/button/index.js +19 -9
- package/lib/module/components/button/index.js.map +1 -1
- package/lib/module/components/carousel/carousel-lifecycle.js +51 -0
- package/lib/module/components/carousel/carousel-lifecycle.js.map +1 -0
- package/lib/module/components/carousel/index.js +86 -35
- package/lib/module/components/carousel/index.js.map +1 -1
- package/lib/module/components/checkbox/index.js +2 -3
- package/lib/module/components/checkbox/index.js.map +1 -1
- package/lib/module/components/context-menu/context-menu-invocation.js +23 -0
- package/lib/module/components/context-menu/context-menu-invocation.js.map +1 -0
- package/lib/module/components/context-menu/index.js +78 -9
- package/lib/module/components/context-menu/index.js.map +1 -1
- package/lib/module/components/dialog/index.js +2 -2
- package/lib/module/components/dialog/index.js.map +1 -1
- package/lib/module/components/drawer/index.js +2 -2
- package/lib/module/components/drawer/index.js.map +1 -1
- package/lib/module/components/fab/index.js +4 -3
- package/lib/module/components/fab/index.js.map +1 -1
- package/lib/module/components/field/index.js +41 -6
- package/lib/module/components/field/index.js.map +1 -1
- package/lib/module/components/flow/flow-accessibility.js +100 -0
- package/lib/module/components/flow/flow-accessibility.js.map +1 -0
- package/lib/module/components/flow/flow-identifiers.js +81 -0
- package/lib/module/components/flow/flow-identifiers.js.map +1 -0
- package/lib/module/components/flow/index.js +112 -57
- package/lib/module/components/flow/index.js.map +1 -1
- package/lib/module/components/form/use-form.js +93 -66
- package/lib/module/components/form/use-form.js.map +1 -1
- package/lib/module/components/heatmap-chart/index.js +2 -2
- package/lib/module/components/heatmap-chart/index.js.map +1 -1
- package/lib/module/components/hex-chart/index.js +2 -2
- package/lib/module/components/hex-chart/index.js.map +1 -1
- package/lib/module/components/kpi/index.js +3 -1
- package/lib/module/components/kpi/index.js.map +1 -1
- package/lib/module/components/line-chart/index.js +3 -3
- package/lib/module/components/line-chart/index.js.map +1 -1
- package/lib/module/components/map/index.js +71 -8
- package/lib/module/components/map/index.js.map +1 -1
- package/lib/module/components/map/map-accessibility.js +20 -0
- package/lib/module/components/map/map-accessibility.js.map +1 -0
- package/lib/module/components/map/maplibre.js.map +1 -1
- package/lib/module/components/menu/index.js +4 -1
- package/lib/module/components/menu/index.js.map +1 -1
- package/lib/module/components/message-scroller/index.js +17 -9
- package/lib/module/components/message-scroller/index.js.map +1 -1
- package/lib/module/components/message-scroller/message-scroller-math.js +20 -0
- package/lib/module/components/message-scroller/message-scroller-math.js.map +1 -0
- package/lib/module/components/number-input/index.js +1 -23
- package/lib/module/components/number-input/index.js.map +1 -1
- package/lib/module/components/number-input/number-input-math.js +44 -0
- package/lib/module/components/number-input/number-input-math.js.map +1 -0
- package/lib/module/components/plot/index.js +2 -2
- package/lib/module/components/plot/index.js.map +1 -1
- package/lib/module/components/popover/index.js.map +1 -1
- package/lib/module/components/radio-group/index.js +1 -2
- package/lib/module/components/radio-group/index.js.map +1 -1
- package/lib/module/components/selection-mode/index.js +26 -31
- package/lib/module/components/selection-mode/index.js.map +1 -1
- package/lib/module/components/selection-mode/selection-mode-contracts.js +48 -0
- package/lib/module/components/selection-mode/selection-mode-contracts.js.map +1 -0
- package/lib/module/components/signature/index.js +62 -20
- package/lib/module/components/signature/index.js.map +1 -1
- package/lib/module/components/signature/signature-accessibility.js +58 -0
- package/lib/module/components/signature/signature-accessibility.js.map +1 -0
- package/lib/module/components/slider/index.js +22 -18
- package/lib/module/components/slider/index.js.map +1 -1
- package/lib/module/components/sortable/index.js +5 -55
- package/lib/module/components/sortable/index.js.map +1 -1
- package/lib/module/components/sortable/reorder.js +63 -0
- package/lib/module/components/sortable/reorder.js.map +1 -0
- package/lib/module/components/swipe/index.js +4 -4
- package/lib/module/components/swipe/index.js.map +1 -1
- package/lib/module/components/switch/index.js +36 -3
- package/lib/module/components/switch/index.js.map +1 -1
- package/lib/module/components/time-picker/accessibility.js +21 -0
- package/lib/module/components/time-picker/accessibility.js.map +1 -0
- package/lib/module/components/time-picker/index.js +34 -8
- package/lib/module/components/time-picker/index.js.map +1 -1
- package/lib/module/components/waterfall-chart/index.js +1325 -0
- package/lib/module/components/waterfall-chart/index.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/primitives/modal-isolation-store.js +29 -0
- package/lib/module/primitives/modal-isolation-store.js.map +1 -0
- package/lib/module/primitives/portal.js +36 -4
- package/lib/module/primitives/portal.js.map +1 -1
- package/lib/module/primitives/scrim.js +94 -3
- package/lib/module/primitives/scrim.js.map +1 -1
- package/lib/module/providers/panel-ui-provider.js +27 -6
- package/lib/module/providers/panel-ui-provider.js.map +1 -1
- package/lib/typescript/src/components/badge/index.d.ts.map +1 -1
- package/lib/typescript/src/components/bar-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/bottom-sheet/index.d.ts +3 -0
- package/lib/typescript/src/components/bottom-sheet/index.d.ts.map +1 -1
- package/lib/typescript/src/components/button/index.d.ts.map +1 -1
- package/lib/typescript/src/components/carousel/carousel-lifecycle.d.ts +23 -0
- package/lib/typescript/src/components/carousel/carousel-lifecycle.d.ts.map +1 -0
- package/lib/typescript/src/components/carousel/index.d.ts +5 -2
- package/lib/typescript/src/components/carousel/index.d.ts.map +1 -1
- package/lib/typescript/src/components/checkbox/index.d.ts.map +1 -1
- package/lib/typescript/src/components/context-menu/context-menu-invocation.d.ts +20 -0
- package/lib/typescript/src/components/context-menu/context-menu-invocation.d.ts.map +1 -0
- package/lib/typescript/src/components/context-menu/index.d.ts +18 -8
- package/lib/typescript/src/components/context-menu/index.d.ts.map +1 -1
- package/lib/typescript/src/components/dialog/index.d.ts +3 -0
- package/lib/typescript/src/components/dialog/index.d.ts.map +1 -1
- package/lib/typescript/src/components/drawer/index.d.ts +3 -0
- package/lib/typescript/src/components/drawer/index.d.ts.map +1 -1
- package/lib/typescript/src/components/fab/index.d.ts.map +1 -1
- package/lib/typescript/src/components/field/index.d.ts +8 -1
- package/lib/typescript/src/components/field/index.d.ts.map +1 -1
- package/lib/typescript/src/components/flow/flow-accessibility.d.ts +57 -0
- package/lib/typescript/src/components/flow/flow-accessibility.d.ts.map +1 -0
- package/lib/typescript/src/components/flow/flow-identifiers.d.ts +24 -0
- package/lib/typescript/src/components/flow/flow-identifiers.d.ts.map +1 -0
- package/lib/typescript/src/components/flow/index.d.ts +20 -7
- package/lib/typescript/src/components/flow/index.d.ts.map +1 -1
- package/lib/typescript/src/components/form/use-form.d.ts.map +1 -1
- package/lib/typescript/src/components/heatmap-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/hex-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/kpi/index.d.ts.map +1 -1
- package/lib/typescript/src/components/line-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/map/index.d.ts +13 -5
- package/lib/typescript/src/components/map/index.d.ts.map +1 -1
- package/lib/typescript/src/components/map/map-accessibility.d.ts +19 -0
- package/lib/typescript/src/components/map/map-accessibility.d.ts.map +1 -0
- package/lib/typescript/src/components/map/maplibre.d.ts +2 -0
- package/lib/typescript/src/components/map/maplibre.d.ts.map +1 -1
- package/lib/typescript/src/components/menu/index.d.ts.map +1 -1
- package/lib/typescript/src/components/message-scroller/index.d.ts.map +1 -1
- package/lib/typescript/src/components/message-scroller/message-scroller-math.d.ts +8 -0
- package/lib/typescript/src/components/message-scroller/message-scroller-math.d.ts.map +1 -0
- package/lib/typescript/src/components/number-input/index.d.ts.map +1 -1
- package/lib/typescript/src/components/number-input/number-input-math.d.ts +9 -0
- package/lib/typescript/src/components/number-input/number-input-math.d.ts.map +1 -0
- package/lib/typescript/src/components/plot/index.d.ts.map +1 -1
- package/lib/typescript/src/components/popover/index.d.ts +3 -0
- package/lib/typescript/src/components/popover/index.d.ts.map +1 -1
- package/lib/typescript/src/components/radio-group/index.d.ts.map +1 -1
- package/lib/typescript/src/components/selection-mode/index.d.ts +6 -4
- package/lib/typescript/src/components/selection-mode/index.d.ts.map +1 -1
- package/lib/typescript/src/components/selection-mode/selection-mode-contracts.d.ts +18 -0
- package/lib/typescript/src/components/selection-mode/selection-mode-contracts.d.ts.map +1 -0
- package/lib/typescript/src/components/signature/index.d.ts +6 -0
- package/lib/typescript/src/components/signature/index.d.ts.map +1 -1
- package/lib/typescript/src/components/signature/signature-accessibility.d.ts +27 -0
- package/lib/typescript/src/components/signature/signature-accessibility.d.ts.map +1 -0
- package/lib/typescript/src/components/slider/index.d.ts.map +1 -1
- package/lib/typescript/src/components/sortable/index.d.ts.map +1 -1
- package/lib/typescript/src/components/sortable/reorder.d.ts +14 -0
- package/lib/typescript/src/components/sortable/reorder.d.ts.map +1 -0
- package/lib/typescript/src/components/swipe/index.d.ts.map +1 -1
- package/lib/typescript/src/components/switch/index.d.ts +3 -3
- package/lib/typescript/src/components/switch/index.d.ts.map +1 -1
- package/lib/typescript/src/components/time-picker/accessibility.d.ts +10 -0
- package/lib/typescript/src/components/time-picker/accessibility.d.ts.map +1 -0
- package/lib/typescript/src/components/time-picker/index.d.ts.map +1 -1
- package/lib/typescript/src/components/waterfall-chart/index.d.ts +379 -0
- package/lib/typescript/src/components/waterfall-chart/index.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/primitives/modal-isolation-store.d.ts +10 -0
- package/lib/typescript/src/primitives/modal-isolation-store.d.ts.map +1 -0
- package/lib/typescript/src/primitives/portal.d.ts +6 -0
- package/lib/typescript/src/primitives/portal.d.ts.map +1 -1
- package/lib/typescript/src/primitives/scrim.d.ts +5 -3
- package/lib/typescript/src/primitives/scrim.d.ts.map +1 -1
- package/lib/typescript/src/providers/panel-ui-provider.d.ts.map +1 -1
- package/package.json +11 -5
- package/src/components/badge/index.tsx +4 -1
- package/src/components/bar-chart/index.tsx +40 -3
- package/src/components/bottom-sheet/index.tsx +6 -3
- package/src/components/button/index.tsx +15 -21
- package/src/components/carousel/carousel-lifecycle.ts +74 -0
- package/src/components/carousel/index.tsx +118 -41
- package/src/components/checkbox/index.tsx +1 -2
- package/src/components/context-menu/context-menu-invocation.ts +44 -0
- package/src/components/context-menu/index.tsx +113 -13
- package/src/components/dialog/index.tsx +6 -3
- package/src/components/drawer/index.tsx +6 -3
- package/src/components/fab/index.tsx +8 -12
- package/src/components/field/index.tsx +52 -10
- package/src/components/flow/flow-accessibility.ts +123 -0
- package/src/components/flow/flow-identifiers.ts +98 -0
- package/src/components/flow/index.tsx +191 -69
- package/src/components/form/use-form.ts +101 -65
- package/src/components/heatmap-chart/index.tsx +2 -3
- package/src/components/hex-chart/index.tsx +2 -3
- package/src/components/kpi/index.tsx +3 -1
- package/src/components/line-chart/index.tsx +3 -2
- package/src/components/map/index.tsx +110 -7
- package/src/components/map/map-accessibility.ts +41 -0
- package/src/components/map/maplibre.ts +2 -0
- package/src/components/menu/index.tsx +4 -1
- package/src/components/message-scroller/index.tsx +39 -7
- package/src/components/message-scroller/message-scroller-math.ts +24 -0
- package/src/components/number-input/index.tsx +1 -26
- package/src/components/number-input/number-input-math.ts +50 -0
- package/src/components/plot/index.tsx +2 -1
- package/src/components/popover/index.tsx +3 -0
- package/src/components/radio-group/index.tsx +1 -2
- package/src/components/selection-mode/index.tsx +37 -30
- package/src/components/selection-mode/selection-mode-contracts.ts +53 -0
- package/src/components/signature/index.tsx +107 -20
- package/src/components/signature/signature-accessibility.ts +67 -0
- package/src/components/slider/index.tsx +28 -18
- package/src/components/sortable/index.tsx +12 -64
- package/src/components/sortable/reorder.ts +88 -0
- package/src/components/swipe/index.tsx +7 -4
- package/src/components/switch/index.tsx +42 -6
- package/src/components/time-picker/accessibility.ts +24 -0
- package/src/components/time-picker/index.tsx +48 -2
- package/src/components/waterfall-chart/index.tsx +1589 -0
- package/src/index.ts +25 -0
- package/src/primitives/modal-isolation-store.ts +31 -0
- package/src/primitives/portal.tsx +34 -4
- package/src/primitives/scrim.tsx +127 -7
- package/src/providers/panel-ui-provider.tsx +41 -9
- package/theme.css +30 -3
|
@@ -48,6 +48,7 @@ import {
|
|
|
48
48
|
useCallback,
|
|
49
49
|
useContext,
|
|
50
50
|
useEffect,
|
|
51
|
+
useId,
|
|
51
52
|
useMemo,
|
|
52
53
|
useRef,
|
|
53
54
|
useState,
|
|
@@ -97,6 +98,22 @@ import {
|
|
|
97
98
|
type FlowRect,
|
|
98
99
|
type FlowSide,
|
|
99
100
|
} from './flow-paths';
|
|
101
|
+
import {
|
|
102
|
+
clampNodePosition,
|
|
103
|
+
FLOW_DELETE_ACTION,
|
|
104
|
+
FLOW_MOVE_ACTIONS,
|
|
105
|
+
getFlowConnectionActions,
|
|
106
|
+
moveNodePosition,
|
|
107
|
+
type FlowAccessibilityHandle,
|
|
108
|
+
type FlowAccessibilityNode,
|
|
109
|
+
} from './flow-accessibility';
|
|
110
|
+
import {
|
|
111
|
+
encodeFlowEdgeKey,
|
|
112
|
+
encodeFlowHandleKey,
|
|
113
|
+
resolveFlowEndpoint,
|
|
114
|
+
type FlowEndpoint,
|
|
115
|
+
type FlowEndpointReference,
|
|
116
|
+
} from './flow-identifiers';
|
|
100
117
|
|
|
101
118
|
const AnimatedPath = Animated.createAnimatedComponent(Path);
|
|
102
119
|
const AnimatedRect = Animated.createAnimatedComponent(Rect);
|
|
@@ -167,13 +184,9 @@ export interface FlowConnection {
|
|
|
167
184
|
targetHandle?: string;
|
|
168
185
|
}
|
|
169
186
|
|
|
170
|
-
interface HandleEntry {
|
|
171
|
-
key: string;
|
|
172
|
-
node: string;
|
|
173
|
-
id: string;
|
|
187
|
+
interface HandleEntry extends FlowAccessibilityHandle {
|
|
174
188
|
side: FlowSide;
|
|
175
189
|
offset: number;
|
|
176
|
-
type: 'source' | 'target' | 'both';
|
|
177
190
|
}
|
|
178
191
|
|
|
179
192
|
interface FlowContextValue {
|
|
@@ -215,7 +228,7 @@ interface FlowContextValue {
|
|
|
215
228
|
maxZoom: number;
|
|
216
229
|
locked: boolean;
|
|
217
230
|
setLocked: (locked: boolean) => void;
|
|
218
|
-
|
|
231
|
+
nodes: FlowAccessibilityNode[];
|
|
219
232
|
/**
|
|
220
233
|
* Which of `nodeIds` are containers rather than nodes. A group writes its box
|
|
221
234
|
* into the same registry — that is what lets an edge name one and the minimap
|
|
@@ -224,7 +237,7 @@ interface FlowContextValue {
|
|
|
224
237
|
groupIds: string[];
|
|
225
238
|
handles: HandleEntry[];
|
|
226
239
|
edges: { key: string; props: FlowEdgeProps }[];
|
|
227
|
-
registerNode: (id: string) => void;
|
|
240
|
+
registerNode: (id: string, label?: string) => void;
|
|
228
241
|
unregisterNode: (id: string) => void;
|
|
229
242
|
registerGroup: (id: string) => void;
|
|
230
243
|
unregisterGroup: (id: string) => void;
|
|
@@ -232,8 +245,8 @@ interface FlowContextValue {
|
|
|
232
245
|
unregisterHandle: (key: string) => void;
|
|
233
246
|
registerEdge: (key: string, props: FlowEdgeProps) => void;
|
|
234
247
|
unregisterEdge: (key: string) => void;
|
|
235
|
-
|
|
236
|
-
|
|
248
|
+
connectNodes: (connection: FlowConnection) => void;
|
|
249
|
+
canConnect: boolean;
|
|
237
250
|
onNodeDragEnd?: (id: string, position: FlowNodePosition) => void;
|
|
238
251
|
fitView: () => void;
|
|
239
252
|
zoomBy: (factor: number) => void;
|
|
@@ -332,7 +345,7 @@ function FlowRoot({
|
|
|
332
345
|
const size = useSharedValue({ width: 0, height: 0 });
|
|
333
346
|
|
|
334
347
|
const [locked, setLocked] = useState(false);
|
|
335
|
-
const [
|
|
348
|
+
const [nodes, setNodes] = useState<FlowAccessibilityNode[]>([]);
|
|
336
349
|
const [groupIds, setGroupIds] = useState<string[]>([]);
|
|
337
350
|
const [handles, setHandles] = useState<HandleEntry[]>([]);
|
|
338
351
|
const [edges, setEdges] = useState<{ key: string; props: FlowEdgeProps }[]>([]);
|
|
@@ -441,12 +454,12 @@ function FlowRoot({
|
|
|
441
454
|
viewportChangeRef.current?.({ x, y, zoom: z });
|
|
442
455
|
}, []);
|
|
443
456
|
|
|
444
|
-
const registerNode = useCallback((id: string) => {
|
|
445
|
-
|
|
457
|
+
const registerNode = useCallback((id: string, label = id) => {
|
|
458
|
+
setNodes((current) => [...current.filter((entry) => entry.id !== id), { id, label }]);
|
|
446
459
|
}, []);
|
|
447
460
|
|
|
448
461
|
const unregisterNode = useCallback((id: string) => {
|
|
449
|
-
|
|
462
|
+
setNodes((current) => current.filter((entry) => entry.id !== id));
|
|
450
463
|
}, []);
|
|
451
464
|
|
|
452
465
|
const registerGroup = useCallback((id: string) => {
|
|
@@ -476,6 +489,15 @@ function FlowRoot({
|
|
|
476
489
|
setEdges((current) => current.filter((edge) => edge.key !== key));
|
|
477
490
|
}, []);
|
|
478
491
|
|
|
492
|
+
const connectRef = useRef(onConnect);
|
|
493
|
+
connectRef.current = onConnect;
|
|
494
|
+
const validConnectionRef = useRef(isValidConnection);
|
|
495
|
+
validConnectionRef.current = isValidConnection;
|
|
496
|
+
const connectNodes = useCallback((next: FlowConnection) => {
|
|
497
|
+
if (validConnectionRef.current && !validConnectionRef.current(next)) return;
|
|
498
|
+
connectRef.current?.(next);
|
|
499
|
+
}, []);
|
|
500
|
+
|
|
479
501
|
const fitView = useCallback(() => {
|
|
480
502
|
const { width, height } = size.value;
|
|
481
503
|
const all = Object.values(rects.value);
|
|
@@ -549,10 +571,10 @@ function FlowRoot({
|
|
|
549
571
|
// mount has nothing to fit to yet. One frame later they do.
|
|
550
572
|
const fitOnMount = useRef(fitViewOnMount);
|
|
551
573
|
useEffect(() => {
|
|
552
|
-
if (!fitOnMount.current ||
|
|
574
|
+
if (!fitOnMount.current || nodes.length === 0) return;
|
|
553
575
|
const timer = setTimeout(fitView, 32);
|
|
554
576
|
return () => clearTimeout(timer);
|
|
555
|
-
}, [fitView,
|
|
577
|
+
}, [fitView, nodes.length]);
|
|
556
578
|
|
|
557
579
|
const panStart = useSharedValue({ x: 0, y: 0 });
|
|
558
580
|
const pinchStart = useSharedValue({ zoom: 1, x: 0, y: 0 });
|
|
@@ -647,7 +669,7 @@ function FlowRoot({
|
|
|
647
669
|
maxZoom,
|
|
648
670
|
locked,
|
|
649
671
|
setLocked,
|
|
650
|
-
|
|
672
|
+
nodes,
|
|
651
673
|
groupIds,
|
|
652
674
|
handles,
|
|
653
675
|
edges,
|
|
@@ -659,8 +681,8 @@ function FlowRoot({
|
|
|
659
681
|
unregisterHandle,
|
|
660
682
|
registerEdge,
|
|
661
683
|
unregisterEdge,
|
|
662
|
-
|
|
663
|
-
|
|
684
|
+
connectNodes,
|
|
685
|
+
canConnect: Boolean(onConnect),
|
|
664
686
|
onNodeDragEnd,
|
|
665
687
|
fitView,
|
|
666
688
|
zoomBy,
|
|
@@ -678,11 +700,11 @@ function FlowRoot({
|
|
|
678
700
|
handles,
|
|
679
701
|
registerEdge,
|
|
680
702
|
unregisterEdge,
|
|
681
|
-
|
|
703
|
+
connectNodes,
|
|
682
704
|
locked,
|
|
683
705
|
maxZoom,
|
|
684
706
|
minZoom,
|
|
685
|
-
|
|
707
|
+
nodes,
|
|
686
708
|
groupIds,
|
|
687
709
|
onConnect,
|
|
688
710
|
onNodeDragEnd,
|
|
@@ -856,7 +878,7 @@ function FlowBackground({
|
|
|
856
878
|
const token = useCSSVariable('--color-muted-foreground');
|
|
857
879
|
const tint = color ?? (typeof token === 'string' ? token : '#737373');
|
|
858
880
|
// A pattern is referenced by id, and two canvases on one screen would collide.
|
|
859
|
-
const id =
|
|
881
|
+
const id = `panelui-flow-${useId().replace(/[^a-zA-Z0-9]/g, '')}`;
|
|
860
882
|
|
|
861
883
|
/*
|
|
862
884
|
* The grid is a tile that follows the viewport in whole-cell steps.
|
|
@@ -972,6 +994,13 @@ export interface FlowNodeProps extends Omit<ViewProps, 'children'> {
|
|
|
972
994
|
selected?: boolean;
|
|
973
995
|
/** Tapping the node — separate from dragging it. */
|
|
974
996
|
onPress?: () => void;
|
|
997
|
+
/**
|
|
998
|
+
* Delete the node when assistive technology requests the advertised Delete
|
|
999
|
+
* node action. No delete action is exposed when this is omitted.
|
|
1000
|
+
*/
|
|
1001
|
+
onDelete?: () => void;
|
|
1002
|
+
/** Graph points covered by each Move up, right, down or left accessibility action. */
|
|
1003
|
+
accessibilityMoveStep?: number;
|
|
975
1004
|
/** Spoken name. Defaults to the node's id. */
|
|
976
1005
|
accessibilityLabel?: string;
|
|
977
1006
|
children?: ReactNode;
|
|
@@ -991,7 +1020,11 @@ function FlowNode({
|
|
|
991
1020
|
pinned = false,
|
|
992
1021
|
selected = false,
|
|
993
1022
|
onPress,
|
|
1023
|
+
onDelete,
|
|
1024
|
+
accessibilityMoveStep = 24,
|
|
994
1025
|
accessibilityLabel,
|
|
1026
|
+
accessibilityActions,
|
|
1027
|
+
onAccessibilityAction,
|
|
995
1028
|
children,
|
|
996
1029
|
...props
|
|
997
1030
|
}: FlowNodeProps) {
|
|
@@ -1009,6 +1042,10 @@ function FlowNode({
|
|
|
1009
1042
|
registerGroup,
|
|
1010
1043
|
unregisterGroup,
|
|
1011
1044
|
onNodeDragEnd,
|
|
1045
|
+
nodes,
|
|
1046
|
+
handles,
|
|
1047
|
+
connectNodes,
|
|
1048
|
+
canConnect,
|
|
1012
1049
|
} = flow;
|
|
1013
1050
|
|
|
1014
1051
|
/*
|
|
@@ -1018,13 +1055,13 @@ function FlowNode({
|
|
|
1018
1055
|
* layer both need to know it is a container and not a card.
|
|
1019
1056
|
*/
|
|
1020
1057
|
useEffect(() => {
|
|
1021
|
-
registerNode(id);
|
|
1058
|
+
registerNode(id, accessibilityLabel ?? id);
|
|
1022
1059
|
registerGroup(id);
|
|
1023
1060
|
return () => {
|
|
1024
1061
|
unregisterNode(id);
|
|
1025
1062
|
unregisterGroup(id);
|
|
1026
1063
|
};
|
|
1027
|
-
}, [id, registerGroup, registerNode, unregisterGroup, unregisterNode]);
|
|
1064
|
+
}, [accessibilityLabel, id, registerGroup, registerNode, unregisterGroup, unregisterNode]);
|
|
1028
1065
|
|
|
1029
1066
|
// Writing on every render would fight the drag, snapping a node back to the
|
|
1030
1067
|
// position it was first given. Only an actual change to the prop moves it.
|
|
@@ -1065,11 +1102,70 @@ function FlowNode({
|
|
|
1065
1102
|
);
|
|
1066
1103
|
|
|
1067
1104
|
const start = useSharedValue({ x: 0, y: 0 });
|
|
1068
|
-
|
|
1069
1105
|
const pressRef = useRef(onPress);
|
|
1070
1106
|
pressRef.current = onPress;
|
|
1071
1107
|
const press = useCallback(() => pressRef.current?.(), []);
|
|
1072
1108
|
|
|
1109
|
+
const moveNode = useCallback(
|
|
1110
|
+
(actionName: string) => {
|
|
1111
|
+
const rect = rects.value[id];
|
|
1112
|
+
if (!rect) return;
|
|
1113
|
+
const bounds = confine && group ? rects.value[group] : undefined;
|
|
1114
|
+
const next = moveNodePosition(rect, bounds, actionName, accessibilityMoveStep);
|
|
1115
|
+
if (!next) return;
|
|
1116
|
+
setNodeRect(id, next);
|
|
1117
|
+
dragEnd(next.x, next.y);
|
|
1118
|
+
},
|
|
1119
|
+
[accessibilityMoveStep, confine, dragEnd, group, id, rects, setNodeRect]
|
|
1120
|
+
);
|
|
1121
|
+
|
|
1122
|
+
const connectionActions = useMemo(
|
|
1123
|
+
() => (canConnect && !locked ? getFlowConnectionActions(id, nodes, handles) : []),
|
|
1124
|
+
[canConnect, handles, id, locked, nodes]
|
|
1125
|
+
);
|
|
1126
|
+
const connectionByAction = useMemo(
|
|
1127
|
+
() => new Map(connectionActions.map((entry) => [entry.name, entry.connection])),
|
|
1128
|
+
[connectionActions]
|
|
1129
|
+
);
|
|
1130
|
+
const movable = draggable && !pinned && !locked;
|
|
1131
|
+
const nodeActions = useMemo(
|
|
1132
|
+
() => [
|
|
1133
|
+
...(onPress ? [{ name: 'activate' }] : []),
|
|
1134
|
+
...(movable ? FLOW_MOVE_ACTIONS : []),
|
|
1135
|
+
...connectionActions.map(({ name, label }) => ({ name, label })),
|
|
1136
|
+
...(onDelete ? [FLOW_DELETE_ACTION] : []),
|
|
1137
|
+
...(accessibilityActions ?? []),
|
|
1138
|
+
],
|
|
1139
|
+
[accessibilityActions, connectionActions, movable, onDelete, onPress]
|
|
1140
|
+
);
|
|
1141
|
+
|
|
1142
|
+
const handleAccessibilityAction = useCallback<
|
|
1143
|
+
NonNullable<ViewProps['onAccessibilityAction']>
|
|
1144
|
+
>(
|
|
1145
|
+
(event) => {
|
|
1146
|
+
const action = event.nativeEvent.actionName;
|
|
1147
|
+
if (action === 'activate' && onPress) {
|
|
1148
|
+
press();
|
|
1149
|
+
return;
|
|
1150
|
+
}
|
|
1151
|
+
if (movable && FLOW_MOVE_ACTIONS.some((entry) => entry.name === action)) {
|
|
1152
|
+
moveNode(action);
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1155
|
+
const nextConnection = connectionByAction.get(action);
|
|
1156
|
+
if (nextConnection) {
|
|
1157
|
+
connectNodes(nextConnection);
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
if (action === FLOW_DELETE_ACTION.name && onDelete) {
|
|
1161
|
+
onDelete();
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
onAccessibilityAction?.(event);
|
|
1165
|
+
},
|
|
1166
|
+
[connectNodes, connectionByAction, movable, moveNode, onAccessibilityAction, onDelete, onPress, press]
|
|
1167
|
+
);
|
|
1168
|
+
|
|
1073
1169
|
const drag = useMemo(
|
|
1074
1170
|
() =>
|
|
1075
1171
|
Gesture.Pan()
|
|
@@ -1096,13 +1192,9 @@ function FlowNode({
|
|
|
1096
1192
|
* would leave the edges drawn to a position the node never reached.
|
|
1097
1193
|
*/
|
|
1098
1194
|
if (confine && group) {
|
|
1099
|
-
const
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
const maxY = box.y + box.height - rect.height;
|
|
1103
|
-
x = x < box.x ? box.x : x > maxX ? maxX : x;
|
|
1104
|
-
y = y < box.y ? box.y : y > maxY ? maxY : y;
|
|
1105
|
-
}
|
|
1195
|
+
const next = clampNodePosition(rect, rects.value[group], { x, y });
|
|
1196
|
+
x = next.x;
|
|
1197
|
+
y = next.y;
|
|
1106
1198
|
}
|
|
1107
1199
|
|
|
1108
1200
|
rects.value = { ...rects.value, [id]: { ...rect, x, y } };
|
|
@@ -1158,6 +1250,8 @@ function FlowNode({
|
|
|
1158
1250
|
accessibilityRole={onPress ? 'button' : 'none'}
|
|
1159
1251
|
accessibilityLabel={accessibilityLabel ?? id}
|
|
1160
1252
|
accessibilityState={{ selected }}
|
|
1253
|
+
accessibilityActions={nodeActions}
|
|
1254
|
+
onAccessibilityAction={handleAccessibilityAction}
|
|
1161
1255
|
{...props}
|
|
1162
1256
|
>
|
|
1163
1257
|
{textChildren(children)}
|
|
@@ -1185,6 +1279,11 @@ export interface FlowHandleProps {
|
|
|
1185
1279
|
/** Where along the face, 0–1. For more than one handle on a side. */
|
|
1186
1280
|
offset?: number;
|
|
1187
1281
|
className?: string;
|
|
1282
|
+
/**
|
|
1283
|
+
* Spoken handle name used in the parent node's connection actions. Defaults
|
|
1284
|
+
* to the handle's id.
|
|
1285
|
+
*/
|
|
1286
|
+
accessibilityLabel?: string;
|
|
1188
1287
|
/** Draw nothing. The handle still anchors edges and still accepts a drop. */
|
|
1189
1288
|
hidden?: boolean;
|
|
1190
1289
|
}
|
|
@@ -1203,6 +1302,7 @@ function FlowHandle({
|
|
|
1203
1302
|
type = 'both',
|
|
1204
1303
|
offset = 0.5,
|
|
1205
1304
|
className,
|
|
1305
|
+
accessibilityLabel,
|
|
1206
1306
|
hidden = false,
|
|
1207
1307
|
}: FlowHandleProps) {
|
|
1208
1308
|
const flow = useFlow('Flow.Handle');
|
|
@@ -1211,31 +1311,51 @@ function FlowHandle({
|
|
|
1211
1311
|
throw new Error('Flow.Handle must be used within a <Flow.Node>');
|
|
1212
1312
|
}
|
|
1213
1313
|
|
|
1214
|
-
const {
|
|
1215
|
-
|
|
1314
|
+
const {
|
|
1315
|
+
rects,
|
|
1316
|
+
zoom,
|
|
1317
|
+
connection,
|
|
1318
|
+
handles,
|
|
1319
|
+
locked,
|
|
1320
|
+
registerHandle,
|
|
1321
|
+
unregisterHandle,
|
|
1322
|
+
connectNodes,
|
|
1323
|
+
} = flow;
|
|
1324
|
+
const key = encodeFlowHandleKey(node, id);
|
|
1216
1325
|
|
|
1217
1326
|
useEffect(() => {
|
|
1218
|
-
registerHandle({
|
|
1327
|
+
registerHandle({
|
|
1328
|
+
key,
|
|
1329
|
+
node,
|
|
1330
|
+
id,
|
|
1331
|
+
label: accessibilityLabel ?? id,
|
|
1332
|
+
side: position,
|
|
1333
|
+
offset,
|
|
1334
|
+
type,
|
|
1335
|
+
});
|
|
1219
1336
|
return () => unregisterHandle(key);
|
|
1220
|
-
}, [
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1337
|
+
}, [
|
|
1338
|
+
accessibilityLabel,
|
|
1339
|
+
id,
|
|
1340
|
+
key,
|
|
1341
|
+
node,
|
|
1342
|
+
offset,
|
|
1343
|
+
position,
|
|
1344
|
+
registerHandle,
|
|
1345
|
+
type,
|
|
1346
|
+
unregisterHandle,
|
|
1347
|
+
]);
|
|
1226
1348
|
|
|
1227
1349
|
const land = useCallback(
|
|
1228
1350
|
(target: string, targetHandle: string | undefined) => {
|
|
1229
|
-
|
|
1351
|
+
connectNodes({
|
|
1230
1352
|
source: node,
|
|
1231
1353
|
sourceHandle: id,
|
|
1232
1354
|
target,
|
|
1233
1355
|
targetHandle,
|
|
1234
|
-
};
|
|
1235
|
-
if (validRef.current && !validRef.current(payload)) return;
|
|
1236
|
-
connectRef.current?.(payload);
|
|
1356
|
+
});
|
|
1237
1357
|
},
|
|
1238
|
-
[id, node]
|
|
1358
|
+
[connectNodes, id, node]
|
|
1239
1359
|
);
|
|
1240
1360
|
|
|
1241
1361
|
// A snapshot of what a drag can land on, rebuilt only when handles come and
|
|
@@ -1354,8 +1474,7 @@ function FlowHandle({
|
|
|
1354
1474
|
<View
|
|
1355
1475
|
collapsable={false}
|
|
1356
1476
|
hitSlop={12}
|
|
1357
|
-
|
|
1358
|
-
accessibilityLabel={`${position} connection point`}
|
|
1477
|
+
accessible={false}
|
|
1359
1478
|
style={placement}
|
|
1360
1479
|
className={flowVariants().handle({ className })}
|
|
1361
1480
|
/>
|
|
@@ -1369,10 +1488,10 @@ FlowHandle.displayName = 'Flow.Handle';
|
|
|
1369
1488
|
/* -------------------------------------------------------------------------- */
|
|
1370
1489
|
|
|
1371
1490
|
export interface FlowEdgeProps {
|
|
1372
|
-
/** Source
|
|
1373
|
-
from:
|
|
1374
|
-
/** Target, same shape. */
|
|
1375
|
-
to:
|
|
1491
|
+
/** Source node or handle. Strings retain the `"nodeId.handleId"` shorthand. */
|
|
1492
|
+
from: FlowEndpointReference;
|
|
1493
|
+
/** Target node or handle, in the same shape. */
|
|
1494
|
+
to: FlowEndpointReference;
|
|
1376
1495
|
/** How the edge is routed. */
|
|
1377
1496
|
variant?: FlowEdgeVariant;
|
|
1378
1497
|
/**
|
|
@@ -1418,7 +1537,7 @@ export interface FlowEdgeProps {
|
|
|
1418
1537
|
*/
|
|
1419
1538
|
function FlowEdge(props: FlowEdgeProps) {
|
|
1420
1539
|
const { registerEdge, unregisterEdge } = useFlow('Flow.Edge');
|
|
1421
|
-
const key =
|
|
1540
|
+
const key = encodeFlowEdgeKey(props.from, props.to);
|
|
1422
1541
|
|
|
1423
1542
|
// Re-registered whenever any prop changes, so `animated` toggling or a
|
|
1424
1543
|
// variant switch reaches the layer that draws it.
|
|
@@ -1459,8 +1578,9 @@ function FlowEdgePath({
|
|
|
1459
1578
|
tint: string;
|
|
1460
1579
|
origin: { x: number; y: number };
|
|
1461
1580
|
}) {
|
|
1462
|
-
const
|
|
1463
|
-
const
|
|
1581
|
+
const nodes = Object.keys(boxes);
|
|
1582
|
+
const source = resolveEnd(from, fromSide, nodes, handles);
|
|
1583
|
+
const target = resolveEnd(to, toSide, nodes, handles);
|
|
1464
1584
|
|
|
1465
1585
|
const fromRect = boxes[source.node];
|
|
1466
1586
|
const toRect = boxes[target.node];
|
|
@@ -1519,22 +1639,24 @@ function FlowEdgePath({
|
|
|
1519
1639
|
}
|
|
1520
1640
|
|
|
1521
1641
|
/**
|
|
1522
|
-
*
|
|
1523
|
-
*
|
|
1642
|
+
* Resolves a node or handle without parsing either identifier. Legacy
|
|
1643
|
+
* `"node.handle"` references are matched against the structured registry.
|
|
1524
1644
|
*/
|
|
1525
1645
|
function resolveEnd(
|
|
1526
|
-
reference:
|
|
1646
|
+
reference: FlowEndpointReference,
|
|
1527
1647
|
explicit: FlowSide | undefined,
|
|
1648
|
+
nodes: string[],
|
|
1528
1649
|
handles: HandleEntry[]
|
|
1529
1650
|
): { node: string; side: FlowSide | undefined; offset: number } {
|
|
1530
|
-
const
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1651
|
+
const endpoint = resolveFlowEndpoint(reference, nodes, handles);
|
|
1652
|
+
const entry =
|
|
1653
|
+
endpoint.handle === undefined
|
|
1654
|
+
? undefined
|
|
1655
|
+
: handles.find(
|
|
1656
|
+
(handle) => handle.node === endpoint.node && handle.id === endpoint.handle
|
|
1657
|
+
);
|
|
1536
1658
|
return {
|
|
1537
|
-
node,
|
|
1659
|
+
node: endpoint.node,
|
|
1538
1660
|
side: explicit ?? entry?.side,
|
|
1539
1661
|
offset: entry?.offset ?? 0.5,
|
|
1540
1662
|
};
|
|
@@ -1645,9 +1767,9 @@ function FlowGroup({
|
|
|
1645
1767
|
} = flow;
|
|
1646
1768
|
|
|
1647
1769
|
useEffect(() => {
|
|
1648
|
-
registerNode(id);
|
|
1770
|
+
registerNode(id, label ?? id);
|
|
1649
1771
|
return () => unregisterNode(id);
|
|
1650
|
-
}, [id, registerNode, unregisterNode]);
|
|
1772
|
+
}, [id, label, registerNode, unregisterNode]);
|
|
1651
1773
|
|
|
1652
1774
|
useEffect(() => {
|
|
1653
1775
|
setNodeRect(id, {
|
|
@@ -1919,7 +2041,7 @@ function FlowMiniMap({
|
|
|
1919
2041
|
height = 84,
|
|
1920
2042
|
nodeColor,
|
|
1921
2043
|
}: FlowMiniMapProps) {
|
|
1922
|
-
const { rects,
|
|
2044
|
+
const { rects, nodes, groupIds, translateX, translateY, zoom, size } =
|
|
1923
2045
|
useFlow('Flow.MiniMap');
|
|
1924
2046
|
const token = useCSSVariable('--color-muted-foreground');
|
|
1925
2047
|
const tint = nodeColor ?? (typeof token === 'string' ? token : '#737373');
|
|
@@ -1999,7 +2121,7 @@ function FlowMiniMap({
|
|
|
1999
2121
|
{/* Containers first and drawn as outlines, so the map reads the way
|
|
2000
2122
|
the canvas does — boxes with things in them, rather than a wash of
|
|
2001
2123
|
identical rectangles where the largest happens to be a group. */}
|
|
2002
|
-
{
|
|
2124
|
+
{nodes.map(({ id }) => {
|
|
2003
2125
|
const group = groups.has(id);
|
|
2004
2126
|
return (
|
|
2005
2127
|
<MiniMapNode
|
|
@@ -2087,4 +2209,4 @@ export const Flow = Object.assign(FlowRoot, {
|
|
|
2087
2209
|
MiniMap: FlowMiniMap,
|
|
2088
2210
|
});
|
|
2089
2211
|
|
|
2090
|
-
export type { FlowSide, FlowRect, FlowPoint };
|
|
2212
|
+
export type { FlowEndpoint, FlowEndpointReference, FlowSide, FlowRect, FlowPoint };
|