Skip to content

Commit f971ea4

Browse files
committed
feat: update column
1 parent 1045084 commit f971ea4

File tree

3 files changed

+72
-38
lines changed

3 files changed

+72
-38
lines changed

docs/registry/default/example/kanban-demo.tsx

+48-29
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@
33
import { Badge } from "@/components/ui/badge";
44
import { Button } from "@/components/ui/button";
55
import * as Kanban from "@/registry/default/ui/kanban";
6-
import {
7-
SortableContext,
8-
horizontalListSortingStrategy,
9-
} from "@dnd-kit/sortable";
106
import { GripVertical } from "lucide-react";
117
import * as React from "react";
128

@@ -113,36 +109,25 @@ export default function KanbanDemo() {
113109
>
114110
<Kanban.Board>
115111
{Object.entries(columns).map(([columnId, tasks]) => (
116-
<Kanban.Column key={columnId} value={columnId}>
117-
<div className="flex items-center justify-between">
118-
<div className="flex items-center gap-2">
119-
<h3 className="font-semibold">{COLUMN_TITLES[columnId]}</h3>
120-
<Badge
121-
variant="secondary"
122-
className="pointer-events-none rounded-sm"
123-
>
124-
{tasks?.length ?? 0}
125-
</Badge>
126-
</div>
127-
<Kanban.ColumnHandle asChild>
128-
<Button variant="ghost" size="icon">
129-
<GripVertical className="h-4 w-4" />
130-
</Button>
131-
</Kanban.ColumnHandle>
132-
</div>
133-
<div className="flex flex-col gap-2 p-0.5">
134-
{tasks?.map((task) => (
135-
<TaskCard key={task.id} task={task} asHandle />
136-
))}
137-
</div>
138-
</Kanban.Column>
112+
<TaskColumn key={columnId} columnId={columnId} tasks={tasks} />
139113
))}
140114
</Kanban.Board>
141115
<Kanban.Overlay>
142-
{(activeItem) => {
116+
{({ value, type }) => {
117+
if (type === "column") {
118+
const [columnId, tasks] =
119+
Object.entries(columns).find(([id]) => id === value) ?? [];
120+
121+
if (!columnId || !tasks) return null;
122+
123+
return (
124+
<TaskColumn key={columnId} columnId={columnId} tasks={tasks} />
125+
);
126+
}
127+
143128
const task = Object.values(columns)
144129
.flat()
145-
.find((task) => task.id === activeItem.value);
130+
.find((task) => task.id === value);
146131

147132
if (!task) return null;
148133

@@ -190,3 +175,37 @@ function TaskCard({ task, ...props }: TaskCardProps) {
190175
</Kanban.Item>
191176
);
192177
}
178+
179+
interface TaskColumnProps
180+
extends Omit<
181+
React.ComponentProps<typeof Kanban.Column>,
182+
"value" | "children"
183+
> {
184+
columnId: string;
185+
tasks: Task[];
186+
}
187+
188+
function TaskColumn({ columnId, tasks, ...props }: TaskColumnProps) {
189+
return (
190+
<Kanban.Column key={columnId} value={columnId} {...props}>
191+
<div className="flex items-center justify-between">
192+
<div className="flex items-center gap-2">
193+
<h3 className="font-semibold">{COLUMN_TITLES[columnId]}</h3>
194+
<Badge variant="secondary" className="pointer-events-none rounded-sm">
195+
{tasks?.length ?? 0}
196+
</Badge>
197+
</div>
198+
<Kanban.ColumnHandle asChild>
199+
<Button variant="ghost" size="icon">
200+
<GripVertical className="h-4 w-4" />
201+
</Button>
202+
</Kanban.ColumnHandle>
203+
</div>
204+
<div className="flex flex-col gap-2 p-0.5">
205+
{tasks?.map((task) => (
206+
<TaskCard key={task.id} task={task} asHandle />
207+
))}
208+
</div>
209+
</Kanban.Column>
210+
);
211+
}

docs/registry/default/ui/kanban.tsx

+24-8
Original file line numberDiff line numberDiff line change
@@ -573,9 +573,10 @@ const KanbanColumn = React.forwardRef<HTMLDivElement, KanbanColumnProps>(
573573

574574
const context = useKanbanContext("column");
575575
const inBoard = React.useContext(KanbanBoardContext);
576+
const inOverlay = React.useContext(KanbanOverlayContext);
576577
const id = React.useId();
577578

578-
if (!inBoard) {
579+
if (!inBoard && !inOverlay) {
579580
throw new Error(KANBAN_ERROR.column);
580581
}
581582

@@ -665,7 +666,6 @@ const KanbanColumn = React.forwardRef<HTMLDivElement, KanbanColumnProps>(
665666
},
666667
);
667668
KanbanColumn.displayName = COLUMN_NAME;
668-
669669
interface KanbanColumnHandleProps
670670
extends React.ComponentPropsWithoutRef<"button"> {
671671
asChild?: boolean;
@@ -750,6 +750,13 @@ const KanbanItem = React.forwardRef<HTMLDivElement, KanbanItemProps>(
750750
...itemProps
751751
} = props;
752752
const context = useKanbanContext("item");
753+
const inBoard = React.useContext(KanbanBoardContext);
754+
const inOverlay = React.useContext(KanbanOverlayContext);
755+
756+
if (!inBoard && !inOverlay) {
757+
throw new Error(KANBAN_ERROR.item);
758+
}
759+
753760
const id = React.useId();
754761
const {
755762
attributes,
@@ -867,6 +874,7 @@ const KanbanItemHandle = React.forwardRef<
867874
});
868875
KanbanItemHandle.displayName = ITEM_HANDLE_NAME;
869876

877+
const KanbanOverlayContext = React.createContext(false);
870878
const dropAnimation: DropAnimation = {
871879
sideEffects: defaultDropAnimationSideEffects({
872880
styles: {
@@ -881,7 +889,10 @@ interface KanbanOverlayProps
881889
extends Omit<React.ComponentPropsWithoutRef<typeof DragOverlay>, "children"> {
882890
container?: HTMLElement | DocumentFragment | null;
883891
children?:
884-
| ((params: { value: UniqueIdentifier }) => React.ReactNode)
892+
| ((params: {
893+
value: UniqueIdentifier;
894+
type: "column" | "item";
895+
}) => React.ReactNode)
885896
| React.ReactNode;
886897
}
887898

@@ -909,11 +920,16 @@ function KanbanOverlay(props: KanbanOverlayProps) {
909920
className={cn(!context.flatCursor && "cursor-grabbing")}
910921
{...overlayProps}
911922
>
912-
{context.activeId && children
913-
? typeof children === "function"
914-
? children({ value: context.activeId })
915-
: children
916-
: null}
923+
<KanbanOverlayContext.Provider value={true}>
924+
{context.activeId && children
925+
? typeof children === "function"
926+
? children({
927+
value: context.activeId,
928+
type: context.activeId in context.items ? "column" : "item",
929+
})
930+
: children
931+
: null}
932+
</KanbanOverlayContext.Provider>
917933
</DragOverlay>,
918934
container,
919935
);

docs/registry/default/ui/sortable.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,6 @@ const SortableItem = React.forwardRef<HTMLDivElement, SortableItemProps>(
382382
className,
383383
...itemProps
384384
} = props;
385-
386385
const inSortableContent = React.useContext(SortableContentContext);
387386
const inSortableOverlay = React.useContext(SortableOverlayContext);
388387

0 commit comments

Comments
 (0)