|
43 | 43 | areColliding, |
44 | 44 | getClosestScrollableAncestor, |
45 | 45 | getCollidingItem, |
| 46 | + getGroupSelector, |
46 | 47 | getId, |
47 | 48 | getIndex, |
48 | 49 | getItemRects, |
|
74 | 75 | export let isLocked: $$Props['isLocked'] = false; |
75 | 76 | export let isDisabled: $$Props['isDisabled'] = false; |
76 | 77 | export let announcements: $$Props['announcements'] = undefined; |
| 78 | + export let group: $$Props['group'] = undefined; |
77 | 79 |
|
78 | 80 | $: _transition = { duration: 240, easing: 'cubic-bezier(0.2, 1, 0.1, 1)', ...transition }; |
79 | 81 | $: _announcements = announcements || announce; |
80 | 82 |
|
81 | | - const rootProps = setRootProps({ |
| 83 | + const rootProps = setRootProps(group, { |
82 | 84 | gap, |
83 | 85 | direction, |
84 | 86 | transition: _transition, |
|
107 | 109 | announcements: _announcements, |
108 | 110 | }; |
109 | 111 |
|
110 | | - const root = setRoot(null); |
| 112 | + const root = setRoot(group, null); |
111 | 113 | let ghostStatus: GhostProps['status'] = 'unset'; |
112 | | - const pointer = setPointer(null); |
113 | | - const pointerOrigin = setPointerOrigin(null); |
114 | | - const itemRects = setItemRects(null); |
115 | | - const draggedItem = setDraggedItem(null); |
116 | | - const targetItem = setTargetItem(null); |
117 | | - const focusedItem = setFocusedItem(null); |
| 114 | + const pointer = setPointer(group, null); |
| 115 | + const pointerOrigin = setPointerOrigin(group, null); |
| 116 | + const itemRects = setItemRects(group, null); |
| 117 | + const draggedItem = setDraggedItem(group, null); |
| 118 | + const targetItem = setTargetItem(group, null); |
| 119 | + const focusedItem = setFocusedItem(group, null); |
118 | 120 | let liveText: string = ''; |
119 | 121 |
|
120 | | - const isPointerDragging = setIsPointerDragging(false); |
121 | | - const isPointerDropping = setIsPointerDropping(false); |
122 | | - const isKeyboardDragging = setIsKeyboardDragging(false); |
123 | | - const isKeyboardDropping = setIsKeyboardDropping(false); |
124 | | - const isPointerCanceling = setIsPointerCanceling(false); |
125 | | - const isKeyboardCanceling = setIsKeyboardCanceling(false); |
126 | | - const isBetweenBounds = setIsBetweenBounds(true); |
127 | | - const isRTL = setIsRTL(false); |
| 122 | + const isPointerDragging = setIsPointerDragging(group, false); |
| 123 | + const isPointerDropping = setIsPointerDropping(group, false); |
| 124 | + const isKeyboardDragging = setIsKeyboardDragging(group, false); |
| 125 | + const isKeyboardDropping = setIsKeyboardDropping(group, false); |
| 126 | + const isPointerCanceling = setIsPointerCanceling(group, false); |
| 127 | + const isKeyboardCanceling = setIsKeyboardCanceling(group, false); |
| 128 | + const isBetweenBounds = setIsBetweenBounds(group, true); |
| 129 | + const isRTL = setIsRTL(group, false); |
128 | 130 |
|
129 | 131 | const dispatch = createEventDispatcher<{ |
130 | 132 | mounted: MountedEventDetail; |
|
201 | 203 | return; |
202 | 204 |
|
203 | 205 | const target = event.target as HTMLElement; |
204 | | - const currItem = target.closest<HTMLLIElement>('.ssl-item'); |
| 206 | + const currItem = target.closest<HTMLLIElement>('.ssl-item' + getGroupSelector(group)); |
205 | 207 | if (!currItem) return; |
206 | 208 |
|
207 | 209 | if ( |
|
226 | 228 | event.preventDefault(); |
227 | 229 |
|
228 | 230 | // Prevent dragging if the current list item contains a handle, but we’re not dragging from it. |
229 | | - const hasHandle = !!currItem.querySelector('[data-role="handle"]'); |
230 | | - const targetIsOrResidesInHandle = target.closest('[data-role="handle"]'); |
| 231 | + const hasHandle = !!currItem.querySelector('[data-role="handle"]' + getGroupSelector(group)); |
| 232 | + const targetIsOrResidesInHandle = target.closest( |
| 233 | + '[data-role="handle"]' + getGroupSelector(group) |
| 234 | + ); |
231 | 235 | if (hasHandle && !targetIsOrResidesInHandle) return; |
232 | 236 |
|
233 | 237 | // Prevent dragging if the current list item contains an interactive element |
|
241 | 245 | $pointer = { x: event.clientX, y: event.clientY }; |
242 | 246 | $pointerOrigin = { x: event.clientX, y: event.clientY }; |
243 | 247 | $draggedItem = currItem; |
244 | | - $itemRects = getItemRects(rootRef); |
| 248 | + $itemRects = getItemRects(group, rootRef); |
245 | 249 | ghostStatus = 'init'; |
246 | 250 | await tick(); |
247 | 251 | $isPointerDragging = true; |
|
291 | 295 |
|
292 | 296 | // Re-set itemRects only during scrolling. |
293 | 297 | // (setting it here instead of in the `scroll()` function to reduce the performance impact) |
294 | | - if (scrollingSpeed !== 0) $itemRects = getItemRects(rootRef); |
| 298 | + if (scrollingSpeed !== 0) $itemRects = getItemRects(group, rootRef); |
295 | 299 | await tick(); |
296 | 300 | const collidingItemRect = getCollidingItem(ghostRef, $itemRects); |
297 | 301 | if (collidingItemRect) |
298 | 302 | $targetItem = rootRef.querySelector<HTMLLIElement>( |
299 | | - `.ssl-item[data-item-id="${collidingItemRect.id}"]` |
| 303 | + `.ssl-item${getGroupSelector(group)}[data-item-id="${collidingItemRect.id}"]` |
300 | 304 | ); |
301 | 305 | else if (canClearOnDragOut || (canRemoveOnDropOut && !$isBetweenBounds)) $targetItem = null; |
302 | 306 |
|
|
343 | 347 | await tick(); |
344 | 348 | $draggedItem = $focusedItem; |
345 | 349 | const draggedIndex = getIndex($focusedItem); |
346 | | - $itemRects = getItemRects(rootRef); |
| 350 | + $itemRects = getItemRects(group, rootRef); |
347 | 351 | dispatch('dragstart', { |
348 | 352 | deviceType: 'keyboard', |
349 | 353 | draggedItem: $draggedItem, |
|
369 | 373 |
|
370 | 374 | if (!$isKeyboardDragging) { |
371 | 375 | if (!$focusedItem || focusedIndex === null) { |
372 | | - const firstItem = rootRef.querySelector<HTMLLIElement>('.ssl-item'); |
| 376 | + const firstItem = rootRef.querySelector<HTMLLIElement>( |
| 377 | + '.ssl-item' + getGroupSelector(group) |
| 378 | + ); |
373 | 379 | if (!firstItem) return; |
374 | 380 | firstItem.focus({ preventScroll: true }); |
375 | 381 | if (scrollableAncestor && !isFullyVisible(firstItem, scrollableAncestor)) |
|
379 | 385 |
|
380 | 386 | // Prevent focusing the previous item if the current one is the first, |
381 | 387 | // and focusing the next item if the current one is the last. |
382 | | - const items = rootRef.querySelectorAll<HTMLLIElement>('.ssl-item'); |
| 388 | + const items = rootRef.querySelectorAll<HTMLLIElement>( |
| 389 | + '.ssl-item' + getGroupSelector(group) |
| 390 | + ); |
383 | 391 | if ( |
384 | 392 | (step === -1 && focusedIndex === 0) || |
385 | 393 | (step === 1 && focusedIndex === items.length - 1) |
|
447 | 455 | if (key === 'Home' || key === 'End') { |
448 | 456 | event.preventDefault(); |
449 | 457 |
|
450 | | - const items = rootRef.querySelectorAll<HTMLLIElement>('.ssl-item'); |
| 458 | + const items = rootRef.querySelectorAll<HTMLLIElement>( |
| 459 | + '.ssl-item' + getGroupSelector(group) |
| 460 | + ); |
451 | 461 | const focusedIndex = ($focusedItem && getIndex($focusedItem)) ?? null; |
452 | 462 |
|
453 | 463 | if (!$isKeyboardDragging) { |
|
607 | 617 | style:--ssl-wrap={hasWrapping ? 'wrap' : 'nowrap'} |
608 | 618 | style:--ssl-transition-duration="{_transition.duration}ms" |
609 | 619 | style:pointer-events={$focusedItem ? 'none' : 'auto'} |
| 620 | + data-group={group} |
610 | 621 | data-has-drop-marker={hasDropMarker} |
611 | 622 | data-can-remove-on-drop-out={canRemoveOnDropOut} |
612 | 623 | data-is-locked={isLocked} |
|
622 | 633 | aria-orientation={direction} |
623 | 634 | aria-activedescendant={$focusedItem ? $focusedItem.id : undefined} |
624 | 635 | aria-disabled={isDisabled} |
625 | | - on:pointerdown={handlePointerDown} |
626 | | - on:pointercancel={handlePointerCancel} |
627 | | - on:keydown={handleKeyDown} |
628 | | - on:itemfocusout={(event) => handlePointerAndKeyboardDrop(event.detail.item, 'keyboard-cancel')} |
| 636 | + on:pointerdown|stopPropagation={handlePointerDown} |
| 637 | + on:pointercancel|stopPropagation={handlePointerCancel} |
| 638 | + on:keydown|stopPropagation={handleKeyDown} |
| 639 | + on:itemfocusout|stopPropagation={(event) => |
| 640 | + handlePointerAndKeyboardDrop(event.detail.item, 'keyboard-cancel')} |
629 | 641 | > |
630 | 642 | <slot> |
631 | 643 | <p> |
|
634 | 646 | </p> |
635 | 647 | </slot> |
636 | 648 | </ul> |
637 | | -<SortableListGhost bind:ghostRef status={ghostStatus} /> |
| 649 | +<SortableListGhost bind:ghostRef status={ghostStatus} {group} /> |
638 | 650 | <div class="ssl-live-region" aria-live="assertive" aria-atomic="true">{liveText}</div> |
639 | 651 |
|
640 | 652 | <!-- |
|
0 commit comments