@ram_28/kf-ai-sdk 1.0.19 → 1.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +45 -12
  2. package/dist/api/client.d.ts.map +1 -1
  3. package/dist/api/datetime.d.ts +59 -10
  4. package/dist/api/datetime.d.ts.map +1 -1
  5. package/dist/api/index.d.ts +3 -2
  6. package/dist/api/index.d.ts.map +1 -1
  7. package/dist/api.cjs +1 -1
  8. package/dist/api.d.ts +1 -1
  9. package/dist/api.d.ts.map +1 -1
  10. package/dist/api.mjs +43 -21
  11. package/dist/api.types.d.ts +2 -1
  12. package/dist/api.types.d.ts.map +1 -1
  13. package/dist/auth/AuthProvider.d.ts.map +1 -1
  14. package/dist/auth.cjs +1 -1
  15. package/dist/auth.mjs +34 -34
  16. package/dist/base-types.d.ts +1 -1
  17. package/dist/base-types.d.ts.map +1 -1
  18. package/dist/client-BIkaIr2y.js +217 -0
  19. package/dist/client-DxjRcEtN.cjs +1 -0
  20. package/dist/components/hooks/useFilter/types.d.ts +14 -11
  21. package/dist/components/hooks/useFilter/types.d.ts.map +1 -1
  22. package/dist/components/hooks/useFilter/useFilter.d.ts +1 -1
  23. package/dist/components/hooks/useFilter/useFilter.d.ts.map +1 -1
  24. package/dist/components/hooks/useForm/apiClient.d.ts +45 -4
  25. package/dist/components/hooks/useForm/apiClient.d.ts.map +1 -1
  26. package/dist/components/hooks/useForm/useForm.d.ts.map +1 -1
  27. package/dist/components/hooks/useKanban/types.d.ts +5 -22
  28. package/dist/components/hooks/useKanban/types.d.ts.map +1 -1
  29. package/dist/components/hooks/useKanban/useKanban.d.ts.map +1 -1
  30. package/dist/components/hooks/useTable/types.d.ts +19 -31
  31. package/dist/components/hooks/useTable/types.d.ts.map +1 -1
  32. package/dist/components/hooks/useTable/useTable.d.ts.map +1 -1
  33. package/dist/error-handling-CAoD0Kwb.cjs +1 -0
  34. package/dist/error-handling-CrhTtD88.js +14 -0
  35. package/dist/filter.cjs +1 -1
  36. package/dist/filter.mjs +1 -1
  37. package/dist/form.cjs +1 -1
  38. package/dist/form.mjs +736 -750
  39. package/dist/index.d.ts +18 -0
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/kanban.cjs +2 -2
  42. package/dist/kanban.mjs +333 -323
  43. package/dist/{metadata-0lZAfuTP.cjs → metadata-Bz8zJqC1.cjs} +1 -1
  44. package/dist/{metadata-B88D_pVS.js → metadata-VbQzyD2C.js} +1 -1
  45. package/dist/table.cjs +1 -1
  46. package/dist/table.mjs +113 -96
  47. package/dist/table.types.d.ts +1 -1
  48. package/dist/table.types.d.ts.map +1 -1
  49. package/dist/types/base-fields.d.ts +71 -17
  50. package/dist/types/base-fields.d.ts.map +1 -1
  51. package/dist/types/common.d.ts +26 -18
  52. package/dist/types/common.d.ts.map +1 -1
  53. package/dist/useFilter-DzpP_ag0.cjs +1 -0
  54. package/dist/useFilter-H5bgAZQF.js +120 -0
  55. package/dist/utils/api/buildListOptions.d.ts +43 -0
  56. package/dist/utils/api/buildListOptions.d.ts.map +1 -0
  57. package/dist/utils/api/index.d.ts +2 -0
  58. package/dist/utils/api/index.d.ts.map +1 -0
  59. package/dist/utils/error-handling.d.ts +41 -0
  60. package/dist/utils/error-handling.d.ts.map +1 -0
  61. package/dist/utils/index.d.ts +2 -0
  62. package/dist/utils/index.d.ts.map +1 -1
  63. package/docs/QUICK_REFERENCE.md +142 -420
  64. package/docs/useAuth.md +52 -340
  65. package/docs/useFilter.md +858 -162
  66. package/docs/useForm.md +712 -501
  67. package/docs/useKanban.md +534 -279
  68. package/docs/useTable.md +725 -214
  69. package/package.json +1 -1
  70. package/sdk/api/client.ts +3 -41
  71. package/sdk/api/datetime.ts +98 -14
  72. package/sdk/api/index.ts +12 -6
  73. package/sdk/api.ts +6 -3
  74. package/sdk/api.types.ts +3 -4
  75. package/sdk/auth/AuthProvider.tsx +22 -24
  76. package/sdk/base-types.ts +2 -0
  77. package/sdk/components/hooks/useFilter/types.ts +14 -11
  78. package/sdk/components/hooks/useFilter/useFilter.ts +20 -18
  79. package/sdk/components/hooks/useForm/apiClient.ts +120 -5
  80. package/sdk/components/hooks/useForm/useForm.ts +97 -61
  81. package/sdk/components/hooks/useKanban/types.ts +7 -23
  82. package/sdk/components/hooks/useKanban/useKanban.ts +54 -18
  83. package/sdk/components/hooks/useTable/types.ts +26 -32
  84. package/sdk/components/hooks/useTable/useTable.llm.txt +8 -22
  85. package/sdk/components/hooks/useTable/useTable.ts +70 -25
  86. package/sdk/index.ts +157 -10
  87. package/sdk/table.types.ts +3 -0
  88. package/sdk/types/base-fields.ts +71 -17
  89. package/sdk/types/common.ts +33 -19
  90. package/sdk/utils/api/buildListOptions.ts +120 -0
  91. package/sdk/utils/api/index.ts +2 -0
  92. package/sdk/utils/error-handling.ts +150 -0
  93. package/sdk/utils/index.ts +6 -0
  94. package/dist/client-DgtkT50N.cjs +0 -1
  95. package/dist/client-V-WzUb8H.js +0 -237
  96. package/dist/useFilter-Dofowpr_.cjs +0 -1
  97. package/dist/useFilter-Dv-mr9QW.js +0 -117
package/docs/useKanban.md CHANGED
@@ -1,17 +1,11 @@
1
1
  # useKanban
2
2
 
3
- ## Brief Description
3
+ Kanban board state management with drag-and-drop, card CRUD operations, and filtering.
4
4
 
5
- - Provides complete kanban board state management including column configuration, card CRUD operations, and drag-and-drop functionality
6
- - Integrates with `useFilter` for filtering cards across the board with support for nested condition groups
7
- - Includes built-in drag-and-drop handlers and prop getters (`getCardProps`, `getColumnProps`) for easy integration with any UI library
8
- - Handles optimistic updates for card operations with automatic rollback on failure
9
-
10
- ## Type Reference
5
+ ## Imports
11
6
 
12
7
  ```typescript
13
8
  import { useKanban } from "@ram_28/kf-ai-sdk/kanban";
14
- import { isCondition, isConditionGroup } from "@ram_28/kf-ai-sdk/filter";
15
9
  import type {
16
10
  UseKanbanOptionsType,
17
11
  UseKanbanReturnType,
@@ -19,15 +13,12 @@ import type {
19
13
  KanbanColumnType,
20
14
  ColumnConfigType,
21
15
  } from "@ram_28/kf-ai-sdk/kanban/types";
22
- import type {
23
- ConditionType,
24
- ConditionGroupType,
25
- ConditionGroupOperatorType,
26
- FilterType,
27
- UseFilterReturnType,
28
- } from "@ram_28/kf-ai-sdk/filter/types";
29
-
30
- // Static column configuration
16
+ ```
17
+
18
+ ## Type Definitions
19
+
20
+ ```typescript
21
+ // Column configuration
31
22
  interface ColumnConfigType {
32
23
  id: string;
33
24
  title: string;
@@ -36,18 +27,16 @@ interface ColumnConfigType {
36
27
  limit?: number;
37
28
  }
38
29
 
39
- // Kanban card with custom fields
40
- type KanbanCardType<T = Record<string, any>> = {
30
+ // Card type with custom fields
31
+ type KanbanCardType<T> = {
41
32
  _id: string;
42
33
  title: string;
43
34
  columnId: string;
44
35
  position: number;
45
- _created_at?: Date;
46
- _modified_at?: Date;
47
36
  } & T;
48
37
 
49
- // Kanban column with cards
50
- interface KanbanColumnType<T = Record<string, any>> {
38
+ // Column with cards
39
+ interface KanbanColumnType<T> {
51
40
  _id: string;
52
41
  title: string;
53
42
  position: number;
@@ -64,177 +53,350 @@ interface UseKanbanOptionsType<T> {
64
53
  enableFiltering?: boolean;
65
54
  enableSearch?: boolean;
66
55
  initialState?: {
67
- filters?: Array<ConditionType | ConditionGroupType>;
68
- filterOperator?: ConditionGroupOperatorType;
56
+ filter?: UseFilterOptionsType; // { conditions?, operator? }
69
57
  search?: string;
58
+ columnOrder?: string[];
59
+ sorting?: { field: keyof T; direction: "asc" | "desc" };
70
60
  };
71
- onCardMove?: (card: KanbanCardType<T>, fromColumnId: string, toColumnId: string) => void;
72
- onCardCreate?: (card: KanbanCardType<T>) => void;
73
- onCardUpdate?: (card: KanbanCardType<T>) => void;
74
- onCardDelete?: (cardId: string) => void;
75
- onError?: (error: Error) => void;
61
+ onCardMove?: (card, fromColumnId, toColumnId) => void;
62
+ onCardCreate?: (card) => void;
63
+ onCardUpdate?: (card) => void;
64
+ onCardDelete?: (cardId) => void;
65
+ onError?: (error) => void;
76
66
  }
77
67
 
78
68
  // Hook return type
79
69
  interface UseKanbanReturnType<T> {
80
- // Data
81
70
  columns: KanbanColumnType<T>[];
82
71
  totalCards: number;
83
-
84
- // Loading states
85
72
  isLoading: boolean;
86
73
  isFetching: boolean;
87
74
  isUpdating: boolean;
88
75
  error: Error | null;
89
76
 
90
77
  // Card operations
91
- createCard: (card: Partial<KanbanCardType<T>> & { columnId: string }) => Promise<string>;
92
- updateCard: (id: string, updates: Partial<KanbanCardType<T>>) => Promise<void>;
93
- deleteCard: (id: string) => Promise<void>;
94
- moveCard: (cardId: string, toColumnId: string, position?: number) => Promise<void>;
95
- reorderCards: (cardIds: string[], columnId: string) => Promise<void>;
78
+ createCard: (card) => Promise<string>;
79
+ updateCard: (id, updates) => Promise<void>;
80
+ deleteCard: (id) => Promise<void>;
81
+ moveCard: (cardId, toColumnId, position?) => Promise<void>;
96
82
 
97
- // Search
83
+ // Search & Filter
98
84
  searchQuery: string;
99
- setSearchQuery: (value: string) => void;
100
- clearSearch: () => void;
101
-
102
- // Filter (uses useFilter internally)
85
+ setSearchQuery: (value) => void;
103
86
  filter: UseFilterReturnType;
104
87
 
105
- // Drag drop state
88
+ // Drag & Drop
106
89
  isDragging: boolean;
107
90
  draggedCard: KanbanCardType<T> | null;
108
- dragOverColumn: string | null;
109
-
110
- // Prop getters
111
- getCardProps: (card: KanbanCardType<T>) => {
112
- draggable: boolean;
113
- role: string;
114
- "aria-selected": boolean;
115
- "aria-grabbed": boolean;
116
- onDragStart: (e: any) => void;
117
- onDragEnd: () => void;
118
- onKeyDown: (e: any) => void;
119
- };
120
- getColumnProps: (columnId: string) => {
121
- "data-column-id": string;
122
- role: string;
123
- onDragOver: (e: any) => void;
124
- onDrop: (e: any) => void;
125
- };
91
+ getCardProps: (card) => object;
92
+ getColumnProps: (columnId) => object;
126
93
 
127
- // Utilities
128
94
  refetch: () => Promise<void>;
129
- loadMore: (columnId: string) => void;
130
95
  }
131
96
  ```
132
97
 
133
- ## Usage Example
98
+ ## Basic Example
99
+
100
+ A minimal kanban board displaying columns and cards.
134
101
 
135
102
  ```tsx
136
103
  import { useKanban } from "@ram_28/kf-ai-sdk/kanban";
137
- import { isCondition, isConditionGroup } from "@ram_28/kf-ai-sdk/filter";
138
- import type {
139
- UseKanbanOptionsType,
140
- UseKanbanReturnType,
141
- KanbanCardType,
142
- KanbanColumnType,
143
- ColumnConfigType,
144
- } from "@ram_28/kf-ai-sdk/kanban/types";
145
- import type {
146
- ConditionType,
147
- ConditionGroupType,
148
- ConditionGroupOperatorType,
149
- FilterType,
150
- UseFilterReturnType,
151
- } from "@ram_28/kf-ai-sdk/filter/types";
152
- import { ProductRestocking, ProductRestockingType } from "../sources";
153
- import { Roles } from "../sources/roles";
154
-
155
- // Get the typed restocking record for the InventoryManager role
156
- type RestockingRecord = ProductRestockingType<typeof Roles.InventoryManager>;
157
-
158
- // Define custom card fields that extend the base KanbanCardType
159
- interface RestockingCardData {
160
- productTitle: string;
161
- productSKU: string;
162
- currentStock: number;
163
- quantityOrdered: number;
164
- warehouse: "Warehouse_A" | "Warehouse_B" | "Warehouse_C";
165
- priority: "Low" | "Medium" | "High" | "Critical";
166
- }
104
+ import type { ColumnConfigType, KanbanCardType } from "@ram_28/kf-ai-sdk/kanban/types";
167
105
 
168
- // Full card type with base fields + custom data
169
- type RestockingCard = KanbanCardType<RestockingCardData>;
106
+ interface TaskData {
107
+ priority: "Low" | "Medium" | "High";
108
+ assignee: string;
109
+ }
170
110
 
171
- function InventoryRestockingBoard() {
172
- // Instantiate the ProductRestocking source with role
173
- const restocking = new ProductRestocking(Roles.InventoryManager);
111
+ type Task = KanbanCardType<TaskData>;
174
112
 
175
- // Static column configurations
176
- const columnConfigs: ColumnConfigType[] = [
177
- { id: "LowStockAlert", title: "Low Stock Alert", position: 0, color: "red" },
178
- { id: "OrderPlaced", title: "Order Placed", position: 1, color: "yellow" },
179
- { id: "InTransit", title: "In Transit", position: 2, color: "blue" },
180
- { id: "Received", title: "Received & Restocked", position: 3, color: "green", limit: 20 },
113
+ function TaskBoard() {
114
+ const columns: ColumnConfigType[] = [
115
+ { id: "todo", title: "To Do", position: 0 },
116
+ { id: "in-progress", title: "In Progress", position: 1 },
117
+ { id: "done", title: "Done", position: 2 },
181
118
  ];
182
119
 
183
- // Hook configuration with full options
184
- const options: UseKanbanOptionsType<RestockingCardData> = {
185
- source: restocking._id, // Use the Business Object ID from the source class
186
- columns: columnConfigs,
187
- enableDragDrop: true,
188
- enableFiltering: true,
189
- enableSearch: true,
190
- initialState: {
191
- filterOperator: "And",
192
- },
193
- onCardMove: (card: RestockingCard, fromColumnId: string, toColumnId: string) => {
194
- console.log(`Moved "${card.productTitle}" from ${fromColumnId} to ${toColumnId}`);
195
- },
196
- onCardCreate: (card: RestockingCard) => console.log("Created:", card.productTitle),
197
- onCardUpdate: (card: RestockingCard) => console.log("Updated:", card._id),
198
- onCardDelete: (cardId: string) => console.log("Deleted:", cardId),
199
- onError: (error: Error) => console.error("Kanban error:", error.message),
200
- };
120
+ const kanban = useKanban<TaskData>({
121
+ source: "BDO_Tasks",
122
+ columns,
123
+ });
124
+
125
+ if (kanban.isLoading) return <div>Loading board...</div>;
126
+ if (kanban.error) return <div>Error: {kanban.error.message}</div>;
201
127
 
202
- const kanban: UseKanbanReturnType<RestockingCardData> = useKanban<RestockingCardData>(options);
128
+ return (
129
+ <div className="kanban-board">
130
+ {kanban.columns.map((column) => (
131
+ <div key={column._id} className="column">
132
+ <h3>{column.title} ({column.cards.length})</h3>
133
+ <div className="cards">
134
+ {column.cards.map((card) => (
135
+ <div key={card._id} className="card">
136
+ <h4>{card.title}</h4>
137
+ <span className="priority">{card.priority}</span>
138
+ <span className="assignee">{card.assignee}</span>
139
+ </div>
140
+ ))}
141
+ </div>
142
+ </div>
143
+ ))}
144
+ </div>
145
+ );
146
+ }
147
+ ```
148
+
149
+ ---
203
150
 
204
- // Access filter state (UseFilterReturnType)
205
- const filterState: UseFilterReturnType = kanban.filter;
151
+ ## Card Operations
152
+
153
+ ### Create Card
154
+
155
+ Add a new card to a column.
156
+
157
+ ```tsx
158
+ function BoardWithCreate() {
159
+ const kanban = useKanban<TaskData>({
160
+ source: "BDO_Tasks",
161
+ columns,
162
+ });
206
163
 
207
- // Create a new card
208
164
  const handleCreateCard = async (columnId: string) => {
209
- const cardId: string = await kanban.createCard({
165
+ const cardId = await kanban.createCard({
210
166
  columnId,
211
- title: "New Restock Task",
212
- productTitle: "Sample Product",
213
- productSKU: "SKU-001",
214
- currentStock: 5,
215
- quantityOrdered: 50,
216
- warehouse: "Warehouse_A",
217
- priority: "High",
167
+ title: "New Task",
168
+ priority: "Medium",
169
+ assignee: "Unassigned",
218
170
  });
219
- console.log("Created card with id:", cardId);
171
+ console.log("Created card:", cardId);
220
172
  };
221
173
 
222
- // Update card priority
223
- const handleUpdatePriority = async (card: RestockingCard, priority: RestockingCardData["priority"]) => {
174
+ return (
175
+ <div className="kanban-board">
176
+ {kanban.columns.map((column) => (
177
+ <div key={column._id} className="column">
178
+ <div className="column-header">
179
+ <h3>{column.title}</h3>
180
+ <button onClick={() => handleCreateCard(column._id)}>
181
+ + Add Card
182
+ </button>
183
+ </div>
184
+ {/* cards */}
185
+ </div>
186
+ ))}
187
+ </div>
188
+ );
189
+ }
190
+ ```
191
+
192
+ ### Update Card
193
+
194
+ Modify an existing card's properties.
195
+
196
+ ```tsx
197
+ function CardWithEdit({ card }: { card: Task }) {
198
+ const kanban = useKanban<TaskData>({
199
+ source: "BDO_Tasks",
200
+ columns,
201
+ });
202
+
203
+ const handleUpdateTitle = async (newTitle: string) => {
204
+ await kanban.updateCard(card._id, { title: newTitle });
205
+ };
206
+
207
+ const handleChangePriority = async (priority: TaskData["priority"]) => {
224
208
  await kanban.updateCard(card._id, { priority });
225
209
  };
226
210
 
227
- // Delete a card
228
- const handleDeleteCard = async (cardId: string) => {
229
- await kanban.deleteCard(cardId);
211
+ return (
212
+ <div className="card">
213
+ <input
214
+ defaultValue={card.title}
215
+ onBlur={(e) => handleUpdateTitle(e.target.value)}
216
+ />
217
+ <select
218
+ value={card.priority}
219
+ onChange={(e) => handleChangePriority(e.target.value as TaskData["priority"])}
220
+ >
221
+ <option value="Low">Low</option>
222
+ <option value="Medium">Medium</option>
223
+ <option value="High">High</option>
224
+ </select>
225
+ </div>
226
+ );
227
+ }
228
+ ```
229
+
230
+ ### Delete Card
231
+
232
+ Remove a card from the board.
233
+
234
+ ```tsx
235
+ function CardWithDelete({ card }: { card: Task }) {
236
+ const kanban = useKanban<TaskData>({
237
+ source: "BDO_Tasks",
238
+ columns,
239
+ });
240
+
241
+ const handleDelete = async () => {
242
+ if (confirm(`Delete "${card.title}"?`)) {
243
+ await kanban.deleteCard(card._id);
244
+ }
230
245
  };
231
246
 
232
- // Move card between columns
233
- const handleMoveCard = async (cardId: string, toColumnId: string) => {
234
- await kanban.moveCard(cardId, toColumnId);
247
+ return (
248
+ <div className="card">
249
+ <h4>{card.title}</h4>
250
+ <button onClick={handleDelete} className="delete-btn">
251
+ Delete
252
+ </button>
253
+ </div>
254
+ );
255
+ }
256
+ ```
257
+
258
+ ### Move Card Between Columns
259
+
260
+ Programmatically move a card to a different column.
261
+
262
+ ```tsx
263
+ function CardWithMoveActions({ card }: { card: Task }) {
264
+ const kanban = useKanban<TaskData>({
265
+ source: "BDO_Tasks",
266
+ columns,
267
+ });
268
+
269
+ const moveTo = async (columnId: string) => {
270
+ await kanban.moveCard(card._id, columnId);
235
271
  };
236
272
 
237
- // Filter by priority
273
+ return (
274
+ <div className="card">
275
+ <h4>{card.title}</h4>
276
+ <div className="move-actions">
277
+ <button onClick={() => moveTo("todo")}>To Do</button>
278
+ <button onClick={() => moveTo("in-progress")}>In Progress</button>
279
+ <button onClick={() => moveTo("done")}>Done</button>
280
+ </div>
281
+ </div>
282
+ );
283
+ }
284
+ ```
285
+
286
+ ---
287
+
288
+ ## Drag and Drop
289
+
290
+ ### Using Prop Getters
291
+
292
+ Apply drag-and-drop handlers using built-in prop getters.
293
+
294
+ ```tsx
295
+ function DraggableBoard() {
296
+ const kanban = useKanban<TaskData>({
297
+ source: "BDO_Tasks",
298
+ columns,
299
+ enableDragDrop: true,
300
+ onCardMove: (card, from, to) => {
301
+ console.log(`Moved "${card.title}" from ${from} to ${to}`);
302
+ },
303
+ });
304
+
305
+ return (
306
+ <div className="kanban-board">
307
+ {kanban.columns.map((column) => (
308
+ <div
309
+ key={column._id}
310
+ className={`column ${kanban.dragOverColumn === column._id ? "drag-over" : ""}`}
311
+ {...kanban.getColumnProps(column._id)}
312
+ >
313
+ <h3>{column.title}</h3>
314
+ <div className="cards">
315
+ {column.cards.map((card) => (
316
+ <div
317
+ key={card._id}
318
+ className={`card ${kanban.draggedCard?._id === card._id ? "dragging" : ""}`}
319
+ {...kanban.getCardProps(card)}
320
+ >
321
+ <h4>{card.title}</h4>
322
+ </div>
323
+ ))}
324
+ </div>
325
+ </div>
326
+ ))}
327
+ </div>
328
+ );
329
+ }
330
+ ```
331
+
332
+ ### Drag State Indicators
333
+
334
+ Show visual feedback during drag operations.
335
+
336
+ ```tsx
337
+ function BoardWithDragIndicators() {
338
+ const kanban = useKanban<TaskData>({
339
+ source: "BDO_Tasks",
340
+ columns,
341
+ enableDragDrop: true,
342
+ });
343
+
344
+ return (
345
+ <div className="kanban-board">
346
+ {/* Drag indicator */}
347
+ {kanban.isDragging && (
348
+ <div className="drag-indicator">
349
+ Moving: {kanban.draggedCard?.title}
350
+ </div>
351
+ )}
352
+
353
+ {kanban.columns.map((column) => (
354
+ <div
355
+ key={column._id}
356
+ className="column"
357
+ style={{
358
+ backgroundColor: kanban.dragOverColumn === column._id ? "#e3f2fd" : "white",
359
+ }}
360
+ {...kanban.getColumnProps(column._id)}
361
+ >
362
+ <h3>{column.title}</h3>
363
+ <div className="cards">
364
+ {column.cards.map((card) => (
365
+ <div
366
+ key={card._id}
367
+ className="card"
368
+ style={{
369
+ opacity: kanban.draggedCard?._id === card._id ? 0.5 : 1,
370
+ }}
371
+ {...kanban.getCardProps(card)}
372
+ >
373
+ {card.title}
374
+ </div>
375
+ ))}
376
+ </div>
377
+ </div>
378
+ ))}
379
+ </div>
380
+ );
381
+ }
382
+ ```
383
+
384
+ ---
385
+
386
+ ## Filtering Cards
387
+
388
+ ### Filter by Priority
389
+
390
+ Show only cards matching a priority level.
391
+
392
+ ```tsx
393
+ function BoardWithPriorityFilter() {
394
+ const kanban = useKanban<TaskData>({
395
+ source: "BDO_Tasks",
396
+ columns,
397
+ enableFiltering: true,
398
+ });
399
+
238
400
  const filterByPriority = (priority: string) => {
239
401
  kanban.filter.clearAllConditions();
240
402
  if (priority !== "all") {
@@ -246,175 +408,268 @@ function InventoryRestockingBoard() {
246
408
  }
247
409
  };
248
410
 
249
- // Add complex filter (Critical OR High priority)
250
- const addUrgentFilter = () => {
251
- const groupId = kanban.filter.addConditionGroup("Or");
411
+ return (
412
+ <div>
413
+ <div className="filter-bar">
414
+ <button onClick={() => filterByPriority("all")}>All</button>
415
+ <button onClick={() => filterByPriority("High")}>High Priority</button>
416
+ <button onClick={() => filterByPriority("Medium")}>Medium</button>
417
+ <button onClick={() => filterByPriority("Low")}>Low</button>
418
+ </div>
419
+
420
+ {/* board rendering */}
421
+ </div>
422
+ );
423
+ }
424
+ ```
425
+
426
+ ### Filter by Assignee (My Tasks)
427
+
428
+ Show only cards assigned to the current user.
429
+
430
+ ```tsx
431
+ function BoardWithMyTasks({ currentUserId }: { currentUserId: string }) {
432
+ const kanban = useKanban<TaskData>({
433
+ source: "BDO_Tasks",
434
+ columns,
435
+ enableFiltering: true,
436
+ });
437
+
438
+ const showMyTasks = () => {
439
+ kanban.filter.clearAllConditions();
252
440
  kanban.filter.addCondition({
253
441
  Operator: "EQ",
254
- LHSField: "priority",
255
- RHSValue: "Critical",
256
- }, groupId);
442
+ LHSField: "assignee",
443
+ RHSValue: currentUserId,
444
+ });
445
+ };
446
+
447
+ const showAllTasks = () => {
448
+ kanban.filter.clearAllConditions();
449
+ };
450
+
451
+ return (
452
+ <div>
453
+ <div className="filter-bar">
454
+ <button onClick={showMyTasks}>My Tasks</button>
455
+ <button onClick={showAllTasks}>All Tasks</button>
456
+ {kanban.filter.hasConditions && (
457
+ <span>Filtered: {kanban.totalCards} cards</span>
458
+ )}
459
+ </div>
460
+
461
+ {/* board rendering */}
462
+ </div>
463
+ );
464
+ }
465
+ ```
466
+
467
+ ### Combined Filters
468
+
469
+ Apply multiple filter conditions.
470
+
471
+ ```tsx
472
+ function BoardWithCombinedFilters() {
473
+ const kanban = useKanban<TaskData>({
474
+ source: "BDO_Tasks",
475
+ columns,
476
+ enableFiltering: true,
477
+ initialState: {
478
+ filter: {
479
+ operator: "And",
480
+ },
481
+ },
482
+ });
483
+
484
+ const applyUrgentFilter = () => {
485
+ kanban.filter.clearAllConditions();
486
+
487
+ // High priority OR overdue
488
+ const groupId = kanban.filter.addConditionGroup("Or");
257
489
  kanban.filter.addCondition({
258
490
  Operator: "EQ",
259
491
  LHSField: "priority",
260
492
  RHSValue: "High",
261
493
  }, groupId);
494
+ kanban.filter.addCondition({
495
+ Operator: "LT",
496
+ LHSField: "dueDate",
497
+ RHSValue: new Date().toISOString(),
498
+ }, groupId);
262
499
  };
263
500
 
264
- // Render active filters using type guards
265
- const renderActiveFilters = () => (
266
- <div className="active-filters">
267
- {kanban.filter.items.map((item) => {
268
- if (isCondition(item)) {
269
- return (
270
- <span key={item.id} className="filter-tag">
271
- {item.LHSField} {item.Operator} {String(item.RHSValue)}
272
- <button onClick={() => kanban.filter.removeCondition(item.id!)}>×</button>
273
- </span>
274
- );
275
- }
276
- if (isConditionGroup(item)) {
277
- return (
278
- <span key={item.id} className="filter-group-tag">
279
- {item.Operator} Group ({item.Condition.length})
280
- <button onClick={() => kanban.filter.removeCondition(item.id!)}>×</button>
281
- </span>
282
- );
283
- }
284
- return null;
285
- })}
501
+ return (
502
+ <div>
503
+ <div className="filter-bar">
504
+ <button onClick={applyUrgentFilter}>Urgent Tasks</button>
505
+ <button onClick={() => kanban.filter.clearAllConditions()}>Clear</button>
506
+ </div>
507
+
508
+ {/* board rendering */}
286
509
  </div>
287
510
  );
511
+ }
512
+ ```
288
513
 
289
- // Get filter payload for debugging
290
- const getFilterPayload = (): FilterType | undefined => {
291
- return kanban.filter.payload;
292
- };
514
+ ---
293
515
 
294
- if (kanban.isLoading) {
295
- return <div>Loading board...</div>;
296
- }
516
+ ## Search
297
517
 
298
- if (kanban.error) {
299
- return (
300
- <div>
301
- <p>Error: {kanban.error.message}</p>
302
- <button onClick={() => kanban.refetch()}>Retry</button>
303
- </div>
304
- );
305
- }
518
+ ### Basic Search
519
+
520
+ Filter cards by text search.
521
+
522
+ ```tsx
523
+ function BoardWithSearch() {
524
+ const kanban = useKanban<TaskData>({
525
+ source: "BDO_Tasks",
526
+ columns,
527
+ enableSearch: true,
528
+ });
306
529
 
307
530
  return (
308
- <div className="kanban-board">
309
- {/* Search */}
531
+ <div>
310
532
  <div className="search-bar">
311
533
  <input
312
534
  type="text"
313
- placeholder="Search products..."
535
+ placeholder="Search tasks..."
314
536
  value={kanban.searchQuery}
315
537
  onChange={(e) => kanban.setSearchQuery(e.target.value)}
316
538
  />
317
- <button onClick={kanban.clearSearch}>Clear</button>
318
- </div>
319
-
320
- {/* Filter Controls */}
321
- <div className="filter-controls">
322
- <button onClick={() => filterByPriority("Critical")}>Critical</button>
323
- <button onClick={() => filterByPriority("High")}>High</button>
324
- <button onClick={addUrgentFilter}>Urgent (Critical OR High)</button>
325
- <button onClick={() => filterByPriority("all")}>All</button>
326
- {kanban.filter.hasConditions && (
327
- <button onClick={() => kanban.filter.clearAllConditions()}>Clear Filters</button>
539
+ {kanban.searchQuery && (
540
+ <button onClick={kanban.clearSearch}>Clear</button>
328
541
  )}
329
- <span>Logic: {kanban.filter.operator}</span>
330
542
  </div>
331
543
 
332
- {/* Active Filters */}
333
- {renderActiveFilters()}
544
+ {/* board rendering */}
545
+ </div>
546
+ );
547
+ }
548
+ ```
334
549
 
335
- {/* Board Stats */}
336
- <div className="board-stats">
337
- <span>Total cards: {kanban.totalCards}</span>
338
- {kanban.isDragging && (
339
- <span>Dragging: {kanban.draggedCard?.productTitle}</span>
340
- )}
341
- {kanban.isUpdating && <span>Updating...</span>}
342
- </div>
550
+ ---
551
+
552
+ ## Column Configuration
553
+
554
+ ### Columns with Limits
343
555
 
344
- {/* Kanban Columns */}
345
- <div className="columns-container">
346
- {kanban.columns.map((column: KanbanColumnType<RestockingCardData>) => (
556
+ Set maximum card limits per column.
557
+
558
+ ```tsx
559
+ function BoardWithLimits() {
560
+ const columns: ColumnConfigType[] = [
561
+ { id: "todo", title: "To Do", position: 0 },
562
+ { id: "in-progress", title: "In Progress", position: 1, limit: 5 },
563
+ { id: "review", title: "Review", position: 2, limit: 3 },
564
+ { id: "done", title: "Done", position: 3 },
565
+ ];
566
+
567
+ const kanban = useKanban<TaskData>({
568
+ source: "BDO_Tasks",
569
+ columns,
570
+ });
571
+
572
+ return (
573
+ <div className="kanban-board">
574
+ {kanban.columns.map((column) => {
575
+ const isOverLimit = column.limit && column.cards.length >= column.limit;
576
+
577
+ return (
347
578
  <div
348
579
  key={column._id}
349
- className={`column ${kanban.dragOverColumn === column._id ? "drag-over" : ""}`}
350
- style={{ backgroundColor: column.color }}
351
- {...kanban.getColumnProps(column._id)}
580
+ className={`column ${isOverLimit ? "over-limit" : ""}`}
352
581
  >
353
- {/* Column Header */}
354
- <div className="column-header">
355
- <h3>{column.title}</h3>
356
- <span>
582
+ <h3>
583
+ {column.title}
584
+ <span className="count">
357
585
  {column.cards.length}
358
586
  {column.limit && ` / ${column.limit}`}
359
587
  </span>
360
- <button onClick={() => handleCreateCard(column._id)}>+ Add</button>
361
- </div>
362
-
363
- {/* Cards */}
364
- <div className="cards-container">
365
- {column.cards.map((card: RestockingCard) => (
366
- <div
367
- key={card._id}
368
- className={`card ${kanban.draggedCard?._id === card._id ? "dragging" : ""}`}
369
- {...kanban.getCardProps(card)}
370
- >
371
- <div className="card-header">
372
- <span className={`priority-badge ${card.priority.toLowerCase()}`}>
373
- {card.priority}
374
- </span>
375
- <button onClick={() => handleDeleteCard(card._id)}>×</button>
376
- </div>
377
- <h4>{card.productTitle}</h4>
378
- <p>SKU: {card.productSKU}</p>
379
- <p>Stock: {card.currentStock} / Ordered: {card.quantityOrdered}</p>
380
- <p>Warehouse: {card.warehouse}</p>
381
- <div className="card-actions">
382
- <button onClick={() => handleUpdatePriority(card, "Critical")}>
383
- Set Critical
384
- </button>
385
- <button onClick={() => handleMoveCard(card._id, "Received")}>
386
- Mark Received
387
- </button>
388
- </div>
389
- </div>
390
- ))}
391
- </div>
392
-
393
- {/* Load More */}
394
- {column.cards.length >= 10 && (
395
- <button
396
- className="load-more"
397
- onClick={() => kanban.loadMore(column._id)}
398
- >
399
- Load More
400
- </button>
401
- )}
588
+ </h3>
589
+ {/* cards */}
402
590
  </div>
403
- ))}
404
- </div>
591
+ );
592
+ })}
593
+ </div>
594
+ );
595
+ }
596
+ ```
405
597
 
406
- {/* Board Actions */}
407
- <div className="board-actions">
408
- <button onClick={() => kanban.refetch()} disabled={kanban.isFetching}>
409
- {kanban.isFetching ? "Refreshing..." : "Refresh Board"}
410
- </button>
411
- </div>
598
+ ### Colored Columns
599
+
600
+ Apply colors to columns for visual distinction.
601
+
602
+ ```tsx
603
+ function ColoredBoard() {
604
+ const columns: ColumnConfigType[] = [
605
+ { id: "backlog", title: "Backlog", position: 0, color: "#f5f5f5" },
606
+ { id: "todo", title: "To Do", position: 1, color: "#fff3e0" },
607
+ { id: "in-progress", title: "In Progress", position: 2, color: "#e3f2fd" },
608
+ { id: "done", title: "Done", position: 3, color: "#e8f5e9" },
609
+ ];
610
+
611
+ const kanban = useKanban<TaskData>({
612
+ source: "BDO_Tasks",
613
+ columns,
614
+ });
615
+
616
+ return (
617
+ <div className="kanban-board">
618
+ {kanban.columns.map((column) => (
619
+ <div
620
+ key={column._id}
621
+ className="column"
622
+ style={{ backgroundColor: column.color }}
623
+ >
624
+ <h3>{column.title}</h3>
625
+ {/* cards */}
626
+ </div>
627
+ ))}
628
+ </div>
629
+ );
630
+ }
631
+ ```
412
632
 
413
- {/* Debug: Filter payload */}
414
- <details>
415
- <summary>Filter Payload (Debug)</summary>
416
- <pre>{JSON.stringify(getFilterPayload(), null, 2)}</pre>
417
- </details>
633
+ ---
634
+
635
+ ## Event Callbacks
636
+
637
+ ### Track Card Operations
638
+
639
+ Handle card lifecycle events.
640
+
641
+ ```tsx
642
+ function BoardWithCallbacks() {
643
+ const kanban = useKanban<TaskData>({
644
+ source: "BDO_Tasks",
645
+ columns,
646
+ onCardMove: (card, fromColumn, toColumn) => {
647
+ console.log(`Card "${card.title}" moved from ${fromColumn} to ${toColumn}`);
648
+
649
+ // Track analytics
650
+ analytics.track("card_moved", {
651
+ cardId: card._id,
652
+ from: fromColumn,
653
+ to: toColumn,
654
+ });
655
+ },
656
+ onCardCreate: (card) => {
657
+ console.log(`Card created: ${card.title}`);
658
+ },
659
+ onCardUpdate: (card) => {
660
+ console.log(`Card updated: ${card._id}`);
661
+ },
662
+ onCardDelete: (cardId) => {
663
+ console.log(`Card deleted: ${cardId}`);
664
+ },
665
+ onError: (error) => {
666
+ alert(`Error: ${error.message}`);
667
+ },
668
+ });
669
+
670
+ return (
671
+ <div className="kanban-board">
672
+ {/* board rendering */}
418
673
  </div>
419
674
  );
420
675
  }