@archbase/kanban 4.0.37

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 (95) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +630 -0
  3. package/dist/archbase-kanban-4.0.37.tgz +0 -0
  4. package/dist/components/Card/Card.d.ts +26 -0
  5. package/dist/components/Card/index.d.ts +1 -0
  6. package/dist/components/CardSkeleton/CardSkeleton.d.ts +9 -0
  7. package/dist/components/CardSkeleton/index.d.ts +2 -0
  8. package/dist/components/Column/Column.d.ts +47 -0
  9. package/dist/components/Column/index.d.ts +1 -0
  10. package/dist/components/ColumnAdder/ColumnAdder.d.ts +6 -0
  11. package/dist/components/ColumnAdder/index.d.ts +1 -0
  12. package/dist/components/ColumnContent/ColumnContent.d.ts +24 -0
  13. package/dist/components/ColumnContent/index.d.ts +1 -0
  14. package/dist/components/ColumnHeader/ColumnHeader.d.ts +10 -0
  15. package/dist/components/ColumnHeader/index.d.ts +1 -0
  16. package/dist/components/DefaultCard/DefaultCard.d.ts +3 -0
  17. package/dist/components/DefaultCard/index.d.ts +1 -0
  18. package/dist/components/GenericItem/GenericItem.d.ts +26 -0
  19. package/dist/components/GenericItem/index.d.ts +1 -0
  20. package/dist/components/Kanban.d.ts +3 -0
  21. package/dist/components/index.d.ts +2 -0
  22. package/dist/components/types.d.ts +124 -0
  23. package/dist/context/KanbanContext.d.ts +5 -0
  24. package/dist/global/dnd/dropManager.d.ts +16 -0
  25. package/dist/global/dnd/useCardDnd.d.ts +22 -0
  26. package/dist/global/dnd/useColumnDnd.d.ts +29 -0
  27. package/dist/index.css +1 -0
  28. package/dist/index.d.ts +4 -0
  29. package/dist/index.js +1041 -0
  30. package/dist/utils/columnsUtils.d.ts +4 -0
  31. package/dist/utils/getPrefix.d.ts +2 -0
  32. package/dist/utils/getSharedProps.d.ts +8 -0
  33. package/dist/utils/infinite-scroll.d.ts +4 -0
  34. package/dist/utils/mergeRefs.d.ts +5 -0
  35. package/dist/utils/scroll.d.ts +2 -0
  36. package/package.json +66 -0
  37. package/src/common/_index.scss +0 -0
  38. package/src/components/Card/Card.tsx +215 -0
  39. package/src/components/Card/_Card.scss +11 -0
  40. package/src/components/Card/_index.scss +1 -0
  41. package/src/components/Card/index.ts +1 -0
  42. package/src/components/CardSkeleton/CardSkeleton.tsx +45 -0
  43. package/src/components/CardSkeleton/_CardSkeleton.scss +245 -0
  44. package/src/components/CardSkeleton/_index.scss +1 -0
  45. package/src/components/CardSkeleton/index.ts +2 -0
  46. package/src/components/Column/Column.tsx +246 -0
  47. package/src/components/Column/_Column.scss +44 -0
  48. package/src/components/Column/_index.scss +1 -0
  49. package/src/components/Column/index.ts +1 -0
  50. package/src/components/ColumnAdder/ColumnAdder.tsx +18 -0
  51. package/src/components/ColumnAdder/_ColumnAdder.scss +0 -0
  52. package/src/components/ColumnAdder/_index.scss +1 -0
  53. package/src/components/ColumnAdder/index.ts +1 -0
  54. package/src/components/ColumnContent/ColumnContent.tsx +238 -0
  55. package/src/components/ColumnContent/_ColumnContent.scss +23 -0
  56. package/src/components/ColumnContent/_index.scss +1 -0
  57. package/src/components/ColumnContent/index.ts +1 -0
  58. package/src/components/ColumnHeader/ColumnHeader.tsx +43 -0
  59. package/src/components/ColumnHeader/_ColumnHeader.scss +26 -0
  60. package/src/components/ColumnHeader/_index.scss +1 -0
  61. package/src/components/ColumnHeader/index.ts +1 -0
  62. package/src/components/DefaultCard/DefaultCard.tsx +9 -0
  63. package/src/components/DefaultCard/_DefaultCard.scss +14 -0
  64. package/src/components/DefaultCard/_index.scss +1 -0
  65. package/src/components/DefaultCard/index.ts +1 -0
  66. package/src/components/GenericItem/GenericItem.tsx +132 -0
  67. package/src/components/GenericItem/_GenericItem.scss +4 -0
  68. package/src/components/GenericItem/_index.scss +1 -0
  69. package/src/components/GenericItem/index.ts +1 -0
  70. package/src/components/Kanban.tsx +102 -0
  71. package/src/components/_Kanban.scss +8 -0
  72. package/src/components/_index.scss +9 -0
  73. package/src/components/index.ts +2 -0
  74. package/src/components/types.ts +155 -0
  75. package/src/context/KanbanContext.tsx +19 -0
  76. package/src/global/_index.scss +3 -0
  77. package/src/global/assets/styles/abstracts/_breakpoints.scss +71 -0
  78. package/src/global/assets/styles/abstracts/_colors.scss +85 -0
  79. package/src/global/assets/styles/abstracts/_functions.scss +3 -0
  80. package/src/global/assets/styles/abstracts/_index.scss +5 -0
  81. package/src/global/assets/styles/abstracts/_mixins.scss +49 -0
  82. package/src/global/assets/styles/abstracts/_padding.scss +1 -0
  83. package/src/global/assets/styles/abstracts/_variables.scss +8 -0
  84. package/src/global/assets/styles/base/_index.scss +34 -0
  85. package/src/global/dnd/dropManager.ts +301 -0
  86. package/src/global/dnd/useCardDnd.tsx +225 -0
  87. package/src/global/dnd/useColumnDnd.tsx +231 -0
  88. package/src/global/theme-default.scss +137 -0
  89. package/src/index.ts +6 -0
  90. package/src/utils/columnsUtils.ts +19 -0
  91. package/src/utils/getPrefix.ts +7 -0
  92. package/src/utils/getSharedProps.ts +18 -0
  93. package/src/utils/infinite-scroll.ts +18 -0
  94. package/src/utils/mergeRefs.ts +23 -0
  95. package/src/utils/scroll.ts +34 -0
package/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2024 Hazem braiek
2
+
3
+ Licensed under the Apache License, Version 2.0.
4
+ You may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,630 @@
1
+ # React Kanban Kit
2
+
3
+ A flexible and customizable Kanban board component for React applications, built with TypeScript and modern drag-and-drop functionality powered by Atlassian's pragmatic-drag-and-drop.
4
+
5
+ ## Demo
6
+
7
+ <img src="https://dl.dropboxusercontent.com/scl/fi/18zb79la4t5xgmt07eihn/1758020089915_GIF-ScreenRecording2025-09-16at11.52.15AM-ezgif.com-video-to-gif-converter.gif?rlkey=ikdmkrl4swpcqht09v4fvm3bo&dl=0"/>
8
+
9
+ Check out the live demo: [https://react-kanban-kit.netlify.app/](https://react-kanban-kit.netlify.app/)
10
+
11
+ ## Features
12
+
13
+ - 🎯 **Drag and Drop**: Cards and columns with smooth animations
14
+ - 📱 **Responsive Design**: Works on desktop, tablet, and mobile
15
+ - 🎨 **Highly Customizable**: Custom renderers for cards, headers, footers, and more
16
+ - 🔄 **Virtual Scrolling**: Optimized performance for large datasets
17
+ - 📦 **TypeScript Support**: Full type safety and IntelliSense
18
+ - 🎮 **View-Only Mode**: Disable interactions when needed
19
+ - 🎯 **Skeleton Loading**: Built-in loading states with animations
20
+ - 🎨 **Custom Styling**: Function-based styling with access to data context
21
+ - 🔥 **Modern Architecture**: Built with React hooks and clean separation of concerns
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ npm install react-kanban-kit
27
+ # or
28
+ yarn add react-kanban-kit
29
+ # or
30
+ pnpm add react-kanban-kit
31
+ ```
32
+
33
+ ## Basic Usage
34
+
35
+ ```tsx
36
+ import { Kanban, dropHandler } from "react-kanban-kit";
37
+ import type { BoardData } from "react-kanban-kit";
38
+
39
+ const MyKanbanBoard = () => {
40
+ const [dataSource, setDataSource] = useState<BoardData>({
41
+ root: {
42
+ id: "root",
43
+ title: "Root",
44
+ children: ["col-1", "col-2", "col-3"],
45
+ totalChildrenCount: 3,
46
+ parentId: null,
47
+ },
48
+ "col-1": {
49
+ id: "col-1",
50
+ title: "To Do",
51
+ children: ["task-1", "task-2"],
52
+ totalChildrenCount: 2,
53
+ parentId: "root",
54
+ },
55
+ "col-2": {
56
+ id: "col-2",
57
+ title: "In Progress",
58
+ children: ["task-3"],
59
+ totalChildrenCount: 1,
60
+ parentId: "root",
61
+ },
62
+ "col-3": {
63
+ id: "col-3",
64
+ title: "Done",
65
+ children: ["task-4"],
66
+ totalChildrenCount: 1,
67
+ parentId: "root",
68
+ },
69
+ "task-1": {
70
+ id: "task-1",
71
+ title: "Design Homepage",
72
+ parentId: "col-1",
73
+ children: [],
74
+ totalChildrenCount: 0,
75
+ type: "card",
76
+ content: {
77
+ description: "Create wireframes and mockups for the homepage",
78
+ priority: "high",
79
+ },
80
+ },
81
+ "task-2": {
82
+ id: "task-2",
83
+ title: "Setup Database",
84
+ parentId: "col-1",
85
+ children: [],
86
+ totalChildrenCount: 0,
87
+ type: "card",
88
+ },
89
+ "task-3": {
90
+ id: "task-3",
91
+ title: "Build Auth Flow",
92
+ parentId: "col-2",
93
+ children: [],
94
+ totalChildrenCount: 0,
95
+ type: "card",
96
+ },
97
+ "task-4": {
98
+ id: "task-4",
99
+ title: "Deploy to Production",
100
+ parentId: "col-3",
101
+ children: [],
102
+ totalChildrenCount: 0,
103
+ type: "card",
104
+ },
105
+ });
106
+
107
+ const configMap = {
108
+ card: {
109
+ render: ({ data }) => (
110
+ <div className="kanban-card">
111
+ <h3>{data.title}</h3>
112
+ {data.content?.description && <p>{data.content.description}</p>}
113
+ {data.content?.priority && (
114
+ <span className={`priority ${data.content.priority}`}>
115
+ {data.content.priority}
116
+ </span>
117
+ )}
118
+ </div>
119
+ ),
120
+ isDraggable: true,
121
+ },
122
+ };
123
+
124
+ return (
125
+ <Kanban
126
+ dataSource={dataSource}
127
+ configMap={configMap}
128
+ onCardMove={(move) => {
129
+ setDataSource(dropHandler(move, dataSource, () => {}));
130
+ }}
131
+ />
132
+ );
133
+ };
134
+ ```
135
+
136
+ ## Advanced Usage
137
+
138
+ ### Custom Card Types and Renderers
139
+
140
+ ```tsx
141
+ const configMap = {
142
+ card: {
143
+ render: ({ data, column, index, isDraggable }) => (
144
+ <div className="task-card">
145
+ <h4>{data.title}</h4>
146
+ <p>{data.content?.description}</p>
147
+ <div className="card-footer">
148
+ <span className="assignee">{data.content?.assignee}</span>
149
+ <span className="due-date">{data.content?.dueDate}</span>
150
+ </div>
151
+ </div>
152
+ ),
153
+ isDraggable: true,
154
+ },
155
+
156
+ divider: {
157
+ render: ({ data }) => (
158
+ <div className="divider">
159
+ <hr />
160
+ <span>{data.title}</span>
161
+ </div>
162
+ ),
163
+ isDraggable: false,
164
+ },
165
+
166
+ footer: {
167
+ render: ({ data, column }) => (
168
+ <button className="add-card-btn">+ Add card to {column.title}</button>
169
+ ),
170
+ isDraggable: false,
171
+ },
172
+ };
173
+ ```
174
+
175
+ ### Custom Column Headers and Footers
176
+
177
+ ```tsx
178
+ <Kanban
179
+ dataSource={dataSource}
180
+ configMap={configMap}
181
+ renderColumnHeader={(column) => (
182
+ <div className="custom-header">
183
+ <h3>{column.title}</h3>
184
+ <span className="count">{column.totalChildrenCount}</span>
185
+ <button className="column-menu">⋯</button>
186
+ </div>
187
+ )}
188
+ renderColumnFooter={(column) => (
189
+ <div className="column-footer">
190
+ <button>Add New Card</button>
191
+ </div>
192
+ )}
193
+ // Column adder
194
+ allowColumnAdder={true}
195
+ renderColumnAdder={() => (
196
+ <button className="add-column-btn">+ Add Column</button>
197
+ )}
198
+ // List footer (shown at the bottom of each column's card list)
199
+ allowListFooter={(column) => column.id !== "done"}
200
+ renderListFooter={(column) => (
201
+ <div className="list-footer">
202
+ <button>+ Add another card</button>
203
+ </div>
204
+ )}
205
+ />
206
+ ```
207
+
208
+ ### Column Drag and Drop
209
+
210
+ Enable column reordering by dragging column headers. Columns are dragged by their header element and show a placeholder indicator at the drop position.
211
+
212
+ ```tsx
213
+ import { Kanban, dropColumnHandler } from "react-kanban-kit";
214
+
215
+ <Kanban
216
+ dataSource={dataSource}
217
+ configMap={configMap}
218
+ allowColumnDrag
219
+ onColumnMove={(move) => {
220
+ setDataSource(dropColumnHandler(move, dataSource));
221
+ }}
222
+ renderColumnHeader={(column) => (
223
+ <div style={{ cursor: "grab" }}>
224
+ <h3>{column.title}</h3>
225
+ </div>
226
+ )}
227
+ />;
228
+ ```
229
+
230
+ #### How it works
231
+
232
+ - The column **header** is the drag handle users grab the header to drag the entire column
233
+ - While dragging, the source column dims (40% opacity), then hides once the cursor leaves it
234
+ - A **drop indicator** (column-sized placeholder) appears between columns to show the landing position
235
+ - On drop, `onColumnMove` fires with `{ columnId, fromIndex, toIndex }`
236
+ - Use the `dropColumnHandler` utility to produce the updated `dataSource`
237
+
238
+ #### Custom Column Drag Preview
239
+
240
+ By default, the drag preview is a DOM clone of the column. Override it with `renderColumnDragPreview`:
241
+
242
+ ```tsx
243
+ <Kanban
244
+ allowColumnDrag
245
+ renderColumnDragPreview={(column, info) => (
246
+ <div
247
+ style={{
248
+ width: info.state.dragging.width,
249
+ height: info.state.dragging.height,
250
+ backgroundColor: "#fff",
251
+ borderRadius: "12px",
252
+ padding: "12px",
253
+ boxShadow: "0 12px 30px rgba(0,0,0,0.2)",
254
+ transform: "rotate(4deg)",
255
+ }}
256
+ >
257
+ <strong>{column.title}</strong>
258
+ <p>{column.totalChildrenCount} cards</p>
259
+ </div>
260
+ )}
261
+ />
262
+ ```
263
+
264
+ #### Custom Column Drop Indicator
265
+
266
+ By default, the drop indicator is a column-sized placeholder box. Override it with `renderColumnDragIndicator`:
267
+
268
+ ```tsx
269
+ <Kanban
270
+ allowColumnDrag
271
+ renderColumnDragIndicator={(column, info) => (
272
+ <div
273
+ style={{
274
+ width: 4,
275
+ height: info.height,
276
+ backgroundColor: "#4a90d9",
277
+ borderRadius: 4,
278
+ }}
279
+ />
280
+ )}
281
+ />
282
+ ```
283
+
284
+ The `info` object provides `{ width, height, edge }` where `edge` is `"left"` or `"right"` indicating which side of the target column the indicator appears on.
285
+
286
+ #### Disable Drag for Specific Columns
287
+
288
+ Set `isDraggable: false` on individual `BoardItem` entries to lock specific columns in place:
289
+
290
+ ```tsx
291
+ const dataSource = {
292
+ // ...
293
+ "col-1": {
294
+ id: "col-1",
295
+ title: "Backlog",
296
+ isDraggable: false, // This column cannot be dragged
297
+ // ...
298
+ },
299
+ };
300
+ ```
301
+
302
+ ### Card Drag and Drop Customization
303
+
304
+ ```tsx
305
+ <Kanban
306
+ renderCardDragPreview={(card, info) => (
307
+ <div className="drag-preview">
308
+ <h4>{card.title}</h4>
309
+ </div>
310
+ )}
311
+ renderCardDragIndicator={(card, info) => (
312
+ <div className="drop-indicator" style={{ height: info.height }} />
313
+ )}
314
+ onCardDndStateChange={(info) => {
315
+ if (info.state.type === "is-dragging") {
316
+ // Card is being dragged
317
+ }
318
+ }}
319
+ onColumnDndStateChange={(info) => {
320
+ if (info.state.type === "is-card-over") {
321
+ // A card is being dragged over this column
322
+ }
323
+ }}
324
+ />
325
+ ```
326
+
327
+ ### Advanced Styling
328
+
329
+ ```tsx
330
+ <Kanban
331
+ rootClassName="my-kanban-board"
332
+ rootStyle={{ backgroundColor: "#f5f5f5", padding: "20px" }}
333
+ columnWrapperStyle={(column) => ({
334
+ border: `2px solid ${column.content?.color || "#ddd"}`,
335
+ })}
336
+ columnWrapperClassName={(column) =>
337
+ `column-wrapper ${column.content?.theme || "default"}`
338
+ }
339
+ columnHeaderStyle={(column) => ({
340
+ backgroundColor: column.content?.headerColor || "#f8f9fa",
341
+ })}
342
+ columnStyle={(column) => ({
343
+ minHeight: column.totalChildrenCount > 10 ? "800px" : "400px",
344
+ })}
345
+ columnClassName={(column) =>
346
+ column.totalChildrenCount === 0 ? "empty-column" : "has-items"
347
+ }
348
+ cardWrapperStyle={(card, column) => ({
349
+ opacity: card.content?.archived ? 0.5 : 1,
350
+ })}
351
+ cardWrapperClassName="custom-card-wrapper"
352
+ cardsGap={12}
353
+ columnListContentStyle={(column) => ({
354
+ padding: column.totalChildrenCount === 0 ? "40px 16px" : "8px",
355
+ })}
356
+ columnListContentClassName={(column) =>
357
+ `column-content ${column.totalChildrenCount === 0 ? "empty" : "filled"}`
358
+ }
359
+ />
360
+ ```
361
+
362
+ ### View-Only Mode
363
+
364
+ ```tsx
365
+ <Kanban dataSource={dataSource} configMap={configMap} viewOnly={true} />
366
+ ```
367
+
368
+ ---
369
+
370
+ ## Infinite Scroll
371
+
372
+ Infinite scroll lets each column load cards on demand as the user scrolls, instead of loading everything upfront.
373
+
374
+ ### How it works
375
+
376
+ The library uses `totalChildrenCount` and the actual `children` array to determine how many skeleton placeholders to render. When `totalChildrenCount > children.length`, the board renders skeleton cards to fill the gap. As the user scrolls and those skeletons become visible in the viewport, the library automatically calls your `loadMore(columnId)` callback.
377
+
378
+ For a full working implementation, see the [Infinite Scroll example in the demo](https://github.com/braiekhazem/react-kanban-kit/tree/main/rkk-demo/src/pages/InfiniteScrollExample) or try it live at [react-kanban-kit.netlify.app](https://react-kanban-kit.netlify.app).
379
+
380
+ ---
381
+
382
+ ## `dropHandler` utility
383
+
384
+ When a card is dropped, `onCardMove` gives you the move details. Use `dropHandler` to produce the updated `dataSource`:
385
+
386
+ ```tsx
387
+ import { dropHandler } from "react-kanban-kit";
388
+
389
+ onCardMove={(move) => {
390
+ setDataSource(
391
+ dropHandler(
392
+ move,
393
+ dataSource,
394
+ () => {}, // called with the moved card (optional)
395
+ (targetColumn) => ({ // optional: update the target column
396
+ ...targetColumn,
397
+ totalChildrenCount: targetColumn.totalChildrenCount + 1,
398
+ }),
399
+ (sourceColumn) => ({ // optional: update the source column
400
+ ...sourceColumn,
401
+ totalChildrenCount: sourceColumn.totalChildrenCount - 1,
402
+ })
403
+ )
404
+ );
405
+ }}
406
+ ```
407
+
408
+ ## `dropColumnHandler` utility
409
+
410
+ When a column is dropped, `onColumnMove` gives you the move details. Use `dropColumnHandler` to produce the updated `dataSource`:
411
+
412
+ ```tsx
413
+ import { dropColumnHandler } from "react-kanban-kit";
414
+
415
+ onColumnMove={(move) => {
416
+ setDataSource(dropColumnHandler(move, dataSource));
417
+ }}
418
+ ```
419
+
420
+ `dropColumnHandler` reorders the `root.children` array to move the column from `fromIndex` to `toIndex`.
421
+
422
+ ---
423
+
424
+ ## Props Reference
425
+
426
+ ### Core Props
427
+
428
+ | Prop | Type | Description |
429
+ | ------------ | ----------- | ---------------------------------------------------- |
430
+ | `dataSource` | `BoardData` | **Required.** The data structure for the board |
431
+ | `configMap` | `ConfigMap` | **Required.** Configuration for different card types |
432
+ | `viewOnly` | `boolean` | Disable all drag and drop interactions |
433
+
434
+ ### Data Loading
435
+
436
+ | Prop | Type | Description |
437
+ | -------------------- | ---------------------------------- | ------------------------------------------------------------------------- |
438
+ | `loadMore` | `(columnId: string) => void` | Called automatically when skeleton cards scroll into view for that column |
439
+ | `renderSkeletonCard` | `({ index, column }) => ReactNode` | Custom skeleton card rendered for items not yet loaded |
440
+
441
+ ### Drag and Drop Events
442
+
443
+ | Prop | Type | Description |
444
+ | ------------------------ | ---------------------------- | ------------------------------ |
445
+ | `onCardMove` | `(move: CardMove) => void` | Fired when a card is dropped |
446
+ | `onColumnMove` | `(move: ColumnMove) => void` | Fired when a column is dropped |
447
+ | `onCardDndStateChange` | `(info: DndState) => void` | Card drag state changes |
448
+ | `onColumnDndStateChange` | `(info: DndState) => void` | Column drag state changes |
449
+
450
+ ### Drag and Drop Customization
451
+
452
+ | Prop | Type | Description |
453
+ | --------------------------- | ----------------------------- | ---------------------------- |
454
+ | `allowColumnDrag` | `boolean` | Enable column reordering |
455
+ | `renderCardDragPreview` | `(card, info) => ReactNode` | Custom card drag preview |
456
+ | `renderCardDragIndicator` | `(card, info) => ReactNode` | Custom card drop indicator |
457
+ | `renderColumnDragPreview` | `(column, info) => ReactNode` | Custom column drag preview |
458
+ | `renderColumnDragIndicator` | `(column, info) => ReactNode` | Custom column drop indicator |
459
+
460
+ ### Column Customization
461
+
462
+ | Prop | Type | Description |
463
+ | --------------------- | ---------------------------------- | ----------------------------- |
464
+ | `renderColumnHeader` | `(column: BoardItem) => ReactNode` | Custom column header |
465
+ | `renderColumnFooter` | `(column: BoardItem) => ReactNode` | Custom column footer |
466
+ | `renderColumnWrapper` | `(column, props) => ReactNode` | Wrap entire column |
467
+ | `allowColumnAdder` | `boolean` | Show add column button |
468
+ | `renderColumnAdder` | `() => ReactNode` | Custom add column button |
469
+ | `renderListFooter` | `(column: BoardItem) => ReactNode` | Footer at bottom of card list |
470
+ | `allowListFooter` | `(column: BoardItem) => boolean` | Show list footer per column |
471
+
472
+ ### Styling Props (Functions)
473
+
474
+ | Prop | Type | Description |
475
+ | ------------------------ | -------------------------------------- | -------------------------- |
476
+ | `columnWrapperStyle` | `(column: BoardItem) => CSSProperties` | Column wrapper styles |
477
+ | `columnHeaderStyle` | `(column: BoardItem) => CSSProperties` | Column header styles |
478
+ | `columnStyle` | `(column: BoardItem) => CSSProperties` | Column inner styles |
479
+ | `columnListContentStyle` | `(column: BoardItem) => CSSProperties` | Column content area styles |
480
+ | `cardWrapperStyle` | `(card, column) => CSSProperties` | Card wrapper styles |
481
+
482
+ ### Styling Props (Class Names)
483
+
484
+ | Prop | Type | Description |
485
+ | ---------------------------- | ------------------------------- | -------------------- |
486
+ | `rootClassName` | `string` | Root container class |
487
+ | `columnWrapperClassName` | `(column: BoardItem) => string` | Column wrapper class |
488
+ | `columnHeaderClassName` | `(column: BoardItem) => string` | Column header class |
489
+ | `columnClassName` | `(column: BoardItem) => string` | Column inner class |
490
+ | `columnListContentClassName` | `(column: BoardItem) => string` | Column content class |
491
+ | `cardWrapperClassName` | `string` | Card wrapper class |
492
+
493
+ ### Performance & Behavior
494
+
495
+ | Prop | Type | Description |
496
+ | ---------------- | --------- | ---------------------------------------- |
497
+ | `virtualization` | `boolean` | Enable virtual scrolling (default: true) |
498
+ | `cardsGap` | `number` | Gap between cards in pixels |
499
+
500
+ ### Event Handlers
501
+
502
+ | Prop | Type | Description |
503
+ | --------------- | --------------------- | --------------------- |
504
+ | `onColumnClick` | `(e, column) => void` | Column click handler |
505
+ | `onCardClick` | `(e, card) => void` | Card click handler |
506
+ | `onScroll` | `(e, column) => void` | Column scroll handler |
507
+
508
+ ---
509
+
510
+ ## Data Structure
511
+
512
+ ### BoardData
513
+
514
+ ```typescript
515
+ interface BoardData {
516
+ root: BoardItem;
517
+ [key: string]: BoardItem;
518
+ }
519
+
520
+ interface BoardItem {
521
+ id: string;
522
+ title: string;
523
+ parentId: string | null;
524
+ children: string[]; // IDs of loaded children
525
+ totalChildrenCount: number; // Real total (including unloaded items)
526
+ content?: any; // Your custom data
527
+ type?: keyof ConfigMap; // Card type key into configMap
528
+ isDraggable?: boolean; // Override per-item draggability
529
+ }
530
+ ```
531
+
532
+ ### ConfigMap
533
+
534
+ ```typescript
535
+ type ConfigMap = {
536
+ [type: string]: {
537
+ render: (props: CardRenderProps) => React.ReactNode;
538
+ isDraggable?: boolean;
539
+ };
540
+ };
541
+
542
+ type CardRenderProps = {
543
+ data: BoardItem;
544
+ column: BoardItem;
545
+ index: number;
546
+ isDraggable: boolean;
547
+ };
548
+ ```
549
+
550
+ ---
551
+
552
+ ## Event Types
553
+
554
+ ### CardMove
555
+
556
+ ```typescript
557
+ interface CardMove {
558
+ cardId: string;
559
+ fromColumnId: string;
560
+ toColumnId: string;
561
+ taskAbove: string | null;
562
+ taskBelow: string | null;
563
+ position: number;
564
+ }
565
+ ```
566
+
567
+ ### ColumnMove
568
+
569
+ ```typescript
570
+ interface ColumnMove {
571
+ columnId: string;
572
+ fromIndex: number;
573
+ toIndex: number;
574
+ }
575
+ ```
576
+
577
+ ---
578
+
579
+ ## CSS Classes
580
+
581
+ ```css
582
+ .rkk-board {
583
+ } /* Root board container */
584
+ .rkk-column-outer {
585
+ } /* Column outer wrapper */
586
+ .rkk-column {
587
+ } /* Column inner container */
588
+ .rkk-column-header {
589
+ } /* Column header area */
590
+ .rkk-column-content {
591
+ } /* Column scrollable area */
592
+ .rkk-column-content-list {
593
+ } /* Virtual / normal list */
594
+ .rkk-generic-item-wrapper {
595
+ } /* Wrapper around each card */
596
+ .rkk-card-outer {
597
+ } /* Card outer element */
598
+ .rkk-card-inner {
599
+ } /* Card inner draggable element */
600
+ .rkk-card-shadow {
601
+ } /* Card drop position indicator */
602
+ .rkk-column-shadow-container {
603
+ } /* Column drop indicator wrapper */
604
+ .rkk-column-shadow {
605
+ } /* Column drop position indicator */
606
+ .rkk-skeleton {
607
+ } /* Default skeleton card */
608
+ ```
609
+
610
+ ---
611
+
612
+ ## TypeScript Support
613
+
614
+ ```typescript
615
+ import type {
616
+ BoardData,
617
+ BoardItem,
618
+ ConfigMap,
619
+ CardRenderProps,
620
+ BoardProps,
621
+ } from "react-kanban-kit";
622
+ ```
623
+
624
+ ## Contributing
625
+
626
+ Contributions are welcome! Please feel free to submit a Pull Request.
627
+
628
+ ## License
629
+
630
+ MIT © Hazem braiek
Binary file
@@ -0,0 +1,26 @@
1
+ import { default as React } from 'react';
2
+ import { BoardItem, DndState } from '../types';
3
+ export declare const CardShadow: React.MemoExoticComponent<({ height, customIndicator, }: {
4
+ height: number;
5
+ customIndicator?: React.ReactNode;
6
+ }) => import("react/jsx-runtime").JSX.Element>;
7
+ interface Props {
8
+ render: (props: {
9
+ data: BoardItem;
10
+ column: BoardItem;
11
+ index: number;
12
+ isDraggable: boolean;
13
+ }) => React.ReactNode;
14
+ data: BoardItem;
15
+ column: BoardItem;
16
+ index: number;
17
+ isDraggable: boolean;
18
+ onClick?: (e: React.MouseEvent<HTMLDivElement>, card: BoardItem) => void;
19
+ cardsGap?: number;
20
+ renderGap?: (column: BoardItem) => React.ReactNode;
21
+ onCardDndStateChange?: (info: DndState) => void;
22
+ renderCardDragIndicator?: (card: BoardItem, info: any) => React.ReactNode;
23
+ renderCardDragPreview?: (card: BoardItem, info: any) => React.ReactNode;
24
+ }
25
+ declare const Card: (props: Props) => import("react/jsx-runtime").JSX.Element;
26
+ export default Card;
@@ -0,0 +1 @@
1
+ export { default } from './Card';
@@ -0,0 +1,9 @@
1
+ import { default as React } from 'react';
2
+ export type SkeletonAnimationType = "shimmer" | "pulse" | "wave";
3
+ interface CardSkeletonProps {
4
+ className?: string;
5
+ style?: React.CSSProperties;
6
+ animationType?: SkeletonAnimationType;
7
+ }
8
+ declare const CardSkeleton: React.FC<CardSkeletonProps>;
9
+ export default CardSkeleton;
@@ -0,0 +1,2 @@
1
+ export { default } from './CardSkeleton';
2
+ export type { SkeletonAnimationType } from './CardSkeleton';