UNPKG

@coveord/plasma-mantine

Version:

A Plasma flavoured Mantine theme

205 lines (204 loc) 8.31 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { DndContext, KeyboardSensor, PointerSensor, useSensor, useSensors } from '@dnd-kit/core'; import { restrictToParentElement, restrictToVerticalAxis } from '@dnd-kit/modifiers'; import { SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy } from '@dnd-kit/sortable'; import { Box, Input, Stack, useProps, useStyles } from '@mantine/core'; import { useDidUpdate } from '@mantine/hooks'; import { identity } from '../../utils/createFactoryComponent.js'; import classes from './Collection.module.css'; import { CollectionAddButton } from './CollectionAddButton.js'; import { CollectionProvider } from './CollectionContext.js'; import { CollectionItem } from './CollectionItem.js'; import { CollectionLayouts } from './layouts/CollectionLayouts.js'; const defaultProps = { draggable: false, addLabel: 'Add item', addDisabledTooltip: 'There is already an empty item', disabled: false, readOnly: false, gap: 'md', required: false, getItemId: ({ id })=>id }; export const Collection = (props)=>{ const { value, onChange, onRemoveItem, onReorderItem, onInsertItem, disabled, readOnly, draggable, children, columns, layout, gap, required, newItem, addLabel, addDisabledTooltip, allowAdd, label, labelProps, withAsterisk, description, descriptionProps, error, errorProps, getItemId, ref, // Style props style, className, classNames, styles, unstyled, ...others } = useProps('Collection', defaultProps, props); // Runtime validation: ensure columns and children are mutually exclusive if (columns && children) { throw new Error('Collection: Cannot use both "columns" and "children" props.'); } if (layout && !columns) { throw new Error('Collection: "layout" prop can only be used with "columns" prop.'); } const getStyles = useStyles({ name: 'Collection', classes, props, className, style, classNames, styles, unstyled }); const sensors = useSensors(useSensor(PointerSensor), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })); const canEdit = !disabled && !readOnly; const items = value ?? []; const hasOnlyOneItem = items.length === 1; /** * Enforcing onChange when the value is modified will make sure the errors are carried through. */ useDidUpdate(()=>{ onChange?.(items); }, [ JSON.stringify(items) ]); const isRequired = typeof withAsterisk === 'boolean' ? withAsterisk : required; const _label = label ? /*#__PURE__*/ _jsx(Input.Label, { required: isRequired, ...labelProps, children: label }) : null; const _description = description ? /*#__PURE__*/ _jsx(Input.Description, { ...descriptionProps, children: description }) : null; const _error = error ? /*#__PURE__*/ _jsx(Input.Error, { ...errorProps, pt: "xs", children: error }) : null; const _header = _label || _description ? /*#__PURE__*/ _jsxs(Stack, { gap: "xxs", pb: "xs", children: [ _label, _description ] }) : null; const standardizedItems = items.map((item, index)=>({ id: getItemId?.(item, index) ?? String(index), data: item })); const getIndex = (id)=>standardizedItems.findIndex((item)=>item.id === id); const handleDragEnd = ({ over, active })=>{ if (over) { const activeIndex = getIndex(String(active.id)); const overIndex = getIndex(String(over.id)); if (activeIndex !== overIndex) { onReorderItem?.({ from: activeIndex, to: overIndex }); } } }; const addAllowed = typeof allowAdd === 'boolean' ? allowAdd : allowAdd?.(items) ?? true; const handleAdd = ()=>{ const newItemValue = typeof newItem === 'function' ? newItem() : newItem; onInsertItem?.(newItemValue, items?.length ?? 0); }; const _addButton = canEdit ? /*#__PURE__*/ _jsx(CollectionAddButton, { addLabel: addLabel, addDisabledTooltip: addDisabledTooltip, addAllowed: addAllowed, onAdd: handleAdd }) : null; // Column-based layout pattern if (columns) { const Layout = layout || CollectionLayouts.Horizontal; return /*#__PURE__*/ _jsx(CollectionProvider, { value: { getStyles, columns: columns }, children: /*#__PURE__*/ _jsx(DndContext, { onDragEnd: handleDragEnd, sensors: sensors, modifiers: [ restrictToVerticalAxis, restrictToParentElement ], children: /*#__PURE__*/ _jsx(SortableContext, { items: standardizedItems, strategy: verticalListSortingStrategy, children: /*#__PURE__*/ _jsxs(Box, { ref: ref, ...others, ...getStyles('root'), children: [ _header, /*#__PURE__*/ _jsxs(Layout, { children: [ /*#__PURE__*/ _jsx(Layout.Header, { draggable: draggable && canEdit, removable: canEdit && !(isRequired && hasOnlyOneItem) }), /*#__PURE__*/ _jsx(Layout.Body, { items: items, onRemove: canEdit ? onRemoveItem : undefined, removable: canEdit && !(isRequired && hasOnlyOneItem), draggable: draggable && canEdit, disabled: disabled, readOnly: readOnly, getItemId: getItemId, gap: gap }) ] }), _addButton, _error ] }) }) }) }); } // Legacy children render prop pattern const renderedItems = standardizedItems.map((item, index)=>/*#__PURE__*/ _jsx(CollectionItem, { id: item.id, disabled: !canEdit, draggable: draggable, onRemove: ()=>onRemoveItem?.(index), removable: !(isRequired && hasOnlyOneItem), children: children(item.data, index) }, item.id)); return /*#__PURE__*/ _jsx(CollectionProvider, { value: { getStyles }, children: /*#__PURE__*/ _jsx(DndContext, { onDragEnd: handleDragEnd, sensors: sensors, modifiers: [ restrictToVerticalAxis, restrictToParentElement ], children: /*#__PURE__*/ _jsx(SortableContext, { items: standardizedItems, strategy: verticalListSortingStrategy, children: /*#__PURE__*/ _jsxs(Box, { ref: ref, ...others, ...getStyles('root'), children: [ _header, /*#__PURE__*/ _jsxs(Stack, { gap: gap, ...getStyles('items'), children: [ renderedItems, _addButton ] }), _error ] }) }) }) }); }; Collection.displayName = 'Collection'; Collection.extend = identity; Collection.Layouts = CollectionLayouts; //# sourceMappingURL=Collection.js.map