@app-studio/web 0.9.31 → 0.9.33
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/docs/components/Accordion.mdx +158 -0
- package/docs/components/Alert.mdx +123 -0
- package/docs/components/AspectRatio.mdx +55 -0
- package/docs/components/Avatar.mdx +85 -0
- package/docs/components/Background.mdx +522 -0
- package/docs/components/Badge.mdx +220 -0
- package/docs/components/Button.mdx +272 -0
- package/docs/components/Calendar.mdx +274 -0
- package/docs/components/Card.mdx +341 -0
- package/docs/components/Carousel.mdx +411 -0
- package/docs/components/Center.mdx +474 -0
- package/docs/components/Chart.mdx +232 -0
- package/docs/components/ChatInput.mdx +373 -0
- package/docs/components/Checkbox.mdx +66 -0
- package/docs/components/ColorInput.mdx +209 -0
- package/docs/components/ComboBox.mdx +364 -0
- package/docs/components/Command.mdx +252 -0
- package/docs/components/ContextMenu.mdx +219 -0
- package/docs/components/CountryPicker.mdx +123 -0
- package/docs/components/DatePicker.mdx +77 -0
- package/docs/components/DragAndDrop.mdx +539 -0
- package/docs/components/DropdownMenu.mdx +205 -0
- package/docs/components/File.mdx +8 -0
- package/docs/components/Flow.mdx +257 -0
- package/docs/components/Form.mdx +681 -0
- package/docs/components/Formik.mdx +621 -0
- package/docs/components/Gradient.mdx +271 -0
- package/docs/components/Horizontal.mdx +40 -0
- package/docs/components/HoverCard.mdx +140 -0
- package/docs/components/Icon.mdx +438 -0
- package/docs/components/Label.mdx +438 -0
- package/docs/components/Link.mdx +83 -0
- package/docs/components/Loader.mdx +527 -0
- package/docs/components/Menubar.mdx +124 -0
- package/docs/components/Message.mdx +571 -0
- package/docs/components/Modal.mdx +533 -0
- package/docs/components/NavigationMenu.mdx +165 -0
- package/docs/components/Pagination.mdx +150 -0
- package/docs/components/Password.mdx +121 -0
- package/docs/components/Resizable.mdx +148 -0
- package/docs/components/Select.mdx +126 -0
- package/docs/components/Separator.mdx +121 -0
- package/docs/components/Sidebar.mdx +147 -0
- package/docs/components/Slider.mdx +232 -0
- package/docs/components/Switch.mdx +62 -0
- package/docs/components/Table.mdx +409 -0
- package/docs/components/Tabs.mdx +215 -0
- package/docs/components/TagInput.mdx +528 -0
- package/docs/components/Text.mdx +163 -0
- package/docs/components/TextArea.mdx +136 -0
- package/docs/components/TextField.mdx +225 -0
- package/docs/components/Title.mdx +535 -0
- package/docs/components/Toast.mdx +165 -0
- package/docs/components/Toggle.mdx +141 -0
- package/docs/components/ToggleGroup.mdx +165 -0
- package/docs/components/Tooltip.mdx +191 -0
- package/docs/components/Tree.mdx +340 -0
- package/docs/components/Uploader.mdx +426 -0
- package/docs/components/Vertical.mdx +566 -0
- package/docs/components.md +285 -0
- package/package.json +1 -1
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# DropdownMenu
|
|
2
|
+
|
|
3
|
+
A dropdown menu component that appears when clicking on a trigger element.
|
|
4
|
+
|
|
5
|
+
### **Import**
|
|
6
|
+
```tsx
|
|
7
|
+
import { DropdownMenu } from '@app-studio/web';
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
### **Default**
|
|
11
|
+
```tsx
|
|
12
|
+
import React from 'react';
|
|
13
|
+
import { DropdownMenu } from '../DropdownMenu';
|
|
14
|
+
import { Button } from '../../Button/Button';
|
|
15
|
+
import { CopyIcon, EditIcon, DeleteIcon } from '../../Icon/Icon';
|
|
16
|
+
|
|
17
|
+
export const DefaultDropdownMenu = () => {
|
|
18
|
+
const items = [
|
|
19
|
+
{
|
|
20
|
+
id: 'copy',
|
|
21
|
+
label: 'Copy',
|
|
22
|
+
icon: <CopyIcon widthHeight={16} />,
|
|
23
|
+
onClick: () => alert('Copy clicked')
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: 'edit',
|
|
27
|
+
label: 'Edit',
|
|
28
|
+
icon: <EditIcon widthHeight={16} />,
|
|
29
|
+
onClick: () => alert('Edit clicked')
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'divider-1',
|
|
33
|
+
divider: true
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 'delete',
|
|
37
|
+
label: 'Delete',
|
|
38
|
+
icon: <DeleteIcon widthHeight={16} />,
|
|
39
|
+
onClick: () => alert('Delete clicked')
|
|
40
|
+
}
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<DropdownMenu
|
|
45
|
+
trigger={<Button>Open Menu</Button>}
|
|
46
|
+
items={items}
|
|
47
|
+
/>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### **Submenu**
|
|
53
|
+
Create nested dropdown menus with submenus.
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
import React from 'react';
|
|
57
|
+
import { DropdownMenu } from '../DropdownMenu';
|
|
58
|
+
import { Button } from '../../Button/Button';
|
|
59
|
+
import {
|
|
60
|
+
CopyIcon,
|
|
61
|
+
EditIcon,
|
|
62
|
+
DownloadIcon,
|
|
63
|
+
ShareIcon
|
|
64
|
+
} from '../../Icon/Icon';
|
|
65
|
+
|
|
66
|
+
export const SubmenuDropdownMenu = () => {
|
|
67
|
+
const items = [
|
|
68
|
+
{
|
|
69
|
+
id: 'copy',
|
|
70
|
+
label: 'Copy',
|
|
71
|
+
icon: <CopyIcon widthHeight={16} />,
|
|
72
|
+
onClick: () => alert('Copy clicked')
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: 'edit',
|
|
76
|
+
label: 'Edit',
|
|
77
|
+
icon: <EditIcon widthHeight={16} />,
|
|
78
|
+
onClick: () => alert('Edit clicked')
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: 'more',
|
|
82
|
+
label: 'More Options',
|
|
83
|
+
items: [
|
|
84
|
+
{
|
|
85
|
+
id: 'download',
|
|
86
|
+
label: 'Download',
|
|
87
|
+
icon: <DownloadIcon widthHeight={16} />,
|
|
88
|
+
onClick: () => alert('Download clicked')
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: 'share',
|
|
92
|
+
label: 'Share',
|
|
93
|
+
icon: <ShareIcon widthHeight={16} />,
|
|
94
|
+
onClick: () => alert('Share clicked')
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<DropdownMenu
|
|
102
|
+
trigger={<Button>Open Menu</Button>}
|
|
103
|
+
items={items}
|
|
104
|
+
/>
|
|
105
|
+
);
|
|
106
|
+
};
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### **Positioning**
|
|
110
|
+
Control the position and alignment of the dropdown menu.
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
import React from 'react';
|
|
114
|
+
import { DropdownMenu } from '../DropdownMenu';
|
|
115
|
+
import { Button } from '../../Button/Button';
|
|
116
|
+
import { CopyIcon, EditIcon } from '../../Icon/Icon';
|
|
117
|
+
|
|
118
|
+
export const PositionedDropdownMenu = () => {
|
|
119
|
+
const items = [
|
|
120
|
+
{
|
|
121
|
+
id: 'copy',
|
|
122
|
+
label: 'Copy',
|
|
123
|
+
icon: <CopyIcon widthHeight={16} />,
|
|
124
|
+
onClick: () => alert('Copy clicked')
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: 'edit',
|
|
128
|
+
label: 'Edit',
|
|
129
|
+
icon: <EditIcon widthHeight={16} />,
|
|
130
|
+
onClick: () => alert('Edit clicked')
|
|
131
|
+
}
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
<>
|
|
136
|
+
<DropdownMenu
|
|
137
|
+
trigger={<Button>Bottom (Default)</Button>}
|
|
138
|
+
items={items}
|
|
139
|
+
side="bottom"
|
|
140
|
+
align="start"
|
|
141
|
+
/>
|
|
142
|
+
|
|
143
|
+
<DropdownMenu
|
|
144
|
+
trigger={<Button>Top Center</Button>}
|
|
145
|
+
items={items}
|
|
146
|
+
side="top"
|
|
147
|
+
align="center"
|
|
148
|
+
/>
|
|
149
|
+
|
|
150
|
+
<DropdownMenu
|
|
151
|
+
trigger={<Button>Right End</Button>}
|
|
152
|
+
items={items}
|
|
153
|
+
side="right"
|
|
154
|
+
align="end"
|
|
155
|
+
/>
|
|
156
|
+
</>
|
|
157
|
+
);
|
|
158
|
+
};
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### **Custom Styling**
|
|
162
|
+
Customize the appearance of the dropdown menu.
|
|
163
|
+
|
|
164
|
+
```tsx
|
|
165
|
+
import React from 'react';
|
|
166
|
+
import { DropdownMenu } from '../DropdownMenu';
|
|
167
|
+
import { Button } from '../../Button/Button';
|
|
168
|
+
import { CopyIcon, EditIcon } from '../../Icon/Icon';
|
|
169
|
+
|
|
170
|
+
export const CustomDropdownMenu = () => {
|
|
171
|
+
const items = [
|
|
172
|
+
{
|
|
173
|
+
id: 'copy',
|
|
174
|
+
label: 'Copy',
|
|
175
|
+
icon: <CopyIcon widthHeight={16} />,
|
|
176
|
+
onClick: () => alert('Copy clicked')
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
id: 'edit',
|
|
180
|
+
label: 'Edit',
|
|
181
|
+
icon: <EditIcon widthHeight={16} />,
|
|
182
|
+
onClick: () => alert('Edit clicked')
|
|
183
|
+
}
|
|
184
|
+
];
|
|
185
|
+
|
|
186
|
+
return (
|
|
187
|
+
<DropdownMenu
|
|
188
|
+
trigger={<Button variant="outline">Custom Menu</Button>}
|
|
189
|
+
items={items}
|
|
190
|
+
views={{
|
|
191
|
+
menu: {
|
|
192
|
+
backgroundColor: 'color.blue',
|
|
193
|
+
color: 'color.white',
|
|
194
|
+
borderRadius: '8px',
|
|
195
|
+
},
|
|
196
|
+
item: {
|
|
197
|
+
_hover: {
|
|
198
|
+
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}}
|
|
202
|
+
/>
|
|
203
|
+
);
|
|
204
|
+
};
|
|
205
|
+
```
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# Flow
|
|
2
|
+
|
|
3
|
+
A component for creating interactive workflow diagrams and flowcharts with support for node connections, drag-and-drop functionality, and viewport controls.
|
|
4
|
+
|
|
5
|
+
### **Import**
|
|
6
|
+
```tsx
|
|
7
|
+
import { Flow } from '@app-studio/web';
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
### **Basic Usage**
|
|
11
|
+
```tsx
|
|
12
|
+
import React, { useState } from 'react';
|
|
13
|
+
import { Flow } from '@app-studio/web';
|
|
14
|
+
import { View } from 'app-studio';
|
|
15
|
+
|
|
16
|
+
export const BasicFlow = () => {
|
|
17
|
+
// Initial nodes and edges
|
|
18
|
+
const [nodes, setNodes] = useState([
|
|
19
|
+
{
|
|
20
|
+
id: 'node-1',
|
|
21
|
+
position: { x: 50, y: 50 },
|
|
22
|
+
data: {
|
|
23
|
+
label: 'Start Node',
|
|
24
|
+
subtitle: 'Begin here'
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: 'node-2',
|
|
29
|
+
position: { x: 50, y: 200 },
|
|
30
|
+
data: {
|
|
31
|
+
label: 'Process Node',
|
|
32
|
+
subtitle: 'Do something'
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
const [edges, setEdges] = useState([
|
|
38
|
+
{ id: 'edge-1-2', source: 'node-1', target: 'node-2' },
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<View height="400px" border="1px solid" borderColor="color.gray.200" borderRadius={8}>
|
|
43
|
+
<Flow
|
|
44
|
+
nodes={nodes}
|
|
45
|
+
edges={edges}
|
|
46
|
+
onNodesChange={setNodes}
|
|
47
|
+
onEdgesChange={setEdges}
|
|
48
|
+
/>
|
|
49
|
+
</View>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### **With Node Addition**
|
|
55
|
+
```tsx
|
|
56
|
+
import React, { useState } from 'react';
|
|
57
|
+
import { Flow } from '@app-studio/web';
|
|
58
|
+
import { View } from 'app-studio';
|
|
59
|
+
import { FlowNode } from '@app-studio/web';
|
|
60
|
+
|
|
61
|
+
export const FlowWithNodeAddition = () => {
|
|
62
|
+
const [nodes, setNodes] = useState([
|
|
63
|
+
{
|
|
64
|
+
id: 'node-1',
|
|
65
|
+
position: { x: 50, y: 50 },
|
|
66
|
+
data: { label: 'Start', subtitle: 'Begin workflow' },
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: 'node-2',
|
|
70
|
+
position: { x: 50, y: 200 },
|
|
71
|
+
data: { label: 'Process', subtitle: 'Do something' },
|
|
72
|
+
},
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
const [edges, setEdges] = useState([
|
|
76
|
+
{ id: 'edge-1-2', source: 'node-1', target: 'node-2' },
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
const [selectedNodeId, setSelectedNodeId] = useState(null);
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<View height="400px" border="1px solid" borderColor="color.gray.200" borderRadius={8}>
|
|
83
|
+
<Flow
|
|
84
|
+
nodes={nodes}
|
|
85
|
+
edges={edges}
|
|
86
|
+
onNodesChange={setNodes}
|
|
87
|
+
onEdgesChange={setEdges}
|
|
88
|
+
selectedNodeId={selectedNodeId}
|
|
89
|
+
onNodeSelect={setSelectedNodeId}
|
|
90
|
+
allowAddingNodes={true}
|
|
91
|
+
onNodeAdd={(newNode: FlowNode) => {
|
|
92
|
+
setNodes((prevNodes) => [...prevNodes, newNode]);
|
|
93
|
+
}}
|
|
94
|
+
/>
|
|
95
|
+
</View>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### **With Drag and Drop**
|
|
101
|
+
```tsx
|
|
102
|
+
import React, { useState } from 'react';
|
|
103
|
+
import { Flow } from '@app-studio/web';
|
|
104
|
+
import { View } from 'app-studio';
|
|
105
|
+
import { FlowNode } from '@app-studio/web';
|
|
106
|
+
|
|
107
|
+
export const FlowWithDragAndDrop = () => {
|
|
108
|
+
const [nodes, setNodes] = useState([
|
|
109
|
+
{
|
|
110
|
+
id: 'node-1',
|
|
111
|
+
position: { x: 250, y: 100 },
|
|
112
|
+
data: { label: 'Menu Item 1', subtitle: 'Drag to reorder' },
|
|
113
|
+
draggable: true,
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: 'node-2',
|
|
117
|
+
position: { x: 250, y: 250 },
|
|
118
|
+
data: { label: 'Menu Item 2', subtitle: 'Drag to reorder' },
|
|
119
|
+
draggable: true,
|
|
120
|
+
},
|
|
121
|
+
]);
|
|
122
|
+
|
|
123
|
+
const [edges, setEdges] = useState([]);
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<View height="400px" border="1px solid" borderColor="color.gray.200" borderRadius={8}>
|
|
127
|
+
<Flow
|
|
128
|
+
nodes={nodes}
|
|
129
|
+
edges={edges}
|
|
130
|
+
onNodesChange={setNodes}
|
|
131
|
+
onEdgesChange={setEdges}
|
|
132
|
+
allowDraggingNodes={true}
|
|
133
|
+
onNodeDragStart={(nodeId) => console.log(`Started dragging: ${nodeId}`)}
|
|
134
|
+
onNodeDragEnd={(nodeId, position) => console.log(`Finished dragging: ${nodeId}`)}
|
|
135
|
+
/>
|
|
136
|
+
</View>
|
|
137
|
+
);
|
|
138
|
+
};
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### **Props**
|
|
142
|
+
|
|
143
|
+
| Prop | Type | Default | Description |
|
|
144
|
+
| ---- | ---- | ------- | ----------- |
|
|
145
|
+
| nodes | FlowNode[] | [] | Array of nodes in the flow |
|
|
146
|
+
| edges | NodeConnection[] | [] | Array of edges/connections between nodes |
|
|
147
|
+
| size | 'sm' \| 'md' \| 'lg' | 'md' | Size of the flow nodes |
|
|
148
|
+
| variant | 'default' \| 'outline' \| 'filled' | 'default' | Visual variant of the flow nodes |
|
|
149
|
+
| direction | 'horizontal' \| 'vertical' | 'vertical' | Direction of the flow layout |
|
|
150
|
+
| showControls | boolean | true | Whether to show viewport controls (zoom in/out, reset) |
|
|
151
|
+
| allowAddingNodes | boolean | true | Whether to allow adding new nodes |
|
|
152
|
+
| allowDraggingNodes | boolean | true | Whether to allow dragging nodes |
|
|
153
|
+
| selectedNodeId | string | undefined | ID of the currently selected node |
|
|
154
|
+
| onNodeSelect | (nodeId: string \| null) => void | undefined | Callback when a node is selected |
|
|
155
|
+
| onNodesChange | (nodes: FlowNode[]) => void | undefined | Callback when nodes change |
|
|
156
|
+
| onEdgesChange | (edges: NodeConnection[]) => void | undefined | Callback when edges change |
|
|
157
|
+
| onNodeAdd | (node: FlowNode) => void | undefined | Callback when a node is added |
|
|
158
|
+
| onNodeDragStart | (nodeId: string) => void | undefined | Callback when node dragging starts |
|
|
159
|
+
| onNodeDrag | (nodeId: string, position: NodePosition) => void | undefined | Callback during node dragging |
|
|
160
|
+
| onNodeDragEnd | (nodeId: string, position: NodePosition) => void | undefined | Callback when node dragging ends |
|
|
161
|
+
| viewport | FlowViewport | { zoom: 1, x: 0, y: 0 } | Current viewport state (zoom level and position) |
|
|
162
|
+
| onViewportChange | (viewport: FlowViewport) => void | undefined | Callback when viewport changes |
|
|
163
|
+
| views | object | {} | Custom styling for different parts of the component |
|
|
164
|
+
|
|
165
|
+
### **Node Structure**
|
|
166
|
+
|
|
167
|
+
The `FlowNode` interface defines the structure of nodes in the Flow component:
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
interface FlowNode {
|
|
171
|
+
id: string;
|
|
172
|
+
type?: 'default' | 'start' | 'end' | 'decision' | 'process' | string;
|
|
173
|
+
position: { x: number; y: number };
|
|
174
|
+
data?: {
|
|
175
|
+
label?: string;
|
|
176
|
+
subtitle?: string;
|
|
177
|
+
icon?: React.ReactNode;
|
|
178
|
+
number?: number;
|
|
179
|
+
[key: string]: any;
|
|
180
|
+
};
|
|
181
|
+
selected?: boolean;
|
|
182
|
+
isDragging?: boolean;
|
|
183
|
+
draggable?: boolean;
|
|
184
|
+
style?: ViewProps;
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### **Edge Structure**
|
|
189
|
+
|
|
190
|
+
The `NodeConnection` interface defines the structure of edges in the Flow component:
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
interface NodeConnection {
|
|
194
|
+
id: string;
|
|
195
|
+
source: string;
|
|
196
|
+
target: string;
|
|
197
|
+
label?: string;
|
|
198
|
+
style?: ViewProps;
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### **Compound Components**
|
|
203
|
+
|
|
204
|
+
The Flow component uses a compound component pattern with the following sub-components:
|
|
205
|
+
|
|
206
|
+
```tsx
|
|
207
|
+
// These are primarily for potential direct use or a more componentized future version
|
|
208
|
+
Flow.Node // Renders a single node
|
|
209
|
+
Flow.Edge // Renders a connection between nodes
|
|
210
|
+
Flow.Controls // Renders viewport controls
|
|
211
|
+
Flow.AddNodeButton // Renders a button to add a new node
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### **Customization**
|
|
215
|
+
|
|
216
|
+
The Flow component can be customized using the `views` prop:
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
<Flow
|
|
220
|
+
// ...other props
|
|
221
|
+
views={{
|
|
222
|
+
container: { /* styles for the main flow container */ },
|
|
223
|
+
node: {
|
|
224
|
+
container: { /* styles for the node's root View */ },
|
|
225
|
+
content: { /* styles for the content wrapper inside the node */ },
|
|
226
|
+
icon: { /* styles for the node's icon View */ },
|
|
227
|
+
},
|
|
228
|
+
edge: {
|
|
229
|
+
path: { /* styles for the SVG path */ },
|
|
230
|
+
label: { /* styles for the edge label */ },
|
|
231
|
+
},
|
|
232
|
+
controls: {
|
|
233
|
+
container: { /* styles for the controls container */ },
|
|
234
|
+
button: { /* styles for individual control buttons */ },
|
|
235
|
+
},
|
|
236
|
+
addNodeButton: { /* styles for the add node button */ },
|
|
237
|
+
}}
|
|
238
|
+
/>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### **Accessibility**
|
|
242
|
+
|
|
243
|
+
The Flow component implements the following accessibility features:
|
|
244
|
+
|
|
245
|
+
- Keyboard navigation for selecting nodes
|
|
246
|
+
- ARIA attributes for interactive elements
|
|
247
|
+
- Focus management for controls and nodes
|
|
248
|
+
- Proper contrast for node and edge colors
|
|
249
|
+
|
|
250
|
+
### **Best Practices**
|
|
251
|
+
|
|
252
|
+
- Provide clear labels and subtitles for nodes to improve understanding
|
|
253
|
+
- Use consistent node types and styling for similar functionality
|
|
254
|
+
- Implement proper error handling for node and edge operations
|
|
255
|
+
- Consider viewport size when determining initial node positions
|
|
256
|
+
- Use the `onNodeAdd` callback to validate new node positions
|
|
257
|
+
- Implement undo/redo functionality for node operations when needed
|