@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
JavaScript
// 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