@rebasepro/ui 0.17.3 → 0.18.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/README.md +4 -0
- package/dist/components/MultiSelect.d.ts +10 -0
- package/dist/index.es.js +2 -1
- package/dist/index.es.js.map +1 -1
- package/package.json +32 -23
- package/src/components/Alert.tsx +0 -118
- package/src/components/Autocomplete.tsx +0 -93
- package/src/components/Avatar.tsx +0 -73
- package/src/components/Badge.tsx +0 -44
- package/src/components/BooleanSwitch.tsx +0 -116
- package/src/components/BooleanSwitchWithLabel.tsx +0 -120
- package/src/components/Button.tsx +0 -110
- package/src/components/Card.tsx +0 -43
- package/src/components/CenteredView.tsx +0 -35
- package/src/components/Checkbox.tsx +0 -129
- package/src/components/Chip.tsx +0 -131
- package/src/components/CircularProgress.tsx +0 -53
- package/src/components/CircularProgressCenter.tsx +0 -27
- package/src/components/Collapse.tsx +0 -66
- package/src/components/ColorPicker.tsx +0 -140
- package/src/components/Container.tsx +0 -51
- package/src/components/DateTimeField.tsx +0 -363
- package/src/components/DebouncedTextField.tsx +0 -76
- package/src/components/Dialog.tsx +0 -159
- package/src/components/DialogActions.tsx +0 -29
- package/src/components/DialogContent.tsx +0 -27
- package/src/components/DialogTitle.tsx +0 -41
- package/src/components/ErrorBoundary.tsx +0 -236
- package/src/components/ExpandablePanel.tsx +0 -130
- package/src/components/FileUpload.tsx +0 -103
- package/src/components/FilterChip.tsx +0 -89
- package/src/components/IconButton.tsx +0 -101
- package/src/components/InfoLabel.tsx +0 -23
- package/src/components/InputLabel.tsx +0 -40
- package/src/components/Label.tsx +0 -32
- package/src/components/LoadingButton.tsx +0 -32
- package/src/components/Markdown.tsx +0 -55
- package/src/components/Menu.tsx +0 -114
- package/src/components/Menubar.tsx +0 -355
- package/src/components/MultiSelect.tsx +0 -433
- package/src/components/Paper.tsx +0 -23
- package/src/components/Popover.tsx +0 -162
- package/src/components/RadioGroup.tsx +0 -74
- package/src/components/ResizablePanels.tsx +0 -189
- package/src/components/SearchBar.tsx +0 -136
- package/src/components/Select.tsx +0 -326
- package/src/components/Separator.tsx +0 -28
- package/src/components/Sheet.tsx +0 -135
- package/src/components/Skeleton.tsx +0 -54
- package/src/components/Slider.tsx +0 -110
- package/src/components/Table.tsx +0 -178
- package/src/components/Tabs.tsx +0 -185
- package/src/components/TextField.tsx +0 -270
- package/src/components/TextareaAutosize.tsx +0 -368
- package/src/components/ToggleButtonGroup.tsx +0 -69
- package/src/components/Tooltip.tsx +0 -153
- package/src/components/Typography.tsx +0 -132
- package/src/components/VirtualTable/VirtualTable.performance.test.tsx +0 -90
- package/src/components/VirtualTable/VirtualTable.tsx +0 -700
- package/src/components/VirtualTable/VirtualTableCell.tsx +0 -59
- package/src/components/VirtualTable/VirtualTableHeader.tsx +0 -327
- package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +0 -250
- package/src/components/VirtualTable/VirtualTableProps.tsx +0 -339
- package/src/components/VirtualTable/VirtualTableRow.tsx +0 -51
- package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +0 -44
- package/src/components/VirtualTable/fields/VirtualTableInput.tsx +0 -89
- package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +0 -71
- package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +0 -107
- package/src/components/VirtualTable/fields/VirtualTableSwitch.tsx +0 -28
- package/src/components/VirtualTable/index.tsx +0 -10
- package/src/components/VirtualTable/selection/SelectionContext.tsx +0 -36
- package/src/components/VirtualTable/selection/SelectionStore.ts +0 -54
- package/src/components/VirtualTable/types.tsx +0 -47
- package/src/components/common/SelectInputLabel.tsx +0 -23
- package/src/components/index.tsx +0 -62
- package/src/hooks/PortalContainerContext.tsx +0 -50
- package/src/hooks/index.ts +0 -7
- package/src/hooks/useDebounceCallback.tsx +0 -21
- package/src/hooks/useDebounceValue.tsx +0 -20
- package/src/hooks/useDebouncedCallback.ts +0 -39
- package/src/hooks/useInjectStyles.tsx +0 -31
- package/src/hooks/useOutsideAlerter.tsx +0 -46
- package/src/icons/GitHubIcon.tsx +0 -21
- package/src/icons/HandleIcon.tsx +0 -23
- package/src/icons/Icon.tsx +0 -33
- package/src/icons/LucideIconByName.tsx +0 -117
- package/src/icons/cool_icon_keys.ts +0 -12
- package/src/icons/icon_keys.ts +0 -1936
- package/src/icons/index.ts +0 -179
- package/src/index.css +0 -169
- package/src/index.ts +0 -47
- package/src/scripts/fixIconSizes.cjs +0 -92
- package/src/scripts/fixIconSizesToConst.cjs +0 -106
- package/src/scripts/generateIconKeys.ts +0 -41
- package/src/scripts/generateIcons.ts +0 -4
- package/src/scripts/saveIconFiles.ts +0 -89
- package/src/styles.ts +0 -141
- package/src/theme.css +0 -168
- package/src/util/chip_colors.ts +0 -242
- package/src/util/cls.ts +0 -8
- package/src/util/debounce.ts +0 -28
- package/src/util/hash.ts +0 -11
- package/src/util/index.ts +0 -4
- package/src/util/key_to_icon_component.ts +0 -11
- package/src/util/lazy_chunk.ts +0 -101
- package/src/views/CardView.tsx +0 -281
- package/src/views/CollectionView/CollectionCardView.tsx +0 -265
- package/src/views/CollectionView/CollectionKanbanView.tsx +0 -246
- package/src/views/CollectionView/CollectionListView.tsx +0 -240
- package/src/views/CollectionView/CollectionTableView.tsx +0 -229
- package/src/views/CollectionView/CollectionView.tsx +0 -450
- package/src/views/CollectionView/CollectionViewToolbar.tsx +0 -242
- package/src/views/CollectionView/CollectionViewTypes.ts +0 -181
- package/src/views/CollectionView/DefaultCellRenderer.tsx +0 -404
- package/src/views/CollectionView/index.ts +0 -39
- package/src/views/CollectionView/resolveTitleProperty.ts +0 -52
- package/src/views/CollectionView/utils.ts +0 -14
- package/src/views/Kanban/Board.tsx +0 -384
- package/src/views/Kanban/BoardColumn.tsx +0 -138
- package/src/views/Kanban/BoardColumnTitle.tsx +0 -47
- package/src/views/Kanban/BoardSortableList.tsx +0 -182
- package/src/views/Kanban/board_types.ts +0 -80
- package/src/views/Kanban/index.tsx +0 -5
- package/src/views/Kanban/placement.ts +0 -62
- package/src/views/KanbanView.tsx +0 -32
- package/src/views/ListView.tsx +0 -296
- package/src/views/index.ts +0 -5
|
@@ -1,384 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useState } from "react";
|
|
2
|
-
import { createPortal } from "react-dom";
|
|
3
|
-
import {
|
|
4
|
-
closestCorners,
|
|
5
|
-
DndContext,
|
|
6
|
-
DragEndEvent,
|
|
7
|
-
DragOverEvent,
|
|
8
|
-
DragOverlay,
|
|
9
|
-
DragStartEvent,
|
|
10
|
-
PointerSensor,
|
|
11
|
-
useSensor,
|
|
12
|
-
useSensors
|
|
13
|
-
} from "@dnd-kit/core";
|
|
14
|
-
import { arrayMove, SortableContext } from "@dnd-kit/sortable";
|
|
15
|
-
import { BoardColumn } from "./BoardColumn";
|
|
16
|
-
import { placeDroppedCard } from "./placement";
|
|
17
|
-
import { BoardItem, BoardItemMap, BoardProps } from "./board_types";
|
|
18
|
-
import { cls } from "../../util";
|
|
19
|
-
|
|
20
|
-
export function Board<T, COLUMN extends string>({
|
|
21
|
-
data,
|
|
22
|
-
columns: columnsProp,
|
|
23
|
-
columnLabels,
|
|
24
|
-
columnColors,
|
|
25
|
-
className,
|
|
26
|
-
assignColumn,
|
|
27
|
-
allowColumnReorder = false,
|
|
28
|
-
onColumnReorder,
|
|
29
|
-
onItemsReorder,
|
|
30
|
-
ItemComponent,
|
|
31
|
-
columnLoadingState,
|
|
32
|
-
onLoadMoreColumn,
|
|
33
|
-
onAddItemToColumn,
|
|
34
|
-
AddColumnComponent
|
|
35
|
-
}: BoardProps<T, COLUMN>) {
|
|
36
|
-
|
|
37
|
-
const [activeItem, setActiveItem] = useState<BoardItem<T> | null>(null);
|
|
38
|
-
const [isDragging, setIsDragging] = useState(false);
|
|
39
|
-
const [dragOverColumnId, setDragOverColumnId] = useState<string | null>(null);
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Which column the card was picked up from.
|
|
43
|
-
*
|
|
44
|
-
* `handleDragOver` moves the card between columns in `itemMapState` while
|
|
45
|
-
* the pointer is still down — that is what makes the gap open up under the
|
|
46
|
-
* cursor. So by the time the drop is handled, looking the card up by id
|
|
47
|
-
* finds it in its *destination*, and the board was reporting the move as
|
|
48
|
-
* source === target: a cross-column drop looked like a plain reorder and
|
|
49
|
-
* the column property was never written. The card snapped back on the next
|
|
50
|
-
* fetch.
|
|
51
|
-
*/
|
|
52
|
-
const dragSourceColumnRef = useRef<COLUMN | null>(null);
|
|
53
|
-
|
|
54
|
-
const [itemMapState, setItemMapState] = useState<BoardItemMap<T>>(() => {
|
|
55
|
-
const dataColumnMap: Record<string, COLUMN> = data.reduce((prev, item: BoardItem<T>) => ({
|
|
56
|
-
...prev,
|
|
57
|
-
[item.id]: assignColumn(item)
|
|
58
|
-
}), {});
|
|
59
|
-
return columnsProp.reduce(
|
|
60
|
-
(previous: BoardItemMap<T>, column: COLUMN) => ({
|
|
61
|
-
...previous,
|
|
62
|
-
[column]: data.filter((item: BoardItem<T>) => dataColumnMap[item.id] === column)
|
|
63
|
-
}),
|
|
64
|
-
{} as BoardItemMap<T>
|
|
65
|
-
);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
const sensors = useSensors(
|
|
69
|
-
useSensor(PointerSensor, {
|
|
70
|
-
activationConstraint: {
|
|
71
|
-
distance: 5
|
|
72
|
-
}
|
|
73
|
-
})
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
useEffect(() => {
|
|
77
|
-
if (isDragging) return;
|
|
78
|
-
|
|
79
|
-
const dataColumnMap: Record<string, COLUMN> = data.reduce((prev, item) => ({
|
|
80
|
-
...prev,
|
|
81
|
-
[item.id]: assignColumn(item)
|
|
82
|
-
}), {});
|
|
83
|
-
|
|
84
|
-
const newItemMap = columnsProp.reduce(
|
|
85
|
-
(previous: BoardItemMap<T>, column: COLUMN) => ({
|
|
86
|
-
...previous,
|
|
87
|
-
[column]: data.filter((item: BoardItem<T>) => dataColumnMap[item.id] === column)
|
|
88
|
-
}),
|
|
89
|
-
{} as BoardItemMap<T>
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
setItemMapState(prevMap => {
|
|
93
|
-
let changed = false;
|
|
94
|
-
|
|
95
|
-
for (const col of columnsProp) {
|
|
96
|
-
const prevItems = prevMap[col] ?? [];
|
|
97
|
-
const newItems = newItemMap[col] ?? [];
|
|
98
|
-
|
|
99
|
-
if (prevItems.length !== newItems.length) {
|
|
100
|
-
changed = true;
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
for (let i = 0; i < prevItems.length; i++) {
|
|
104
|
-
if (prevItems[i].id !== newItems[i].id || prevItems[i].data !== newItems[i].data) {
|
|
105
|
-
changed = true;
|
|
106
|
-
break;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (!changed) {
|
|
112
|
-
return prevMap;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const updated: BoardItemMap<T> = {};
|
|
116
|
-
for (const col of columnsProp) {
|
|
117
|
-
const prevItems = prevMap[col] ?? [];
|
|
118
|
-
const newItems = newItemMap[col] ?? [];
|
|
119
|
-
|
|
120
|
-
const prevById = new Map<string, BoardItem<T>>();
|
|
121
|
-
for (const item of prevItems) {
|
|
122
|
-
prevById.set(item.id, item);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
updated[col] = newItems.map(newItem => {
|
|
126
|
-
const prev = prevById.get(newItem.id);
|
|
127
|
-
if (prev && prev.data === newItem.data) {
|
|
128
|
-
return prev;
|
|
129
|
-
}
|
|
130
|
-
return newItem;
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
return updated;
|
|
134
|
-
});
|
|
135
|
-
}, [data, columnsProp, assignColumn]);
|
|
136
|
-
|
|
137
|
-
const findColumnByItemId = (id: string): string | undefined => {
|
|
138
|
-
return Object.keys(itemMapState).find(col => itemMapState[col]?.some(i => i.id === id));
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const handleDragStart = (event: DragStartEvent) => {
|
|
142
|
-
setIsDragging(true);
|
|
143
|
-
setDragOverColumnId(null);
|
|
144
|
-
const { active } = event;
|
|
145
|
-
|
|
146
|
-
if (active.data.current?.type === "ITEM") {
|
|
147
|
-
const columnId = findColumnByItemId(active.id as string);
|
|
148
|
-
dragSourceColumnRef.current = (columnId as COLUMN | undefined) ?? null;
|
|
149
|
-
if (columnId) {
|
|
150
|
-
const item = itemMapState[columnId]?.find(i => i.id === active.id);
|
|
151
|
-
setActiveItem(item || null);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
const handleDragOver = (event: DragOverEvent) => {
|
|
157
|
-
const {
|
|
158
|
-
active,
|
|
159
|
-
over
|
|
160
|
-
} = event;
|
|
161
|
-
|
|
162
|
-
if (!over) {
|
|
163
|
-
setDragOverColumnId(null);
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
let currentHoveredColumnId: string | null = null;
|
|
168
|
-
const overId = over.id as string;
|
|
169
|
-
const overDataType = over.data.current?.type as string | undefined;
|
|
170
|
-
|
|
171
|
-
if (overDataType === "ITEM-LIST" || overDataType === "COLUMN") {
|
|
172
|
-
currentHoveredColumnId = overId;
|
|
173
|
-
} else if (overDataType === "ITEM") {
|
|
174
|
-
currentHoveredColumnId = findColumnByItemId(overId) || null;
|
|
175
|
-
} else if (columnsProp.includes(overId as COLUMN)) {
|
|
176
|
-
currentHoveredColumnId = overId;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
setDragOverColumnId(currentHoveredColumnId);
|
|
180
|
-
|
|
181
|
-
if (active.data.current?.type !== "ITEM") {
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const activeId = active.id as string;
|
|
186
|
-
const activeItemColumn = findColumnByItemId(activeId);
|
|
187
|
-
let overColumnForMove = findColumnByItemId(overId);
|
|
188
|
-
|
|
189
|
-
if (!overColumnForMove && overDataType === "ITEM-LIST") {
|
|
190
|
-
overColumnForMove = overId;
|
|
191
|
-
}
|
|
192
|
-
if (!overColumnForMove && columnsProp.includes(overId as COLUMN)) {
|
|
193
|
-
overColumnForMove = overId;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (!activeItemColumn || !overColumnForMove) return;
|
|
197
|
-
if (activeItemColumn === overColumnForMove) return;
|
|
198
|
-
|
|
199
|
-
if (itemMapState[overColumnForMove]?.some(i => i.id === activeId)) {
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
setItemMapState(currentMap => {
|
|
204
|
-
const activeItems = [...(currentMap[activeItemColumn] || [])];
|
|
205
|
-
const overItems = [...(currentMap[overColumnForMove!] || [])];
|
|
206
|
-
const activeIndex = activeItems.findIndex(i => i.id === activeId);
|
|
207
|
-
|
|
208
|
-
if (activeIndex === -1) return currentMap;
|
|
209
|
-
|
|
210
|
-
let overIndex;
|
|
211
|
-
if (overDataType === "ITEM-LIST" || (columnsProp.includes(overId as COLUMN) && !findColumnByItemId(overId))) {
|
|
212
|
-
overIndex = overItems.length;
|
|
213
|
-
} else {
|
|
214
|
-
overIndex = overItems.findIndex(i => i.id === overId);
|
|
215
|
-
if (overIndex !== -1) {
|
|
216
|
-
const activeTop = active.rect.current.translated?.top ?? 0;
|
|
217
|
-
const activeHeight = active.rect.current.translated?.height ?? 0;
|
|
218
|
-
const activeCenter = activeTop + activeHeight / 2;
|
|
219
|
-
|
|
220
|
-
const overTop = over?.rect.top ?? 0;
|
|
221
|
-
const overHeight = over?.rect.height ?? 0;
|
|
222
|
-
const overCenter = overTop + overHeight / 2;
|
|
223
|
-
|
|
224
|
-
const isBelowOverItem = activeCenter > overCenter;
|
|
225
|
-
|
|
226
|
-
const modifier = isBelowOverItem ? 1 : 0;
|
|
227
|
-
overIndex = overIndex >= 0 ? overIndex + modifier : overItems.length;
|
|
228
|
-
} else {
|
|
229
|
-
overIndex = overItems.length;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const newItemMap = { ...currentMap };
|
|
234
|
-
const [moved] = activeItems.splice(activeIndex, 1);
|
|
235
|
-
overItems.splice(overIndex, 0, moved);
|
|
236
|
-
newItemMap[activeItemColumn] = activeItems;
|
|
237
|
-
newItemMap[overColumnForMove!] = overItems;
|
|
238
|
-
return newItemMap;
|
|
239
|
-
});
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
// Escape, or a drop outside the board. `handleDragOver` may already have
|
|
243
|
-
// moved the card between columns, so the next `data` effect has to be
|
|
244
|
-
// allowed to put it back.
|
|
245
|
-
const handleDragCancel = () => {
|
|
246
|
-
setIsDragging(false);
|
|
247
|
-
setActiveItem(null);
|
|
248
|
-
setDragOverColumnId(null);
|
|
249
|
-
dragSourceColumnRef.current = null;
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
const handleDragEnd = (event: DragEndEvent) => {
|
|
253
|
-
const {
|
|
254
|
-
active,
|
|
255
|
-
over
|
|
256
|
-
} = event;
|
|
257
|
-
|
|
258
|
-
const sourceColumn = dragSourceColumnRef.current;
|
|
259
|
-
|
|
260
|
-
setIsDragging(false);
|
|
261
|
-
setActiveItem(null);
|
|
262
|
-
setDragOverColumnId(null);
|
|
263
|
-
dragSourceColumnRef.current = null;
|
|
264
|
-
|
|
265
|
-
if (!over) return;
|
|
266
|
-
|
|
267
|
-
const activeId = active.id as string;
|
|
268
|
-
const overId = over.id as string;
|
|
269
|
-
|
|
270
|
-
if (active.data.current?.type === "COLUMN") {
|
|
271
|
-
if (activeId !== overId) {
|
|
272
|
-
const oldIndex = columnsProp.indexOf(activeId as COLUMN);
|
|
273
|
-
const newIndex = columnsProp.indexOf(overId as COLUMN);
|
|
274
|
-
if (oldIndex !== -1 && newIndex !== -1) {
|
|
275
|
-
const reordered = arrayMove(columnsProp, oldIndex, newIndex);
|
|
276
|
-
onColumnReorder?.(reordered);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Where the card sits right now — `handleDragOver` has already put it in
|
|
283
|
-
// the column being hovered, so this is the destination, not the origin.
|
|
284
|
-
const currentCol = findColumnByItemId(activeId) as COLUMN | undefined;
|
|
285
|
-
let targetCol = findColumnByItemId(overId) as COLUMN | undefined;
|
|
286
|
-
|
|
287
|
-
if (!targetCol) {
|
|
288
|
-
const overDataType = over.data.current?.type;
|
|
289
|
-
if (overDataType === "ITEM-LIST" || columnsProp.includes(overId as COLUMN)) {
|
|
290
|
-
targetCol = overId as COLUMN;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
targetCol = targetCol ?? currentCol;
|
|
294
|
-
|
|
295
|
-
if (!currentCol || !targetCol) return;
|
|
296
|
-
|
|
297
|
-
const targetItems = itemMapState[targetCol] || [];
|
|
298
|
-
const movedItem = (itemMapState[currentCol] || []).find(i => i.id === activeId);
|
|
299
|
-
if (!movedItem) return;
|
|
300
|
-
|
|
301
|
-
const finalTargetItems = placeDroppedCard({
|
|
302
|
-
targetItems,
|
|
303
|
-
movedItem,
|
|
304
|
-
overId,
|
|
305
|
-
changedColumn: (sourceColumn ?? currentCol) !== targetCol
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
onItemsReorder?.(finalTargetItems, {
|
|
309
|
-
itemId: activeId,
|
|
310
|
-
// The column the pointer went down in. `currentCol` would report a
|
|
311
|
-
// cross-column move as a same-column reorder.
|
|
312
|
-
sourceColumn: (sourceColumn ?? currentCol),
|
|
313
|
-
targetColumn: targetCol
|
|
314
|
-
});
|
|
315
|
-
};
|
|
316
|
-
|
|
317
|
-
return (
|
|
318
|
-
<DndContext
|
|
319
|
-
sensors={sensors}
|
|
320
|
-
// `rectIntersection`, the default, only reports a target while the
|
|
321
|
-
// dragged rect physically overlaps it, and prefers whichever
|
|
322
|
-
// overlap is largest — on a board of tall columns that means a card
|
|
323
|
-
// held over a gap reports nothing, and one held near a column edge
|
|
324
|
-
// reports the neighbour. `closestCorners` is the sortable-list
|
|
325
|
-
// recommendation and is what makes the drop land where it looks
|
|
326
|
-
// like it will.
|
|
327
|
-
collisionDetection={closestCorners}
|
|
328
|
-
onDragStart={handleDragStart}
|
|
329
|
-
onDragOver={handleDragOver}
|
|
330
|
-
onDragEnd={handleDragEnd}
|
|
331
|
-
onDragCancel={handleDragCancel}
|
|
332
|
-
>
|
|
333
|
-
<div className={cls("flex flex-row h-full w-full overflow-x-auto p-4 select-none items-start", className)}>
|
|
334
|
-
<SortableContext items={columnsProp}>
|
|
335
|
-
{columnsProp.map((col, index) => {
|
|
336
|
-
const colItems = itemMapState[col] || [];
|
|
337
|
-
const loadingState = columnLoadingState?.[col];
|
|
338
|
-
return (
|
|
339
|
-
<BoardColumn
|
|
340
|
-
key={String(col)}
|
|
341
|
-
id={String(col)}
|
|
342
|
-
title={columnLabels?.[col] ?? String(col)}
|
|
343
|
-
items={colItems}
|
|
344
|
-
index={index}
|
|
345
|
-
ItemComponent={ItemComponent}
|
|
346
|
-
isDragging={isDragging}
|
|
347
|
-
isDragOverColumn={dragOverColumnId === String(col)}
|
|
348
|
-
allowReorder={allowColumnReorder}
|
|
349
|
-
loading={loadingState?.loading}
|
|
350
|
-
hasMore={loadingState?.hasMore}
|
|
351
|
-
error={loadingState?.error}
|
|
352
|
-
totalCount={loadingState?.totalCount}
|
|
353
|
-
color={columnColors?.[col]}
|
|
354
|
-
onLoadMore={onLoadMoreColumn ? () => onLoadMoreColumn(col) : undefined}
|
|
355
|
-
onAddItem={onAddItemToColumn ? () => onAddItemToColumn(col) : undefined}
|
|
356
|
-
/>
|
|
357
|
-
);
|
|
358
|
-
})}
|
|
359
|
-
</SortableContext>
|
|
360
|
-
{AddColumnComponent}
|
|
361
|
-
</div>
|
|
362
|
-
|
|
363
|
-
{/* The overlay used to be positioned by hand, from `mousemove`
|
|
364
|
-
listeners on `window` and a grab offset measured off whatever
|
|
365
|
-
`[role='button']` the pointer went down on. dnd-kit already
|
|
366
|
-
tracks the pointer and already knows the grab offset — the
|
|
367
|
-
hand-rolled copy drifted from the position collision detection
|
|
368
|
-
was actually using, so the card you saw and the slot you got
|
|
369
|
-
were two different things. */}
|
|
370
|
-
{typeof document !== "undefined" && createPortal(
|
|
371
|
-
<DragOverlay dropAnimation={null} zIndex={9999}>
|
|
372
|
-
{activeItem && (
|
|
373
|
-
<ItemComponent
|
|
374
|
-
item={activeItem}
|
|
375
|
-
isDragging={true}
|
|
376
|
-
isClone={true}
|
|
377
|
-
/>
|
|
378
|
-
)}
|
|
379
|
-
</DragOverlay>,
|
|
380
|
-
document.body
|
|
381
|
-
)}
|
|
382
|
-
</DndContext>
|
|
383
|
-
);
|
|
384
|
-
}
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import React, { memo, useMemo } from "react";
|
|
2
|
-
import { SortableContext, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
|
3
|
-
import { CSS } from "@dnd-kit/utilities";
|
|
4
|
-
import { BoardSortableList } from "./BoardSortableList";
|
|
5
|
-
import { BoardColumnTitle } from "./BoardColumnTitle";
|
|
6
|
-
import { BoardItem, BoardItemViewProps } from "./board_types";
|
|
7
|
-
import {
|
|
8
|
-
IconButton
|
|
9
|
-
} from "../../components";
|
|
10
|
-
import { cls } from "../../util";
|
|
11
|
-
import { iconSize, PlusIcon } from "../../icons";
|
|
12
|
-
|
|
13
|
-
export interface BoardColumnProps<T> {
|
|
14
|
-
id: string;
|
|
15
|
-
title: string;
|
|
16
|
-
items: BoardItem<T>[];
|
|
17
|
-
index: number;
|
|
18
|
-
ItemComponent: React.ComponentType<BoardItemViewProps<T>>;
|
|
19
|
-
isDragging: boolean;
|
|
20
|
-
isDragOverColumn: boolean;
|
|
21
|
-
allowReorder?: boolean;
|
|
22
|
-
loading?: boolean;
|
|
23
|
-
hasMore?: boolean;
|
|
24
|
-
error?: Error;
|
|
25
|
-
onLoadMore?: () => void;
|
|
26
|
-
onAddItem?: () => void;
|
|
27
|
-
totalCount?: number;
|
|
28
|
-
color?: any;
|
|
29
|
-
style?: React.CSSProperties;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const BoardColumn = memo(function BoardColumn<T>({
|
|
33
|
-
id,
|
|
34
|
-
title,
|
|
35
|
-
items,
|
|
36
|
-
ItemComponent,
|
|
37
|
-
isDragging,
|
|
38
|
-
isDragOverColumn,
|
|
39
|
-
allowReorder = false,
|
|
40
|
-
loading = false,
|
|
41
|
-
hasMore = false,
|
|
42
|
-
error,
|
|
43
|
-
onLoadMore,
|
|
44
|
-
onAddItem,
|
|
45
|
-
totalCount,
|
|
46
|
-
color,
|
|
47
|
-
style
|
|
48
|
-
}: BoardColumnProps<T>) {
|
|
49
|
-
const {
|
|
50
|
-
setNodeRef,
|
|
51
|
-
attributes,
|
|
52
|
-
listeners,
|
|
53
|
-
isDragging: isColumnBeingDragged,
|
|
54
|
-
transform,
|
|
55
|
-
transition
|
|
56
|
-
} = useSortable({
|
|
57
|
-
id,
|
|
58
|
-
data: { type: "COLUMN" },
|
|
59
|
-
disabled: !allowReorder
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const combinedStyle = useMemo(() => ({
|
|
63
|
-
...style,
|
|
64
|
-
transform: CSS.Translate.toString(transform),
|
|
65
|
-
transition,
|
|
66
|
-
zIndex: isColumnBeingDragged ? 2 : 1
|
|
67
|
-
}), [style, transform, transition, isColumnBeingDragged]);
|
|
68
|
-
|
|
69
|
-
const dragListeners = allowReorder ? listeners : {};
|
|
70
|
-
|
|
71
|
-
const columnClassName = useMemo(() => cls(
|
|
72
|
-
"border h-full w-80 min-w-80 mx-2 flex flex-col rounded-md border-surface-200 dark:border-surface-800",
|
|
73
|
-
isColumnBeingDragged ? "ring-2 ring-primary" : ""
|
|
74
|
-
), [isColumnBeingDragged]);
|
|
75
|
-
|
|
76
|
-
const headerClassName = useMemo(() => cls(
|
|
77
|
-
"flex items-center justify-between px-2 rounded-t-md transition-colors duration-200 ease-in-out",
|
|
78
|
-
isColumnBeingDragged
|
|
79
|
-
? "bg-surface-100 dark:bg-surface-700"
|
|
80
|
-
: "bg-surface-50 hover:bg-surface-100 dark:bg-surface-800 dark:hover:bg-surface-700",
|
|
81
|
-
allowReorder ? "cursor-grab" : ""
|
|
82
|
-
), [isColumnBeingDragged, allowReorder]);
|
|
83
|
-
|
|
84
|
-
const itemIds = useMemo(() => items.map(i => i.id), [items]);
|
|
85
|
-
|
|
86
|
-
return (
|
|
87
|
-
<div
|
|
88
|
-
ref={setNodeRef}
|
|
89
|
-
style={combinedStyle}
|
|
90
|
-
{...attributes}
|
|
91
|
-
className={columnClassName}
|
|
92
|
-
>
|
|
93
|
-
<div
|
|
94
|
-
{...dragListeners}
|
|
95
|
-
className={headerClassName}
|
|
96
|
-
>
|
|
97
|
-
<div className="flex items-center gap-2">
|
|
98
|
-
<BoardColumnTitle aria-label={`${title} item list`} color={color}>
|
|
99
|
-
{title}
|
|
100
|
-
</BoardColumnTitle>
|
|
101
|
-
{totalCount !== undefined && (
|
|
102
|
-
<span className="text-xs text-surface-500 dark:text-surface-400">
|
|
103
|
-
{totalCount}
|
|
104
|
-
</span>
|
|
105
|
-
)}
|
|
106
|
-
</div>
|
|
107
|
-
{onAddItem && (
|
|
108
|
-
<IconButton
|
|
109
|
-
size="small"
|
|
110
|
-
onClick={(e: React.MouseEvent) => {
|
|
111
|
-
e.stopPropagation();
|
|
112
|
-
onAddItem();
|
|
113
|
-
}}
|
|
114
|
-
className="opacity-60 hover:opacity-100"
|
|
115
|
-
>
|
|
116
|
-
<PlusIcon size={iconSize.small}/>
|
|
117
|
-
</IconButton>
|
|
118
|
-
)}
|
|
119
|
-
</div>
|
|
120
|
-
<SortableContext
|
|
121
|
-
items={itemIds}
|
|
122
|
-
strategy={verticalListSortingStrategy}
|
|
123
|
-
>
|
|
124
|
-
<BoardSortableList
|
|
125
|
-
columnId={id}
|
|
126
|
-
items={items}
|
|
127
|
-
ItemComponent={ItemComponent}
|
|
128
|
-
isDragging={isDragging}
|
|
129
|
-
isDragOverColumn={isDragOverColumn}
|
|
130
|
-
loading={loading}
|
|
131
|
-
hasMore={hasMore}
|
|
132
|
-
error={error}
|
|
133
|
-
onLoadMore={onLoadMore}
|
|
134
|
-
/>
|
|
135
|
-
</SortableContext>
|
|
136
|
-
</div>
|
|
137
|
-
);
|
|
138
|
-
}) as <T>(props: BoardColumnProps<T>) => React.ReactElement;
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import React, { useMemo } from "react";
|
|
2
|
-
import { Typography } from "../../components";
|
|
3
|
-
import { cls, getColorSchemeForKey } from "../../util";
|
|
4
|
-
|
|
5
|
-
export interface BoardColumnTitleProps {
|
|
6
|
-
children: React.ReactNode;
|
|
7
|
-
className?: string;
|
|
8
|
-
"aria-label"?: string;
|
|
9
|
-
color?: any;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function BoardColumnTitle({
|
|
13
|
-
children,
|
|
14
|
-
className,
|
|
15
|
-
color,
|
|
16
|
-
...props
|
|
17
|
-
}: BoardColumnTitleProps) {
|
|
18
|
-
const colorScheme = useMemo(() => {
|
|
19
|
-
if (!color) return undefined;
|
|
20
|
-
if (typeof color === "string") {
|
|
21
|
-
return getColorSchemeForKey(color);
|
|
22
|
-
}
|
|
23
|
-
return color;
|
|
24
|
-
}, [color]);
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<Typography
|
|
28
|
-
variant="subtitle2"
|
|
29
|
-
component="h4"
|
|
30
|
-
className={
|
|
31
|
-
cls("py-3 px-3 transition-colors duration-200 flex-grow select-none relative outline-none focus:outline focus:outline-2 focus:outline-offset-2 flex items-center gap-3",
|
|
32
|
-
className)
|
|
33
|
-
}
|
|
34
|
-
{...props}
|
|
35
|
-
>
|
|
36
|
-
{colorScheme && (
|
|
37
|
-
<div
|
|
38
|
-
className="w-3 h-3 rounded-full flex-shrink-0"
|
|
39
|
-
style={{
|
|
40
|
-
backgroundColor: colorScheme.darkColor ?? colorScheme.color
|
|
41
|
-
}}
|
|
42
|
-
/>
|
|
43
|
-
)}
|
|
44
|
-
{children}
|
|
45
|
-
</Typography>
|
|
46
|
-
);
|
|
47
|
-
}
|