@invopop/popui 0.1.4-beta.45 → 0.1.4-beta.47
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/BaseDropdown.svelte
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
import { createFloatingActions } from 'svelte-floating-ui'
|
|
4
4
|
import { clickOutside } from './clickOutside.js'
|
|
5
5
|
import { portal } from 'svelte-portal'
|
|
6
|
-
import { slide } from 'svelte/transition'
|
|
7
6
|
import type { BaseDropdownProps } from './types.js'
|
|
7
|
+
import type { TransitionConfig } from 'svelte/transition'
|
|
8
8
|
|
|
9
9
|
let {
|
|
10
10
|
isOpen = $bindable(false),
|
|
@@ -46,6 +46,33 @@
|
|
|
46
46
|
middleware
|
|
47
47
|
})
|
|
48
48
|
|
|
49
|
+
// Custom transition that mimics shadcn style
|
|
50
|
+
function dropdownTransition(
|
|
51
|
+
node: HTMLElement,
|
|
52
|
+
{ duration = 150 }: { duration?: number } = {}
|
|
53
|
+
): TransitionConfig {
|
|
54
|
+
const side = placement.split('-')[0]
|
|
55
|
+
|
|
56
|
+
// Calculate slide direction
|
|
57
|
+
let slideY = 0
|
|
58
|
+
let slideX = 0
|
|
59
|
+
if (side === 'bottom') slideY = -8
|
|
60
|
+
if (side === 'top') slideY = 8
|
|
61
|
+
if (side === 'left') slideX = 8
|
|
62
|
+
if (side === 'right') slideX = -8
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
duration,
|
|
66
|
+
css: (t) => {
|
|
67
|
+
const eased = t * (2 - t) // ease-out
|
|
68
|
+
return `
|
|
69
|
+
opacity: ${eased};
|
|
70
|
+
transform: scale(${0.95 + eased * 0.05}) translate(${slideX * (1 - eased)}px, ${slideY * (1 - eased)}px);
|
|
71
|
+
`
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
49
76
|
export const toggle = () => {
|
|
50
77
|
isOpen = !isOpen
|
|
51
78
|
}
|
|
@@ -83,7 +110,7 @@
|
|
|
83
110
|
}, 100)
|
|
84
111
|
isOpen = false
|
|
85
112
|
}}
|
|
86
|
-
transition:
|
|
113
|
+
transition:dropdownTransition={{ duration: 150 }}
|
|
87
114
|
>
|
|
88
115
|
{@render children?.()}
|
|
89
116
|
</div>
|
|
@@ -8,8 +8,26 @@
|
|
|
8
8
|
import { ChevronRight } from '@steeze-ui/heroicons'
|
|
9
9
|
import { slide } from 'svelte/transition'
|
|
10
10
|
import { flip } from 'svelte/animate'
|
|
11
|
-
import {
|
|
12
|
-
|
|
11
|
+
import {
|
|
12
|
+
draggable as makeDraggable,
|
|
13
|
+
dropTargetForElements
|
|
14
|
+
} from '@atlaskit/pragmatic-drag-and-drop/element/adapter'
|
|
15
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine'
|
|
16
|
+
import { autoScrollForElements } from '@atlaskit/pragmatic-drag-and-drop-auto-scroll/element'
|
|
17
|
+
import { reorder } from '@atlaskit/pragmatic-drag-and-drop/reorder'
|
|
18
|
+
import {
|
|
19
|
+
attachClosestEdge,
|
|
20
|
+
extractClosestEdge,
|
|
21
|
+
type Edge
|
|
22
|
+
} from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge'
|
|
23
|
+
import { onMount, onDestroy, untrack } from 'svelte'
|
|
24
|
+
import {
|
|
25
|
+
shouldShowDropIndicator,
|
|
26
|
+
reorderItems,
|
|
27
|
+
moveItemBetweenGroups,
|
|
28
|
+
type DropIndicatorState,
|
|
29
|
+
type DndItem as DndItemType
|
|
30
|
+
} from './drawer-dnd-helpers'
|
|
13
31
|
|
|
14
32
|
const flipDurationMs = 150
|
|
15
33
|
|
|
@@ -59,6 +77,9 @@
|
|
|
59
77
|
let itemsCache = $state<DrawerOption[]>([])
|
|
60
78
|
let isDragging = $state(false)
|
|
61
79
|
let emitTimeout: number | undefined
|
|
80
|
+
let draggedOverGroup = $state<string | null>(null)
|
|
81
|
+
let dropIndicator = $state<DropIndicatorState>(null)
|
|
82
|
+
let cleanupFunctions: (() => void)[] = []
|
|
62
83
|
|
|
63
84
|
// Build internal DND items from external items
|
|
64
85
|
function buildListIn() {
|
|
@@ -140,14 +161,18 @@
|
|
|
140
161
|
itemsCache = JSON.parse(JSON.stringify(items))
|
|
141
162
|
buildListIn()
|
|
142
163
|
mounted = true
|
|
164
|
+
|
|
165
|
+
// Set up auto-scroll
|
|
166
|
+
const autoScrollCleanup = autoScrollForElements({
|
|
167
|
+
element: document.documentElement
|
|
168
|
+
})
|
|
169
|
+
cleanupFunctions.push(autoScrollCleanup)
|
|
143
170
|
})
|
|
144
171
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
}
|
|
172
|
+
onDestroy(() => {
|
|
173
|
+
cleanupFunctions.forEach((cleanup) => cleanup())
|
|
174
|
+
cleanupFunctions = []
|
|
175
|
+
})
|
|
151
176
|
|
|
152
177
|
function emitGroupDistribution() {
|
|
153
178
|
if (ondropitem && hasGroups) {
|
|
@@ -168,40 +193,199 @@
|
|
|
168
193
|
}
|
|
169
194
|
}
|
|
170
195
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
196
|
+
// Setup draggable item (Svelte action)
|
|
197
|
+
function setupDraggableItem(element: HTMLElement, params: [DndItem, string]) {
|
|
198
|
+
const [dndItem, groupSlug] = params
|
|
199
|
+
if (!element || dndItem.locked) return
|
|
200
|
+
|
|
201
|
+
const cleanup = makeDraggable({
|
|
202
|
+
element,
|
|
203
|
+
getInitialData: () => ({ id: dndItem.id, groupSlug, type: 'drawer-item' }),
|
|
204
|
+
onDragStart: () => {
|
|
205
|
+
isDragging = true
|
|
206
|
+
dropIndicator = null
|
|
207
|
+
},
|
|
208
|
+
onDrop: () => {
|
|
209
|
+
isDragging = false
|
|
210
|
+
dropIndicator = null
|
|
211
|
+
}
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
destroy() {
|
|
216
|
+
cleanup()
|
|
217
|
+
}
|
|
174
218
|
}
|
|
175
|
-
groupDndItems[groupSlug] = e.detail.items
|
|
176
219
|
}
|
|
177
220
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
221
|
+
// Setup drop zone for a container (group or ungrouped) (Svelte action)
|
|
222
|
+
function setupDropZone(element: HTMLElement, groupSlug: string) {
|
|
223
|
+
if (!element) return
|
|
224
|
+
|
|
225
|
+
const cleanup = dropTargetForElements({
|
|
226
|
+
element,
|
|
227
|
+
getData: () => {
|
|
228
|
+
const items =
|
|
229
|
+
groupSlug === 'ungrouped' ? ungroupedDndItems : groupDndItems[groupSlug] || []
|
|
230
|
+
return { groupSlug, items: items.map((i) => i.id) }
|
|
231
|
+
},
|
|
232
|
+
canDrop: ({ source }) => source.data.type === 'drawer-item',
|
|
233
|
+
onDragEnter: () => {
|
|
234
|
+
draggedOverGroup = groupSlug
|
|
235
|
+
},
|
|
236
|
+
onDragLeave: () => {
|
|
237
|
+
if (draggedOverGroup === groupSlug) {
|
|
238
|
+
draggedOverGroup = null
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
onDrop: ({ source, location }) => {
|
|
242
|
+
draggedOverGroup = null
|
|
243
|
+
dropIndicator = null
|
|
244
|
+
const sourceId = source.data.id as string
|
|
245
|
+
const sourceGroup = source.data.groupSlug as string
|
|
246
|
+
const targetGroup = groupSlug
|
|
247
|
+
|
|
248
|
+
// Get source and target arrays
|
|
249
|
+
const sourceItems =
|
|
250
|
+
sourceGroup === 'ungrouped' ? ungroupedDndItems : groupDndItems[sourceGroup] || []
|
|
251
|
+
const targetItems =
|
|
252
|
+
targetGroup === 'ungrouped' ? ungroupedDndItems : groupDndItems[targetGroup] || []
|
|
253
|
+
|
|
254
|
+
// Find the dragged item
|
|
255
|
+
const sourceIndex = sourceItems.findIndex((item) => item.id === sourceId)
|
|
256
|
+
if (sourceIndex === -1) return
|
|
257
|
+
|
|
258
|
+
const draggedItem = sourceItems[sourceIndex]
|
|
259
|
+
|
|
260
|
+
// If moving within the same group, we need to handle reordering
|
|
261
|
+
if (sourceGroup === targetGroup) {
|
|
262
|
+
// Check if we're dropping on another item
|
|
263
|
+
const dropTargets = location.current.dropTargets
|
|
264
|
+
const itemDropTarget = dropTargets.find((target) => target.data.itemId)
|
|
265
|
+
|
|
266
|
+
if (itemDropTarget) {
|
|
267
|
+
const targetItemId = itemDropTarget.data.itemId as string
|
|
268
|
+
const edge = extractClosestEdge(itemDropTarget.data)
|
|
269
|
+
|
|
270
|
+
if (edge) {
|
|
271
|
+
const newItems = reorderItems(targetItems, sourceId, targetItemId, edge)
|
|
272
|
+
|
|
273
|
+
if (targetGroup === 'ungrouped') {
|
|
274
|
+
ungroupedDndItems = newItems
|
|
275
|
+
} else {
|
|
276
|
+
groupDndItems[targetGroup] = newItems
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
} else {
|
|
281
|
+
// Moving between groups
|
|
282
|
+
const dropTargets = location.current.dropTargets
|
|
283
|
+
const itemDropTarget = dropTargets.find((target) => target.data.itemId)
|
|
181
284
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
285
|
+
let targetItemId: string | undefined
|
|
286
|
+
let edge: Edge | undefined
|
|
287
|
+
|
|
288
|
+
if (itemDropTarget) {
|
|
289
|
+
targetItemId = itemDropTarget.data.itemId as string
|
|
290
|
+
edge = extractClosestEdge(itemDropTarget.data) || undefined
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const { newSourceItems, newTargetItems } = moveItemBetweenGroups(
|
|
294
|
+
sourceItems,
|
|
295
|
+
targetItems,
|
|
296
|
+
sourceId,
|
|
297
|
+
targetItemId,
|
|
298
|
+
edge
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
if (sourceGroup === 'ungrouped') {
|
|
302
|
+
ungroupedDndItems = newSourceItems
|
|
303
|
+
} else {
|
|
304
|
+
groupDndItems[sourceGroup] = newSourceItems
|
|
305
|
+
}
|
|
188
306
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
307
|
+
if (targetGroup === 'ungrouped') {
|
|
308
|
+
ungroupedDndItems = newTargetItems
|
|
309
|
+
} else {
|
|
310
|
+
groupDndItems[targetGroup] = newTargetItems
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Update items and notify
|
|
315
|
+
const newItems = buildListOut()
|
|
316
|
+
items = newItems
|
|
317
|
+
itemsCache = JSON.parse(JSON.stringify(items))
|
|
318
|
+
onreorder?.(newItems)
|
|
319
|
+
emitGroupDistribution()
|
|
320
|
+
}
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
return {
|
|
324
|
+
destroy() {
|
|
325
|
+
cleanup()
|
|
326
|
+
}
|
|
192
327
|
}
|
|
193
|
-
ungroupedDndItems = e.detail.items
|
|
194
328
|
}
|
|
195
329
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
330
|
+
// Setup drop zone for individual items (for reordering within same group) (Svelte action)
|
|
331
|
+
function setupItemDropZone(element: HTMLElement, params: [DndItem, string]) {
|
|
332
|
+
const [dndItem, groupSlug] = params
|
|
333
|
+
if (!element) return
|
|
334
|
+
|
|
335
|
+
const cleanup = dropTargetForElements({
|
|
336
|
+
element,
|
|
337
|
+
getData: ({ input }) => {
|
|
338
|
+
const data = { itemId: dndItem.id, groupSlug }
|
|
339
|
+
return attachClosestEdge(data, {
|
|
340
|
+
element,
|
|
341
|
+
input,
|
|
342
|
+
allowedEdges: ['top', 'bottom']
|
|
343
|
+
})
|
|
344
|
+
},
|
|
345
|
+
canDrop: ({ source }) => {
|
|
346
|
+
return source.data.type === 'drawer-item' && source.data.id !== dndItem.id
|
|
347
|
+
},
|
|
348
|
+
onDragEnter: ({ self, source }) => {
|
|
349
|
+
const edge = extractClosestEdge(self.data)
|
|
350
|
+
if (!edge) return
|
|
351
|
+
|
|
352
|
+
const sourceId = source.data.id as string
|
|
353
|
+
const sourceGroup = source.data.groupSlug as string
|
|
354
|
+
const items = groupSlug === 'ungrouped' ? ungroupedDndItems : groupDndItems[groupSlug] || []
|
|
355
|
+
|
|
356
|
+
if (shouldShowDropIndicator(sourceId, dndItem.id, sourceGroup, groupSlug, edge, items)) {
|
|
357
|
+
dropIndicator = { itemId: dndItem.id, edge }
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
onDrag: ({ self, source }) => {
|
|
361
|
+
const edge = extractClosestEdge(self.data)
|
|
362
|
+
if (!edge) return
|
|
363
|
+
|
|
364
|
+
const sourceId = source.data.id as string
|
|
365
|
+
const sourceGroup = source.data.groupSlug as string
|
|
366
|
+
const items = groupSlug === 'ungrouped' ? ungroupedDndItems : groupDndItems[groupSlug] || []
|
|
367
|
+
|
|
368
|
+
if (shouldShowDropIndicator(sourceId, dndItem.id, sourceGroup, groupSlug, edge, items)) {
|
|
369
|
+
dropIndicator = { itemId: dndItem.id, edge }
|
|
370
|
+
} else {
|
|
371
|
+
dropIndicator = null
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
onDragLeave: () => {
|
|
375
|
+
if (dropIndicator?.itemId === dndItem.id) {
|
|
376
|
+
dropIndicator = null
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
onDrop: () => {
|
|
380
|
+
dropIndicator = null
|
|
381
|
+
}
|
|
382
|
+
})
|
|
199
383
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
384
|
+
return {
|
|
385
|
+
destroy() {
|
|
386
|
+
cleanup()
|
|
387
|
+
}
|
|
388
|
+
}
|
|
205
389
|
}
|
|
206
390
|
|
|
207
391
|
function updateItem(item: DrawerOption) {
|
|
@@ -231,7 +415,7 @@
|
|
|
231
415
|
>
|
|
232
416
|
{@render children?.()}
|
|
233
417
|
|
|
234
|
-
{#if hasGroups}
|
|
418
|
+
{#if hasGroups && groups}
|
|
235
419
|
{#each groups as group, index}
|
|
236
420
|
{@const groupItems = groupedItems.get(group.slug) || []}
|
|
237
421
|
{@const isLastGroup = index === groups!.length - 1}
|
|
@@ -281,15 +465,8 @@
|
|
|
281
465
|
>
|
|
282
466
|
{#if draggable}
|
|
283
467
|
<div
|
|
284
|
-
use:
|
|
285
|
-
|
|
286
|
-
flipDurationMs,
|
|
287
|
-
dropTargetStyle: {},
|
|
288
|
-
type: 'drawer-item',
|
|
289
|
-
transformDraggedElement
|
|
290
|
-
}}
|
|
291
|
-
onconsider={(e) => handleDndConsider(group.slug, e)}
|
|
292
|
-
onfinalize={(e) => handleDndFinalize(group.slug, e)}
|
|
468
|
+
use:setupDropZone={group.slug}
|
|
469
|
+
class="min-h-[40px]"
|
|
293
470
|
>
|
|
294
471
|
{#if !groupItems.length}
|
|
295
472
|
<div class="px-1 pt-1 pb-5">
|
|
@@ -301,7 +478,19 @@
|
|
|
301
478
|
</div>
|
|
302
479
|
{:else}
|
|
303
480
|
{#each groupDndItems[group.slug] || [] as dndItem (dndItem.id)}
|
|
304
|
-
|
|
481
|
+
{@const showTopIndicator =
|
|
482
|
+
dropIndicator?.itemId === dndItem.id && dropIndicator?.edge === 'top'}
|
|
483
|
+
{@const showBottomIndicator =
|
|
484
|
+
dropIndicator?.itemId === dndItem.id && dropIndicator?.edge === 'bottom'}
|
|
485
|
+
<div
|
|
486
|
+
animate:flip={{ duration: isDragging ? flipDurationMs : 0 }}
|
|
487
|
+
use:setupDraggableItem={[dndItem, group.slug]}
|
|
488
|
+
use:setupItemDropZone={[dndItem, group.slug]}
|
|
489
|
+
class:border-t-2={showTopIndicator}
|
|
490
|
+
class:border-t-border-selected={showTopIndicator}
|
|
491
|
+
class:border-b-2={showBottomIndicator}
|
|
492
|
+
class:border-b-border-selected={showBottomIndicator}
|
|
493
|
+
>
|
|
305
494
|
{@render drawerItem(dndItem)}
|
|
306
495
|
</div>
|
|
307
496
|
{/each}
|
|
@@ -332,19 +521,23 @@
|
|
|
332
521
|
{#if ungroupedItems.length}
|
|
333
522
|
{#if draggable}
|
|
334
523
|
<div
|
|
335
|
-
class="flex-shrink-0 overflow-y-auto max-h-[564px]"
|
|
336
|
-
use:
|
|
337
|
-
items: ungroupedDndItems,
|
|
338
|
-
flipDurationMs,
|
|
339
|
-
dropTargetStyle: {},
|
|
340
|
-
type: 'drawer-item',
|
|
341
|
-
transformDraggedElement
|
|
342
|
-
}}
|
|
343
|
-
onconsider={handleUngroupedDndConsider}
|
|
344
|
-
onfinalize={handleUngroupedDndFinalize}
|
|
524
|
+
class="flex-shrink-0 overflow-y-auto max-h-[564px] min-h-[40px]"
|
|
525
|
+
use:setupDropZone={'ungrouped'}
|
|
345
526
|
>
|
|
346
527
|
{#each ungroupedDndItems as dndItem (dndItem.id)}
|
|
347
|
-
|
|
528
|
+
{@const showTopIndicator =
|
|
529
|
+
dropIndicator?.itemId === dndItem.id && dropIndicator?.edge === 'top'}
|
|
530
|
+
{@const showBottomIndicator =
|
|
531
|
+
dropIndicator?.itemId === dndItem.id && dropIndicator?.edge === 'bottom'}
|
|
532
|
+
<div
|
|
533
|
+
animate:flip={{ duration: isDragging ? flipDurationMs : 0 }}
|
|
534
|
+
use:setupDraggableItem={[dndItem, 'ungrouped']}
|
|
535
|
+
use:setupItemDropZone={[dndItem, 'ungrouped']}
|
|
536
|
+
class:border-t-2={showTopIndicator}
|
|
537
|
+
class:border-t-border-selected={showTopIndicator}
|
|
538
|
+
class:border-b-2={showBottomIndicator}
|
|
539
|
+
class:border-b-border-selected={showBottomIndicator}
|
|
540
|
+
>
|
|
348
541
|
{@render drawerItem(dndItem)}
|
|
349
542
|
</div>
|
|
350
543
|
{/each}
|
|
@@ -78,6 +78,7 @@ export interface DataTableProps<TData> {
|
|
|
78
78
|
initialSortDirection?: TableSortBy;
|
|
79
79
|
initialFrozenColumns?: string[];
|
|
80
80
|
initialColumnOrder?: string[];
|
|
81
|
+
initialColumnVisibility?: Record<string, boolean>;
|
|
81
82
|
pageSizeOptions?: number[];
|
|
82
83
|
emptyState?: Omit<EmptyStateProps, 'children' | 'check'>;
|
|
83
84
|
onRowClick?: (row: TData) => void;
|
|
@@ -96,6 +97,7 @@ export interface DataTableProps<TData> {
|
|
|
96
97
|
onFreezeChange?: (columnId: string) => void;
|
|
97
98
|
onColumnResize?: (columnSizes: Record<string, number>) => void;
|
|
98
99
|
onColumnOrderChange?: (columnOrder: string[]) => void;
|
|
100
|
+
onColumnVisibilityChange?: (visibility: Record<string, boolean>) => void;
|
|
99
101
|
getRowClassName?: (row: TData) => string;
|
|
100
102
|
getRowState?: (row: TData) => {
|
|
101
103
|
isSuccess?: boolean;
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
initialSortDirection,
|
|
46
46
|
initialFrozenColumns = [],
|
|
47
47
|
initialColumnOrder = [],
|
|
48
|
+
initialColumnVisibility = {},
|
|
48
49
|
emptyState = {
|
|
49
50
|
iconSource: Search,
|
|
50
51
|
title: 'No results',
|
|
@@ -65,6 +66,7 @@
|
|
|
65
66
|
onFreezeChange,
|
|
66
67
|
onColumnResize,
|
|
67
68
|
onColumnOrderChange,
|
|
69
|
+
onColumnVisibilityChange,
|
|
68
70
|
getRowClassName,
|
|
69
71
|
getRowState,
|
|
70
72
|
children
|
|
@@ -74,7 +76,7 @@
|
|
|
74
76
|
const enablePagination = !disablePagination
|
|
75
77
|
|
|
76
78
|
let rowSelection = $state<RowSelectionState>({})
|
|
77
|
-
let columnVisibility = $state<VisibilityState>(
|
|
79
|
+
let columnVisibility = $state<VisibilityState>(initialColumnVisibility)
|
|
78
80
|
let sorting = $state<SortingState>(
|
|
79
81
|
initialSortColumn && initialSortDirection
|
|
80
82
|
? [{ id: initialSortColumn, desc: initialSortDirection === 'desc' }]
|
|
@@ -151,6 +153,13 @@
|
|
|
151
153
|
}
|
|
152
154
|
})
|
|
153
155
|
|
|
156
|
+
// Track column visibility changes
|
|
157
|
+
$effect(() => {
|
|
158
|
+
if (onColumnVisibilityChange && Object.keys(columnVisibility).length > 0) {
|
|
159
|
+
onColumnVisibilityChange(columnVisibility)
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
|
|
154
163
|
const table = setupTable({
|
|
155
164
|
getData: () => data,
|
|
156
165
|
getColumns: () => columns,
|
|
@@ -263,8 +272,9 @@
|
|
|
263
272
|
if (header.id === columnId) {
|
|
264
273
|
break
|
|
265
274
|
}
|
|
266
|
-
//
|
|
267
|
-
|
|
275
|
+
// Only add width of previous frozen columns that are visible (or select column)
|
|
276
|
+
const isVisible = header.column?.getIsVisible?.() ?? true
|
|
277
|
+
if (isVisible && (frozenColumns.has(header.id) || header.id === 'select')) {
|
|
268
278
|
offset += header.getSize()
|
|
269
279
|
}
|
|
270
280
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Edge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
|
|
2
|
+
export type DndItem = {
|
|
3
|
+
id: string;
|
|
4
|
+
locked?: boolean;
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
};
|
|
7
|
+
export type DropIndicatorState = {
|
|
8
|
+
itemId: string;
|
|
9
|
+
edge: Edge;
|
|
10
|
+
} | null;
|
|
11
|
+
/**
|
|
12
|
+
* Checks if dropping an item would result in no position change
|
|
13
|
+
* (i.e., dropping right next to its current position)
|
|
14
|
+
*/
|
|
15
|
+
export declare function shouldShowDropIndicator(sourceId: string, targetId: string, sourceGroup: string, targetGroup: string, edge: Edge, items: DndItem[]): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Calculates the new index where a dragged item should be inserted
|
|
18
|
+
*/
|
|
19
|
+
export declare function calculateInsertIndex(sourceIndex: number, targetIndex: number, edge: Edge): number;
|
|
20
|
+
/**
|
|
21
|
+
* Reorders items within the same group
|
|
22
|
+
*/
|
|
23
|
+
export declare function reorderItems<T extends DndItem>(items: T[], sourceId: string, targetId: string, edge: Edge): T[];
|
|
24
|
+
/**
|
|
25
|
+
* Moves an item from one group to another
|
|
26
|
+
*/
|
|
27
|
+
export declare function moveItemBetweenGroups<T extends DndItem>(sourceItems: T[], targetItems: T[], sourceId: string, targetId?: string, edge?: Edge): {
|
|
28
|
+
newSourceItems: T[];
|
|
29
|
+
newTargetItems: T[];
|
|
30
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if dropping an item would result in no position change
|
|
3
|
+
* (i.e., dropping right next to its current position)
|
|
4
|
+
*/
|
|
5
|
+
export function shouldShowDropIndicator(sourceId, targetId, sourceGroup, targetGroup, edge, items) {
|
|
6
|
+
// Always show for cross-group drops
|
|
7
|
+
if (sourceGroup !== targetGroup) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
// Check if dropping would result in no position change
|
|
11
|
+
const sourceIndex = items.findIndex((item) => item.id === sourceId);
|
|
12
|
+
const targetIndex = items.findIndex((item) => item.id === targetId);
|
|
13
|
+
// Don't show indicator if dropping adjacent to current position
|
|
14
|
+
const isAdjacentTop = edge === 'top' && targetIndex === sourceIndex + 1;
|
|
15
|
+
const isAdjacentBottom = edge === 'bottom' && targetIndex === sourceIndex - 1;
|
|
16
|
+
return !isAdjacentTop && !isAdjacentBottom;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Calculates the new index where a dragged item should be inserted
|
|
20
|
+
*/
|
|
21
|
+
export function calculateInsertIndex(sourceIndex, targetIndex, edge) {
|
|
22
|
+
let insertIndex = targetIndex;
|
|
23
|
+
// Adjust target index if source was before target (array shifts after removal)
|
|
24
|
+
if (sourceIndex < targetIndex) {
|
|
25
|
+
insertIndex = targetIndex - 1;
|
|
26
|
+
}
|
|
27
|
+
// If dropping on bottom edge, insert after
|
|
28
|
+
if (edge === 'bottom') {
|
|
29
|
+
insertIndex = insertIndex + 1;
|
|
30
|
+
}
|
|
31
|
+
return insertIndex;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Reorders items within the same group
|
|
35
|
+
*/
|
|
36
|
+
export function reorderItems(items, sourceId, targetId, edge) {
|
|
37
|
+
const sourceIndex = items.findIndex((item) => item.id === sourceId);
|
|
38
|
+
const targetIndex = items.findIndex((item) => item.id === targetId);
|
|
39
|
+
if (sourceIndex === -1 || targetIndex === -1) {
|
|
40
|
+
return items;
|
|
41
|
+
}
|
|
42
|
+
const newItems = [...items];
|
|
43
|
+
const [draggedItem] = newItems.splice(sourceIndex, 1);
|
|
44
|
+
const insertIndex = calculateInsertIndex(sourceIndex, targetIndex, edge);
|
|
45
|
+
newItems.splice(insertIndex, 0, draggedItem);
|
|
46
|
+
return newItems;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Moves an item from one group to another
|
|
50
|
+
*/
|
|
51
|
+
export function moveItemBetweenGroups(sourceItems, targetItems, sourceId, targetId, edge) {
|
|
52
|
+
const draggedItem = sourceItems.find((item) => item.id === sourceId);
|
|
53
|
+
if (!draggedItem) {
|
|
54
|
+
return { newSourceItems: sourceItems, newTargetItems: targetItems };
|
|
55
|
+
}
|
|
56
|
+
const newSourceItems = sourceItems.filter((item) => item.id !== sourceId);
|
|
57
|
+
// If no target specified, append to end
|
|
58
|
+
if (!targetId || !edge) {
|
|
59
|
+
const newTargetItems = [...targetItems, draggedItem];
|
|
60
|
+
return { newSourceItems, newTargetItems };
|
|
61
|
+
}
|
|
62
|
+
// Insert at specific position based on target and edge
|
|
63
|
+
const targetIndex = targetItems.findIndex((item) => item.id === targetId);
|
|
64
|
+
if (targetIndex === -1) {
|
|
65
|
+
const newTargetItems = [...targetItems, draggedItem];
|
|
66
|
+
return { newSourceItems, newTargetItems };
|
|
67
|
+
}
|
|
68
|
+
const newTargetItems = [...targetItems];
|
|
69
|
+
const insertIndex = edge === 'bottom' ? targetIndex + 1 : targetIndex;
|
|
70
|
+
newTargetItems.splice(insertIndex, 0, draggedItem);
|
|
71
|
+
return { newSourceItems, newTargetItems };
|
|
72
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@invopop/popui",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "0.1.4-beta.
|
|
4
|
+
"version": "0.1.4-beta.47",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/invopop/popui"
|
|
7
7
|
},
|
|
@@ -81,6 +81,9 @@
|
|
|
81
81
|
"types": "./dist/index.d.ts",
|
|
82
82
|
"type": "module",
|
|
83
83
|
"dependencies": {
|
|
84
|
+
"@atlaskit/pragmatic-drag-and-drop": "^1.7.7",
|
|
85
|
+
"@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^2.1.5",
|
|
86
|
+
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.1.0",
|
|
84
87
|
"@floating-ui/core": "^1.5.1",
|
|
85
88
|
"@invopop/ui-icons": "^0.0.78",
|
|
86
89
|
"@steeze-ui/heroicons": "^2.2.3",
|
|
@@ -97,7 +100,6 @@
|
|
|
97
100
|
"inter-ui": "^3.19.3",
|
|
98
101
|
"lodash-es": "^4.17.21",
|
|
99
102
|
"mode-watcher": "^1.1.0",
|
|
100
|
-
"svelte-dnd-action": "^0.9.69",
|
|
101
103
|
"svelte-floating-ui": "^1.5.8",
|
|
102
104
|
"svelte-headlessui": "^0.0.46",
|
|
103
105
|
"svelte-intersection-observer-action": "^0.0.4",
|
|
@@ -106,6 +108,7 @@
|
|
|
106
108
|
"svelte-transition": "^0.0.17",
|
|
107
109
|
"svelte-viewport-info": "^1.0.2",
|
|
108
110
|
"tailwind-variants": "^1.0.0",
|
|
111
|
+
"tailwindcss-animate": "^1.0.7",
|
|
109
112
|
"zod": "^4.3.5"
|
|
110
113
|
}
|
|
111
114
|
}
|