@app-studio/web 0.9.45 → 0.9.47

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.
@@ -1,258 +0,0 @@
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/web';
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/web';
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/web';
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
258
-
@@ -1,286 +0,0 @@
1
- # KanbanBoard
2
-
3
- A flexible Kanban board component for managing tasks and workflows. Features drag-and-drop functionality for cards between columns, customizable card and column rendering, and comprehensive styling options.
4
-
5
- ## When to use
6
- Use the Kanban Board component to:
7
- - Visualize a workflow or process.
8
- - Manage tasks or items as they move through different stages.
9
- - Allow users to reorder and re-categorize items using drag-and-drop.
10
- - Build project management tools, task trackers, or any workflow-based UI.
11
-
12
- ### **Import**
13
- ```tsx
14
- import { KanbanBoard } from '@app-studio/web';
15
- ```
16
-
17
- ### **Default**
18
- A basic Kanban board with three columns and some cards.
19
-
20
- ![Default Kanban Board](https://placehold.co/800x450)
21
-
22
- ```tsx
23
- import React, { useState } from 'react';
24
- import { KanbanBoard } from '@app-studio/web';
25
- import { KanbanBoardColumn } from '@app-studio/web';
26
-
27
- export const DefaultKanbanBoard = () => {
28
- const [columns, setColumns] = useState<KanbanBoardColumn[]>([
29
- {
30
- id: 'todo',
31
- title: 'To Do',
32
- cards: [
33
- { id: '1', title: 'Design System', description: 'Create a new design system.' },
34
- { id: '2', title: 'API Integration', description: 'Integrate with the new API.' },
35
- ],
36
- },
37
- {
38
- id: 'inprogress',
39
- title: 'In Progress',
40
- cards: [
41
- { id: '3', title: 'User Dashboard', description: 'Develop the main user dashboard.' },
42
- ],
43
- },
44
- {
45
- id: 'done',
46
- title: 'Done',
47
- cards: [
48
- { id: '4', title: 'Project Setup', description: 'Initial project setup and configuration.' },
49
- ],
50
- },
51
- ]);
52
-
53
- return <KanbanBoard columns={columns} onChange={setColumns} />;
54
- };
55
- ```
56
-
57
- ### **Custom Card Rendering**
58
- Customize how cards are displayed using the `renderCard` prop. This is useful for adding priority indicators, avatars, or other custom elements to your cards.
59
-
60
- ![Kanban Board with custom cards](https://placehold.co/800x500)
61
-
62
- ```tsx
63
- import React, { useState } from 'react';
64
- import { KanbanBoard } from '@app-studio/web';
65
- import { KanbanBoardColumn, KanbanBoardCard } from '@app-studio/web';
66
- import { View, Text, Horizontal } from '@app-studio/web';
67
-
68
- export const CustomRenderKanbanBoard = () => {
69
- const [columns, setColumns] = useState<KanbanBoardColumn[]>([
70
- {
71
- id: 'todo',
72
- title: 'To Do',
73
- cards: [
74
- { id: '1', title: 'Design System', description: 'Create a new design system.', metadata: { priority: 'high' } },
75
- { id: '2', title: 'API Integration', description: 'Integrate with the new API.', metadata: { priority: 'low' } },
76
- ],
77
- },
78
- {
79
- id: 'inprogress',
80
- title: 'In Progress',
81
- cards: [
82
- { id: '3', title: 'User Dashboard', description: 'Develop the main user dashboard.', metadata: { priority: 'medium' } },
83
- ],
84
- },
85
- {
86
- id: 'done',
87
- title: 'Done',
88
- cards: [
89
- { id: '4', title: 'Project Setup', description: 'Initial project setup and configuration.', metadata: { priority: 'low' } },
90
- ],
91
- },
92
- ]);
93
-
94
- const renderCard = (card: KanbanBoardCard, column: KanbanBoardColumn) => {
95
- const priority = card.metadata?.priority as string;
96
- const priorityColors = {
97
- low: 'color.green.500',
98
- medium: 'color.yellow.500',
99
- high: 'color.red.500',
100
- };
101
-
102
- return (
103
- <View>
104
- <Horizontal alignItems="center" marginBottom={8}>
105
- <View
106
- width={8}
107
- height={8}
108
- borderRadius="50%"
109
- backgroundColor={priorityColors[priority]}
110
- marginRight={8}
111
- />
112
- <Text fontWeight="semibold">{card.title}</Text>
113
- </Horizontal>
114
- <Text fontSize={14} color="color.gray.600">
115
- {card.description}
116
- </Text>
117
- </View>
118
- );
119
- };
120
-
121
- return <KanbanBoard columns={columns} onChange={setColumns} renderCard={renderCard} />;
122
- };
123
- ```
124
-
125
- ### **Custom Column Header and Adding Cards**
126
- Use `renderColumnHeader` to create a custom header, for example to add an "Add Card" button. The `onCardCreate` prop can then be used to handle the creation of new cards.
127
-
128
- ![Kanban Board with custom column header](https://placehold.co/800x450)
129
-
130
- ```tsx
131
- import React, { useState } from 'react';
132
- import { KanbanBoard } from '@app-studio/web';
133
- import { Button } from '@app-studio/web';
134
- import { KanbanBoardColumn, KanbanBoardCard } from '@app-studio/web';
135
- import { View, Text, Horizontal } from '@app-studio/web';
136
-
137
- export const CustomHeaderKanbanBoard = () => {
138
- const [columns, setColumns] = useState<KanbanBoardColumn[]>([
139
- { id: 'todo', title: 'To Do', cards: [] },
140
- ]);
141
-
142
- const handleCardCreate = (card, column) => {
143
- const newCard = {
144
- id: `${Date.now()}`,
145
- title: 'New Card',
146
- description: 'A new card was added.',
147
- };
148
- const newColumns = columns.map(col => {
149
- if (col.id === column.id) {
150
- return { ...col, cards: [...col.cards, newCard] };
151
- }
152
- return col;
153
- });
154
- setColumns(newColumns);
155
- };
156
-
157
- const renderColumnHeader = (column: KanbanBoardColumn) => {
158
- return (
159
- <Horizontal justifyContent="space-between" alignItems="center">
160
- <Text fontWeight="bold">{column.title}</Text>
161
- <Button size="sm" onClick={() => handleCardCreate(null, column)}>+ Add</Button>
162
- </Horizontal>
163
- );
164
- };
165
-
166
- return <KanbanBoard columns={columns} onChange={setColumns} onCardCreate={handleCardCreate} renderColumnHeader={renderColumnHeader} />;
167
- };
168
- ```
169
-
170
- ### **Inline Editing**
171
- You can implement inline editing of card titles by using the `onCardTitleChange` prop and a custom `renderCard` function that displays an input field on double click.
172
-
173
- ![Kanban Board with inline editing](https://placehold.co/800x450)
174
-
175
- ```tsx
176
- import React, { useState } from 'react';
177
- import { KanbanBoard } from '@app-studio/web';
178
- import { KanbanBoardColumn, KanbanBoardCard } from '@app-studio/web';
179
- import { Input, Text } from '@app-studio/web';
180
-
181
- export const EditableKanbanBoard = () => {
182
- const [columns, setColumns] = useState<KanbanBoardColumn[]>([
183
- {
184
- id: 'todo',
185
- title: 'To Do',
186
- cards: [{ id: '1', title: 'Editable Card' }],
187
- },
188
- ]);
189
- const [editingCardId, setEditingCardId] = useState<string | null>(null);
190
-
191
- const handleTitleChange = (card, column, newTitle) => {
192
- const newColumns = columns.map(col => {
193
- if (col.id === column.id) {
194
- const newCards = col.cards.map(c => c.id === card.id ? { ...c, title: newTitle } : c);
195
- return { ...col, cards: newCards };
196
- }
197
- return col;
198
- });
199
- setColumns(newColumns);
200
- setEditingCardId(null);
201
- };
202
-
203
- const renderCard = (card, column) => {
204
- if (editingCardId === card.id) {
205
- return (
206
- <Input
207
- autoFocus
208
- defaultValue={card.title}
209
- onBlur={(e) => handleTitleChange(card, column, e.target.value)}
210
- onKeyDown={(e) => {
211
- if (e.key === 'Enter') {
212
- handleTitleChange(card, column, e.currentTarget.value);
213
- }
214
- }}
215
- />
216
- );
217
- }
218
- return <Text onDoubleClick={() => setEditingCardId(card.id)}>{card.title}</Text>;
219
- };
220
-
221
- return (
222
- <KanbanBoard
223
- columns={columns}
224
- onChange={setColumns}
225
- onCardTitleChange={handleTitleChange}
226
- renderCard={renderCard}
227
- />
228
- );
229
- };
230
- ```
231
-
232
- ## Live Demo
233
- A live demo of the Kanban Board component with all its features is available [here](https://app-studio-web.vercel.app/components/kanban-board).
234
-
235
- ## Props
236
-
237
- | Prop | Type | Description | Default |
238
- | --- | --- | --- | --- |
239
- | `columns` | `KanbanBoardColumn[]` | Array of columns to display. | `[]` |
240
- | `onChange` | `(columns: KanbanBoardColumn[]) => void` | Callback when columns or cards are changed (e.g., after drag-and-drop). | - |
241
- | `onCardMove` | `(card: KanbanBoardCard, fromColumn: KanbanBoardColumn, toColumn: KanbanBoardColumn) => void` | Callback when a card is moved to a different column. | - |
242
- | `onCardCreate` | `(card: KanbanBoardCard, column: KanbanBoardColumn) => void` | Callback when a card is created. | - |
243
- | `onCardDelete` | `(card: KanbanBoardCard, column: KanbanBoardColumn) => void` | Callback when a card is deleted. | - |
244
- | `onCardClick` | `(card: KanbanBoardCard, column: KanbanBoardColumn) => void` | Callback when a card is clicked. | - |
245
- | `onCardDoubleClick` | `(card: KanbanBoardCard, column: KanbanBoardColumn) => void` | Callback when a card is double-clicked. | - |
246
- | `onCardTitleChange` | `(card: KanbanBoardCard, column: KanbanBoardColumn, newTitle: string) => void` | Callback when a card's title is changed. | - |
247
- | `onCardDescriptionChange` | `(card: KanbanBoardCard, column: KanbanBoardColumn, newDescription: string) => void` | Callback when a card's description is changed. | - |
248
- | `renderCard` | `(card: KanbanBoardCard, column: KanbanBoardColumn) => React.ReactNode` | Custom render method for cards. | - |
249
- | `renderColumnHeader` | `(column: KanbanBoardColumn) => React.ReactNode` | Custom render method for column headers. | - |
250
- | `renderEmptyState` | `(column: KanbanBoardColumn) => React.ReactNode` | Custom render method for empty column state. | - |
251
- | `views` | `KanbanBoardViews` | Style overrides for various parts of the component. | `{}` |
252
-
253
- ## KanbanBoardColumn Interface
254
-
255
- | Property | Type | Description |
256
- | --- | --- | --- |
257
- | `id` | `string` | Unique identifier for the column. |
258
- | `title` | `string` | Column title shown in the header. |
259
- | `cards` | `KanbanBoardCard[]` | Array of cards within the column. |
260
- | `footer` | `React.ReactNode` | Optional footer content for the column. |
261
- | `metadata` | `Record<string, unknown>` | Additional metadata for the column. |
262
-
263
- ## KanbanBoardCard Interface
264
-
265
- | Property | Type | Description |
266
- | --- | --- | --- |
267
- | `id` | `string` | Unique identifier for the card. |
268
- | `title` | `string` | Card title. |
269
- | `description` | `string` | Optional card description. |
270
- | `metadata` | `Record<string, unknown>` | Additional metadata for the card. |
271
-
272
- ## KanbanBoardViews Interface
273
-
274
- Customize the appearance of different Kanban board elements.
275
-
276
- | Property | Type | Description |
277
- | --- | --- | --- |
278
- | `board` | `ViewProps` | Main board container. |
279
- | `column` | `ViewProps` | Individual column container. |
280
- | `columnHeader` | `ViewProps` | Column header container. |
281
- | `columnTitle` | `TextProps` | Column title text. |
282
- | `columnBody` | `ViewProps` | Column body container (wraps cards). |
283
- | `columnFooter` | `ViewProps` | Column footer container. |
284
- | `card` | `ViewProps` | Individual card container. |
285
- | `cardContent` | `ViewProps` | Content wrapper inside the card. |
286
- | `emptyState` | `ViewProps` | Empty state container in a column. |