UNPKG

@awsui/components-react

Version:

On July 19th, 2022, we launched [Cloudscape Design System](https://cloudscape.design). Cloudscape is an evolution of AWS-UI. It consists of user interface guidelines, front-end components, design resources, and development tools for building intuitive, en

136 lines 7.25 kB
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import React, { useEffect, useRef } from 'react'; import { DndContext, DragOverlay } from '@dnd-kit/core'; import { arrayMove, SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; import clsx from 'clsx'; import { Portal } from '@awsui/component-toolkit/internal'; import { fireNonCancelableEvent } from '../../events'; import { joinStrings } from '../../utils/strings'; import { EventName } from './keyboard-sensor/utilities/events'; import useDragAndDropReorder from './use-drag-and-drop-reorder'; import useLiveAnnouncements from './use-live-announcements'; import styles from './styles.css.js'; export default function SortableArea({ items, itemDefinition, renderItem, onItemsChange, disableReorder, i18nStrings, }) { var _a; const { activeItemId, setActiveItemId, collisionDetection, handleKeyDown, sensors, isKeyboard } = useDragAndDropReorder({ items, itemDefinition, }); const activeItem = activeItemId ? items.find(item => itemDefinition.id(item) === activeItemId) : null; const isDragging = activeItemId !== null; const announcements = useLiveAnnouncements({ items, itemDefinition, isDragging, ...i18nStrings }); const portalContainer = usePortalContainer(); return (React.createElement(DndContext, { sensors: sensors, collisionDetection: collisionDetection, accessibility: { announcements, restoreFocus: false, screenReaderInstructions: (i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.dragHandleAriaDescription) ? { draggable: i18nStrings.dragHandleAriaDescription } : undefined, container: portalContainer !== null && portalContainer !== void 0 ? portalContainer : undefined, }, onDragStart: ({ active }) => setActiveItemId(active.id), onDragEnd: event => { setActiveItemId(null); const { active, over } = event; if (over && active.id !== over.id) { const movedItem = items.find(item => itemDefinition.id(item) === active.id); const oldIndex = items.findIndex(item => itemDefinition.id(item) === active.id); const newIndex = items.findIndex(item => itemDefinition.id(item) === over.id); fireNonCancelableEvent(onItemsChange, { items: arrayMove([...items], oldIndex, newIndex), movedItem }); } }, onDragCancel: () => setActiveItemId(null) }, React.createElement(SortableContext, { disabled: disableReorder, items: items.map(item => itemDefinition.id(item)), strategy: verticalListSortingStrategy }, items.map(item => (React.createElement(DraggableItem, { key: itemDefinition.id(item), item: item, itemDefinition: itemDefinition, showDirectionButtons: item === activeItem && isKeyboard.current, renderItem: renderItem, onKeyDown: handleKeyDown, dragHandleAriaLabel: i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.dragHandleAriaLabel })))), React.createElement(Portal, { container: portalContainer }, React.createElement(DragOverlay, { className: clsx(styles['drag-overlay'], styles[`drag-overlay-${getBorderRadiusVariant(itemDefinition)}`]), dropAnimation: null, style: { zIndex: 5000 }, transition: isKeyboard.current ? 'transform 250ms' : '' }, activeItem && renderItem({ item: activeItem, id: activeItemId.toString(), style: {}, className: styles.active, isDropPlaceholder: true, isSortingActive: false, isDragGhost: true, dragHandleProps: { ariaLabel: (_a = joinStrings(i18nStrings === null || i18nStrings === void 0 ? void 0 : i18nStrings.dragHandleAriaLabel, itemDefinition.label(activeItem))) !== null && _a !== void 0 ? _a : '', active: true, onKeyDown: handleKeyDown, }, }))))); } function usePortalContainer() { const portalContainerRef = useRef(typeof document !== 'undefined' ? document.createElement('div') : null); useEffect(() => { const container = portalContainerRef.current; if (container && !container.isConnected) { document.body.appendChild(container); } return () => { if (container && container.isConnected) { document.body.removeChild(container); } }; }, []); return portalContainerRef.current; } function DraggableItem({ item, itemDefinition, dragHandleAriaLabel, showDirectionButtons, onKeyDown, renderItem, }) { var _a; const id = itemDefinition.id(item); const { isDragging, isSorting, listeners, setNodeRef, transform, attributes } = useSortable({ id, }); const style = { transform: CSS.Translate.toString(transform) }; const dragHandleListeners = attributes['aria-disabled'] ? {} : { ...listeners, onKeyDown: (event) => { if (onKeyDown) { onKeyDown(event); } if (listeners === null || listeners === void 0 ? void 0 : listeners.onKeyDown) { listeners.onKeyDown(event); } }, }; const className = clsx(isDragging && clsx(styles.placeholder, styles[`placeholder-${getBorderRadiusVariant(itemDefinition)}`]), isSorting && styles.sorting); const dragHandleRef = useRef(null); return (React.createElement(React.Fragment, null, renderItem({ item, id, ref: setNodeRef, style, className, isDropPlaceholder: isDragging, isSortingActive: isSorting, isDragGhost: false, dragHandleProps: { ...dragHandleListeners, ariaLabel: (_a = joinStrings(dragHandleAriaLabel, itemDefinition.label(item))) !== null && _a !== void 0 ? _a : '', ariaDescribedby: attributes['aria-describedby'], disabled: attributes['aria-disabled'], triggerMode: 'controlled', controlledShowButtons: showDirectionButtons, ref: dragHandleRef, directions: showDirectionButtons ? { 'block-start': 'active', 'block-end': 'active', } : undefined, onDirectionClick: direction => { var _a; const event = new Event(direction === 'block-start' ? EventName.CustomUp : EventName.CustomDown, { bubbles: true, cancelable: true, }); onKeyDown(event); (_a = dragHandleRef.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event); }, }, }))); } export function getBorderRadiusVariant(itemDefinition) { var _a; return (_a = itemDefinition.borderRadius) !== null && _a !== void 0 ? _a : 'item'; } //# sourceMappingURL=index.js.map