@moises.ai/design-system 3.10.7 → 3.10.9
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/dist/index.js +6636 -9767
- package/package.json +21 -5
- package/src/components/DataTable/DataTable.jsx +34 -15
- package/src/components/DataTable/DataTable.module.css +8 -0
- package/src/components/DataTable/DataTable.stories.jsx +8 -7
- package/src/components/DataTable/DataTableBody.jsx +2 -0
- package/src/components/DataTable/dnd/DataTableRowSortable.jsx +45 -0
- package/src/components/DataTable/dnd/useDataTableDnd.js +58 -0
- package/src/components/SetlistList/SetlistList.jsx +6 -0
- package/src/components/SetlistList/SetlistList.stories.jsx +35 -83
- package/src/components/ToastProvider/ToastProvider.module.css +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moises.ai/design-system",
|
|
3
|
-
"version": "3.10.
|
|
3
|
+
"version": "3.10.9",
|
|
4
4
|
"description": "Design System package based on @radix-ui/themes with custom defaults",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -36,10 +36,6 @@
|
|
|
36
36
|
"extract": "lingui extract"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@dnd-kit/core": "^6.3.1",
|
|
40
|
-
"@dnd-kit/modifiers": "^9.0.0",
|
|
41
|
-
"@dnd-kit/sortable": "^10.0.0",
|
|
42
|
-
"@dnd-kit/utilities": "^3.2.2",
|
|
43
39
|
"@radix-ui/react-icons": "1.3.2",
|
|
44
40
|
"@radix-ui/themes": "3.2.1",
|
|
45
41
|
"@wavesurfer/react": "^1.0.11",
|
|
@@ -47,10 +43,26 @@
|
|
|
47
43
|
"wavesurfer.js": "^7.11.1"
|
|
48
44
|
},
|
|
49
45
|
"peerDependencies": {
|
|
46
|
+
"@dnd-kit/core": "^6.3.1",
|
|
47
|
+
"@dnd-kit/modifiers": "^9.0.0",
|
|
48
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
49
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
50
50
|
"react": "^19.0.0",
|
|
51
51
|
"react-dom": "^19.0.0"
|
|
52
52
|
},
|
|
53
53
|
"peerDependenciesMeta": {
|
|
54
|
+
"@dnd-kit/core": {
|
|
55
|
+
"optional": false
|
|
56
|
+
},
|
|
57
|
+
"@dnd-kit/modifiers": {
|
|
58
|
+
"optional": false
|
|
59
|
+
},
|
|
60
|
+
"@dnd-kit/sortable": {
|
|
61
|
+
"optional": false
|
|
62
|
+
},
|
|
63
|
+
"@dnd-kit/utilities": {
|
|
64
|
+
"optional": false
|
|
65
|
+
},
|
|
54
66
|
"react": {
|
|
55
67
|
"optional": false
|
|
56
68
|
},
|
|
@@ -59,6 +71,10 @@
|
|
|
59
71
|
}
|
|
60
72
|
},
|
|
61
73
|
"devDependencies": {
|
|
74
|
+
"@dnd-kit/core": "^6.3.1",
|
|
75
|
+
"@dnd-kit/modifiers": "^9.0.0",
|
|
76
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
77
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
62
78
|
"@lingui/cli": "^5.6.0",
|
|
63
79
|
"@storybook/addon-essentials": "^8.6.14",
|
|
64
80
|
"@storybook/addon-interactions": "^8.6.14",
|
|
@@ -5,7 +5,7 @@ import { Table } from '../../index'
|
|
|
5
5
|
import styles from './DataTable.module.css'
|
|
6
6
|
import classNames from 'classnames'
|
|
7
7
|
import { DataTableDragOverlay } from './dnd/DataTableDragOverlay'
|
|
8
|
-
import { useDataTableDnd } from './dnd/useDataTableDnd'
|
|
8
|
+
import { useDataTableDnd, DataTableDndMonitor } from './dnd/useDataTableDnd'
|
|
9
9
|
import { resolveRowId, toDragRow } from './dnd/dataTableDnd.utils'
|
|
10
10
|
import { DataTableHeader } from './DataTableHeader'
|
|
11
11
|
import { DataTableBody } from './DataTableBody'
|
|
@@ -34,6 +34,7 @@ export const DataTable = ({
|
|
|
34
34
|
getDragPreviewCountLabel,
|
|
35
35
|
renderDragPreview,
|
|
36
36
|
renderDndContext = true,
|
|
37
|
+
dndScopeId,
|
|
37
38
|
...props
|
|
38
39
|
}) => {
|
|
39
40
|
const anchorRowIndexRef = useRef(null)
|
|
@@ -124,6 +125,7 @@ export const DataTable = ({
|
|
|
124
125
|
overDragRowId,
|
|
125
126
|
activeDragContext,
|
|
126
127
|
sortableItems,
|
|
128
|
+
monitorHandlers,
|
|
127
129
|
} = useDataTableDnd({
|
|
128
130
|
rows: normalizedRows,
|
|
129
131
|
selectedSet,
|
|
@@ -131,10 +133,13 @@ export const DataTable = ({
|
|
|
131
133
|
reorderable,
|
|
132
134
|
onReorder,
|
|
133
135
|
onRowDragStart,
|
|
134
|
-
onRowDragMove,
|
|
135
136
|
onRowDragEnd,
|
|
137
|
+
dndScopeId,
|
|
136
138
|
})
|
|
137
139
|
|
|
140
|
+
const monitorHandlersRef = useRef(monitorHandlers)
|
|
141
|
+
monitorHandlersRef.current = monitorHandlers
|
|
142
|
+
|
|
138
143
|
const { style, ...restProps } = props
|
|
139
144
|
const stickyOffsetValue =
|
|
140
145
|
typeof stickyOffset === 'number' ? `${stickyOffset}px` : stickyOffset
|
|
@@ -185,29 +190,43 @@ export const DataTable = ({
|
|
|
185
190
|
reorderable={reorderable}
|
|
186
191
|
activeDragRowId={activeDragRowId}
|
|
187
192
|
overDragRowId={overDragRowId}
|
|
193
|
+
dndScopeId={dndScopeId}
|
|
188
194
|
/>
|
|
189
195
|
</Table.Root>
|
|
190
196
|
)
|
|
191
197
|
|
|
198
|
+
const dragOverlay = (
|
|
199
|
+
<DragOverlay modifiers={[snapCenterToCursor]}>
|
|
200
|
+
{activeDragContext ? (
|
|
201
|
+
<div className={styles.dragOverlayContent}>
|
|
202
|
+
<DataTableDragOverlay
|
|
203
|
+
model={activeDragContext}
|
|
204
|
+
renderDragPreview={renderDragPreview}
|
|
205
|
+
getDragPreviewLabel={getDragPreviewLabel}
|
|
206
|
+
getDragPreviewCountLabel={getDragPreviewCountLabel}
|
|
207
|
+
/>
|
|
208
|
+
</div>
|
|
209
|
+
) : null}
|
|
210
|
+
</DragOverlay>
|
|
211
|
+
)
|
|
212
|
+
|
|
192
213
|
if (!renderDndContext) {
|
|
193
|
-
return
|
|
214
|
+
return (
|
|
215
|
+
<>
|
|
216
|
+
<DataTableDndMonitor
|
|
217
|
+
handlers={monitorHandlersRef}
|
|
218
|
+
dndScopeId={dndScopeId}
|
|
219
|
+
/>
|
|
220
|
+
{tableRoot}
|
|
221
|
+
{dragOverlay}
|
|
222
|
+
</>
|
|
223
|
+
)
|
|
194
224
|
}
|
|
195
225
|
|
|
196
226
|
return (
|
|
197
227
|
<DndContext {...dndContextProps}>
|
|
198
228
|
{tableRoot}
|
|
199
|
-
|
|
200
|
-
{activeDragContext ? (
|
|
201
|
-
<div className={styles.dragOverlayContent}>
|
|
202
|
-
<DataTableDragOverlay
|
|
203
|
-
model={activeDragContext}
|
|
204
|
-
renderDragPreview={renderDragPreview}
|
|
205
|
-
getDragPreviewLabel={getDragPreviewLabel}
|
|
206
|
-
getDragPreviewCountLabel={getDragPreviewCountLabel}
|
|
207
|
-
/>
|
|
208
|
-
</div>
|
|
209
|
-
) : null}
|
|
210
|
-
</DragOverlay>
|
|
229
|
+
{dragOverlay}
|
|
211
230
|
</DndContext>
|
|
212
231
|
)
|
|
213
232
|
}
|
|
@@ -137,6 +137,7 @@
|
|
|
137
137
|
|
|
138
138
|
.selectColumn {
|
|
139
139
|
cursor: pointer;
|
|
140
|
+
touch-action: manipulation;
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
.checkboxCell {
|
|
@@ -157,6 +158,12 @@
|
|
|
157
158
|
opacity: 1;
|
|
158
159
|
}
|
|
159
160
|
|
|
161
|
+
@media (pointer: coarse) {
|
|
162
|
+
.checkboxCell {
|
|
163
|
+
opacity: 1;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
160
167
|
.showCheckboxHeader,
|
|
161
168
|
.showCheckboxCell {
|
|
162
169
|
opacity: 1;
|
|
@@ -278,6 +285,7 @@
|
|
|
278
285
|
|
|
279
286
|
.projectCell:not(.dropdownColumn) {
|
|
280
287
|
cursor: pointer;
|
|
288
|
+
touch-action: manipulation;
|
|
281
289
|
}
|
|
282
290
|
|
|
283
291
|
.DataTable :global(.rt-TableRow:hover) .projectCell:not(.dropdownColumn) :not(.artistText) {
|
|
@@ -195,17 +195,17 @@ const auxHeaderTable = [
|
|
|
195
195
|
id: 'title',
|
|
196
196
|
label: 'Title',
|
|
197
197
|
sortable: true,
|
|
198
|
-
onClick: () => {},
|
|
198
|
+
onClick: () => { },
|
|
199
199
|
},
|
|
200
200
|
{
|
|
201
201
|
id: 'RECENT',
|
|
202
202
|
label: 'Created',
|
|
203
203
|
sortable: true,
|
|
204
|
-
onClick: () => {},
|
|
204
|
+
onClick: () => { },
|
|
205
205
|
},
|
|
206
|
-
{ id: 'BPM', label: 'BPM', onClick: () => {}, sortable: true },
|
|
207
|
-
{ id: 'KEY', label: 'Key', onClick: () => {}, sortable: true },
|
|
208
|
-
{ id: 'DURATION', label: 'Duration', onClick: () => {}, sortable: true },
|
|
206
|
+
{ id: 'BPM', label: 'BPM', onClick: () => { }, sortable: true },
|
|
207
|
+
{ id: 'KEY', label: 'Key', onClick: () => { }, sortable: true },
|
|
208
|
+
{ id: 'DURATION', label: 'Duration', onClick: () => { }, sortable: true },
|
|
209
209
|
]
|
|
210
210
|
|
|
211
211
|
const applyReorder = (rows, payload) => {
|
|
@@ -381,6 +381,7 @@ const SelectableTemplate = (args) => {
|
|
|
381
381
|
|
|
382
382
|
const handleClick = (row) => {
|
|
383
383
|
console.log('Row clicked:', row)
|
|
384
|
+
alert(`Row clicked: ${row.title}`)
|
|
384
385
|
}
|
|
385
386
|
|
|
386
387
|
const selectedFilesLabel =
|
|
@@ -601,8 +602,8 @@ export const Default = {
|
|
|
601
602
|
children: 'DataTable Component',
|
|
602
603
|
reorderable: false,
|
|
603
604
|
rowDraggable: true,
|
|
604
|
-
onSort: () => {},
|
|
605
|
-
onClick: () => {},
|
|
605
|
+
onSort: () => { },
|
|
606
|
+
onClick: () => { },
|
|
606
607
|
renderHeaderActions: ({ selectedCount, total }) => (
|
|
607
608
|
<>
|
|
608
609
|
<Button size="1" variant="soft" color="gray" disabled={!selectedCount}>
|
|
@@ -42,6 +42,7 @@ export const DataTableBody = ({
|
|
|
42
42
|
reorderable,
|
|
43
43
|
activeDragRowId,
|
|
44
44
|
overDragRowId,
|
|
45
|
+
dndScopeId,
|
|
45
46
|
}) => {
|
|
46
47
|
const totalColumns = columns.length + 1 + (hasDropdownOptions ? 1 : 0)
|
|
47
48
|
|
|
@@ -116,6 +117,7 @@ export const DataTableBody = ({
|
|
|
116
117
|
isDragOver={
|
|
117
118
|
reorderable && overDragRowId === row.id && activeDragRowId !== row.id
|
|
118
119
|
}
|
|
120
|
+
dndScopeId={dndScopeId}
|
|
119
121
|
/>
|
|
120
122
|
))}
|
|
121
123
|
|
|
@@ -26,8 +26,11 @@ export const DataTableRowSortable = React.memo(function DataTableRowSortable({
|
|
|
26
26
|
rowDraggable,
|
|
27
27
|
reorderable,
|
|
28
28
|
isDragOver,
|
|
29
|
+
dndScopeId,
|
|
29
30
|
}) {
|
|
30
31
|
const shiftClickRef = useRef(false)
|
|
32
|
+
const touchHandledRef = useRef(false)
|
|
33
|
+
const checkboxTouchHandledRef = useRef(false)
|
|
31
34
|
const {
|
|
32
35
|
attributes,
|
|
33
36
|
listeners,
|
|
@@ -38,6 +41,13 @@ export const DataTableRowSortable = React.memo(function DataTableRowSortable({
|
|
|
38
41
|
} = useSortable({
|
|
39
42
|
id: rowId,
|
|
40
43
|
disabled: !resolveRowDraggable({ row, rowDraggable, reorderable }),
|
|
44
|
+
data: {
|
|
45
|
+
source: 'data-table',
|
|
46
|
+
dndScopeId,
|
|
47
|
+
rowId,
|
|
48
|
+
row,
|
|
49
|
+
rowIndex,
|
|
50
|
+
},
|
|
41
51
|
})
|
|
42
52
|
|
|
43
53
|
const sortableStyle = {
|
|
@@ -49,6 +59,10 @@ export const DataTableRowSortable = React.memo(function DataTableRowSortable({
|
|
|
49
59
|
: sortableStyle
|
|
50
60
|
|
|
51
61
|
const handleRowClick = (e) => {
|
|
62
|
+
if (touchHandledRef.current) {
|
|
63
|
+
touchHandledRef.current = false
|
|
64
|
+
return
|
|
65
|
+
}
|
|
52
66
|
if (e.shiftKey) {
|
|
53
67
|
e.preventDefault()
|
|
54
68
|
onShiftClickRow?.(row, rowIndex)
|
|
@@ -57,6 +71,16 @@ export const DataTableRowSortable = React.memo(function DataTableRowSortable({
|
|
|
57
71
|
}
|
|
58
72
|
}
|
|
59
73
|
|
|
74
|
+
const handleRowPointerUp = (e) => {
|
|
75
|
+
if (e.pointerType !== 'touch') return
|
|
76
|
+
touchHandledRef.current = true
|
|
77
|
+
if (e.shiftKey) {
|
|
78
|
+
onShiftClickRow?.(row, rowIndex)
|
|
79
|
+
} else {
|
|
80
|
+
onRowClick?.(row)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
60
84
|
const handleCheckboxClick = (e) => {
|
|
61
85
|
e.stopPropagation()
|
|
62
86
|
if (e.shiftKey) {
|
|
@@ -71,6 +95,10 @@ export const DataTableRowSortable = React.memo(function DataTableRowSortable({
|
|
|
71
95
|
|
|
72
96
|
const handleCheckboxCellClick = (e) => {
|
|
73
97
|
e.stopPropagation()
|
|
98
|
+
if (checkboxTouchHandledRef.current) {
|
|
99
|
+
checkboxTouchHandledRef.current = false
|
|
100
|
+
return
|
|
101
|
+
}
|
|
74
102
|
if (e.shiftKey) {
|
|
75
103
|
e.preventDefault()
|
|
76
104
|
onShiftClickRow?.(row, rowIndex)
|
|
@@ -79,11 +107,26 @@ export const DataTableRowSortable = React.memo(function DataTableRowSortable({
|
|
|
79
107
|
}
|
|
80
108
|
}
|
|
81
109
|
|
|
110
|
+
const handleCheckboxCellPointerUp = (e) => {
|
|
111
|
+
if (e.pointerType !== 'touch') return
|
|
112
|
+
e.stopPropagation()
|
|
113
|
+
checkboxTouchHandledRef.current = true
|
|
114
|
+
if (e.shiftKey) {
|
|
115
|
+
onShiftClickRow?.(row, rowIndex)
|
|
116
|
+
} else if (rowId != null) {
|
|
117
|
+
onSelectRow?.(rowId, !isSelected)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
82
121
|
const handleCheckedChange = (value) => {
|
|
83
122
|
if (shiftClickRef.current) {
|
|
84
123
|
shiftClickRef.current = false
|
|
85
124
|
return
|
|
86
125
|
}
|
|
126
|
+
if (checkboxTouchHandledRef.current) {
|
|
127
|
+
checkboxTouchHandledRef.current = false
|
|
128
|
+
return
|
|
129
|
+
}
|
|
87
130
|
if (rowId != null) onSelectRow?.(rowId, value === true)
|
|
88
131
|
}
|
|
89
132
|
|
|
@@ -111,6 +154,7 @@ export const DataTableRowSortable = React.memo(function DataTableRowSortable({
|
|
|
111
154
|
data-column-id="select"
|
|
112
155
|
data-sorted="false"
|
|
113
156
|
onClick={handleCheckboxCellClick}
|
|
157
|
+
onPointerUp={handleCheckboxCellPointerUp}
|
|
114
158
|
>
|
|
115
159
|
<Checkbox
|
|
116
160
|
size="1"
|
|
@@ -137,6 +181,7 @@ export const DataTableRowSortable = React.memo(function DataTableRowSortable({
|
|
|
137
181
|
data-column-id={column.id}
|
|
138
182
|
data-sorted={sortedKey === column.id}
|
|
139
183
|
onClick={handleRowClick}
|
|
184
|
+
onPointerUp={handleRowPointerUp}
|
|
140
185
|
>
|
|
141
186
|
{index === 0 ? renderProjectCell(row) : renderDataCell(row, column, index)}
|
|
142
187
|
</Table.Cell>
|
|
@@ -2,6 +2,7 @@ import { useCallback, useMemo, useState } from 'react'
|
|
|
2
2
|
import {
|
|
3
3
|
pointerWithin,
|
|
4
4
|
PointerSensor,
|
|
5
|
+
useDndMonitor,
|
|
5
6
|
useSensor,
|
|
6
7
|
useSensors,
|
|
7
8
|
} from '@dnd-kit/core'
|
|
@@ -11,6 +12,51 @@ import {
|
|
|
11
12
|
DATA_TABLE_DROP_BOTTOM_ID,
|
|
12
13
|
} from './dataTableDnd.utils'
|
|
13
14
|
|
|
15
|
+
const isDataTableDrag = (event, dndScopeId) => {
|
|
16
|
+
const data = event.active?.data?.current
|
|
17
|
+
if (data?.source !== 'data-table') return false
|
|
18
|
+
if (dndScopeId && data.dndScopeId !== dndScopeId) return false
|
|
19
|
+
return true
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Renderless component that calls useDndMonitor inside a parent DndContext.
|
|
24
|
+
* Only mounted when renderDndContext={false} so we guarantee a DndContext ancestor.
|
|
25
|
+
*/
|
|
26
|
+
export const DataTableDndMonitor = ({ handlers, dndScopeId }) => {
|
|
27
|
+
useDndMonitor({
|
|
28
|
+
onDragStart: useCallback(
|
|
29
|
+
(event) => {
|
|
30
|
+
if (!isDataTableDrag(event, dndScopeId)) return
|
|
31
|
+
handlers.current.onDragStart(event)
|
|
32
|
+
},
|
|
33
|
+
[dndScopeId, handlers],
|
|
34
|
+
),
|
|
35
|
+
onDragOver: useCallback(
|
|
36
|
+
(event) => {
|
|
37
|
+
if (!isDataTableDrag(event, dndScopeId)) return
|
|
38
|
+
handlers.current.onDragOver(event)
|
|
39
|
+
},
|
|
40
|
+
[dndScopeId, handlers],
|
|
41
|
+
),
|
|
42
|
+
onDragCancel: useCallback(
|
|
43
|
+
(event) => {
|
|
44
|
+
if (!isDataTableDrag(event, dndScopeId)) return
|
|
45
|
+
handlers.current.onDragCancel(event)
|
|
46
|
+
},
|
|
47
|
+
[dndScopeId, handlers],
|
|
48
|
+
),
|
|
49
|
+
onDragEnd: useCallback(
|
|
50
|
+
(event) => {
|
|
51
|
+
if (!isDataTableDrag(event, dndScopeId)) return
|
|
52
|
+
handlers.current.onDragEnd(event)
|
|
53
|
+
},
|
|
54
|
+
[dndScopeId, handlers],
|
|
55
|
+
),
|
|
56
|
+
})
|
|
57
|
+
return null
|
|
58
|
+
}
|
|
59
|
+
|
|
14
60
|
export const useDataTableDnd = ({
|
|
15
61
|
rows,
|
|
16
62
|
selectedSet,
|
|
@@ -19,6 +65,7 @@ export const useDataTableDnd = ({
|
|
|
19
65
|
onReorder,
|
|
20
66
|
onRowDragStart,
|
|
21
67
|
onRowDragEnd,
|
|
68
|
+
dndScopeId,
|
|
22
69
|
}) => {
|
|
23
70
|
const [activeDragRowId, setActiveDragRowId] = useState(null)
|
|
24
71
|
const [overDragRowId, setOverDragRowId] = useState(null)
|
|
@@ -143,11 +190,22 @@ export const useDataTableDnd = ({
|
|
|
143
190
|
[handleDndCancel, handleDndEnd, handleDndOver, handleDndStart, sensors],
|
|
144
191
|
)
|
|
145
192
|
|
|
193
|
+
const monitorHandlers = useMemo(
|
|
194
|
+
() => ({
|
|
195
|
+
onDragStart: handleDndStart,
|
|
196
|
+
onDragOver: handleDndOver,
|
|
197
|
+
onDragCancel: handleDndCancel,
|
|
198
|
+
onDragEnd: handleDndEnd,
|
|
199
|
+
}),
|
|
200
|
+
[handleDndStart, handleDndOver, handleDndCancel, handleDndEnd],
|
|
201
|
+
)
|
|
202
|
+
|
|
146
203
|
return {
|
|
147
204
|
dndContextProps,
|
|
148
205
|
activeDragRowId,
|
|
149
206
|
overDragRowId,
|
|
150
207
|
activeDragContext,
|
|
151
208
|
sortableItems: rows.map((row) => row.id),
|
|
209
|
+
monitorHandlers,
|
|
152
210
|
}
|
|
153
211
|
}
|
|
@@ -293,6 +293,7 @@ export const SetlistList = ({
|
|
|
293
293
|
isMobile = false,
|
|
294
294
|
droppable = false,
|
|
295
295
|
activeDropSetlistId = null,
|
|
296
|
+
enableDndDropTargets = false,
|
|
296
297
|
}) => {
|
|
297
298
|
const { close, isMobile: isMobileDrawer } = useMobileDrawerContext()
|
|
298
299
|
const [openSetlistMenuId, setOpenSetlistMenuId] = useState(null)
|
|
@@ -471,6 +472,11 @@ export const SetlistList = ({
|
|
|
471
472
|
onClick={() => handleSetlistClick(setlist.id)}
|
|
472
473
|
droppable={droppable}
|
|
473
474
|
isDropTarget={activeDropSetlistId === setlist.id}
|
|
475
|
+
dndDroppableId={
|
|
476
|
+
enableDndDropTargets
|
|
477
|
+
? `setlist:${setlist.id}`
|
|
478
|
+
: undefined
|
|
479
|
+
}
|
|
474
480
|
onDragOver={(event) => {
|
|
475
481
|
onSetlistDragOver?.(setlist.id, event)
|
|
476
482
|
}}
|
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
import { useState,
|
|
1
|
+
import { useState, useCallback } from 'react'
|
|
2
2
|
import {
|
|
3
3
|
DndContext,
|
|
4
|
-
DragOverlay,
|
|
5
4
|
PointerSensor,
|
|
6
5
|
useSensor,
|
|
7
6
|
useSensors,
|
|
8
7
|
pointerWithin,
|
|
9
8
|
} from '@dnd-kit/core'
|
|
10
|
-
import {
|
|
11
|
-
import { SetlistList, SetlistItem } from './SetlistList'
|
|
9
|
+
import { SetlistList } from './SetlistList'
|
|
12
10
|
import { DataTable } from '../DataTable/DataTable'
|
|
13
|
-
import { DataTableDragOverlay } from '../DataTable/dnd/DataTableDragOverlay'
|
|
14
|
-
import { toDragRow } from '../DataTable/dnd/dataTableDnd.utils'
|
|
15
11
|
|
|
16
12
|
const defaultSetlists = [
|
|
17
13
|
{
|
|
@@ -307,81 +303,53 @@ const dndSetlists = defaultSetlists.slice(0, 4)
|
|
|
307
303
|
export const DragFromDataTable = {
|
|
308
304
|
render: () => {
|
|
309
305
|
const [selectedRowIds, setSelectedRowIds] = useState([])
|
|
310
|
-
const [
|
|
306
|
+
const [selectedSetlistId, setSelectedSetlistId] = useState(
|
|
307
|
+
dndSetlists[0].id,
|
|
308
|
+
)
|
|
311
309
|
const [dropLog, setDropLog] = useState([])
|
|
312
310
|
|
|
313
311
|
const sensors = useSensors(
|
|
314
312
|
useSensor(PointerSensor, { activationConstraint: { distance: 6 } }),
|
|
315
313
|
)
|
|
316
314
|
|
|
317
|
-
const normalizedRows = useMemo(
|
|
318
|
-
() => trackRows.map((row, index) => toDragRow(row, index)),
|
|
319
|
-
[],
|
|
320
|
-
)
|
|
321
|
-
|
|
322
|
-
const selectedSet = useMemo(
|
|
323
|
-
() => new Set(selectedRowIds.map(String)),
|
|
324
|
-
[selectedRowIds],
|
|
325
|
-
)
|
|
326
|
-
|
|
327
|
-
const handleDragStart = useCallback(
|
|
328
|
-
(event) => {
|
|
329
|
-
const activeId = String(event.active?.id ?? '')
|
|
330
|
-
const dragRow = normalizedRows.find((r) => r.id === activeId)
|
|
331
|
-
if (!dragRow) return
|
|
332
|
-
|
|
333
|
-
const isDraggedRowSelected = selectedSet.has(activeId)
|
|
334
|
-
const selectedRows = isDraggedRowSelected
|
|
335
|
-
? normalizedRows.filter((r) => selectedSet.has(r.id))
|
|
336
|
-
: [dragRow]
|
|
337
|
-
|
|
338
|
-
setActiveDragContext({
|
|
339
|
-
row: dragRow,
|
|
340
|
-
selectedRows,
|
|
341
|
-
isDraggedRowSelected,
|
|
342
|
-
})
|
|
343
|
-
},
|
|
344
|
-
[normalizedRows, selectedSet],
|
|
345
|
-
)
|
|
346
|
-
|
|
347
315
|
const handleDragEnd = useCallback(
|
|
348
316
|
(event) => {
|
|
349
317
|
const { active, over } = event
|
|
318
|
+
if (!over) return
|
|
350
319
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const setlist = dndSetlists.find((s) => s.id === setlistId)
|
|
320
|
+
const data = active.data?.current
|
|
321
|
+
if (data?.source !== 'data-table') return
|
|
354
322
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
.map((r) => r.title)
|
|
358
|
-
.join(', ')
|
|
359
|
-
setDropLog((prev) => [
|
|
360
|
-
{
|
|
361
|
-
id: Date.now(),
|
|
362
|
-
text: `"${trackNames}" → "${setlist.label}"`,
|
|
363
|
-
},
|
|
364
|
-
...prev.slice(0, 4),
|
|
365
|
-
])
|
|
366
|
-
}
|
|
367
|
-
}
|
|
323
|
+
const overId = String(over.id)
|
|
324
|
+
if (!overId.startsWith('setlist:')) return
|
|
368
325
|
|
|
369
|
-
|
|
326
|
+
const setlistId = overId.replace('setlist:', '')
|
|
327
|
+
const setlist = dndSetlists.find((s) => s.id === setlistId)
|
|
328
|
+
if (!setlist) return
|
|
329
|
+
|
|
330
|
+
const selectedSet = new Set(selectedRowIds.map(String))
|
|
331
|
+
const isDraggedSelected = selectedSet.has(data.rowId)
|
|
332
|
+
const draggedRows = isDraggedSelected
|
|
333
|
+
? trackRows.filter((r) => selectedSet.has(r.id))
|
|
334
|
+
: [data.row]
|
|
335
|
+
|
|
336
|
+
const trackNames = draggedRows.map((r) => r.title).join(', ')
|
|
337
|
+
setDropLog((prev) => [
|
|
338
|
+
{
|
|
339
|
+
id: Date.now(),
|
|
340
|
+
text: `"${trackNames}" → "${setlist.label}"`,
|
|
341
|
+
},
|
|
342
|
+
...prev.slice(0, 4),
|
|
343
|
+
])
|
|
370
344
|
},
|
|
371
|
-
[
|
|
345
|
+
[selectedRowIds],
|
|
372
346
|
)
|
|
373
347
|
|
|
374
|
-
const handleDragCancel = useCallback(() => {
|
|
375
|
-
setActiveDragContext(null)
|
|
376
|
-
}, [])
|
|
377
|
-
|
|
378
348
|
return (
|
|
379
349
|
<DndContext
|
|
380
350
|
sensors={sensors}
|
|
381
351
|
collisionDetection={pointerWithin}
|
|
382
|
-
onDragStart={handleDragStart}
|
|
383
352
|
onDragEnd={handleDragEnd}
|
|
384
|
-
onDragCancel={handleDragCancel}
|
|
385
353
|
>
|
|
386
354
|
<div style={{ display: 'flex', gap: 24, height: '100%' }}>
|
|
387
355
|
<div
|
|
@@ -445,15 +413,12 @@ export const DragFromDataTable = {
|
|
|
445
413
|
Drop on a setlist
|
|
446
414
|
</div>
|
|
447
415
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
dndDroppableId={`setlist-drop-${setlist.id}`}
|
|
455
|
-
/>
|
|
456
|
-
))}
|
|
416
|
+
<SetlistList
|
|
417
|
+
setlists={dndSetlists}
|
|
418
|
+
selectedSetlistId={selectedSetlistId}
|
|
419
|
+
onSetlistClick={setSelectedSetlistId}
|
|
420
|
+
enableDndDropTargets
|
|
421
|
+
/>
|
|
457
422
|
|
|
458
423
|
{dropLog.length > 0 && (
|
|
459
424
|
<div
|
|
@@ -494,19 +459,6 @@ export const DragFromDataTable = {
|
|
|
494
459
|
)}
|
|
495
460
|
</div>
|
|
496
461
|
</div>
|
|
497
|
-
|
|
498
|
-
<DragOverlay modifiers={[snapCenterToCursor]}>
|
|
499
|
-
{activeDragContext ? (
|
|
500
|
-
<DataTableDragOverlay
|
|
501
|
-
model={activeDragContext}
|
|
502
|
-
getDragPreviewLabel={(row, selectedRows) =>
|
|
503
|
-
selectedRows.length > 1
|
|
504
|
-
? `${selectedRows.length} files`
|
|
505
|
-
: (row.trackName ?? row.title)
|
|
506
|
-
}
|
|
507
|
-
/>
|
|
508
|
-
) : null}
|
|
509
|
-
</DragOverlay>
|
|
510
462
|
</DndContext>
|
|
511
463
|
)
|
|
512
464
|
},
|