@comitor/ui 2.0.0 → 2.1.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 +35 -0
- package/README.md +14 -6
- package/dist/components/ui/action-bar-constants.d.ts +31 -0
- package/dist/components/ui/action-bar-constants.js +9 -0
- package/dist/components/ui/action-bar-constants.js.map +1 -0
- package/dist/components/ui/action-bar.d.ts +67 -0
- package/dist/components/ui/action-bar.js +522 -0
- package/dist/components/ui/action-bar.js.map +1 -0
- package/dist/components/ui/badge-overflow.d.ts +30 -0
- package/dist/components/ui/badge-overflow.js +179 -0
- package/dist/components/ui/badge-overflow.js.map +1 -0
- package/dist/components/ui/banner.d.ts +79 -0
- package/dist/components/ui/banner.js +518 -0
- package/dist/components/ui/banner.js.map +1 -0
- package/dist/components/ui/circular-progress.d.ts +50 -0
- package/dist/components/ui/circular-progress.js +266 -0
- package/dist/components/ui/circular-progress.js.map +1 -0
- package/dist/components/ui/cropper-constants.d.ts +34 -0
- package/dist/components/ui/cropper-constants.js +10 -0
- package/dist/components/ui/cropper-constants.js.map +1 -0
- package/dist/components/ui/cropper.d.ts +106 -0
- package/dist/components/ui/cropper.js +1269 -0
- package/dist/components/ui/cropper.js.map +1 -0
- package/dist/components/ui/drawer.d.ts +1 -1
- package/dist/components/ui/drawer.js +2 -2
- package/dist/components/ui/drawer.js.map +1 -1
- package/dist/components/ui/kanban-constants.d.ts +61 -0
- package/dist/components/ui/kanban-constants.js +21 -0
- package/dist/components/ui/kanban-constants.js.map +1 -0
- package/dist/components/ui/kanban.d.ts +72 -0
- package/dist/components/ui/kanban.js +787 -0
- package/dist/components/ui/kanban.js.map +1 -0
- package/dist/components/ui/key-value-constants.d.ts +33 -0
- package/dist/components/ui/key-value-constants.js +11 -0
- package/dist/components/ui/key-value-constants.js.map +1 -0
- package/dist/components/ui/key-value.d.ts +96 -0
- package/dist/components/ui/key-value.js +641 -0
- package/dist/components/ui/key-value.js.map +1 -0
- package/dist/components/ui/mask-input-constants.d.ts +99 -0
- package/dist/components/ui/mask-input-constants.js +601 -0
- package/dist/components/ui/mask-input-constants.js.map +1 -0
- package/dist/components/ui/mask-input.d.ts +36 -0
- package/dist/components/ui/mask-input.js +558 -0
- package/dist/components/ui/mask-input.js.map +1 -0
- package/dist/components/ui/mention.d.ts +31 -0
- package/dist/components/ui/mention.js +128 -0
- package/dist/components/ui/mention.js.map +1 -0
- package/dist/components/ui/phone-input-constants.d.ts +54 -0
- package/dist/components/ui/phone-input-constants.js +9 -0
- package/dist/components/ui/phone-input-constants.js.map +1 -0
- package/dist/components/ui/phone-input.d.ts +85 -0
- package/dist/components/ui/phone-input.js +743 -0
- package/dist/components/ui/phone-input.js.map +1 -0
- package/dist/components/ui/rating.d.ts +56 -0
- package/dist/components/ui/rating.js +646 -0
- package/dist/components/ui/rating.js.map +1 -0
- package/dist/components/ui/responsive-dialog.d.ts +35 -0
- package/dist/components/ui/responsive-dialog.js +193 -0
- package/dist/components/ui/responsive-dialog.js.map +1 -0
- package/dist/components/ui/scroll-spy.d.ts +42 -0
- package/dist/components/ui/scroll-spy.js +334 -0
- package/dist/components/ui/scroll-spy.js.map +1 -0
- package/dist/components/ui/stepper-constants.d.ts +29 -0
- package/dist/components/ui/stepper-constants.js +9 -0
- package/dist/components/ui/stepper-constants.js.map +1 -0
- package/dist/components/ui/stepper.d.ts +80 -0
- package/dist/components/ui/stepper.js +902 -0
- package/dist/components/ui/stepper.js.map +1 -0
- package/dist/components/ui/tags-input.d.ts +41 -0
- package/dist/components/ui/tags-input.js +127 -0
- package/dist/components/ui/tags-input.js.map +1 -0
- package/dist/components/ui/time-picker-constants.d.ts +48 -0
- package/dist/components/ui/time-picker-constants.js +14 -0
- package/dist/components/ui/time-picker-constants.js.map +1 -0
- package/dist/components/ui/time-picker.d.ts +115 -0
- package/dist/components/ui/time-picker.js +1620 -0
- package/dist/components/ui/time-picker.js.map +1 -0
- package/dist/components/ui/timeline.d.ts +32 -0
- package/dist/components/ui/timeline.js +559 -0
- package/dist/components/ui/timeline.js.map +1 -0
- package/dist/components/ui/tour-constants.d.ts +39 -0
- package/dist/components/ui/tour-constants.js +12 -0
- package/dist/components/ui/tour-constants.js.map +1 -0
- package/dist/components/ui/tour.d.ts +124 -0
- package/dist/components/ui/tour.js +1207 -0
- package/dist/components/ui/tour.js.map +1 -0
- package/dist/data-grid/data-grid-cell-wrapper.js +1 -1
- package/dist/data-grid/data-grid-cell-wrapper.js.map +1 -1
- package/dist/data-grid/data-grid-context-menu.js +1 -1
- package/dist/data-grid/data-grid-context-menu.js.map +1 -1
- package/dist/data-grid/data-grid-paste-dialog.js +1 -1
- package/dist/data-grid/data-grid-paste-dialog.js.map +1 -1
- package/dist/data-grid/data-grid-row.js +1 -1
- package/dist/data-grid/data-grid-row.js.map +1 -1
- package/dist/data-grid/data-grid-search.js +1 -1
- package/dist/data-grid/data-grid-search.js.map +1 -1
- package/dist/data-grid/data-grid.js +1 -1
- package/dist/data-grid/data-grid.js.map +1 -1
- package/dist/data-grid/sortable.js +1 -1
- package/dist/data-grid/sortable.js.map +1 -1
- package/dist/data-grid/use-data-grid-undo-redo.js +2 -2
- package/dist/data-grid/use-data-grid-undo-redo.js.map +1 -1
- package/dist/data-grid/use-data-grid.js +3 -3
- package/dist/data-grid/use-data-grid.js.map +1 -1
- package/dist/index.d.ts +31 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/compose-refs.js.map +1 -0
- package/dist/lib/use-as-ref.js.map +1 -0
- package/dist/lib/use-is-mobile.d.ts +10 -0
- package/dist/lib/use-is-mobile.js +21 -0
- package/dist/lib/use-is-mobile.js.map +1 -0
- package/dist/lib/use-isomorphic-layout-effect.js.map +1 -0
- package/dist/lib/use-lazy-ref.js.map +1 -0
- package/dist/lib/visually-hidden-input.d.ts +12 -0
- package/dist/lib/visually-hidden-input.js +105 -0
- package/dist/lib/visually-hidden-input.js.map +1 -0
- package/package.json +5 -1
- package/styles.css +19 -0
- package/dist/data-grid/compose-refs.js.map +0 -1
- package/dist/data-grid/use-as-ref.js.map +0 -1
- package/dist/data-grid/use-isomorphic-layout-effect.js.map +0 -1
- package/dist/data-grid/use-lazy-ref.js.map +0 -1
- /package/dist/{data-grid → lib}/compose-refs.d.ts +0 -0
- /package/dist/{data-grid → lib}/compose-refs.js +0 -0
- /package/dist/{data-grid → lib}/use-as-ref.d.ts +0 -0
- /package/dist/{data-grid → lib}/use-as-ref.js +0 -0
- /package/dist/{data-grid → lib}/use-isomorphic-layout-effect.d.ts +0 -0
- /package/dist/{data-grid → lib}/use-isomorphic-layout-effect.js +0 -0
- /package/dist/{data-grid → lib}/use-lazy-ref.d.ts +0 -0
- /package/dist/{data-grid → lib}/use-lazy-ref.js +0 -0
|
@@ -0,0 +1,787 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import {
|
|
4
|
+
closestCenter,
|
|
5
|
+
closestCorners,
|
|
6
|
+
DndContext,
|
|
7
|
+
DragOverlay,
|
|
8
|
+
defaultDropAnimationSideEffects,
|
|
9
|
+
getFirstCollision,
|
|
10
|
+
KeyboardCode,
|
|
11
|
+
KeyboardSensor,
|
|
12
|
+
MeasuringStrategy,
|
|
13
|
+
MouseSensor,
|
|
14
|
+
pointerWithin,
|
|
15
|
+
rectIntersection,
|
|
16
|
+
TouchSensor,
|
|
17
|
+
useSensor,
|
|
18
|
+
useSensors
|
|
19
|
+
} from "@dnd-kit/core";
|
|
20
|
+
import {
|
|
21
|
+
arrayMove,
|
|
22
|
+
defaultAnimateLayoutChanges,
|
|
23
|
+
horizontalListSortingStrategy,
|
|
24
|
+
SortableContext,
|
|
25
|
+
useSortable,
|
|
26
|
+
verticalListSortingStrategy
|
|
27
|
+
} from "@dnd-kit/sortable";
|
|
28
|
+
import { CSS, isKeyboardEvent } from "@dnd-kit/utilities";
|
|
29
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
30
|
+
import * as React from "react";
|
|
31
|
+
import * as ReactDOM from "react-dom";
|
|
32
|
+
import { cn } from "../../lib/cn.js";
|
|
33
|
+
import { useComposedRefs } from "../../lib/compose-refs.js";
|
|
34
|
+
import { useIsomorphicLayoutEffect } from "../../lib/use-isomorphic-layout-effect.js";
|
|
35
|
+
import { DEFAULT_KANBAN_LABELS } from "./kanban-constants.js";
|
|
36
|
+
const directions = /* @__PURE__ */ new Set([KeyboardCode.Down, KeyboardCode.Right, KeyboardCode.Up, KeyboardCode.Left]);
|
|
37
|
+
function getIsDirectionCode(code) {
|
|
38
|
+
return directions.has(code);
|
|
39
|
+
}
|
|
40
|
+
const coordinateGetter = (event, { context }) => {
|
|
41
|
+
const { active, droppableRects, droppableContainers, collisionRect } = context;
|
|
42
|
+
if (getIsDirectionCode(event.code)) {
|
|
43
|
+
event.preventDefault();
|
|
44
|
+
if (!active || !collisionRect) return;
|
|
45
|
+
const filteredContainers = [];
|
|
46
|
+
for (const entry of droppableContainers.getEnabled()) {
|
|
47
|
+
if (!entry || entry?.disabled) continue;
|
|
48
|
+
const rect = droppableRects.get(entry.id);
|
|
49
|
+
if (!rect) continue;
|
|
50
|
+
const data = entry.data.current;
|
|
51
|
+
if (data) {
|
|
52
|
+
const { type, children } = data;
|
|
53
|
+
if (type === "container" && children?.length > 0) {
|
|
54
|
+
if (active.data.current?.type !== "container") {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
switch (event.code) {
|
|
60
|
+
case KeyboardCode.Down:
|
|
61
|
+
if (collisionRect.top < rect.top) {
|
|
62
|
+
filteredContainers.push(entry);
|
|
63
|
+
}
|
|
64
|
+
break;
|
|
65
|
+
case KeyboardCode.Up:
|
|
66
|
+
if (collisionRect.top > rect.top) {
|
|
67
|
+
filteredContainers.push(entry);
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
case KeyboardCode.Left:
|
|
71
|
+
if (collisionRect.left >= rect.left + rect.width) {
|
|
72
|
+
filteredContainers.push(entry);
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
case KeyboardCode.Right:
|
|
76
|
+
if (collisionRect.left + collisionRect.width <= rect.left) {
|
|
77
|
+
filteredContainers.push(entry);
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const collisions = closestCorners({
|
|
83
|
+
active,
|
|
84
|
+
collisionRect,
|
|
85
|
+
droppableRects,
|
|
86
|
+
droppableContainers: filteredContainers,
|
|
87
|
+
pointerCoordinates: null
|
|
88
|
+
});
|
|
89
|
+
const closestId = getFirstCollision(collisions, "id");
|
|
90
|
+
if (closestId != null) {
|
|
91
|
+
const newDroppable = droppableContainers.get(closestId);
|
|
92
|
+
const newNode = newDroppable?.node.current;
|
|
93
|
+
const newRect = newDroppable?.rect.current;
|
|
94
|
+
if (newNode && newRect) {
|
|
95
|
+
if (newDroppable.id === "placeholder") {
|
|
96
|
+
return {
|
|
97
|
+
x: newRect.left + (newRect.width - collisionRect.width) / 2,
|
|
98
|
+
y: newRect.top + (newRect.height - collisionRect.height) / 2
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (newDroppable.data.current?.type === "container") {
|
|
102
|
+
return {
|
|
103
|
+
x: newRect.left + 20,
|
|
104
|
+
y: newRect.top + 74
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
x: newRect.left,
|
|
109
|
+
y: newRect.top
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return void 0;
|
|
115
|
+
};
|
|
116
|
+
function isDragPrevented(event) {
|
|
117
|
+
return event.activatorEvent.defaultPrevented && !isKeyboardEvent(event.activatorEvent);
|
|
118
|
+
}
|
|
119
|
+
const ROOT_NAME = "Kanban";
|
|
120
|
+
const BOARD_NAME = "KanbanBoard";
|
|
121
|
+
const COLUMN_NAME = "KanbanColumn";
|
|
122
|
+
const COLUMN_HANDLE_NAME = "KanbanColumnHandle";
|
|
123
|
+
const ITEM_NAME = "KanbanItem";
|
|
124
|
+
const ITEM_HANDLE_NAME = "KanbanItemHandle";
|
|
125
|
+
const OVERLAY_NAME = "KanbanOverlay";
|
|
126
|
+
const KanbanContext = React.createContext(null);
|
|
127
|
+
function useKanbanContext(consumerName) {
|
|
128
|
+
const context = React.useContext(KanbanContext);
|
|
129
|
+
if (!context) {
|
|
130
|
+
throw new Error(`\`${consumerName}\` ph\u1EA3i n\u1EB1m b\xEAn trong \`${ROOT_NAME}\``);
|
|
131
|
+
}
|
|
132
|
+
return context;
|
|
133
|
+
}
|
|
134
|
+
function Kanban(props) {
|
|
135
|
+
const {
|
|
136
|
+
value,
|
|
137
|
+
onValueChange,
|
|
138
|
+
modifiers,
|
|
139
|
+
strategy = verticalListSortingStrategy,
|
|
140
|
+
orientation = "horizontal",
|
|
141
|
+
onMove,
|
|
142
|
+
getItemValue: getItemValueProp,
|
|
143
|
+
accessibility,
|
|
144
|
+
flatCursor = false,
|
|
145
|
+
labels: labelsProp,
|
|
146
|
+
...kanbanProps
|
|
147
|
+
} = props;
|
|
148
|
+
const id = React.useId();
|
|
149
|
+
const [activeId, setActiveId] = React.useState(null);
|
|
150
|
+
const lastOverIdRef = React.useRef(null);
|
|
151
|
+
const hasMovedRef = React.useRef(false);
|
|
152
|
+
const valueAtDragStartRef = React.useRef(null);
|
|
153
|
+
const sensors = useSensors(
|
|
154
|
+
useSensor(MouseSensor),
|
|
155
|
+
useSensor(TouchSensor),
|
|
156
|
+
useSensor(KeyboardSensor, {
|
|
157
|
+
coordinateGetter
|
|
158
|
+
})
|
|
159
|
+
);
|
|
160
|
+
const labels = React.useMemo(() => ({ ...DEFAULT_KANBAN_LABELS, ...labelsProp }), [labelsProp]);
|
|
161
|
+
const getItemValue = React.useCallback(
|
|
162
|
+
(item) => {
|
|
163
|
+
if (typeof item === "object" && !getItemValueProp) {
|
|
164
|
+
throw new Error("`getItemValue` l\xE0 b\u1EAFt bu\u1ED9c khi th\u1EBB l\xE0 object");
|
|
165
|
+
}
|
|
166
|
+
return getItemValueProp ? getItemValueProp(item) : item;
|
|
167
|
+
},
|
|
168
|
+
[getItemValueProp]
|
|
169
|
+
);
|
|
170
|
+
const getColumn = React.useCallback(
|
|
171
|
+
(targetId) => {
|
|
172
|
+
if (targetId in value) return targetId;
|
|
173
|
+
for (const [columnId, columnItems] of Object.entries(value)) {
|
|
174
|
+
if (columnItems.some((item) => getItemValue(item) === targetId)) {
|
|
175
|
+
return columnId;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return null;
|
|
179
|
+
},
|
|
180
|
+
[value, getItemValue]
|
|
181
|
+
);
|
|
182
|
+
const collisionDetection = React.useCallback(
|
|
183
|
+
(args) => {
|
|
184
|
+
if (activeId && activeId in value) {
|
|
185
|
+
return closestCenter({
|
|
186
|
+
...args,
|
|
187
|
+
droppableContainers: args.droppableContainers.filter((container) => container.id in value)
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
const pointerIntersections = pointerWithin(args);
|
|
191
|
+
const intersections = pointerIntersections.length > 0 ? pointerIntersections : rectIntersection(args);
|
|
192
|
+
let overId = getFirstCollision(intersections, "id");
|
|
193
|
+
if (!overId) {
|
|
194
|
+
if (hasMovedRef.current) {
|
|
195
|
+
lastOverIdRef.current = activeId;
|
|
196
|
+
}
|
|
197
|
+
return lastOverIdRef.current ? [{ id: lastOverIdRef.current }] : [];
|
|
198
|
+
}
|
|
199
|
+
if (overId in value) {
|
|
200
|
+
const containerItems = value[overId];
|
|
201
|
+
if (containerItems && containerItems.length > 0) {
|
|
202
|
+
const closestItem = closestCenter({
|
|
203
|
+
...args,
|
|
204
|
+
droppableContainers: args.droppableContainers.filter(
|
|
205
|
+
(container) => container.id !== overId && containerItems.some((item) => getItemValue(item) === container.id)
|
|
206
|
+
)
|
|
207
|
+
});
|
|
208
|
+
if (closestItem.length > 0) {
|
|
209
|
+
overId = closestItem[0]?.id ?? overId;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
lastOverIdRef.current = overId;
|
|
214
|
+
return [{ id: overId }];
|
|
215
|
+
},
|
|
216
|
+
[activeId, value, getItemValue]
|
|
217
|
+
);
|
|
218
|
+
const onDragStart = React.useCallback(
|
|
219
|
+
(event) => {
|
|
220
|
+
kanbanProps.onDragStart?.(event);
|
|
221
|
+
if (isDragPrevented(event)) return;
|
|
222
|
+
setActiveId(event.active.id);
|
|
223
|
+
valueAtDragStartRef.current = value;
|
|
224
|
+
},
|
|
225
|
+
[value, kanbanProps.onDragStart]
|
|
226
|
+
);
|
|
227
|
+
const onDragOver = React.useCallback(
|
|
228
|
+
(event) => {
|
|
229
|
+
kanbanProps.onDragOver?.(event);
|
|
230
|
+
if (isDragPrevented(event)) return;
|
|
231
|
+
const { active, over } = event;
|
|
232
|
+
if (!over) return;
|
|
233
|
+
const activeColumn = getColumn(active.id);
|
|
234
|
+
const overColumn = getColumn(over.id);
|
|
235
|
+
if (!activeColumn || !overColumn) return;
|
|
236
|
+
if (activeColumn === overColumn) {
|
|
237
|
+
const items = value[activeColumn];
|
|
238
|
+
if (!items) return;
|
|
239
|
+
const activeIndex = items.findIndex((item) => getItemValue(item) === active.id);
|
|
240
|
+
const overIndex = items.findIndex((item) => getItemValue(item) === over.id);
|
|
241
|
+
if (activeIndex !== overIndex) {
|
|
242
|
+
const newColumns = { ...value };
|
|
243
|
+
newColumns[activeColumn] = arrayMove(items, activeIndex, overIndex);
|
|
244
|
+
onValueChange?.(newColumns);
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
const activeItems = value[activeColumn];
|
|
248
|
+
const overItems = value[overColumn];
|
|
249
|
+
if (!activeItems || !overItems) return;
|
|
250
|
+
const activeIndex = activeItems.findIndex((item) => getItemValue(item) === active.id);
|
|
251
|
+
if (activeIndex === -1) return;
|
|
252
|
+
const activeItem = activeItems[activeIndex];
|
|
253
|
+
if (!activeItem) return;
|
|
254
|
+
const updatedItems = {
|
|
255
|
+
...value,
|
|
256
|
+
[activeColumn]: activeItems.filter((item) => getItemValue(item) !== active.id),
|
|
257
|
+
[overColumn]: [...overItems, activeItem]
|
|
258
|
+
};
|
|
259
|
+
onValueChange?.(updatedItems);
|
|
260
|
+
hasMovedRef.current = true;
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
[value, getColumn, getItemValue, onValueChange, kanbanProps.onDragOver]
|
|
264
|
+
);
|
|
265
|
+
const onDragEnd = React.useCallback(
|
|
266
|
+
(event) => {
|
|
267
|
+
kanbanProps.onDragEnd?.(event);
|
|
268
|
+
if (isDragPrevented(event)) return;
|
|
269
|
+
valueAtDragStartRef.current = null;
|
|
270
|
+
const { active, over } = event;
|
|
271
|
+
if (!over) {
|
|
272
|
+
setActiveId(null);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (active.id in value && over.id in value) {
|
|
276
|
+
const activeIndex = Object.keys(value).indexOf(active.id);
|
|
277
|
+
const overIndex = Object.keys(value).indexOf(over.id);
|
|
278
|
+
if (activeIndex !== overIndex) {
|
|
279
|
+
const orderedColumns = Object.keys(value);
|
|
280
|
+
const newOrder = arrayMove(orderedColumns, activeIndex, overIndex);
|
|
281
|
+
const newColumns = {};
|
|
282
|
+
for (const key of newOrder) {
|
|
283
|
+
const items = value[key];
|
|
284
|
+
if (items) {
|
|
285
|
+
newColumns[key] = items;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (onMove) {
|
|
289
|
+
onMove({ ...event, activeIndex, overIndex });
|
|
290
|
+
} else {
|
|
291
|
+
onValueChange?.(newColumns);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
} else {
|
|
295
|
+
const activeColumn = getColumn(active.id);
|
|
296
|
+
const overColumn = getColumn(over.id);
|
|
297
|
+
if (!activeColumn || !overColumn) {
|
|
298
|
+
setActiveId(null);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (activeColumn === overColumn) {
|
|
302
|
+
const items = value[activeColumn];
|
|
303
|
+
if (!items) {
|
|
304
|
+
setActiveId(null);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const activeIndex = items.findIndex((item) => getItemValue(item) === active.id);
|
|
308
|
+
const overIndex = items.findIndex((item) => getItemValue(item) === over.id);
|
|
309
|
+
if (activeIndex !== overIndex) {
|
|
310
|
+
const newColumns = { ...value };
|
|
311
|
+
newColumns[activeColumn] = arrayMove(items, activeIndex, overIndex);
|
|
312
|
+
if (onMove) {
|
|
313
|
+
onMove({
|
|
314
|
+
...event,
|
|
315
|
+
activeIndex,
|
|
316
|
+
overIndex
|
|
317
|
+
});
|
|
318
|
+
} else {
|
|
319
|
+
onValueChange?.(newColumns);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
setActiveId(null);
|
|
325
|
+
hasMovedRef.current = false;
|
|
326
|
+
},
|
|
327
|
+
[value, getColumn, getItemValue, onValueChange, onMove, kanbanProps.onDragEnd]
|
|
328
|
+
);
|
|
329
|
+
const onDragCancel = React.useCallback(
|
|
330
|
+
(event) => {
|
|
331
|
+
kanbanProps.onDragCancel?.(event);
|
|
332
|
+
if (isDragPrevented(event)) return;
|
|
333
|
+
const valueAtDragStart = valueAtDragStartRef.current;
|
|
334
|
+
valueAtDragStartRef.current = null;
|
|
335
|
+
if (valueAtDragStart && valueAtDragStart !== value) {
|
|
336
|
+
onValueChange?.(valueAtDragStart);
|
|
337
|
+
}
|
|
338
|
+
setActiveId(null);
|
|
339
|
+
hasMovedRef.current = false;
|
|
340
|
+
},
|
|
341
|
+
[value, onValueChange, kanbanProps.onDragCancel]
|
|
342
|
+
);
|
|
343
|
+
const announcements = React.useMemo(
|
|
344
|
+
() => ({
|
|
345
|
+
onDragStart({ active }) {
|
|
346
|
+
const isColumn = active.id in value;
|
|
347
|
+
const variant = isColumn ? "column" : "item";
|
|
348
|
+
const position = isColumn ? Object.keys(value).indexOf(active.id) + 1 : (() => {
|
|
349
|
+
const column = getColumn(active.id);
|
|
350
|
+
if (!column || !value[column]) return 1;
|
|
351
|
+
return value[column].findIndex((item) => getItemValue(item) === active.id) + 1;
|
|
352
|
+
})();
|
|
353
|
+
const total = isColumn ? Object.keys(value).length : (() => {
|
|
354
|
+
const column = getColumn(active.id);
|
|
355
|
+
return column ? value[column]?.length ?? 0 : 0;
|
|
356
|
+
})();
|
|
357
|
+
return labels.pickedUp({ variant, value: active.id, position, total });
|
|
358
|
+
},
|
|
359
|
+
onDragOver({ active, over }) {
|
|
360
|
+
if (!over) return;
|
|
361
|
+
const isColumn = active.id in value;
|
|
362
|
+
const variant = isColumn ? "column" : "item";
|
|
363
|
+
const position = isColumn ? Object.keys(value).indexOf(over.id) + 1 : (() => {
|
|
364
|
+
const column = getColumn(over.id);
|
|
365
|
+
if (!column || !value[column]) return 1;
|
|
366
|
+
return value[column].findIndex((item) => getItemValue(item) === over.id) + 1;
|
|
367
|
+
})();
|
|
368
|
+
const total = isColumn ? Object.keys(value).length : (() => {
|
|
369
|
+
const column = getColumn(over.id);
|
|
370
|
+
return column ? value[column]?.length ?? 0 : 0;
|
|
371
|
+
})();
|
|
372
|
+
const overColumn = getColumn(over.id);
|
|
373
|
+
const activeColumn = getColumn(active.id);
|
|
374
|
+
if (isColumn) {
|
|
375
|
+
return labels.moved({ variant, value: active.id, position, total });
|
|
376
|
+
}
|
|
377
|
+
if (activeColumn !== overColumn) {
|
|
378
|
+
return labels.moved({ variant, value: active.id, position, total, column: overColumn ?? void 0 });
|
|
379
|
+
}
|
|
380
|
+
return labels.moved({ variant, value: active.id, position, total });
|
|
381
|
+
},
|
|
382
|
+
onDragEnd({ active, over }) {
|
|
383
|
+
if (!over) return;
|
|
384
|
+
const isColumn = active.id in value;
|
|
385
|
+
const variant = isColumn ? "column" : "item";
|
|
386
|
+
const position = isColumn ? Object.keys(value).indexOf(over.id) + 1 : (() => {
|
|
387
|
+
const column = getColumn(over.id);
|
|
388
|
+
if (!column || !value[column]) return 1;
|
|
389
|
+
return value[column].findIndex((item) => getItemValue(item) === over.id) + 1;
|
|
390
|
+
})();
|
|
391
|
+
const total = isColumn ? Object.keys(value).length : (() => {
|
|
392
|
+
const column = getColumn(over.id);
|
|
393
|
+
return column ? value[column]?.length ?? 0 : 0;
|
|
394
|
+
})();
|
|
395
|
+
const overColumn = getColumn(over.id);
|
|
396
|
+
const activeColumn = getColumn(active.id);
|
|
397
|
+
if (isColumn) {
|
|
398
|
+
return labels.dropped({ variant, value: active.id, position, total });
|
|
399
|
+
}
|
|
400
|
+
if (activeColumn !== overColumn) {
|
|
401
|
+
return labels.dropped({ variant, value: active.id, position, total, column: overColumn ?? void 0 });
|
|
402
|
+
}
|
|
403
|
+
return labels.dropped({ variant, value: active.id, position, total });
|
|
404
|
+
},
|
|
405
|
+
onDragCancel({ active }) {
|
|
406
|
+
const isColumn = active.id in value;
|
|
407
|
+
return labels.cancelled({ variant: isColumn ? "column" : "item", value: active.id });
|
|
408
|
+
}
|
|
409
|
+
}),
|
|
410
|
+
[value, getColumn, getItemValue, labels]
|
|
411
|
+
);
|
|
412
|
+
const contextValue = React.useMemo(
|
|
413
|
+
() => ({
|
|
414
|
+
id,
|
|
415
|
+
items: value,
|
|
416
|
+
modifiers,
|
|
417
|
+
strategy,
|
|
418
|
+
orientation,
|
|
419
|
+
activeId,
|
|
420
|
+
setActiveId,
|
|
421
|
+
getItemValue,
|
|
422
|
+
flatCursor,
|
|
423
|
+
labels
|
|
424
|
+
}),
|
|
425
|
+
[id, value, activeId, modifiers, strategy, orientation, getItemValue, flatCursor, labels]
|
|
426
|
+
);
|
|
427
|
+
return /* @__PURE__ */ jsx(KanbanContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
|
|
428
|
+
DndContext,
|
|
429
|
+
{
|
|
430
|
+
collisionDetection,
|
|
431
|
+
modifiers,
|
|
432
|
+
sensors,
|
|
433
|
+
...kanbanProps,
|
|
434
|
+
id,
|
|
435
|
+
measuring: {
|
|
436
|
+
droppable: {
|
|
437
|
+
strategy: MeasuringStrategy.Always
|
|
438
|
+
}
|
|
439
|
+
},
|
|
440
|
+
onDragStart,
|
|
441
|
+
onDragOver,
|
|
442
|
+
onDragEnd,
|
|
443
|
+
onDragCancel,
|
|
444
|
+
accessibility: {
|
|
445
|
+
announcements,
|
|
446
|
+
screenReaderInstructions: {
|
|
447
|
+
draggable: labels.instructions
|
|
448
|
+
},
|
|
449
|
+
...accessibility
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
) });
|
|
453
|
+
}
|
|
454
|
+
const KanbanBoardContext = React.createContext(false);
|
|
455
|
+
function KanbanBoard(props) {
|
|
456
|
+
const { asChild, className, ref, ...boardProps } = props;
|
|
457
|
+
const context = useKanbanContext(BOARD_NAME);
|
|
458
|
+
const columns = React.useMemo(() => {
|
|
459
|
+
return Object.keys(context.items);
|
|
460
|
+
}, [context.items]);
|
|
461
|
+
const BoardPrimitive = asChild ? Slot : "div";
|
|
462
|
+
return /* @__PURE__ */ jsx(KanbanBoardContext.Provider, { value: true, children: /* @__PURE__ */ jsx(
|
|
463
|
+
SortableContext,
|
|
464
|
+
{
|
|
465
|
+
items: columns,
|
|
466
|
+
strategy: context.orientation === "horizontal" ? horizontalListSortingStrategy : verticalListSortingStrategy,
|
|
467
|
+
children: /* @__PURE__ */ jsx(
|
|
468
|
+
BoardPrimitive,
|
|
469
|
+
{
|
|
470
|
+
"aria-orientation": context.orientation,
|
|
471
|
+
"data-orientation": context.orientation,
|
|
472
|
+
"data-slot": "kanban-board",
|
|
473
|
+
...boardProps,
|
|
474
|
+
ref,
|
|
475
|
+
className: cn(
|
|
476
|
+
"flex size-full gap-4",
|
|
477
|
+
context.orientation === "horizontal" ? "flex-row" : "flex-col",
|
|
478
|
+
className
|
|
479
|
+
)
|
|
480
|
+
}
|
|
481
|
+
)
|
|
482
|
+
}
|
|
483
|
+
) });
|
|
484
|
+
}
|
|
485
|
+
const KanbanColumnContext = React.createContext(null);
|
|
486
|
+
function useKanbanColumnContext(consumerName) {
|
|
487
|
+
const context = React.useContext(KanbanColumnContext);
|
|
488
|
+
if (!context) {
|
|
489
|
+
throw new Error(`\`${consumerName}\` ph\u1EA3i n\u1EB1m b\xEAn trong \`${COLUMN_NAME}\``);
|
|
490
|
+
}
|
|
491
|
+
return context;
|
|
492
|
+
}
|
|
493
|
+
const animateLayoutChanges = (args) => defaultAnimateLayoutChanges({ ...args, wasDragging: true });
|
|
494
|
+
function KanbanColumn(props) {
|
|
495
|
+
const { value, asChild, asHandle, disabled, className, style, ref, ...columnProps } = props;
|
|
496
|
+
const id = React.useId();
|
|
497
|
+
const context = useKanbanContext(COLUMN_NAME);
|
|
498
|
+
const inBoard = React.useContext(KanbanBoardContext);
|
|
499
|
+
const inOverlay = React.useContext(KanbanOverlayContext);
|
|
500
|
+
if (!inBoard && !inOverlay) {
|
|
501
|
+
throw new Error(`\`${COLUMN_NAME}\` ph\u1EA3i n\u1EB1m b\xEAn trong \`${BOARD_NAME}\` ho\u1EB7c \`${OVERLAY_NAME}\``);
|
|
502
|
+
}
|
|
503
|
+
if (value === "") {
|
|
504
|
+
throw new Error(`\`value\` c\u1EE7a \`${COLUMN_NAME}\` kh\xF4ng \u0111\u01B0\u1EE3c l\xE0 chu\u1ED7i r\u1ED7ng`);
|
|
505
|
+
}
|
|
506
|
+
const { attributes, listeners, setNodeRef, setActivatorNodeRef, transform, transition, isDragging } = useSortable({
|
|
507
|
+
id: value,
|
|
508
|
+
disabled,
|
|
509
|
+
animateLayoutChanges,
|
|
510
|
+
// ⚠ Khác thượng nguồn: dnd-kit mặc định đọc vai trò là "sortable" (tiếng Anh).
|
|
511
|
+
attributes: { roleDescription: context.labels.columnRoleDescription }
|
|
512
|
+
});
|
|
513
|
+
const onNodeRefChange = React.useCallback(
|
|
514
|
+
(node) => {
|
|
515
|
+
if (disabled) return;
|
|
516
|
+
setNodeRef(node);
|
|
517
|
+
},
|
|
518
|
+
[disabled, setNodeRef]
|
|
519
|
+
);
|
|
520
|
+
const composedRef = useComposedRefs(ref, onNodeRefChange);
|
|
521
|
+
const composedStyle = React.useMemo(() => {
|
|
522
|
+
return {
|
|
523
|
+
transform: CSS.Transform.toString(transform),
|
|
524
|
+
transition,
|
|
525
|
+
...style
|
|
526
|
+
};
|
|
527
|
+
}, [transform, transition, style]);
|
|
528
|
+
const items = React.useMemo(() => {
|
|
529
|
+
const columnItems = context.items[value] ?? [];
|
|
530
|
+
return columnItems.map((item) => context.getItemValue(item));
|
|
531
|
+
}, [context.items, value, context.getItemValue]);
|
|
532
|
+
const columnContext = React.useMemo(
|
|
533
|
+
() => ({
|
|
534
|
+
id,
|
|
535
|
+
attributes,
|
|
536
|
+
listeners,
|
|
537
|
+
setActivatorNodeRef,
|
|
538
|
+
isDragging,
|
|
539
|
+
disabled
|
|
540
|
+
}),
|
|
541
|
+
[id, attributes, listeners, setActivatorNodeRef, isDragging, disabled]
|
|
542
|
+
);
|
|
543
|
+
const ColumnPrimitive = asChild ? Slot : "div";
|
|
544
|
+
return /* @__PURE__ */ jsx(KanbanColumnContext.Provider, { value: columnContext, children: /* @__PURE__ */ jsx(
|
|
545
|
+
SortableContext,
|
|
546
|
+
{
|
|
547
|
+
items,
|
|
548
|
+
strategy: context.orientation === "horizontal" ? horizontalListSortingStrategy : verticalListSortingStrategy,
|
|
549
|
+
children: /* @__PURE__ */ jsx(
|
|
550
|
+
ColumnPrimitive,
|
|
551
|
+
{
|
|
552
|
+
id,
|
|
553
|
+
"data-disabled": disabled ? "" : void 0,
|
|
554
|
+
"data-dragging": isDragging ? "" : void 0,
|
|
555
|
+
"data-slot": "kanban-column",
|
|
556
|
+
...columnProps,
|
|
557
|
+
...asHandle && !disabled ? attributes : {},
|
|
558
|
+
...asHandle && !disabled ? listeners : {},
|
|
559
|
+
ref: composedRef,
|
|
560
|
+
style: composedStyle,
|
|
561
|
+
className: cn(
|
|
562
|
+
/*
|
|
563
|
+
* ⚠ Khác thượng nguồn: `bg-zinc-100 dark:bg-zinc-900` là thang mặc định của Tailwind
|
|
564
|
+
* (cổng màu chặn) → `bg-muted`, tự lật theo theme. Khung cột là viền TRANG TRÍ (không
|
|
565
|
+
* bấm được, không mang trạng thái) nên `border-border` là đúng vai trò.
|
|
566
|
+
*/
|
|
567
|
+
"flex size-full flex-col gap-2 rounded-lg border border-border bg-muted p-2.5 aria-disabled:pointer-events-none aria-disabled:opacity-50",
|
|
568
|
+
{
|
|
569
|
+
"touch-none select-none": asHandle,
|
|
570
|
+
"cursor-default": context.flatCursor,
|
|
571
|
+
"data-dragging:cursor-grabbing": !context.flatCursor,
|
|
572
|
+
"cursor-grab": !isDragging && asHandle && !context.flatCursor,
|
|
573
|
+
"opacity-50": isDragging,
|
|
574
|
+
"pointer-events-none opacity-50": disabled,
|
|
575
|
+
// ⚠ Khác thượng nguồn: bản sao trong `KanbanOverlay` được nâng lên bằng bóng nổi.
|
|
576
|
+
"shadow-overlay": inOverlay
|
|
577
|
+
},
|
|
578
|
+
className
|
|
579
|
+
)
|
|
580
|
+
}
|
|
581
|
+
)
|
|
582
|
+
}
|
|
583
|
+
) });
|
|
584
|
+
}
|
|
585
|
+
function KanbanColumnHandle(props) {
|
|
586
|
+
const { asChild, disabled, className, ref, ...columnHandleProps } = props;
|
|
587
|
+
const context = useKanbanContext(COLUMN_HANDLE_NAME);
|
|
588
|
+
const columnContext = useKanbanColumnContext(COLUMN_HANDLE_NAME);
|
|
589
|
+
const isDisabled = disabled ?? columnContext.disabled;
|
|
590
|
+
const { setActivatorNodeRef } = columnContext;
|
|
591
|
+
const onActivatorNodeRef = React.useCallback(
|
|
592
|
+
(node) => {
|
|
593
|
+
if (isDisabled) return;
|
|
594
|
+
setActivatorNodeRef(node);
|
|
595
|
+
},
|
|
596
|
+
[isDisabled, setActivatorNodeRef]
|
|
597
|
+
);
|
|
598
|
+
const composedRef = useComposedRefs(ref, onActivatorNodeRef);
|
|
599
|
+
const HandlePrimitive = asChild ? Slot : "button";
|
|
600
|
+
return /* @__PURE__ */ jsx(
|
|
601
|
+
HandlePrimitive,
|
|
602
|
+
{
|
|
603
|
+
type: "button",
|
|
604
|
+
"aria-label": context.labels.columnHandleLabel,
|
|
605
|
+
"aria-controls": columnContext.id,
|
|
606
|
+
"data-disabled": isDisabled ? "" : void 0,
|
|
607
|
+
"data-dragging": columnContext.isDragging ? "" : void 0,
|
|
608
|
+
"data-slot": "kanban-column-handle",
|
|
609
|
+
...columnHandleProps,
|
|
610
|
+
...isDisabled ? {} : columnContext.attributes,
|
|
611
|
+
...isDisabled ? {} : columnContext.listeners,
|
|
612
|
+
ref: composedRef,
|
|
613
|
+
className: cn(
|
|
614
|
+
"select-none disabled:pointer-events-none disabled:opacity-50",
|
|
615
|
+
context.flatCursor ? "cursor-default" : "cursor-grab data-dragging:cursor-grabbing",
|
|
616
|
+
className
|
|
617
|
+
),
|
|
618
|
+
disabled: isDisabled
|
|
619
|
+
}
|
|
620
|
+
);
|
|
621
|
+
}
|
|
622
|
+
const KanbanItemContext = React.createContext(null);
|
|
623
|
+
function useKanbanItemContext(consumerName) {
|
|
624
|
+
const context = React.useContext(KanbanItemContext);
|
|
625
|
+
if (!context) {
|
|
626
|
+
throw new Error(`\`${consumerName}\` ph\u1EA3i n\u1EB1m b\xEAn trong \`${ITEM_NAME}\``);
|
|
627
|
+
}
|
|
628
|
+
return context;
|
|
629
|
+
}
|
|
630
|
+
function KanbanItem(props) {
|
|
631
|
+
const { value, style, asHandle, asChild, disabled, className, ref, ...itemProps } = props;
|
|
632
|
+
const id = React.useId();
|
|
633
|
+
const context = useKanbanContext(ITEM_NAME);
|
|
634
|
+
const inBoard = React.useContext(KanbanBoardContext);
|
|
635
|
+
const inOverlay = React.useContext(KanbanOverlayContext);
|
|
636
|
+
if (!inBoard && !inOverlay) {
|
|
637
|
+
throw new Error(`\`${ITEM_NAME}\` ph\u1EA3i n\u1EB1m b\xEAn trong \`${BOARD_NAME}\``);
|
|
638
|
+
}
|
|
639
|
+
const { attributes, listeners, setNodeRef, setActivatorNodeRef, transform, transition, isDragging } = useSortable({
|
|
640
|
+
id: value,
|
|
641
|
+
disabled,
|
|
642
|
+
// ⚠ Khác thượng nguồn: dnd-kit mặc định đọc vai trò là "sortable" (tiếng Anh).
|
|
643
|
+
attributes: { roleDescription: context.labels.itemRoleDescription }
|
|
644
|
+
});
|
|
645
|
+
if (value === "") {
|
|
646
|
+
throw new Error(`\`value\` c\u1EE7a \`${ITEM_NAME}\` kh\xF4ng \u0111\u01B0\u1EE3c l\xE0 chu\u1ED7i r\u1ED7ng`);
|
|
647
|
+
}
|
|
648
|
+
const onNodeRef = React.useCallback(
|
|
649
|
+
(node) => {
|
|
650
|
+
if (disabled) return;
|
|
651
|
+
setNodeRef(node);
|
|
652
|
+
},
|
|
653
|
+
[disabled, setNodeRef]
|
|
654
|
+
);
|
|
655
|
+
const composedRef = useComposedRefs(ref, onNodeRef);
|
|
656
|
+
const composedStyle = React.useMemo(() => {
|
|
657
|
+
return {
|
|
658
|
+
transform: CSS.Transform.toString(transform),
|
|
659
|
+
transition,
|
|
660
|
+
...style
|
|
661
|
+
};
|
|
662
|
+
}, [transform, transition, style]);
|
|
663
|
+
const itemContext = React.useMemo(
|
|
664
|
+
() => ({
|
|
665
|
+
id,
|
|
666
|
+
attributes,
|
|
667
|
+
listeners,
|
|
668
|
+
setActivatorNodeRef,
|
|
669
|
+
isDragging,
|
|
670
|
+
disabled
|
|
671
|
+
}),
|
|
672
|
+
[id, attributes, listeners, setActivatorNodeRef, isDragging, disabled]
|
|
673
|
+
);
|
|
674
|
+
const ItemPrimitive = asChild ? Slot : "div";
|
|
675
|
+
return /* @__PURE__ */ jsx(KanbanItemContext.Provider, { value: itemContext, children: /* @__PURE__ */ jsx(
|
|
676
|
+
ItemPrimitive,
|
|
677
|
+
{
|
|
678
|
+
id,
|
|
679
|
+
"data-disabled": disabled ? "" : void 0,
|
|
680
|
+
"data-dragging": isDragging ? "" : void 0,
|
|
681
|
+
"data-slot": "kanban-item",
|
|
682
|
+
...itemProps,
|
|
683
|
+
...asHandle && !disabled ? attributes : {},
|
|
684
|
+
...asHandle && !disabled ? listeners : {},
|
|
685
|
+
ref: composedRef,
|
|
686
|
+
style: composedStyle,
|
|
687
|
+
className: cn(
|
|
688
|
+
// Viền focus cùng khuôn với `Checkbox`/`RadioGroup` của gói.
|
|
689
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
690
|
+
{
|
|
691
|
+
"touch-none select-none": asHandle,
|
|
692
|
+
"cursor-default": context.flatCursor,
|
|
693
|
+
"data-dragging:cursor-grabbing": !context.flatCursor,
|
|
694
|
+
"cursor-grab": !isDragging && asHandle && !context.flatCursor,
|
|
695
|
+
"opacity-50": isDragging,
|
|
696
|
+
"pointer-events-none opacity-50": disabled,
|
|
697
|
+
// ⚠ Khác thượng nguồn: bản sao trong `KanbanOverlay` được nâng lên bằng bóng nổi.
|
|
698
|
+
// Bóng theo bo góc của CHÍNH phần tử — dùng `asChild` lên thẻ để bóng ôm đúng góc.
|
|
699
|
+
"shadow-overlay": inOverlay
|
|
700
|
+
},
|
|
701
|
+
className
|
|
702
|
+
)
|
|
703
|
+
}
|
|
704
|
+
) });
|
|
705
|
+
}
|
|
706
|
+
function KanbanItemHandle(props) {
|
|
707
|
+
const { asChild, disabled, className, ref, ...itemHandleProps } = props;
|
|
708
|
+
const context = useKanbanContext(ITEM_HANDLE_NAME);
|
|
709
|
+
const itemContext = useKanbanItemContext(ITEM_HANDLE_NAME);
|
|
710
|
+
const isDisabled = disabled ?? itemContext.disabled;
|
|
711
|
+
const { setActivatorNodeRef } = itemContext;
|
|
712
|
+
const onActivatorNodeRef = React.useCallback(
|
|
713
|
+
(node) => {
|
|
714
|
+
if (isDisabled) return;
|
|
715
|
+
setActivatorNodeRef(node);
|
|
716
|
+
},
|
|
717
|
+
[isDisabled, setActivatorNodeRef]
|
|
718
|
+
);
|
|
719
|
+
const composedRef = useComposedRefs(ref, onActivatorNodeRef);
|
|
720
|
+
const HandlePrimitive = asChild ? Slot : "button";
|
|
721
|
+
return /* @__PURE__ */ jsx(
|
|
722
|
+
HandlePrimitive,
|
|
723
|
+
{
|
|
724
|
+
type: "button",
|
|
725
|
+
"aria-label": context.labels.itemHandleLabel,
|
|
726
|
+
"aria-controls": itemContext.id,
|
|
727
|
+
"data-disabled": isDisabled ? "" : void 0,
|
|
728
|
+
"data-dragging": itemContext.isDragging ? "" : void 0,
|
|
729
|
+
"data-slot": "kanban-item-handle",
|
|
730
|
+
...itemHandleProps,
|
|
731
|
+
...isDisabled ? {} : itemContext.attributes,
|
|
732
|
+
...isDisabled ? {} : itemContext.listeners,
|
|
733
|
+
ref: composedRef,
|
|
734
|
+
className: cn(
|
|
735
|
+
"select-none disabled:pointer-events-none disabled:opacity-50",
|
|
736
|
+
context.flatCursor ? "cursor-default" : "cursor-grab data-dragging:cursor-grabbing",
|
|
737
|
+
className
|
|
738
|
+
),
|
|
739
|
+
disabled: isDisabled
|
|
740
|
+
}
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
const KanbanOverlayContext = React.createContext(false);
|
|
744
|
+
const dropAnimation = {
|
|
745
|
+
sideEffects: defaultDropAnimationSideEffects({
|
|
746
|
+
styles: {
|
|
747
|
+
active: {
|
|
748
|
+
opacity: "0.4"
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
})
|
|
752
|
+
};
|
|
753
|
+
function KanbanOverlay(props) {
|
|
754
|
+
const { container: containerProp, children, ...overlayProps } = props;
|
|
755
|
+
const context = useKanbanContext(OVERLAY_NAME);
|
|
756
|
+
const [mounted, setMounted] = React.useState(false);
|
|
757
|
+
useIsomorphicLayoutEffect(() => setMounted(true), []);
|
|
758
|
+
const container = containerProp ?? (mounted ? globalThis.document?.body : null);
|
|
759
|
+
if (!container) return null;
|
|
760
|
+
const variant = context.activeId && context.activeId in context.items ? "column" : "item";
|
|
761
|
+
return ReactDOM.createPortal(
|
|
762
|
+
/* @__PURE__ */ jsx(
|
|
763
|
+
DragOverlay,
|
|
764
|
+
{
|
|
765
|
+
dropAnimation,
|
|
766
|
+
modifiers: context.modifiers,
|
|
767
|
+
className: cn(!context.flatCursor && "cursor-grabbing"),
|
|
768
|
+
...overlayProps,
|
|
769
|
+
children: /* @__PURE__ */ jsx(KanbanOverlayContext.Provider, { value: true, children: context.activeId && children ? typeof children === "function" ? children({
|
|
770
|
+
value: context.activeId,
|
|
771
|
+
variant
|
|
772
|
+
}) : children : null })
|
|
773
|
+
}
|
|
774
|
+
),
|
|
775
|
+
container
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
export {
|
|
779
|
+
Kanban,
|
|
780
|
+
KanbanBoard,
|
|
781
|
+
KanbanColumn,
|
|
782
|
+
KanbanColumnHandle,
|
|
783
|
+
KanbanItem,
|
|
784
|
+
KanbanItemHandle,
|
|
785
|
+
KanbanOverlay
|
|
786
|
+
};
|
|
787
|
+
//# sourceMappingURL=kanban.js.map
|