@ram_28/kf-ai-sdk 1.0.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.
- package/LICENSE +21 -0
- package/README.md +840 -0
- package/dist/api/client.d.ts +78 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/datetime.d.ts +21 -0
- package/dist/api/datetime.d.ts.map +1 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/metadata.d.ts +75 -0
- package/dist/api/metadata.d.ts.map +1 -0
- package/dist/components/hooks/index.d.ts +8 -0
- package/dist/components/hooks/index.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/index.d.ts +5 -0
- package/dist/components/hooks/useFilter/index.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/payloadBuilder.utils.d.ts +33 -0
- package/dist/components/hooks/useFilter/payloadBuilder.utils.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/types.d.ts +137 -0
- package/dist/components/hooks/useFilter/types.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/useFilter.d.ts +3 -0
- package/dist/components/hooks/useFilter/useFilter.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/validation.utils.d.ts +38 -0
- package/dist/components/hooks/useFilter/validation.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/apiClient.d.ts +71 -0
- package/dist/components/hooks/useForm/apiClient.d.ts.map +1 -0
- package/dist/components/hooks/useForm/expressionValidator.utils.d.ts +28 -0
- package/dist/components/hooks/useForm/expressionValidator.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/index.d.ts +6 -0
- package/dist/components/hooks/useForm/index.d.ts.map +1 -0
- package/dist/components/hooks/useForm/optimizedExpressionValidator.utils.d.ts +88 -0
- package/dist/components/hooks/useForm/optimizedExpressionValidator.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/ruleClassifier.utils.d.ts +28 -0
- package/dist/components/hooks/useForm/ruleClassifier.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/schemaParser.utils.d.ts +29 -0
- package/dist/components/hooks/useForm/schemaParser.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/types.d.ts +412 -0
- package/dist/components/hooks/useForm/types.d.ts.map +1 -0
- package/dist/components/hooks/useForm/useForm.d.ts +3 -0
- package/dist/components/hooks/useForm/useForm.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/apiClient.d.ts +99 -0
- package/dist/components/hooks/useKanban/apiClient.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/context.d.ts +4 -0
- package/dist/components/hooks/useKanban/context.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/dragDropManager.d.ts +27 -0
- package/dist/components/hooks/useKanban/dragDropManager.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/index.d.ts +6 -0
- package/dist/components/hooks/useKanban/index.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/types.d.ts +438 -0
- package/dist/components/hooks/useKanban/types.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/useKanban.d.ts +3 -0
- package/dist/components/hooks/useKanban/useKanban.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/useKanbanSimple.d.ts +62 -0
- package/dist/components/hooks/useKanban/useKanbanSimple.d.ts.map +1 -0
- package/dist/components/hooks/useTable/index.d.ts +3 -0
- package/dist/components/hooks/useTable/index.d.ts.map +1 -0
- package/dist/components/hooks/useTable/types.d.ts +107 -0
- package/dist/components/hooks/useTable/types.d.ts.map +1 -0
- package/dist/components/hooks/useTable/useTable.d.ts +8 -0
- package/dist/components/hooks/useTable/useTable.d.ts.map +1 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/ui/index.d.ts +2 -0
- package/dist/components/ui/index.d.ts.map +1 -0
- package/dist/components/ui/kanban/Kanban.d.ts +12 -0
- package/dist/components/ui/kanban/Kanban.d.ts.map +1 -0
- package/dist/components/ui/kanban/index.d.ts +2 -0
- package/dist/components/ui/kanban/index.d.ts.map +1 -0
- package/dist/index.cjs +45 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +6522 -0
- package/dist/types/base-fields.d.ts +182 -0
- package/dist/types/base-fields.d.ts.map +1 -0
- package/dist/types/common.d.ts +238 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/cn.d.ts +7 -0
- package/dist/utils/cn.d.ts.map +1 -0
- package/dist/utils/formatting.d.ts +52 -0
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/package.json +98 -0
- package/sdk/api/client.ts +447 -0
- package/sdk/api/datetime.ts +33 -0
- package/sdk/api/index.ts +61 -0
- package/sdk/api/metadata.ts +148 -0
- package/sdk/components/hooks/index.ts +34 -0
- package/sdk/components/hooks/useFilter/index.ts +37 -0
- package/sdk/components/hooks/useFilter/payloadBuilder.utils.ts +298 -0
- package/sdk/components/hooks/useFilter/types.ts +158 -0
- package/sdk/components/hooks/useFilter/useFilter.llm.txt +497 -0
- package/sdk/components/hooks/useFilter/useFilter.ts +494 -0
- package/sdk/components/hooks/useFilter/validation.utils.ts +401 -0
- package/sdk/components/hooks/useForm/apiClient.ts +441 -0
- package/sdk/components/hooks/useForm/expressionValidator.utils.ts +444 -0
- package/sdk/components/hooks/useForm/index.ts +64 -0
- package/sdk/components/hooks/useForm/optimizedExpressionValidator.utils.ts +482 -0
- package/sdk/components/hooks/useForm/ruleClassifier.utils.ts +424 -0
- package/sdk/components/hooks/useForm/schemaParser.utils.ts +519 -0
- package/sdk/components/hooks/useForm/types.ts +630 -0
- package/sdk/components/hooks/useForm/useForm.llm.txt +340 -0
- package/sdk/components/hooks/useForm/useForm.ts +821 -0
- package/sdk/components/hooks/useKanban/apiClient.ts +494 -0
- package/sdk/components/hooks/useKanban/context.ts +14 -0
- package/sdk/components/hooks/useKanban/dragDropManager.ts +529 -0
- package/sdk/components/hooks/useKanban/index.ts +63 -0
- package/sdk/components/hooks/useKanban/types.ts +606 -0
- package/sdk/components/hooks/useKanban/useKanban.llm.txt +482 -0
- package/sdk/components/hooks/useKanban/useKanban.ts +725 -0
- package/sdk/components/hooks/useKanban/useKanbanSimple.ts +389 -0
- package/sdk/components/hooks/useTable/index.ts +5 -0
- package/sdk/components/hooks/useTable/types.ts +154 -0
- package/sdk/components/hooks/useTable/useTable.llm.txt +344 -0
- package/sdk/components/hooks/useTable/useTable.ts +413 -0
- package/sdk/components/index.ts +15 -0
- package/sdk/components/ui/index.ts +2 -0
- package/sdk/components/ui/kanban/Kanban.tsx +134 -0
- package/sdk/components/ui/kanban/index.ts +11 -0
- package/sdk/index.ts +13 -0
- package/sdk/types/base-fields.ts +221 -0
- package/sdk/types/common.ts +306 -0
- package/sdk/types/index.ts +5 -0
- package/sdk/utils/cn.ts +10 -0
- package/sdk/utils/formatting.ts +212 -0
- package/sdk/utils/index.ts +5 -0
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
# useKanban Hook - LLM Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `useKanban` hook is a React hook for building Kanban board interfaces with:
|
|
6
|
+
- Column-based card organization
|
|
7
|
+
- Drag and drop support (mouse, touch, keyboard)
|
|
8
|
+
- CRUD operations for cards
|
|
9
|
+
- Search functionality
|
|
10
|
+
- Filter support
|
|
11
|
+
- Real-time state management
|
|
12
|
+
- API integration with TanStack Query
|
|
13
|
+
|
|
14
|
+
## Import
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { useKanban } from "kf-ai-sdk";
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Basic Usage
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
const COLUMNS = [
|
|
24
|
+
{ id: "todo", title: "To Do", position: 0, color: "gray" },
|
|
25
|
+
{ id: "inProgress", title: "In Progress", position: 1, color: "blue" },
|
|
26
|
+
{ id: "done", title: "Done", position: 2, color: "green" },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const kanban = useKanban<TaskType>({
|
|
30
|
+
source: "BDO_Tasks",
|
|
31
|
+
columns: COLUMNS,
|
|
32
|
+
enableDragDrop: true,
|
|
33
|
+
onCardMove: (card, fromColumnId, toColumnId) => {
|
|
34
|
+
console.log(`Moved ${card.title} from ${fromColumnId} to ${toColumnId}`);
|
|
35
|
+
},
|
|
36
|
+
onError: (error) => {
|
|
37
|
+
console.error(error);
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Configuration Options
|
|
43
|
+
|
|
44
|
+
### UseKanbanOptions<T>
|
|
45
|
+
|
|
46
|
+
| Property | Type | Required | Default | Description |
|
|
47
|
+
|----------|------|----------|---------|-------------|
|
|
48
|
+
| `source` | `string` | Yes | - | Data source identifier (BDO name) |
|
|
49
|
+
| `columns` | `ColumnDefinition[]` | Yes | - | Static column configurations |
|
|
50
|
+
| `enableDragDrop` | `boolean` | No | `false` | Enable drag and drop |
|
|
51
|
+
| `enableFiltering` | `boolean` | No | `false` | Enable filtering |
|
|
52
|
+
| `enableSearch` | `boolean` | No | `false` | Enable search |
|
|
53
|
+
| `initialSearch` | `string` | No | `""` | Initial search query |
|
|
54
|
+
| `onCardMove` | `(card, fromColumnId, toColumnId) => void` | No | - | Card move callback |
|
|
55
|
+
| `onCardCreate` | `(card) => void` | No | - | Card create callback |
|
|
56
|
+
| `onCardUpdate` | `(card) => void` | No | - | Card update callback |
|
|
57
|
+
| `onCardDelete` | `(cardId) => void` | No | - | Card delete callback |
|
|
58
|
+
| `onSuccess` | `(data) => void` | No | - | Success callback |
|
|
59
|
+
| `onError` | `(error) => void` | No | - | Error callback |
|
|
60
|
+
| `onFilterError` | `(errors) => void` | No | - | Filter error callback |
|
|
61
|
+
|
|
62
|
+
### ColumnDefinition
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
interface ColumnDefinition {
|
|
66
|
+
id: string; // Unique column identifier
|
|
67
|
+
title: string; // Display title
|
|
68
|
+
position: number; // Display order (0-indexed)
|
|
69
|
+
color?: string; // Optional color for header
|
|
70
|
+
limit?: number; // Optional WIP limit
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Return Value
|
|
75
|
+
|
|
76
|
+
### UseKanbanReturn<T>
|
|
77
|
+
|
|
78
|
+
#### Data
|
|
79
|
+
| Property | Type | Description |
|
|
80
|
+
|----------|------|-------------|
|
|
81
|
+
| `columns` | `KanbanColumn<T>[]` | All columns with their cards |
|
|
82
|
+
| `totalCards` | `number` | Total card count |
|
|
83
|
+
|
|
84
|
+
#### Loading States
|
|
85
|
+
| Property | Type | Description |
|
|
86
|
+
|----------|------|-------------|
|
|
87
|
+
| `isLoading` | `boolean` | Initial data loading |
|
|
88
|
+
| `isFetching` | `boolean` | Background refetching |
|
|
89
|
+
| `isUpdating` | `boolean` | Any mutation in progress |
|
|
90
|
+
|
|
91
|
+
#### Error Handling
|
|
92
|
+
| Property | Type | Description |
|
|
93
|
+
|----------|------|-------------|
|
|
94
|
+
| `error` | `Error \| null` | Current error state |
|
|
95
|
+
|
|
96
|
+
#### Search
|
|
97
|
+
| Property | Type | Description |
|
|
98
|
+
|----------|------|-------------|
|
|
99
|
+
| `searchQuery` | `string` | Current search query |
|
|
100
|
+
| `setSearchQuery` | `(query: string) => void` | Set search query |
|
|
101
|
+
| `clearSearch` | `() => void` | Clear search |
|
|
102
|
+
|
|
103
|
+
#### Card Operations
|
|
104
|
+
| Property | Type | Description |
|
|
105
|
+
|----------|------|-------------|
|
|
106
|
+
| `createCard` | `(card) => Promise<void>` | Create a new card |
|
|
107
|
+
| `updateCard` | `(id, updates) => Promise<void>` | Update a card |
|
|
108
|
+
| `deleteCard` | `(id) => Promise<void>` | Delete a card |
|
|
109
|
+
| `moveCard` | `(cardId, toColumnId, position?) => Promise<void>` | Move card to column |
|
|
110
|
+
|
|
111
|
+
#### Drag Drop State
|
|
112
|
+
| Property | Type | Description |
|
|
113
|
+
|----------|------|-------------|
|
|
114
|
+
| `isDragging` | `boolean` | Drag operation in progress |
|
|
115
|
+
| `draggedCard` | `KanbanCard<T> \| null` | Currently dragged card |
|
|
116
|
+
| `handleDragStart` | `(card) => void` | Handle drag start |
|
|
117
|
+
| `handleDragEnd` | `() => void` | Handle drag end |
|
|
118
|
+
| `handleKeyboardMove` | `(cardId, direction) => Promise<void>` | Keyboard navigation |
|
|
119
|
+
|
|
120
|
+
#### Utilities
|
|
121
|
+
| Property | Type | Description |
|
|
122
|
+
|----------|------|-------------|
|
|
123
|
+
| `refresh` | `() => Promise<void>` | Refresh data |
|
|
124
|
+
| `refetch` | `() => Promise<void>` | Refetch data |
|
|
125
|
+
| `loadMore` | `(columnId: string) => void` | Load more cards |
|
|
126
|
+
|
|
127
|
+
## Data Types
|
|
128
|
+
|
|
129
|
+
### KanbanCard<T>
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
interface KanbanCard<T = Record<string, any>> {
|
|
133
|
+
_id: string; // Unique identifier
|
|
134
|
+
title: string; // Card title
|
|
135
|
+
columnId: string; // Column this card belongs to
|
|
136
|
+
position: number; // Position within column (0-indexed)
|
|
137
|
+
_created_at?: Date; // Creation timestamp
|
|
138
|
+
_modified_at?: Date; // Modification timestamp
|
|
139
|
+
} & T; // Custom fields from T
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### KanbanColumn<T>
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
interface KanbanColumn<T = Record<string, any>> {
|
|
146
|
+
_id: string; // Unique identifier (from ColumnDefinition.id)
|
|
147
|
+
title: string; // Column title
|
|
148
|
+
position: number; // Position among columns
|
|
149
|
+
color?: string; // Optional color
|
|
150
|
+
limit?: number; // Optional WIP limit
|
|
151
|
+
cards: KanbanCard<T>[]; // Cards in this column
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## E-Commerce App Usage Example
|
|
156
|
+
|
|
157
|
+
### Inventory Restocking Page (InventoryRestockingPage.tsx)
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
const RESTOCKING_COLUMNS = [
|
|
161
|
+
{ id: "LowStockAlert", title: "Low Stock Alert", position: 0, color: "red" },
|
|
162
|
+
{ id: "OrderPlaced", title: "Order Placed", position: 1, color: "yellow" },
|
|
163
|
+
{ id: "InTransit", title: "In Transit", position: 2, color: "blue" },
|
|
164
|
+
{ id: "Received", title: "Received & Restocked", position: 3, color: "green" },
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
const kanban = useKanban<InventoryManagerRestocking>({
|
|
168
|
+
source: "BDO_ProductRestocking",
|
|
169
|
+
columns: RESTOCKING_COLUMNS,
|
|
170
|
+
enableDragDrop: true,
|
|
171
|
+
enableFiltering: true,
|
|
172
|
+
enableSearch: true,
|
|
173
|
+
onCardMove: (card, fromColumnId, toColumnId) => {
|
|
174
|
+
// When moving to "Received" column, show stock update modal
|
|
175
|
+
if (toColumnId === "Received") {
|
|
176
|
+
setSelectedCard(card);
|
|
177
|
+
setShowStockUpdateModal(true);
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
onError: (error) => {
|
|
181
|
+
toast.error(`Failed to move card: ${error.message}`);
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Search
|
|
186
|
+
<Input
|
|
187
|
+
placeholder="Search by product title or SKU..."
|
|
188
|
+
value={kanban.searchQuery || ""}
|
|
189
|
+
onChange={(e) => kanban.setSearchQuery(e.target.value)}
|
|
190
|
+
/>
|
|
191
|
+
|
|
192
|
+
// Error handling
|
|
193
|
+
{kanban.error ? (
|
|
194
|
+
<div className="text-center py-12 bg-red-50">
|
|
195
|
+
<p className="text-red-600">{kanban.error.message}</p>
|
|
196
|
+
<Button onClick={() => kanban.refetch()}>Try Again</Button>
|
|
197
|
+
</div>
|
|
198
|
+
) : kanban.isLoading ? (
|
|
199
|
+
<div className="animate-spin">...</div>
|
|
200
|
+
) : (
|
|
201
|
+
// Kanban board
|
|
202
|
+
<KanbanBoard instance={kanban}>
|
|
203
|
+
{kanban.columns.map((column) => (
|
|
204
|
+
<KanbanColumn key={column._id} columnId={column._id}>
|
|
205
|
+
<KanbanColumnHeader>
|
|
206
|
+
<KanbanColumnTitle>{column.title}</KanbanColumnTitle>
|
|
207
|
+
<Badge>{column.cards.length}</Badge>
|
|
208
|
+
</KanbanColumnHeader>
|
|
209
|
+
|
|
210
|
+
<KanbanColumnContent>
|
|
211
|
+
{column.cards.map((card) => (
|
|
212
|
+
<KanbanCard key={card._id} card={card}>
|
|
213
|
+
<KanbanCardTitle>{card.productTitle}</KanbanCardTitle>
|
|
214
|
+
<KanbanCardDescription>
|
|
215
|
+
<div>SKU: {card.productSKU}</div>
|
|
216
|
+
<div>Stock: {card.currentStock}</div>
|
|
217
|
+
<div>Ordered: {card.quantityOrdered}</div>
|
|
218
|
+
</KanbanCardDescription>
|
|
219
|
+
<Badge variant={getPriorityVariant(card.priority)}>
|
|
220
|
+
{card.priority}
|
|
221
|
+
</Badge>
|
|
222
|
+
</KanbanCard>
|
|
223
|
+
))}
|
|
224
|
+
</KanbanColumnContent>
|
|
225
|
+
|
|
226
|
+
{column.cards.length >= 10 && (
|
|
227
|
+
<KanbanColumnFooter>
|
|
228
|
+
<Button onClick={() => kanban.loadMore(column._id)}>
|
|
229
|
+
Load More
|
|
230
|
+
</Button>
|
|
231
|
+
</KanbanColumnFooter>
|
|
232
|
+
)}
|
|
233
|
+
</KanbanColumn>
|
|
234
|
+
))}
|
|
235
|
+
</KanbanBoard>
|
|
236
|
+
)}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Card Operations
|
|
240
|
+
|
|
241
|
+
### Create Card
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
await kanban.createCard({
|
|
245
|
+
title: "New Task",
|
|
246
|
+
columnId: "todo",
|
|
247
|
+
// Custom fields
|
|
248
|
+
description: "Task description",
|
|
249
|
+
priority: "High",
|
|
250
|
+
});
|
|
251
|
+
// Position is auto-calculated
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Update Card
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
await kanban.updateCard(cardId, {
|
|
258
|
+
title: "Updated Title",
|
|
259
|
+
description: "New description",
|
|
260
|
+
});
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Delete Card
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
await kanban.deleteCard(cardId);
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Move Card
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
// Move to another column
|
|
273
|
+
await kanban.moveCard(cardId, "inProgress");
|
|
274
|
+
|
|
275
|
+
// Move to specific position
|
|
276
|
+
await kanban.moveCard(cardId, "inProgress", 2);
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Drag and Drop
|
|
280
|
+
|
|
281
|
+
### Mouse Drag
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
// Handled automatically when enableDragDrop: true
|
|
285
|
+
// Use the provided getCardProps and getColumnProps for event binding
|
|
286
|
+
|
|
287
|
+
const cardProps = kanban.getCardProps(card);
|
|
288
|
+
const columnProps = kanban.getColumnProps(columnId);
|
|
289
|
+
|
|
290
|
+
<div {...columnProps}>
|
|
291
|
+
{cards.map(card => (
|
|
292
|
+
<div {...cardProps}>{card.title}</div>
|
|
293
|
+
))}
|
|
294
|
+
</div>
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Keyboard Navigation
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
// Move card left/right with keyboard
|
|
301
|
+
await kanban.handleKeyboardMove(cardId, "left"); // Previous column
|
|
302
|
+
await kanban.handleKeyboardMove(cardId, "right"); // Next column
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Touch Support
|
|
306
|
+
|
|
307
|
+
The hook includes touch handlers for mobile devices:
|
|
308
|
+
- `handleTouchStart`
|
|
309
|
+
- `handleTouchMove`
|
|
310
|
+
- `handleTouchEnd`
|
|
311
|
+
|
|
312
|
+
## Drag Drop Manager
|
|
313
|
+
|
|
314
|
+
For advanced drag and drop control, use the exported `useDragDropManager`:
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
import { useDragDropManager } from "kf-ai-sdk";
|
|
318
|
+
|
|
319
|
+
const dragDrop = useDragDropManager<TaskType>({
|
|
320
|
+
onCardMove: handleMove,
|
|
321
|
+
onError: handleError,
|
|
322
|
+
columns: kanban.columns,
|
|
323
|
+
announceMove: (card, from, to) => {
|
|
324
|
+
// Accessibility announcement
|
|
325
|
+
console.log(`Moved ${card.title} from ${from} to ${to}`);
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### DragDropManager Features
|
|
331
|
+
|
|
332
|
+
| Property | Type | Description |
|
|
333
|
+
|----------|------|-------------|
|
|
334
|
+
| `isDragging` | `boolean` | Drag in progress |
|
|
335
|
+
| `draggedCard` | `KanbanCard<T>` | Currently dragged card |
|
|
336
|
+
| `dragOverColumn` | `string \| null` | Column being hovered |
|
|
337
|
+
| `dragOverPosition` | `number \| null` | Position being hovered |
|
|
338
|
+
| `dragSourceColumn` | `string \| null` | Source column |
|
|
339
|
+
| `handleDragStart` | `(event, card) => void` | Start drag |
|
|
340
|
+
| `handleDragOver` | `(event, columnId) => void` | Handle drag over |
|
|
341
|
+
| `handleDrop` | `(event, columnId) => void` | Handle drop |
|
|
342
|
+
| `handleDragEnd` | `() => void` | End drag |
|
|
343
|
+
| `handleKeyDown` | `(event, card) => void` | Keyboard handler |
|
|
344
|
+
| `handleTouchStart` | `(event, card) => void` | Touch start |
|
|
345
|
+
| `handleTouchMove` | `(event) => void` | Touch move |
|
|
346
|
+
| `handleTouchEnd` | `(event) => void` | Touch end |
|
|
347
|
+
| `reset` | `() => void` | Reset state |
|
|
348
|
+
|
|
349
|
+
## Context Provider
|
|
350
|
+
|
|
351
|
+
For component tree access, use the KanbanContext:
|
|
352
|
+
|
|
353
|
+
```typescript
|
|
354
|
+
import { KanbanContext, useKanbanContext } from "kf-ai-sdk";
|
|
355
|
+
|
|
356
|
+
// Provider
|
|
357
|
+
<KanbanContext.Provider value={kanban}>
|
|
358
|
+
<KanbanBoard />
|
|
359
|
+
</KanbanContext.Provider>
|
|
360
|
+
|
|
361
|
+
// Consumer
|
|
362
|
+
function KanbanCard() {
|
|
363
|
+
const kanban = useKanbanContext<TaskType>();
|
|
364
|
+
// Access kanban state and methods
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## API Client Functions
|
|
369
|
+
|
|
370
|
+
The hook exports utility functions for direct API access:
|
|
371
|
+
|
|
372
|
+
```typescript
|
|
373
|
+
import {
|
|
374
|
+
mergeCardsIntoColumns,
|
|
375
|
+
calculateCardPosition,
|
|
376
|
+
calculateColumnPosition,
|
|
377
|
+
normalizePositions,
|
|
378
|
+
handleKanbanApiError,
|
|
379
|
+
validateApiResponse,
|
|
380
|
+
} from "kf-ai-sdk";
|
|
381
|
+
|
|
382
|
+
// Merge fetched cards into column structure
|
|
383
|
+
const columnsWithCards = mergeCardsIntoColumns(columns, cards);
|
|
384
|
+
|
|
385
|
+
// Calculate optimal position for new card
|
|
386
|
+
const position = calculateCardPosition(column, insertIndex);
|
|
387
|
+
|
|
388
|
+
// Normalize positions after reorder
|
|
389
|
+
const normalized = normalizePositions(items);
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## Filter Integration
|
|
393
|
+
|
|
394
|
+
When `enableFiltering: true`, the hook includes filter functionality similar to useTable:
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
kanban.filter.addCondition({
|
|
398
|
+
lhsField: "priority",
|
|
399
|
+
operator: "EQ",
|
|
400
|
+
rhsValue: "High",
|
|
401
|
+
rhsType: "Constant",
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
kanban.filter.clearConditions();
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## Key Behaviors
|
|
408
|
+
|
|
409
|
+
1. **Static columns**: Columns are defined at configuration time, not fetched from API
|
|
410
|
+
2. **Auto-sorting**: Cards sorted by position within each column
|
|
411
|
+
3. **Position auto-calculation**: New cards get position based on column length
|
|
412
|
+
4. **WIP limit checking**: Drop is prevented if column limit is reached
|
|
413
|
+
5. **Optimistic updates**: UI updates immediately, then syncs with server
|
|
414
|
+
6. **Auto-scroll**: Scrolls horizontally during drag near edges
|
|
415
|
+
7. **Accessibility**: ARIA attributes and screen reader announcements
|
|
416
|
+
8. **30s stale time**: Data considered fresh for 30 seconds
|
|
417
|
+
|
|
418
|
+
## API Format
|
|
419
|
+
|
|
420
|
+
### Sort Format
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
Sort: [
|
|
424
|
+
{ columnId: "ASC" },
|
|
425
|
+
{ position: "ASC" }
|
|
426
|
+
]
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### Move Card Request
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
{
|
|
433
|
+
columnId: "newColumnId",
|
|
434
|
+
position: 2 // Optional
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
## Architecture Notes
|
|
439
|
+
|
|
440
|
+
- Built on TanStack Query for data fetching
|
|
441
|
+
- Separate queries for cards and count
|
|
442
|
+
- Uses `useMemo` for column processing
|
|
443
|
+
- Mutations with automatic refetch on success
|
|
444
|
+
- Supports generic card types with TypeScript
|
|
445
|
+
- Includes comprehensive drag and drop manager
|
|
446
|
+
- Context provider for component tree access
|
|
447
|
+
- Full keyboard accessibility support
|
|
448
|
+
|
|
449
|
+
## Error Handling
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
const kanban = useKanban({
|
|
453
|
+
source: "BDO_Tasks",
|
|
454
|
+
columns: COLUMNS,
|
|
455
|
+
onError: (error) => {
|
|
456
|
+
// Handle general errors
|
|
457
|
+
toast.error(error.message);
|
|
458
|
+
},
|
|
459
|
+
onFilterError: (errors) => {
|
|
460
|
+
// Handle filter validation errors
|
|
461
|
+
errors.forEach(err => console.log(err.message));
|
|
462
|
+
},
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
// Check error state
|
|
466
|
+
if (kanban.error) {
|
|
467
|
+
return <ErrorDisplay error={kanban.error} onRetry={kanban.refresh} />;
|
|
468
|
+
}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
## WIP Limits
|
|
472
|
+
|
|
473
|
+
Columns can have work-in-progress limits:
|
|
474
|
+
|
|
475
|
+
```typescript
|
|
476
|
+
const COLUMNS = [
|
|
477
|
+
{ id: "inProgress", title: "In Progress", position: 1, limit: 5 },
|
|
478
|
+
];
|
|
479
|
+
|
|
480
|
+
// Drop will be prevented if limit is reached
|
|
481
|
+
// Error callback will be triggered with limit message
|
|
482
|
+
```
|