beads-kanban-ui 0.1.0 → 0.1.1

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 (154) hide show
  1. package/README.md +16 -222
  2. package/package.json +18 -55
  3. package/.designs/beads-kanban-ui-bj0.md +0 -73
  4. package/.designs/beads-kanban-ui-qxq.md +0 -144
  5. package/.designs/epic-support.md +0 -282
  6. package/.env.local.example +0 -2
  7. package/.eslintrc.json +0 -3
  8. package/.gitattributes +0 -3
  9. package/.github/workflows/release.yml +0 -123
  10. package/.history/README_20260121193710.md +0 -227
  11. package/.history/README_20260121193918.md +0 -227
  12. package/.history/README_20260121193921.md +0 -227
  13. package/.history/README_20260121193933.md +0 -227
  14. package/.history/README_20260121193934.md +0 -227
  15. package/.history/README_20260121193944.md +0 -227
  16. package/.history/README_20260121193953.md +0 -227
  17. package/.history/src/app/page_20260121133429.tsx +0 -134
  18. package/.history/src/app/page_20260121133928.tsx +0 -134
  19. package/.history/src/app/page_20260121144850.tsx +0 -138
  20. package/.history/src/app/page_20260121144854.tsx +0 -138
  21. package/.history/src/app/page_20260121144858.tsx +0 -138
  22. package/.history/src/app/page_20260121144902.tsx +0 -138
  23. package/.history/src/app/page_20260121144906.tsx +0 -138
  24. package/.history/src/app/page_20260121144911.tsx +0 -138
  25. package/.history/src/app/page_20260121144928.tsx +0 -138
  26. package/.playwright-mcp/.playwright-mcp/morphing-dialog-wheel-scroll-fix.png +0 -0
  27. package/.playwright-mcp/beams-test.png +0 -0
  28. package/.playwright-mcp/card-verification.png +0 -0
  29. package/.playwright-mcp/design-doc-dialog-fix-verification.png +0 -0
  30. package/.playwright-mcp/dialog-width-test.png +0 -0
  31. package/.playwright-mcp/homepage.png +0 -0
  32. package/.playwright-mcp/morphing-dialog-expanded.png +0 -0
  33. package/.playwright-mcp/morphing-dialog-fixes-final.png +0 -0
  34. package/.playwright-mcp/morphing-dialog-open.png +0 -0
  35. package/.playwright-mcp/page-2026-01-21T14-08-31-529Z.png +0 -0
  36. package/.playwright-mcp/page-2026-01-21T14-09-23-431Z.png +0 -0
  37. package/.playwright-mcp/page-2026-01-21T14-10-28-773Z.png +0 -0
  38. package/.playwright-mcp/page-2026-01-21T14-10-47-432Z.png +0 -0
  39. package/.playwright-mcp/page-2026-01-21T14-11-12-350Z.png +0 -0
  40. package/.playwright-mcp/screenshot-after-click.png +0 -0
  41. package/.playwright-mcp/screenshot-after-dialog-click.png +0 -0
  42. package/.playwright-mcp/sheet-restored-after-dialog-close.png +0 -0
  43. package/.playwright-mcp/test-1-sheet-open-with-overlay.png +0 -0
  44. package/.playwright-mcp/test-2-morphing-dialog-with-overlay.png +0 -0
  45. package/.playwright-mcp/test-3-sheet-open-dark-overlay.png +0 -0
  46. package/.playwright-mcp/test-4-morphing-dialog-with-dark-overlay.png +0 -0
  47. package/.playwright-mcp/test-5-morphing-dialog-scrolled.png +0 -0
  48. package/.playwright-mcp/test-6-sheet-restored-after-dialog-close.png +0 -0
  49. package/.playwright-mcp/wheel-scroll-fixed.png +0 -0
  50. package/Screenshots/bead-detail.png +0 -0
  51. package/Screenshots/dashboard.png +0 -0
  52. package/Screenshots/kanban-board.png +0 -0
  53. package/components.json +0 -27
  54. package/logo/logo.svg +0 -1
  55. package/next.config.js +0 -9
  56. package/npm/README.md +0 -37
  57. package/npm/package.json +0 -20
  58. package/postcss.config.js +0 -6
  59. package/public/logo.svg +0 -1
  60. package/restart.sh +0 -5
  61. package/server/Cargo.lock +0 -1685
  62. package/server/Cargo.toml +0 -24
  63. package/server/src/db.rs +0 -570
  64. package/server/src/main.rs +0 -141
  65. package/server/src/routes/beads.rs +0 -413
  66. package/server/src/routes/cli.rs +0 -150
  67. package/server/src/routes/fs.rs +0 -360
  68. package/server/src/routes/git.rs +0 -169
  69. package/server/src/routes/mod.rs +0 -107
  70. package/server/src/routes/projects.rs +0 -177
  71. package/server/src/routes/watch.rs +0 -211
  72. package/src/app/globals.css +0 -101
  73. package/src/app/layout.tsx +0 -36
  74. package/src/app/page.tsx +0 -348
  75. package/src/app/project/kanban-board.tsx +0 -356
  76. package/src/app/project/page.tsx +0 -18
  77. package/src/app/settings/page.tsx +0 -224
  78. package/src/components/Beams.css +0 -5
  79. package/src/components/Beams.jsx +0 -307
  80. package/src/components/Galaxy.css +0 -5
  81. package/src/components/Galaxy.jsx +0 -333
  82. package/src/components/activity-timeline.tsx +0 -172
  83. package/src/components/add-project-dialog.tsx +0 -219
  84. package/src/components/bead-card.tsx +0 -196
  85. package/src/components/bead-detail.tsx +0 -306
  86. package/src/components/color-picker.tsx +0 -101
  87. package/src/components/comment-input.tsx +0 -155
  88. package/src/components/comment-list.tsx +0 -147
  89. package/src/components/dependency-badge.tsx +0 -106
  90. package/src/components/design-doc-dialog.tsx +0 -58
  91. package/src/components/design-doc-preview.tsx +0 -97
  92. package/src/components/design-doc-viewer.tsx +0 -199
  93. package/src/components/editable-project-name.tsx +0 -178
  94. package/src/components/epic-card.tsx +0 -263
  95. package/src/components/folder-browser.tsx +0 -273
  96. package/src/components/footer.tsx +0 -27
  97. package/src/components/kanban/default.tsx +0 -184
  98. package/src/components/kanban-column.tsx +0 -167
  99. package/src/components/project-card.tsx +0 -191
  100. package/src/components/quick-filter-bar.tsx +0 -279
  101. package/src/components/scan-directory-dialog.tsx +0 -368
  102. package/src/components/status-donut.tsx +0 -197
  103. package/src/components/subtask-list.tsx +0 -128
  104. package/src/components/tag-picker.tsx +0 -252
  105. package/src/components/ui/.gitkeep +0 -0
  106. package/src/components/ui/alert-dialog.tsx +0 -141
  107. package/src/components/ui/avatar.tsx +0 -67
  108. package/src/components/ui/badge.tsx +0 -230
  109. package/src/components/ui/button.tsx +0 -433
  110. package/src/components/ui/card/index.tsx +0 -24
  111. package/src/components/ui/card/roiui-card.module.css +0 -197
  112. package/src/components/ui/card/roiui-card.tsx +0 -154
  113. package/src/components/ui/card/shadcn-card.tsx +0 -76
  114. package/src/components/ui/chart.tsx +0 -369
  115. package/src/components/ui/dialog.tsx +0 -122
  116. package/src/components/ui/dropdown-menu.tsx +0 -201
  117. package/src/components/ui/input.tsx +0 -22
  118. package/src/components/ui/kanban.tsx +0 -522
  119. package/src/components/ui/morphing-dialog.tsx +0 -457
  120. package/src/components/ui/popover.tsx +0 -33
  121. package/src/components/ui/progress.tsx +0 -28
  122. package/src/components/ui/scroll-area.tsx +0 -48
  123. package/src/components/ui/select.tsx +0 -159
  124. package/src/components/ui/separator.tsx +0 -31
  125. package/src/components/ui/sheet.tsx +0 -142
  126. package/src/components/ui/skeleton.tsx +0 -15
  127. package/src/components/ui/toast.tsx +0 -129
  128. package/src/components/ui/toaster.tsx +0 -35
  129. package/src/components/ui/tooltip.tsx +0 -30
  130. package/src/hooks/.gitkeep +0 -0
  131. package/src/hooks/use-bead-filters.ts +0 -261
  132. package/src/hooks/use-beads.ts +0 -162
  133. package/src/hooks/use-branch-statuses.ts +0 -161
  134. package/src/hooks/use-epics.ts +0 -173
  135. package/src/hooks/use-file-watcher.ts +0 -111
  136. package/src/hooks/use-keyboard-navigation.ts +0 -282
  137. package/src/hooks/use-project.ts +0 -61
  138. package/src/hooks/use-projects.ts +0 -93
  139. package/src/hooks/use-toast.ts +0 -194
  140. package/src/hooks/useClickOutside.tsx +0 -26
  141. package/src/lib/.gitkeep +0 -0
  142. package/src/lib/api.ts +0 -186
  143. package/src/lib/beads-parser.ts +0 -252
  144. package/src/lib/cli.ts +0 -193
  145. package/src/lib/db.ts +0 -145
  146. package/src/lib/design-doc.ts +0 -74
  147. package/src/lib/epic-parser.ts +0 -242
  148. package/src/lib/git.ts +0 -102
  149. package/src/lib/utils.ts +0 -12
  150. package/src/types/index.ts +0 -107
  151. package/tailwind.config.ts +0 -85
  152. package/tsconfig.json +0 -26
  153. /package/{npm/bin → bin}/cli.js +0 -0
  154. /package/{npm/scripts → scripts}/postinstall.js +0 -0
@@ -1,522 +0,0 @@
1
- 'use client';
2
-
3
- import * as React from 'react';
4
- import { cn } from '@/lib/utils';
5
- import {
6
- defaultDropAnimation,
7
- defaultDropAnimationSideEffects,
8
- DndContext,
9
- DragEndEvent,
10
- DragOverEvent,
11
- DragOverlay,
12
- DragStartEvent,
13
- DropAnimation,
14
- KeyboardSensor,
15
- PointerSensor,
16
- UniqueIdentifier,
17
- useSensor,
18
- useSensors,
19
- type DraggableAttributes,
20
- type DraggableSyntheticListeners,
21
- } from '@dnd-kit/core';
22
- import {
23
- arrayMove,
24
- rectSortingStrategy,
25
- SortableContext,
26
- sortableKeyboardCoordinates,
27
- useSortable,
28
- verticalListSortingStrategy,
29
- } from '@dnd-kit/sortable';
30
- import { CSS } from '@dnd-kit/utilities';
31
- import { Slot } from '@radix-ui/react-slot';
32
-
33
- interface KanbanContextProps<T> {
34
- columns: Record<string, T[]>;
35
- setColumns: (columns: Record<string, T[]>) => void;
36
- getItemId: (item: T) => string;
37
- columnIds: string[];
38
- activeId: UniqueIdentifier | null;
39
- setActiveId: (id: UniqueIdentifier | null) => void;
40
- findContainer: (id: UniqueIdentifier) => string | undefined;
41
- isColumn: (id: UniqueIdentifier) => boolean;
42
- }
43
-
44
- const KanbanContext = React.createContext<KanbanContextProps<any>>({
45
- columns: {},
46
- setColumns: () => {},
47
- getItemId: () => '',
48
- columnIds: [],
49
- activeId: null,
50
- setActiveId: () => {},
51
- findContainer: () => undefined,
52
- isColumn: () => false,
53
- });
54
-
55
- const ColumnContext = React.createContext<{
56
- attributes: DraggableAttributes;
57
- listeners: DraggableSyntheticListeners | undefined;
58
- isDragging?: boolean;
59
- disabled?: boolean;
60
- }>({
61
- attributes: {} as DraggableAttributes,
62
- listeners: undefined,
63
- isDragging: false,
64
- disabled: false,
65
- });
66
-
67
- const ItemContext = React.createContext<{
68
- listeners: DraggableSyntheticListeners | undefined;
69
- isDragging?: boolean;
70
- disabled?: boolean;
71
- }>({
72
- listeners: undefined,
73
- isDragging: false,
74
- disabled: false,
75
- });
76
-
77
- const dropAnimationConfig: DropAnimation = {
78
- ...defaultDropAnimation,
79
- sideEffects: defaultDropAnimationSideEffects({
80
- styles: {
81
- active: {
82
- opacity: '0.4',
83
- },
84
- },
85
- }),
86
- };
87
-
88
- export interface KanbanMoveEvent {
89
- event: DragEndEvent;
90
- activeContainer: string;
91
- activeIndex: number;
92
- overContainer: string;
93
- overIndex: number;
94
- }
95
-
96
- export interface KanbanRootProps<T> {
97
- value: Record<string, T[]>;
98
- onValueChange: (value: Record<string, T[]>) => void;
99
- getItemValue: (item: T) => string;
100
- children: React.ReactNode;
101
- className?: string;
102
- onMove?: (event: KanbanMoveEvent) => void;
103
- }
104
-
105
- function Kanban<T>({ value, onValueChange, getItemValue, children, className, onMove }: KanbanRootProps<T>) {
106
- const columns = value;
107
- const setColumns = onValueChange;
108
- const [activeId, setActiveId] = React.useState<UniqueIdentifier | null>(null);
109
-
110
- const sensors = useSensors(
111
- useSensor(PointerSensor, {
112
- activationConstraint: {
113
- distance: 10,
114
- },
115
- }),
116
- useSensor(KeyboardSensor, {
117
- coordinateGetter: sortableKeyboardCoordinates,
118
- }),
119
- );
120
-
121
- const columnIds = React.useMemo(() => Object.keys(columns), [columns]);
122
-
123
- const isColumn = React.useCallback((id: UniqueIdentifier) => columnIds.includes(id as string), [columnIds]);
124
-
125
- const findContainer = React.useCallback(
126
- (id: UniqueIdentifier) => {
127
- if (isColumn(id)) return id as string;
128
- return columnIds.find((key) => columns[key].some((item) => getItemValue(item) === id));
129
- },
130
- [columns, columnIds, getItemValue, isColumn],
131
- );
132
-
133
- const handleDragStart = React.useCallback((event: DragStartEvent) => {
134
- setActiveId(event.active.id);
135
- }, []);
136
-
137
- const handleDragOver = React.useCallback(
138
- (event: DragOverEvent) => {
139
- if (onMove) {
140
- return;
141
- }
142
-
143
- const { active, over } = event;
144
- if (!over) return;
145
-
146
- if (isColumn(active.id)) return;
147
-
148
- const activeContainer = findContainer(active.id);
149
- const overContainer = findContainer(over.id);
150
-
151
- // Only handle moving items between different columns
152
- if (!activeContainer || !overContainer || activeContainer === overContainer) {
153
- return;
154
- }
155
-
156
- const activeItems = columns[activeContainer];
157
- const overItems = columns[overContainer];
158
-
159
- const activeIndex = activeItems.findIndex((item: T) => getItemValue(item) === active.id);
160
- let overIndex = overItems.findIndex((item: T) => getItemValue(item) === over.id);
161
-
162
- // If dropping on the column itself, not an item
163
- if (isColumn(over.id)) {
164
- overIndex = overItems.length;
165
- }
166
-
167
- const newOverItems = [...overItems];
168
- const [movedItem] = activeItems.splice(activeIndex, 1);
169
- newOverItems.splice(overIndex, 0, movedItem);
170
-
171
- setColumns({
172
- ...columns,
173
- [activeContainer]: [...activeItems],
174
- [overContainer]: newOverItems,
175
- });
176
- },
177
- [findContainer, getItemValue, isColumn, setColumns, columns, onMove],
178
- );
179
-
180
- const handleDragEnd = React.useCallback(
181
- (event: DragEndEvent) => {
182
- const { active, over } = event;
183
- setActiveId(null);
184
-
185
- if (!over) return;
186
-
187
- // Handle item move callback
188
- if (onMove && !isColumn(active.id)) {
189
- const activeContainer = findContainer(active.id);
190
- const overContainer = findContainer(over.id);
191
-
192
- if (activeContainer && overContainer) {
193
- const activeIndex = columns[activeContainer].findIndex((item: T) => getItemValue(item) === active.id);
194
- const overIndex = isColumn(over.id)
195
- ? columns[overContainer].length
196
- : columns[overContainer].findIndex((item: T) => getItemValue(item) === over.id);
197
-
198
- onMove({
199
- event,
200
- activeContainer,
201
- activeIndex,
202
- overContainer,
203
- overIndex,
204
- });
205
- }
206
- return;
207
- }
208
-
209
- // Handle column reordering
210
- if (isColumn(active.id) && isColumn(over.id)) {
211
- const activeIndex = columnIds.indexOf(active.id as string);
212
- const overIndex = columnIds.indexOf(over.id as string);
213
- if (activeIndex !== overIndex) {
214
- const newOrder = arrayMove(Object.keys(columns), activeIndex, overIndex);
215
- const newColumns: Record<string, T[]> = {};
216
- newOrder.forEach((key) => {
217
- newColumns[key] = columns[key];
218
- });
219
- setColumns(newColumns);
220
- }
221
- return;
222
- }
223
-
224
- const activeContainer = findContainer(active.id);
225
- const overContainer = findContainer(over.id);
226
-
227
- // Handle item reordering within the same column
228
- if (activeContainer && overContainer && activeContainer === overContainer) {
229
- const container = activeContainer;
230
- const activeIndex = columns[container].findIndex((item: T) => getItemValue(item) === active.id);
231
- const overIndex = columns[container].findIndex((item: T) => getItemValue(item) === over.id);
232
-
233
- if (activeIndex !== overIndex) {
234
- setColumns({
235
- ...columns,
236
- [container]: arrayMove(columns[container], activeIndex, overIndex),
237
- });
238
- }
239
- }
240
- },
241
- [columnIds, columns, findContainer, getItemValue, isColumn, setColumns, onMove],
242
- );
243
-
244
- const contextValue = React.useMemo(
245
- () => ({
246
- columns,
247
- setColumns,
248
- getItemId: getItemValue,
249
- columnIds,
250
- activeId,
251
- setActiveId,
252
- findContainer,
253
- isColumn,
254
- }),
255
- [columns, setColumns, getItemValue, columnIds, activeId, findContainer, isColumn],
256
- );
257
-
258
- return (
259
- <KanbanContext.Provider value={contextValue}>
260
- <DndContext sensors={sensors} onDragStart={handleDragStart} onDragOver={handleDragOver} onDragEnd={handleDragEnd}>
261
- <div data-slot="kanban" data-dragging={activeId !== null} className={cn(className)}>
262
- {children}
263
- </div>
264
- </DndContext>
265
- </KanbanContext.Provider>
266
- );
267
- }
268
-
269
- export interface KanbanBoardProps {
270
- className?: string;
271
- children: React.ReactNode;
272
- }
273
-
274
- function KanbanBoard({ children, className }: KanbanBoardProps) {
275
- const { columnIds } = React.useContext(KanbanContext);
276
-
277
- return (
278
- <SortableContext items={columnIds} strategy={rectSortingStrategy}>
279
- <div data-slot="kanban-board" className={cn('grid auto-rows-fr sm:grid-cols-3 gap-4', className)}>
280
- {children}
281
- </div>
282
- </SortableContext>
283
- );
284
- }
285
-
286
- export interface KanbanColumnProps {
287
- value: string;
288
- className?: string;
289
- children: React.ReactNode;
290
- disabled?: boolean;
291
- }
292
-
293
- function KanbanColumn({ value, className, children, disabled }: KanbanColumnProps) {
294
- const {
295
- setNodeRef,
296
- transform,
297
- transition,
298
- attributes,
299
- listeners,
300
- isDragging: isSortableDragging,
301
- } = useSortable({
302
- id: value,
303
- disabled,
304
- });
305
-
306
- const { activeId, isColumn } = React.useContext(KanbanContext);
307
- const isColumnDragging = activeId ? isColumn(activeId) : false;
308
-
309
- const style = {
310
- transition,
311
- transform: CSS.Translate.toString(transform),
312
- } as React.CSSProperties;
313
-
314
- return (
315
- <ColumnContext.Provider value={{ attributes, listeners, isDragging: isColumnDragging, disabled }}>
316
- <div
317
- data-slot="kanban-column"
318
- data-value={value}
319
- data-dragging={isSortableDragging}
320
- data-disabled={disabled}
321
- ref={setNodeRef}
322
- style={style}
323
- className={cn(
324
- 'group/kanban-column flex flex-col',
325
- isSortableDragging && 'opacity-50',
326
- disabled && 'opacity-50',
327
- className,
328
- )}
329
- >
330
- {children}
331
- </div>
332
- </ColumnContext.Provider>
333
- );
334
- }
335
-
336
- export interface KanbanColumnHandleProps {
337
- asChild?: boolean;
338
- className?: string;
339
- children?: React.ReactNode;
340
- cursor?: boolean;
341
- }
342
-
343
- function KanbanColumnHandle({ asChild, className, children, cursor = true }: KanbanColumnHandleProps) {
344
- const { attributes, listeners, isDragging, disabled } = React.useContext(ColumnContext);
345
-
346
- const Comp = asChild ? Slot : 'div';
347
-
348
- return (
349
- <Comp
350
- data-slot="kanban-column-handle"
351
- data-dragging={isDragging}
352
- data-disabled={disabled}
353
- {...attributes}
354
- {...listeners}
355
- className={cn(
356
- 'opacity-0 transition-opacity group-hover/kanban-column:opacity-100',
357
- cursor && (isDragging ? '!cursor-grabbing' : '!cursor-grab'),
358
- className,
359
- )}
360
- >
361
- {children}
362
- </Comp>
363
- );
364
- }
365
-
366
- export interface KanbanItemProps {
367
- value: string;
368
- asChild?: boolean;
369
- className?: string;
370
- children: React.ReactNode;
371
- disabled?: boolean;
372
- }
373
-
374
- function KanbanItem({ value, asChild = false, className, children, disabled }: KanbanItemProps) {
375
- const {
376
- setNodeRef,
377
- transform,
378
- transition,
379
- attributes,
380
- listeners,
381
- isDragging: isSortableDragging,
382
- } = useSortable({
383
- id: value,
384
- disabled,
385
- });
386
-
387
- const { activeId, isColumn } = React.useContext(KanbanContext);
388
- const isItemDragging = activeId ? !isColumn(activeId) : false;
389
-
390
- const style = {
391
- transition,
392
- transform: CSS.Translate.toString(transform),
393
- } as React.CSSProperties;
394
-
395
- const Comp = asChild ? Slot : 'div';
396
-
397
- return (
398
- <ItemContext.Provider value={{ listeners, isDragging: isItemDragging, disabled }}>
399
- <Comp
400
- data-slot="kanban-item"
401
- data-value={value}
402
- data-dragging={isSortableDragging}
403
- data-disabled={disabled}
404
- ref={setNodeRef}
405
- style={style}
406
- {...attributes}
407
- className={cn(isSortableDragging && 'opacity-50', disabled && 'opacity-50', className)}
408
- >
409
- {children}
410
- </Comp>
411
- </ItemContext.Provider>
412
- );
413
- }
414
-
415
- export interface KanbanItemHandleProps {
416
- asChild?: boolean;
417
- className?: string;
418
- children?: React.ReactNode;
419
- cursor?: boolean;
420
- }
421
-
422
- function KanbanItemHandle({ asChild, className, children, cursor = true }: KanbanItemHandleProps) {
423
- const { listeners, isDragging, disabled } = React.useContext(ItemContext);
424
-
425
- const Comp = asChild ? Slot : 'div';
426
-
427
- return (
428
- <Comp
429
- data-slot="kanban-item-handle"
430
- data-dragging={isDragging}
431
- data-disabled={disabled}
432
- {...listeners}
433
- className={cn(cursor && (isDragging ? '!cursor-grabbing' : '!cursor-grab'), className)}
434
- >
435
- {children}
436
- </Comp>
437
- );
438
- }
439
-
440
- export interface KanbanColumnContentProps {
441
- value: string;
442
- className?: string;
443
- children: React.ReactNode;
444
- }
445
-
446
- function KanbanColumnContent({ value, className, children }: KanbanColumnContentProps) {
447
- const { columns, getItemId } = React.useContext(KanbanContext);
448
-
449
- const itemIds = React.useMemo(() => columns[value].map(getItemId), [columns, getItemId, value]);
450
-
451
- return (
452
- <SortableContext items={itemIds} strategy={verticalListSortingStrategy}>
453
- <div data-slot="kanban-column-content" className={cn('flex flex-col gap-2', className)}>
454
- {children}
455
- </div>
456
- </SortableContext>
457
- );
458
- }
459
-
460
- export interface KanbanOverlayProps {
461
- className?: string;
462
- children?: React.ReactNode | ((params: { value: UniqueIdentifier; variant: 'column' | 'item' }) => React.ReactNode);
463
- }
464
-
465
- function KanbanOverlay({ children, className }: KanbanOverlayProps) {
466
- const { activeId, isColumn } = React.useContext(KanbanContext);
467
- const [dimensions, setDimensions] = React.useState<{ width: number; height: number } | null>(null);
468
-
469
- React.useEffect(() => {
470
- if (activeId) {
471
- const element = document.querySelector(
472
- `[data-slot="kanban-${isColumn(activeId) ? 'column' : 'item'}"][data-value="${activeId}"]`,
473
- );
474
- if (element) {
475
- const rect = element.getBoundingClientRect();
476
- setDimensions({ width: rect.width, height: rect.height });
477
- }
478
- } else {
479
- setDimensions(null);
480
- }
481
- }, [activeId]);
482
-
483
- const style = {
484
- width: dimensions?.width,
485
- height: dimensions?.height,
486
- } as React.CSSProperties;
487
-
488
- const content = React.useMemo(() => {
489
- if (!activeId) return null;
490
- if (typeof children === 'function') {
491
- return children({
492
- value: activeId,
493
- variant: isColumn(activeId) ? 'column' : 'item',
494
- });
495
- }
496
- return children;
497
- }, [activeId, children, isColumn]);
498
-
499
- return (
500
- <DragOverlay dropAnimation={dropAnimationConfig}>
501
- <div
502
- data-slot="kanban-overlay"
503
- data-dragging={true}
504
- style={style}
505
- className={cn('pointer-events-none', className, activeId ? '!cursor-grabbing' : '')}
506
- >
507
- {content}
508
- </div>
509
- </DragOverlay>
510
- );
511
- }
512
-
513
- export {
514
- Kanban,
515
- KanbanBoard,
516
- KanbanColumn,
517
- KanbanColumnHandle,
518
- KanbanItem,
519
- KanbanItemHandle,
520
- KanbanColumnContent,
521
- KanbanOverlay,
522
- };