@inkra/react 0.1.0 → 0.3.0
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/README.md +186 -1
- package/dist/PencilIcon.js +14 -16
- package/dist/PencilLine.js +18 -12
- package/dist/PencilText.js +192 -59
- package/dist/alert-dialog/index.d.ts +64 -0
- package/dist/alert-dialog/index.js +111 -0
- package/dist/audio-player/index.d.ts +60 -0
- package/dist/audio-player/index.js +101 -0
- package/dist/carousel/index.d.ts +51 -0
- package/dist/carousel/index.js +290 -0
- package/dist/choice-grid/index.d.ts +38 -0
- package/dist/choice-grid/index.js +85 -0
- package/dist/color-picker/color.d.ts +15 -0
- package/dist/color-picker/color.js +55 -0
- package/dist/color-picker/index.d.ts +31 -0
- package/dist/color-picker/index.js +69 -0
- package/dist/command/index.d.ts +45 -0
- package/dist/command/index.js +39 -0
- package/dist/context-menu/index.d.ts +76 -0
- package/dist/context-menu/index.js +241 -0
- package/dist/data-table/index.d.ts +47 -0
- package/dist/data-table/index.js +91 -0
- package/dist/date-picker/index.d.ts +50 -0
- package/dist/date-picker/index.js +180 -0
- package/dist/display/ProgressRing.d.ts +6 -0
- package/dist/display/ProgressRing.js +146 -0
- package/dist/display/index.d.ts +27 -0
- package/dist/display/index.js +18 -2
- package/dist/dockable-panel/index.d.ts +41 -0
- package/dist/dockable-panel/index.js +253 -0
- package/dist/dockable-panel/model.d.ts +21 -0
- package/dist/dockable-panel/model.js +61 -0
- package/dist/drawer/index.d.ts +63 -0
- package/dist/drawer/index.js +88 -0
- package/dist/dropdown-menu/index.d.ts +1 -1
- package/dist/dropdown-menu/index.js +3 -2
- package/dist/editable/index.d.ts +53 -0
- package/dist/editable/index.js +162 -0
- package/dist/empty/index.d.ts +21 -0
- package/dist/empty/index.js +23 -0
- package/dist/flip/index.d.ts +49 -0
- package/dist/flip/index.js +138 -0
- package/dist/form/EditablePencilText.js +188 -143
- package/dist/form/Input.js +1 -1
- package/dist/form/Textarea.d.ts +12 -0
- package/dist/form/Textarea.js +83 -4
- package/dist/form/index.d.ts +1 -1
- package/dist/heatmap/index.d.ts +59 -0
- package/dist/heatmap/index.js +248 -0
- package/dist/hotkey/index.d.ts +37 -0
- package/dist/hotkey/index.js +130 -0
- package/dist/hotkey/model.d.ts +27 -0
- package/dist/hotkey/model.js +97 -0
- package/dist/hover-card/index.d.ts +33 -0
- package/dist/hover-card/index.js +141 -0
- package/dist/image-cropper/index.d.ts +82 -0
- package/dist/image-cropper/index.js +261 -0
- package/dist/image-cropper/model.d.ts +42 -0
- package/dist/image-cropper/model.js +94 -0
- package/dist/image-viewer/index.d.ts +79 -0
- package/dist/image-viewer/index.js +220 -0
- package/dist/image-viewer/model.d.ts +9 -0
- package/dist/image-viewer/model.js +18 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +47 -0
- package/dist/input-number/index.d.ts +6 -0
- package/dist/input-number/index.js +126 -15
- package/dist/input-number/model.d.ts +13 -0
- package/dist/input-number/model.js +50 -0
- package/dist/internal/cache.d.ts +1 -1
- package/dist/internal/cache.js +1 -1
- package/dist/internal/renderTokens.d.ts +10 -0
- package/dist/internal/renderTokens.js +13 -0
- package/dist/internal/surfaceRenderer.d.ts +14 -6
- package/dist/internal/surfaceRenderer.js +15 -12
- package/dist/internal/textRenderer.d.ts +1 -0
- package/dist/internal/textRenderer.js +33 -7
- package/dist/internal/usePencilSurface.js +16 -8
- package/dist/internal/useSelectionDrawing.js +15 -11
- package/dist/journey-map/MapScale.js +3 -1
- package/dist/journey-map/index.js +3 -1
- package/dist/keypad/index.d.ts +23 -0
- package/dist/keypad/index.js +63 -0
- package/dist/keypad/model.d.ts +20 -0
- package/dist/keypad/model.js +33 -0
- package/dist/layout/index.d.ts +63 -0
- package/dist/layout/index.js +62 -0
- package/dist/log/index.d.ts +45 -0
- package/dist/log/index.js +159 -0
- package/dist/log/model.d.ts +16 -0
- package/dist/log/model.js +13 -0
- package/dist/node-graph/index.d.ts +123 -0
- package/dist/node-graph/index.js +304 -0
- package/dist/number-ticker/index.d.ts +31 -0
- package/dist/number-ticker/index.js +135 -0
- package/dist/number-ticker/model.d.ts +41 -0
- package/dist/number-ticker/model.js +163 -0
- package/dist/number-ticker/precision.d.ts +7 -0
- package/dist/number-ticker/precision.js +134 -0
- package/dist/overflow-list/index.d.ts +39 -0
- package/dist/overflow-list/index.js +230 -0
- package/dist/overflow-list/layout.d.ts +19 -0
- package/dist/overflow-list/layout.js +44 -0
- package/dist/overlay/Overlay.d.ts +1 -1
- package/dist/overlay/Overlay.js +4 -2
- package/dist/overlay/Popover.d.ts +1 -1
- package/dist/overlay/Popover.js +3 -2
- package/dist/overlay/themeBridge.d.ts +12 -1
- package/dist/overlay/themeBridge.js +27 -1
- package/dist/pagination/index.d.ts +23 -0
- package/dist/pagination/index.js +41 -0
- package/dist/pagination/model.d.ts +4 -0
- package/dist/pagination/model.js +42 -0
- package/dist/pan-zoom/index.d.ts +71 -0
- package/dist/pan-zoom/index.js +175 -0
- package/dist/radar/index.d.ts +56 -0
- package/dist/radar/index.js +220 -0
- package/dist/range-slider/index.d.ts +16 -0
- package/dist/range-slider/index.js +22 -0
- package/dist/rating/index.d.ts +28 -0
- package/dist/rating/index.js +127 -0
- package/dist/resizable/index.d.ts +32 -0
- package/dist/resizable/index.js +50 -0
- package/dist/scroll-area/index.d.ts +36 -0
- package/dist/scroll-area/index.js +44 -0
- package/dist/segmented-progress/SegmentedProgress.d.ts +17 -0
- package/dist/segmented-progress/SegmentedProgress.js +42 -0
- package/dist/slider/index.js +1 -1
- package/dist/slot/index.d.ts +24 -0
- package/dist/slot/index.js +29 -0
- package/dist/sortable/index.d.ts +50 -0
- package/dist/sortable/index.js +283 -0
- package/dist/sortable/model.d.ts +30 -0
- package/dist/sortable/model.js +64 -0
- package/dist/sparkline/index.d.ts +19 -0
- package/dist/sparkline/index.js +240 -0
- package/dist/sparkline/model.d.ts +16 -0
- package/dist/sparkline/model.js +28 -0
- package/dist/steps/index.d.ts +16 -0
- package/dist/steps/index.js +37 -0
- package/dist/styles.css +4957 -269
- package/dist/tag-input/index.d.ts +69 -0
- package/dist/tag-input/index.js +325 -0
- package/dist/tag-input/model.d.ts +14 -0
- package/dist/tag-input/model.js +38 -0
- package/dist/time-picker/index.d.ts +15 -0
- package/dist/time-picker/index.js +168 -0
- package/dist/timeline/index.d.ts +14 -0
- package/dist/timeline/index.js +16 -0
- package/dist/toast/index.d.ts +27 -0
- package/dist/toast/index.js +36 -0
- package/dist/toggle-group/index.d.ts +17 -0
- package/dist/toggle-group/index.js +26 -0
- package/dist/tokens.css +10 -9
- package/dist/tooltip/Tooltip.d.ts +1 -1
- package/dist/tooltip/Tooltip.js +3 -2
- package/dist/transfer/index.d.ts +64 -0
- package/dist/transfer/index.js +174 -0
- package/dist/transfer/model.d.ts +12 -0
- package/dist/transfer/model.js +33 -0
- package/dist/tree/index.d.ts +39 -0
- package/dist/tree/index.js +36 -0
- package/dist/tree-select/index.d.ts +59 -0
- package/dist/tree-select/index.js +142 -0
- package/dist/tree-select/model.d.ts +31 -0
- package/dist/tree-select/model.js +135 -0
- package/dist/typewriter/index.d.ts +21 -0
- package/dist/typewriter/index.js +101 -0
- package/dist/typewriter/model.d.ts +7 -0
- package/dist/typewriter/model.js +45 -0
- package/dist/upload/index.d.ts +59 -0
- package/dist/upload/index.js +230 -0
- package/dist/virtual-list/index.d.ts +44 -0
- package/dist/virtual-list/index.js +129 -0
- package/dist/virtual-list/model.d.ts +7 -0
- package/dist/virtual-list/model.js +27 -0
- package/package.json +23 -3
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { PencilSurface } from '../PencilSurface.js';
|
|
3
|
+
function segmentFill(index, count, percent, policy) {
|
|
4
|
+
if (percent === null)
|
|
5
|
+
return 1;
|
|
6
|
+
const raw = percent / 100 * count - index;
|
|
7
|
+
if (policy === 'complete')
|
|
8
|
+
return raw >= 1 ? 1 : 0;
|
|
9
|
+
if (policy === 'next')
|
|
10
|
+
return raw > 0 ? 1 : 0;
|
|
11
|
+
return Math.max(0, Math.min(1, raw));
|
|
12
|
+
}
|
|
13
|
+
function thresholdColor(index, count, max, thresholds) {
|
|
14
|
+
if (!thresholds?.length)
|
|
15
|
+
return undefined;
|
|
16
|
+
const segmentValue = index / count * max;
|
|
17
|
+
let color;
|
|
18
|
+
for (const threshold of thresholds) {
|
|
19
|
+
if (!Number.isFinite(threshold.value) || !threshold.color || threshold.value > segmentValue)
|
|
20
|
+
continue;
|
|
21
|
+
color = threshold.color;
|
|
22
|
+
}
|
|
23
|
+
return color;
|
|
24
|
+
}
|
|
25
|
+
export function SegmentedProgress({ count, gap, max, partialSegment, percent, seed, segmentColors, thresholds, }) {
|
|
26
|
+
const normalizedThresholds = thresholds
|
|
27
|
+
?.filter(threshold => Number.isFinite(threshold.value) && threshold.color)
|
|
28
|
+
.map(threshold => ({ ...threshold, value: Math.max(0, Math.min(max, threshold.value)) }))
|
|
29
|
+
.sort((left, right) => left.value - right.value);
|
|
30
|
+
return (_jsx("span", { "aria-hidden": "true", className: "inkra-progress__segments", style: {
|
|
31
|
+
'--inkra-progress-segment-count': count,
|
|
32
|
+
'--inkra-progress-segment-gap': `${gap}px`,
|
|
33
|
+
}, children: Array.from({ length: count }, (_, index) => {
|
|
34
|
+
const fill = segmentFill(index, count, percent, partialSegment);
|
|
35
|
+
const color = segmentColors?.[index] || thresholdColor(index, count, max, normalizedThresholds);
|
|
36
|
+
const style = {
|
|
37
|
+
'--inkra-progress-segment-fill': `${fill * 100}%`,
|
|
38
|
+
...(color ? { '--inkra-selection-pigment': color } : {}),
|
|
39
|
+
};
|
|
40
|
+
return (_jsxs("span", { className: "inkra-progress__segment", "data-fill": fill === 0 ? 'empty' : fill === 1 ? 'full' : 'partial', children: [_jsx(PencilSurface, { as: "span", className: "inkra-progress__segment-outline", radius: 3, seed: `${seed}-segment-${index}-outline`, variant: "outline" }), _jsx("span", { className: "inkra-progress__segment-fill-clip", style: style, children: _jsx(PencilSurface, { as: "span", className: "inkra-progress__segment-fill", radius: 3, seed: `${seed}-segment-${index}-fill`, variant: "selection" }) })] }, index));
|
|
41
|
+
}) }));
|
|
42
|
+
}
|
package/dist/slider/index.js
CHANGED
|
@@ -40,6 +40,6 @@ export const Slider = forwardRef(function Slider({ 'aria-label': ariaLabel, 'ari
|
|
|
40
40
|
const thumbLabel = thumbLabels?.[index];
|
|
41
41
|
const labelledBy = thumbLabel ? undefined : ariaLabelledBy;
|
|
42
42
|
const label = thumbLabel ?? (ariaLabel ? `${ariaLabel}${values.length > 1 ? ` ${index + 1}` : ''}` : labelledBy ? undefined : `Value${values.length > 1 ? ` ${index + 1}` : ''}`);
|
|
43
|
-
return _jsx(SliderPrimitive.Thumb, { "aria-describedby": ariaDescribedBy, "aria-label": label, "aria-labelledby": labelledBy, "aria-valuetext": getValueLabel?.(current, index) ?? ariaValueText, className: "inkra-slider__thumb", children: _jsx(PencilSurface, { as: "span", "aria-hidden": "true", className: "inkra-slider__thumb-surface", variant: "paper", radius: 8, seed: `${resolvedSeed}-thumb-${index}`, children: _jsx(PencilSurface, { as: "span", className: "inkra-slider__focus-ring", variant: "outline", radius: 8, seed: `${resolvedSeed}-focus-${index}` }) }) }, index);
|
|
43
|
+
return _jsx(SliderPrimitive.Thumb, { "aria-describedby": ariaDescribedBy, "aria-label": label, "aria-labelledby": labelledBy, "aria-valuenow": current, "aria-valuetext": getValueLabel?.(current, index) ?? ariaValueText, className: "inkra-slider__thumb", children: _jsx(PencilSurface, { as: "span", "aria-hidden": "true", className: "inkra-slider__thumb-surface", variant: "paper", radius: 8, seed: `${resolvedSeed}-thumb-${index}`, children: _jsx(PencilSurface, { as: "span", className: "inkra-slider__focus-ring", variant: "outline", radius: 8, seed: `${resolvedSeed}-focus-${index}` }) }) }, index);
|
|
44
44
|
})] });
|
|
45
45
|
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes, HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export type SlotSize = 'sm' | 'md' | 'lg';
|
|
3
|
+
interface SlotSharedProps {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
/** Shows emptyContent instead of children while preserving the slot geometry. */
|
|
6
|
+
empty?: boolean;
|
|
7
|
+
emptyContent?: ReactNode;
|
|
8
|
+
selected?: boolean;
|
|
9
|
+
size?: SlotSize;
|
|
10
|
+
count?: number;
|
|
11
|
+
/** Replaces the default Badge while keeping the count anchored to the slot. */
|
|
12
|
+
renderCount?: (count: number) => ReactNode;
|
|
13
|
+
seed?: string | number;
|
|
14
|
+
}
|
|
15
|
+
export interface StaticSlotProps extends SlotSharedProps, Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
16
|
+
interactive?: false;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface InteractiveSlotProps extends SlotSharedProps, Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {
|
|
20
|
+
interactive: true;
|
|
21
|
+
}
|
|
22
|
+
export type SlotProps = StaticSlotProps | InteractiveSlotProps;
|
|
23
|
+
export declare const Slot: import("react").ForwardRefExoticComponent<SlotProps & import("react").RefAttributes<HTMLButtonElement | HTMLDivElement>>;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useId } from 'react';
|
|
3
|
+
import { Badge } from '../display/index.js';
|
|
4
|
+
import { PencilSurface } from '../PencilSurface.js';
|
|
5
|
+
const classes = (...values) => values.filter(Boolean).join(' ');
|
|
6
|
+
export const Slot = forwardRef(function Slot({ children, className, count, disabled = false, empty = false, emptyContent, interactive = false, renderCount, seed, selected = false, size = 'md', ...props }, ref) {
|
|
7
|
+
const generatedId = useId();
|
|
8
|
+
const resolvedSeed = seed ?? `inkra-slot-${generatedId}`;
|
|
9
|
+
const content = empty
|
|
10
|
+
? (emptyContent ?? _jsx("span", { className: "inkra-slot__empty-mark", "aria-hidden": "true", children: "+" }))
|
|
11
|
+
: children;
|
|
12
|
+
const countContent = count == null
|
|
13
|
+
? null
|
|
14
|
+
: renderCount?.(count) ?? _jsx(Badge, { size: "sm", "aria-label": `${count}`, children: count });
|
|
15
|
+
const commonProps = {
|
|
16
|
+
...props,
|
|
17
|
+
className: classes('inkra-slot', className),
|
|
18
|
+
'data-disabled': disabled || undefined,
|
|
19
|
+
'data-empty': empty || undefined,
|
|
20
|
+
'data-interactive': interactive || undefined,
|
|
21
|
+
'data-selected': selected || undefined,
|
|
22
|
+
'data-size': size,
|
|
23
|
+
};
|
|
24
|
+
const body = _jsxs(_Fragment, { children: [selected && _jsx(PencilSurface, { as: "span", "aria-hidden": "true", className: "inkra-slot__selected-wash", seed: `${resolvedSeed}-wash`, variant: "selection" }), _jsx("span", { className: "inkra-slot__content", children: content }), selected && _jsx(PencilSurface, { as: "span", "aria-hidden": "true", className: "inkra-slot__selected-outline", radius: 8, seed: `${resolvedSeed}-outline`, variant: "outline" }), countContent != null && _jsx("span", { className: "inkra-slot__count", children: countContent })] });
|
|
25
|
+
if (interactive) {
|
|
26
|
+
return _jsx(PencilSurface, { ...commonProps, as: "button", "aria-pressed": selected, disabled: disabled, radius: 8, ref: ref, seed: resolvedSeed, variant: "paper", children: body });
|
|
27
|
+
}
|
|
28
|
+
return _jsx(PencilSurface, { ...commonProps, as: "div", "aria-disabled": disabled || undefined, radius: 8, ref: ref, seed: resolvedSeed, variant: "paper", children: body });
|
|
29
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import type { SortableChangeDetails, SortableContainerData, SortableIdentifier } from './model.js';
|
|
3
|
+
export type { SortableChangeDetails, SortableContainerData, SortableIdentifier, SortableLayout, SortableLocation, } from './model.js';
|
|
4
|
+
export interface SortableLabels {
|
|
5
|
+
handle?: string;
|
|
6
|
+
screenReaderInstructions?: string;
|
|
7
|
+
pickedUp?: (item: string, container: string, position: number, count: number) => string;
|
|
8
|
+
movedOver?: (item: string, container: string, position: number, count: number) => string;
|
|
9
|
+
dropped?: (item: string, container: string, position: number, count: number) => string;
|
|
10
|
+
cancelled?: (item: string) => string;
|
|
11
|
+
}
|
|
12
|
+
export interface SortableItemRenderState<Item> {
|
|
13
|
+
item: Item;
|
|
14
|
+
id: SortableIdentifier;
|
|
15
|
+
containerId: SortableIdentifier;
|
|
16
|
+
index: number;
|
|
17
|
+
disabled: boolean;
|
|
18
|
+
isDragging: boolean;
|
|
19
|
+
isOverlay: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface SortableHandleRenderState<Item> extends SortableItemRenderState<Item> {
|
|
22
|
+
props: ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
23
|
+
ref: (element: HTMLButtonElement | null) => void;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export interface SortableContainerRenderState<Item> {
|
|
27
|
+
container: SortableContainerData<Item>;
|
|
28
|
+
isOver: boolean;
|
|
29
|
+
itemCount: number;
|
|
30
|
+
}
|
|
31
|
+
export interface SortableProps<Item> {
|
|
32
|
+
containers: readonly SortableContainerData<Item>[];
|
|
33
|
+
getItemId: (item: Item) => SortableIdentifier;
|
|
34
|
+
renderItem: (state: SortableItemRenderState<Item>) => ReactNode;
|
|
35
|
+
onChange: (containers: SortableContainerData<Item>[], details: SortableChangeDetails<Item>) => void;
|
|
36
|
+
onReorder?: (details: SortableChangeDetails<Item>) => void;
|
|
37
|
+
onMove?: (details: SortableChangeDetails<Item>) => void;
|
|
38
|
+
renderContainerHeader?: (state: SortableContainerRenderState<Item>) => ReactNode;
|
|
39
|
+
renderOverlay?: (state: SortableItemRenderState<Item>) => ReactNode;
|
|
40
|
+
handle?: boolean | ((state: SortableHandleRenderState<Item>) => ReactNode);
|
|
41
|
+
isItemDisabled?: (item: Item, container: SortableContainerData<Item>) => boolean;
|
|
42
|
+
getItemLabel?: (item: Item) => string;
|
|
43
|
+
getContainerLabel?: (container: SortableContainerData<Item>) => string;
|
|
44
|
+
labels?: SortableLabels;
|
|
45
|
+
className?: string;
|
|
46
|
+
containerClassName?: string;
|
|
47
|
+
itemClassName?: string;
|
|
48
|
+
autoScroll?: boolean;
|
|
49
|
+
}
|
|
50
|
+
export declare function Sortable<Item>({ autoScroll, className, containerClassName, containers, getContainerLabel, getItemId, getItemLabel, handle, isItemDisabled, itemClassName, labels: labelsProp, onChange, onMove, onReorder, renderContainerHeader, renderItem, renderOverlay, }: SortableProps<Item>): import("react").JSX.Element;
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { __iconData as gripIconData } from 'lucide-react/dist/esm/icons/grip-vertical.mjs';
|
|
3
|
+
import { DndContext, DragOverlay, KeyboardSensor, MouseSensor, TouchSensor, closestCenter, pointerWithin, rectIntersection, useDroppable, useSensor, useSensors, } from '@dnd-kit/core';
|
|
4
|
+
import { SortableContext, rectSortingStrategy, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy, } from '@dnd-kit/sortable';
|
|
5
|
+
import { CSS } from '@dnd-kit/utilities';
|
|
6
|
+
import { useMemo, useRef, useState } from 'react';
|
|
7
|
+
import { PencilIcon } from '../PencilIcon.js';
|
|
8
|
+
import { PencilLine } from '../PencilLine.js';
|
|
9
|
+
import { PencilSurface } from '../PencilSurface.js';
|
|
10
|
+
import { PencilText } from '../PencilText.js';
|
|
11
|
+
import { cloneSortableContainers, findSortableLocation, projectSortableMove, sortableContainersEqual, } from './model.js';
|
|
12
|
+
const gripIcon = gripIconData.node.map(([, attributes]) => {
|
|
13
|
+
const { cx, cy, r } = attributes;
|
|
14
|
+
const x = Number(cx);
|
|
15
|
+
const y = Number(cy);
|
|
16
|
+
const radius = Number(r);
|
|
17
|
+
return { d: `M ${x - radius} ${y} A ${radius} ${radius} 0 1 0 ${x + radius} ${y} A ${radius} ${radius} 0 1 0 ${x - radius} ${y}` };
|
|
18
|
+
});
|
|
19
|
+
function engineItemId(id) {
|
|
20
|
+
return `inkra-sortable-item:${typeof id}:${String(id)}`;
|
|
21
|
+
}
|
|
22
|
+
function engineContainerId(id) {
|
|
23
|
+
return `inkra-sortable-container:${typeof id}:${String(id)}`;
|
|
24
|
+
}
|
|
25
|
+
function isInteractiveTarget(target) {
|
|
26
|
+
return target instanceof Element && Boolean(target.closest('button, a, input, select, textarea, [contenteditable="true"], [data-sortable-no-drag]'));
|
|
27
|
+
}
|
|
28
|
+
function filterItemActivatorProps(props) {
|
|
29
|
+
return {
|
|
30
|
+
...props,
|
|
31
|
+
onKeyDown: (event) => {
|
|
32
|
+
if (!isInteractiveTarget(event.target))
|
|
33
|
+
props.onKeyDown?.(event);
|
|
34
|
+
},
|
|
35
|
+
onMouseDown: (event) => {
|
|
36
|
+
if (!isInteractiveTarget(event.target))
|
|
37
|
+
props.onMouseDown?.(event);
|
|
38
|
+
},
|
|
39
|
+
onTouchStart: (event) => {
|
|
40
|
+
if (!isInteractiveTarget(event.target))
|
|
41
|
+
props.onTouchStart?.(event);
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const defaultLabels = {
|
|
46
|
+
handle: 'Drag item',
|
|
47
|
+
screenReaderInstructions: 'Press Space or Enter to pick up an item. Use the arrow keys to move it, Space or Enter to drop it, and Escape to cancel.',
|
|
48
|
+
pickedUp: (item, container, position, count) => `Picked up ${item}, item ${position} of ${count} in ${container}.`,
|
|
49
|
+
movedOver: (item, container, position, count) => `${item} is over position ${position} of ${count} in ${container}.`,
|
|
50
|
+
dropped: (item, container, position, count) => `Dropped ${item} at position ${position} of ${count} in ${container}.`,
|
|
51
|
+
cancelled: (item) => `Sorting cancelled. ${item} returned to its original position.`,
|
|
52
|
+
};
|
|
53
|
+
function getEngineData(value) {
|
|
54
|
+
const data = value?.data.current;
|
|
55
|
+
return data?.type === 'inkra-sortable-item' || data?.type === 'inkra-sortable-container' ? data : null;
|
|
56
|
+
}
|
|
57
|
+
function getCollisionEngineData(collision) {
|
|
58
|
+
return collision.data?.droppableContainer
|
|
59
|
+
? getEngineData(collision.data.droppableContainer)
|
|
60
|
+
: null;
|
|
61
|
+
}
|
|
62
|
+
function getDropProjection(containers, event, getItemId) {
|
|
63
|
+
const activeData = getEngineData(event.active);
|
|
64
|
+
const overData = getEngineData(event.over);
|
|
65
|
+
if (activeData?.itemId === undefined || !overData || overData.disabled)
|
|
66
|
+
return cloneSortableContainers(containers);
|
|
67
|
+
const targetContainer = containers.find((container) => container.id === overData.containerId);
|
|
68
|
+
const translated = event.active.rect.current.translated;
|
|
69
|
+
const source = findSortableLocation(containers, activeData.itemId, getItemId);
|
|
70
|
+
const target = overData.itemId === undefined ? null : findSortableLocation(containers, overData.itemId, getItemId);
|
|
71
|
+
const keyboardDrag = typeof KeyboardEvent !== 'undefined' && event.activatorEvent instanceof KeyboardEvent;
|
|
72
|
+
const insertAfter = keyboardDrag
|
|
73
|
+
? source !== null && target !== null && source.containerId === target.containerId && source.index < target.index
|
|
74
|
+
: overData.itemId !== undefined && translated !== null && targetContainer?.layout === 'grid'
|
|
75
|
+
? translated.left + translated.width / 2 > event.over.rect.left + event.over.rect.width / 2
|
|
76
|
+
: overData.itemId !== undefined && translated !== null
|
|
77
|
+
&& translated.top + translated.height / 2 > event.over.rect.top + event.over.rect.height / 2;
|
|
78
|
+
return projectSortableMove(containers, activeData.itemId, getItemId, {
|
|
79
|
+
overContainerId: overData.containerId,
|
|
80
|
+
overItemId: overData.itemId,
|
|
81
|
+
insertAfter,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
const collisionDetection = (args) => {
|
|
85
|
+
const pointer = pointerWithin(args);
|
|
86
|
+
const pointerItems = pointer.filter((collision) => getCollisionEngineData(collision)?.type === 'inkra-sortable-item');
|
|
87
|
+
if (pointerItems.length > 0)
|
|
88
|
+
return pointerItems;
|
|
89
|
+
if (pointer.length > 0)
|
|
90
|
+
return pointer;
|
|
91
|
+
const intersections = rectIntersection(args);
|
|
92
|
+
const intersectingItems = intersections.filter((collision) => getCollisionEngineData(collision)?.type === 'inkra-sortable-item');
|
|
93
|
+
if (intersectingItems.length > 0)
|
|
94
|
+
return intersectingItems;
|
|
95
|
+
return intersections.length > 0 ? intersections : closestCenter(args);
|
|
96
|
+
};
|
|
97
|
+
function SortableContainer({ container, getItemId, renderItem, renderContainerHeader, handle, isItemDisabled, itemClassName, containerClassName, activeId, handleLabel, getItemLabel, }) {
|
|
98
|
+
const disabled = container.disabled === true;
|
|
99
|
+
const { isOver, setNodeRef } = useDroppable({
|
|
100
|
+
id: engineContainerId(container.id),
|
|
101
|
+
data: { type: 'inkra-sortable-container', containerId: container.id, disabled },
|
|
102
|
+
});
|
|
103
|
+
const ids = container.items.map((item) => engineItemId(getItemId(item)));
|
|
104
|
+
const layout = container.layout ?? 'list';
|
|
105
|
+
const acceptingOver = isOver && !disabled;
|
|
106
|
+
return _jsxs(PencilSurface, { as: "section", className: ['inkra-sortable__container', containerClassName].filter(Boolean).join(' '), "data-disabled": disabled || undefined, "data-layout": layout, "data-over": acceptingOver || undefined, "aria-disabled": disabled || undefined, "aria-label": container.label ?? String(container.id), ref: setNodeRef, seed: `sortable-container-${String(container.id)}`, variant: "paper", children: [acceptingOver && _jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-sortable__container-target", seed: `sortable-container-${String(container.id)}-target`, variant: "selection" }), (renderContainerHeader || container.label) && _jsxs("div", { className: "inkra-sortable__container-header", children: [_jsx("div", { className: "inkra-sortable__container-title", children: renderContainerHeader
|
|
107
|
+
? renderContainerHeader({ container, isOver: acceptingOver, itemCount: container.items.length })
|
|
108
|
+
: container.label ? _jsx(PencilText, { children: container.label }) : null }), _jsx(PencilLine, { "aria-hidden": "true", className: "inkra-sortable__container-divider", seed: `sortable-container-${String(container.id)}-divider` })] }), _jsx(SortableContext, { items: ids, strategy: layout === 'grid' ? rectSortingStrategy : verticalListSortingStrategy, children: _jsxs("div", { className: "inkra-sortable__items", children: [container.items.map((item, index) => {
|
|
109
|
+
const id = getItemId(item);
|
|
110
|
+
return _jsx(SortableItem, { activeId: activeId, container: container, disabled: disabled || isItemDisabled?.(item, container) === true, handle: handle, handleLabel: `${handleLabel}: ${getItemLabel(item)}`, id: id, index: index, item: item, itemClassName: itemClassName, renderItem: renderItem }, engineItemId(id));
|
|
111
|
+
}), container.items.length === 0 && _jsx("div", { className: "inkra-sortable__empty", "aria-hidden": "true" })] }) })] });
|
|
112
|
+
}
|
|
113
|
+
function SortableItem({ activeId, container, disabled, handle, handleLabel, id, index, item, itemClassName, renderItem, }) {
|
|
114
|
+
const hasHandle = handle === true || typeof handle === 'function';
|
|
115
|
+
const { attributes, isDragging, listeners, setActivatorNodeRef, setNodeRef, transform, transition, } = useSortable({
|
|
116
|
+
id: engineItemId(id),
|
|
117
|
+
disabled: disabled ? { draggable: true, droppable: false } : false,
|
|
118
|
+
data: { type: 'inkra-sortable-item', containerId: container.id, itemId: id, disabled },
|
|
119
|
+
});
|
|
120
|
+
const state = {
|
|
121
|
+
item,
|
|
122
|
+
id,
|
|
123
|
+
containerId: container.id,
|
|
124
|
+
index,
|
|
125
|
+
disabled,
|
|
126
|
+
isDragging,
|
|
127
|
+
isOverlay: false,
|
|
128
|
+
};
|
|
129
|
+
const activatorProps = { ...attributes, ...listeners };
|
|
130
|
+
const itemActivatorProps = filterItemActivatorProps({ ...attributes, ...listeners });
|
|
131
|
+
const setItemRef = (element) => {
|
|
132
|
+
setNodeRef(element);
|
|
133
|
+
if (!hasHandle)
|
|
134
|
+
setActivatorNodeRef(element);
|
|
135
|
+
};
|
|
136
|
+
return _jsxs("div", { ...(!hasHandle ? itemActivatorProps : {}), "aria-disabled": disabled || undefined, "aria-label": !hasHandle ? handleLabel : undefined, className: ['inkra-sortable__item', itemClassName].filter(Boolean).join(' '), "data-disabled": disabled || undefined, "data-dragging": isDragging || undefined, "data-handle": hasHandle || undefined, "data-sortable-id": String(id), ref: setItemRef, style: { transform: CSS.Transform.toString(transform), transition }, children: [_jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-sortable__item-surface", seed: `sortable-item-${String(id)}`, variant: "paper" }), _jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-sortable__focus", seed: `sortable-focus-${String(id)}`, variant: "outline" }), activeId === id && _jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-sortable__placeholder", seed: `sortable-placeholder-${String(id)}`, variant: "selection" }), _jsx("div", { className: "inkra-sortable__item-content", children: renderItem(state) }), hasHandle && _jsx("div", { className: "inkra-sortable__handle-slot", children: typeof handle === 'function'
|
|
137
|
+
? handle({ ...state, props: { ...activatorProps, 'aria-label': handleLabel, disabled, ref: setActivatorNodeRef } })
|
|
138
|
+
: _jsx("button", { ...activatorProps, "aria-label": handleLabel, className: "inkra-sortable__handle", "data-sortable-handle": "", disabled: disabled, ref: setActivatorNodeRef, type: "button", children: _jsx(PencilIcon, { "aria-hidden": "true", paths: gripIcon, size: 24, sourceSize: 24 }) }) })] });
|
|
139
|
+
}
|
|
140
|
+
export function Sortable({ autoScroll = true, className, containerClassName, containers, getContainerLabel = (container) => container.label ?? String(container.id), getItemId, getItemLabel = (item) => String(getItemId(item)), handle = false, isItemDisabled, itemClassName, labels: labelsProp, onChange, onMove, onReorder, renderContainerHeader, renderItem, renderOverlay, }) {
|
|
141
|
+
const labels = { ...defaultLabels, ...labelsProp };
|
|
142
|
+
const [activeId, setActiveId] = useState(null);
|
|
143
|
+
const [activeWidth, setActiveWidth] = useState(null);
|
|
144
|
+
const [projected, setProjected] = useState(null);
|
|
145
|
+
const initialRef = useRef([]);
|
|
146
|
+
const projectedRef = useRef([]);
|
|
147
|
+
const sensors = useSensors(useSensor(MouseSensor, { activationConstraint: { distance: 6 } }), useSensor(TouchSensor, { activationConstraint: { delay: 180, tolerance: 8 } }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }));
|
|
148
|
+
const visibleContainers = projected ?? cloneSortableContainers(containers);
|
|
149
|
+
const activeLocation = activeId === null ? null : findSortableLocation(visibleContainers, activeId, getItemId);
|
|
150
|
+
const activeContainer = activeLocation === null
|
|
151
|
+
? null
|
|
152
|
+
: visibleContainers.find((container) => container.id === activeLocation.containerId) ?? null;
|
|
153
|
+
const activeItem = activeContainer && activeLocation
|
|
154
|
+
? activeContainer.items[activeLocation.index]
|
|
155
|
+
: undefined;
|
|
156
|
+
const announcements = useMemo(() => ({
|
|
157
|
+
onDragStart({ active }) {
|
|
158
|
+
const data = getEngineData(active);
|
|
159
|
+
if (data?.itemId === undefined)
|
|
160
|
+
return undefined;
|
|
161
|
+
const location = findSortableLocation(containers, data.itemId, getItemId);
|
|
162
|
+
const container = location && containers.find((entry) => entry.id === location.containerId);
|
|
163
|
+
const item = container && location ? container.items[location.index] : undefined;
|
|
164
|
+
return container && location && item !== undefined
|
|
165
|
+
? labels.pickedUp(getItemLabel(item), getContainerLabel(container), location.index + 1, container.items.length)
|
|
166
|
+
: undefined;
|
|
167
|
+
},
|
|
168
|
+
onDragOver({ active, over }) {
|
|
169
|
+
const data = getEngineData(active);
|
|
170
|
+
const overData = getEngineData(over);
|
|
171
|
+
if (data?.itemId === undefined || !overData || overData.disabled)
|
|
172
|
+
return undefined;
|
|
173
|
+
const current = projectedRef.current.length > 0 ? projectedRef.current : containers;
|
|
174
|
+
const location = findSortableLocation(current, data.itemId, getItemId);
|
|
175
|
+
const container = location && current.find((entry) => entry.id === location.containerId);
|
|
176
|
+
const item = container && location ? container.items[location.index] : undefined;
|
|
177
|
+
return container && location && item !== undefined
|
|
178
|
+
? labels.movedOver(getItemLabel(item), getContainerLabel(container), location.index + 1, container.items.length)
|
|
179
|
+
: undefined;
|
|
180
|
+
},
|
|
181
|
+
onDragEnd({ active, over }) {
|
|
182
|
+
const data = getEngineData(active);
|
|
183
|
+
const overData = getEngineData(over);
|
|
184
|
+
if (data?.itemId === undefined || !over)
|
|
185
|
+
return undefined;
|
|
186
|
+
if (overData?.disabled) {
|
|
187
|
+
const location = findSortableLocation(initialRef.current, data.itemId, getItemId);
|
|
188
|
+
const container = location && initialRef.current.find((entry) => entry.id === location.containerId);
|
|
189
|
+
const item = container && location ? container.items[location.index] : undefined;
|
|
190
|
+
return item === undefined ? undefined : labels.cancelled(getItemLabel(item));
|
|
191
|
+
}
|
|
192
|
+
const current = projectedRef.current;
|
|
193
|
+
const location = findSortableLocation(current, data.itemId, getItemId);
|
|
194
|
+
const container = location && current.find((entry) => entry.id === location.containerId);
|
|
195
|
+
const item = container && location ? container.items[location.index] : undefined;
|
|
196
|
+
return container && location && item !== undefined
|
|
197
|
+
? labels.dropped(getItemLabel(item), getContainerLabel(container), location.index + 1, container.items.length)
|
|
198
|
+
: undefined;
|
|
199
|
+
},
|
|
200
|
+
onDragCancel({ active }) {
|
|
201
|
+
const data = getEngineData(active);
|
|
202
|
+
if (data?.itemId === undefined)
|
|
203
|
+
return undefined;
|
|
204
|
+
const location = findSortableLocation(initialRef.current, data.itemId, getItemId);
|
|
205
|
+
const container = location && initialRef.current.find((entry) => entry.id === location.containerId);
|
|
206
|
+
const item = container && location ? container.items[location.index] : undefined;
|
|
207
|
+
return item === undefined ? undefined : labels.cancelled(getItemLabel(item));
|
|
208
|
+
},
|
|
209
|
+
}), [containers, getContainerLabel, getItemId, getItemLabel, labels]);
|
|
210
|
+
function resetDrag() {
|
|
211
|
+
setActiveId(null);
|
|
212
|
+
setActiveWidth(null);
|
|
213
|
+
setProjected(null);
|
|
214
|
+
projectedRef.current = [];
|
|
215
|
+
}
|
|
216
|
+
function handleDragStart(event) {
|
|
217
|
+
const data = getEngineData(event.active);
|
|
218
|
+
if (data?.itemId === undefined)
|
|
219
|
+
return;
|
|
220
|
+
const snapshot = cloneSortableContainers(containers);
|
|
221
|
+
initialRef.current = snapshot;
|
|
222
|
+
projectedRef.current = snapshot;
|
|
223
|
+
setProjected(snapshot);
|
|
224
|
+
setActiveId(data.itemId);
|
|
225
|
+
setActiveWidth(event.active.rect.current.initial?.width ?? null);
|
|
226
|
+
}
|
|
227
|
+
function handleDragOver(event) {
|
|
228
|
+
const overData = getEngineData(event.over);
|
|
229
|
+
if (!event.over || overData?.disabled) {
|
|
230
|
+
const restored = cloneSortableContainers(initialRef.current);
|
|
231
|
+
projectedRef.current = restored;
|
|
232
|
+
setProjected(restored);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const next = getDropProjection(projectedRef.current, event, getItemId);
|
|
236
|
+
projectedRef.current = next;
|
|
237
|
+
setProjected(next);
|
|
238
|
+
}
|
|
239
|
+
function handleDragEnd(event) {
|
|
240
|
+
const data = getEngineData(event.active);
|
|
241
|
+
const overData = getEngineData(event.over);
|
|
242
|
+
if (data?.itemId === undefined || !event.over || overData?.disabled) {
|
|
243
|
+
resetDrag();
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const next = projectedRef.current;
|
|
247
|
+
const from = findSortableLocation(initialRef.current, data.itemId, getItemId);
|
|
248
|
+
const to = findSortableLocation(next, data.itemId, getItemId);
|
|
249
|
+
const sourceContainer = from && initialRef.current.find((container) => container.id === from.containerId);
|
|
250
|
+
const item = sourceContainer && from ? sourceContainer.items[from.index] : undefined;
|
|
251
|
+
if (from && to && item !== undefined && !sortableContainersEqual(initialRef.current, next, getItemId)) {
|
|
252
|
+
const details = {
|
|
253
|
+
activeId: data.itemId,
|
|
254
|
+
overId: overData?.itemId ?? null,
|
|
255
|
+
from,
|
|
256
|
+
to,
|
|
257
|
+
item,
|
|
258
|
+
type: from.containerId === to.containerId ? 'reorder' : 'move',
|
|
259
|
+
};
|
|
260
|
+
onChange(next, details);
|
|
261
|
+
if (details.type === 'reorder')
|
|
262
|
+
onReorder?.(details);
|
|
263
|
+
else
|
|
264
|
+
onMove?.(details);
|
|
265
|
+
}
|
|
266
|
+
resetDrag();
|
|
267
|
+
}
|
|
268
|
+
function handleDragCancel(_event) {
|
|
269
|
+
resetDrag();
|
|
270
|
+
}
|
|
271
|
+
return _jsxs(DndContext, { accessibility: {
|
|
272
|
+
announcements,
|
|
273
|
+
screenReaderInstructions: { draggable: labels.screenReaderInstructions },
|
|
274
|
+
}, autoScroll: autoScroll, collisionDetection: collisionDetection, onDragCancel: handleDragCancel, onDragEnd: handleDragEnd, onDragOver: handleDragOver, onDragStart: handleDragStart, sensors: sensors, children: [_jsx("div", { className: ['inkra-sortable', className].filter(Boolean).join(' '), "data-dragging": activeId !== null || undefined, children: visibleContainers.map((container) => _jsx(SortableContainer, { activeId: activeId, container: container, containerClassName: containerClassName, getItemId: getItemId, getItemLabel: getItemLabel, handle: handle, handleLabel: labels.handle, isItemDisabled: isItemDisabled, itemClassName: itemClassName, renderContainerHeader: renderContainerHeader, renderItem: renderItem }, container.id)) }), _jsx(DragOverlay, { dropAnimation: null, children: activeItem !== undefined && activeContainer && activeLocation ? _jsxs("div", { className: "inkra-sortable__overlay", style: activeWidth === null ? undefined : { '--inkra-sortable-overlay-width': `${activeWidth}px` }, children: [_jsx(PencilSurface, { "aria-hidden": "true", as: "span", className: "inkra-sortable__overlay-surface", seed: `sortable-overlay-${String(activeId)}`, variant: "paper" }), _jsx("div", { className: "inkra-sortable__item-content", children: (renderOverlay ?? renderItem)({
|
|
275
|
+
item: activeItem,
|
|
276
|
+
id: activeId,
|
|
277
|
+
containerId: activeContainer.id,
|
|
278
|
+
index: activeLocation.index,
|
|
279
|
+
disabled: false,
|
|
280
|
+
isDragging: true,
|
|
281
|
+
isOverlay: true,
|
|
282
|
+
}) })] }) : null })] });
|
|
283
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type SortableIdentifier = string | number;
|
|
2
|
+
export type SortableLayout = 'list' | 'grid';
|
|
3
|
+
export interface SortableContainerData<Item> {
|
|
4
|
+
id: SortableIdentifier;
|
|
5
|
+
items: readonly Item[];
|
|
6
|
+
label?: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
layout?: SortableLayout;
|
|
9
|
+
}
|
|
10
|
+
export interface SortableLocation {
|
|
11
|
+
containerId: SortableIdentifier;
|
|
12
|
+
index: number;
|
|
13
|
+
}
|
|
14
|
+
export interface SortableChangeDetails<Item> {
|
|
15
|
+
activeId: SortableIdentifier;
|
|
16
|
+
overId: SortableIdentifier | null;
|
|
17
|
+
from: SortableLocation;
|
|
18
|
+
to: SortableLocation;
|
|
19
|
+
item: Item;
|
|
20
|
+
type: 'reorder' | 'move';
|
|
21
|
+
}
|
|
22
|
+
export interface SortableProjectionOptions {
|
|
23
|
+
overContainerId: SortableIdentifier;
|
|
24
|
+
overItemId?: SortableIdentifier;
|
|
25
|
+
insertAfter?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare function cloneSortableContainers<Item>(containers: readonly SortableContainerData<Item>[]): SortableContainerData<Item>[];
|
|
28
|
+
export declare function findSortableLocation<Item>(containers: readonly SortableContainerData<Item>[], itemId: SortableIdentifier, getItemId: (item: Item) => SortableIdentifier): SortableLocation | null;
|
|
29
|
+
export declare function projectSortableMove<Item>(containers: readonly SortableContainerData<Item>[], activeId: SortableIdentifier, getItemId: (item: Item) => SortableIdentifier, options: SortableProjectionOptions): SortableContainerData<Item>[];
|
|
30
|
+
export declare function sortableContainersEqual<Item>(left: readonly SortableContainerData<Item>[], right: readonly SortableContainerData<Item>[], getItemId: (item: Item) => SortableIdentifier): boolean;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export function cloneSortableContainers(containers) {
|
|
2
|
+
return containers.map((container) => ({ ...container, items: [...container.items] }));
|
|
3
|
+
}
|
|
4
|
+
export function findSortableLocation(containers, itemId, getItemId) {
|
|
5
|
+
for (const container of containers) {
|
|
6
|
+
const index = container.items.findIndex((item) => getItemId(item) === itemId);
|
|
7
|
+
if (index >= 0)
|
|
8
|
+
return { containerId: container.id, index };
|
|
9
|
+
}
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
export function projectSortableMove(containers, activeId, getItemId, options) {
|
|
13
|
+
const source = findSortableLocation(containers, activeId, getItemId);
|
|
14
|
+
const targetContainerIndex = containers.findIndex((container) => container.id === options.overContainerId);
|
|
15
|
+
if (!source || targetContainerIndex < 0 || containers[targetContainerIndex]?.disabled) {
|
|
16
|
+
return cloneSortableContainers(containers);
|
|
17
|
+
}
|
|
18
|
+
if (options.overItemId === activeId)
|
|
19
|
+
return cloneSortableContainers(containers);
|
|
20
|
+
const sourceContainerIndex = containers.findIndex((container) => container.id === source.containerId);
|
|
21
|
+
const result = cloneSortableContainers(containers);
|
|
22
|
+
const sourceItems = [...result[sourceContainerIndex].items];
|
|
23
|
+
const [activeItem] = sourceItems.splice(source.index, 1);
|
|
24
|
+
if (activeItem === undefined)
|
|
25
|
+
return result;
|
|
26
|
+
if (sourceContainerIndex === targetContainerIndex) {
|
|
27
|
+
const originalTargetIndex = options.overItemId === undefined
|
|
28
|
+
? sourceItems.length
|
|
29
|
+
: containers[targetContainerIndex].items.findIndex((item) => getItemId(item) === options.overItemId);
|
|
30
|
+
if (originalTargetIndex < 0)
|
|
31
|
+
return result;
|
|
32
|
+
let targetIndex = originalTargetIndex;
|
|
33
|
+
if (source.index < originalTargetIndex)
|
|
34
|
+
targetIndex -= 1;
|
|
35
|
+
if (options.insertAfter)
|
|
36
|
+
targetIndex += 1;
|
|
37
|
+
targetIndex = Math.max(0, Math.min(targetIndex, sourceItems.length));
|
|
38
|
+
sourceItems.splice(targetIndex, 0, activeItem);
|
|
39
|
+
result[sourceContainerIndex] = { ...result[sourceContainerIndex], items: sourceItems };
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
const targetItems = [...result[targetContainerIndex].items];
|
|
43
|
+
let targetIndex = options.overItemId === undefined
|
|
44
|
+
? targetItems.length
|
|
45
|
+
: targetItems.findIndex((item) => getItemId(item) === options.overItemId);
|
|
46
|
+
if (targetIndex < 0)
|
|
47
|
+
targetIndex = targetItems.length;
|
|
48
|
+
if (options.insertAfter)
|
|
49
|
+
targetIndex += 1;
|
|
50
|
+
targetIndex = Math.max(0, Math.min(targetIndex, targetItems.length));
|
|
51
|
+
targetItems.splice(targetIndex, 0, activeItem);
|
|
52
|
+
result[sourceContainerIndex] = { ...result[sourceContainerIndex], items: sourceItems };
|
|
53
|
+
result[targetContainerIndex] = { ...result[targetContainerIndex], items: targetItems };
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
export function sortableContainersEqual(left, right, getItemId) {
|
|
57
|
+
return left.length === right.length && left.every((container, containerIndex) => {
|
|
58
|
+
const other = right[containerIndex];
|
|
59
|
+
return other !== undefined
|
|
60
|
+
&& container.id === other.id
|
|
61
|
+
&& container.items.length === other.items.length
|
|
62
|
+
&& container.items.every((item, itemIndex) => getItemId(item) === getItemId(other.items[itemIndex]));
|
|
63
|
+
});
|
|
64
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'react';
|
|
2
|
+
import type { SparklineDatum } from './model.js';
|
|
3
|
+
export type SparklineType = 'line' | 'bar';
|
|
4
|
+
export interface SparklineProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
5
|
+
data: readonly SparklineDatum[];
|
|
6
|
+
type?: SparklineType;
|
|
7
|
+
width?: number;
|
|
8
|
+
height?: number;
|
|
9
|
+
min?: number;
|
|
10
|
+
max?: number;
|
|
11
|
+
label?: string;
|
|
12
|
+
showPoints?: boolean;
|
|
13
|
+
showArea?: boolean;
|
|
14
|
+
showSummary?: boolean;
|
|
15
|
+
getLabel?: (value: number | null, index: number) => string;
|
|
16
|
+
}
|
|
17
|
+
export declare const Sparkline: import("react").ForwardRefExoticComponent<SparklineProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
18
|
+
export { createSparklineGeometry, normalizeSparklineData, sparklineDomain } from './model.js';
|
|
19
|
+
export type { SparklineDatum, SparklinePoint } from './model.js';
|