@pallasoft/ps-table-components 1.22.2 → 1.23.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/dist/components/ps-data-table.d.ts +2 -1
- package/dist/components/ps-data-table.js +45 -10
- package/dist/components/ps-table-reorder-frame.js +15 -2
- package/dist/components/ps-table-reorder-handle.js +1 -1
- package/dist/components/ps-table-sort-header.js +1 -1
- package/dist/components/ps-table-sortable-row.d.ts +5 -1
- package/dist/components/ps-table-sortable-row.js +12 -4
- package/dist/constants/ps-table-drop-classes.d.ts +2 -0
- package/dist/constants/ps-table-drop-classes.js +8 -0
- package/dist/constants/ps-table-drop-placement.d.ts +6 -0
- package/dist/constants/ps-table-drop-placement.js +8 -0
- package/dist/constants/ps-table-pin-classes.d.ts +16 -0
- package/dist/constants/ps-table-pin-classes.js +19 -0
- package/dist/constants/table-breakpoint.d.ts +7 -0
- package/dist/constants/table-breakpoint.js +13 -0
- package/dist/esm/components/ps-data-table.js +46 -11
- package/dist/esm/components/ps-table-reorder-frame.js +15 -2
- package/dist/esm/components/ps-table-reorder-handle.js +1 -1
- package/dist/esm/components/ps-table-sort-header.js +1 -1
- package/dist/esm/components/ps-table-sortable-row.js +12 -4
- package/dist/esm/constants/ps-table-drop-classes.js +5 -0
- package/dist/esm/constants/ps-table-drop-placement.js +5 -0
- package/dist/esm/constants/ps-table-pin-classes.js +16 -0
- package/dist/esm/constants/table-breakpoint.js +10 -0
- package/dist/esm/hooks/use-ps-table-overflow.js +19 -0
- package/dist/esm/hooks/use-ps-table-reorder.js +89 -15
- package/dist/esm/index.js +10 -0
- package/dist/esm/interfaces/table-drop.js +1 -0
- package/dist/esm/interfaces/table-nesting-announcements.js +1 -0
- package/dist/esm/interfaces/table-overflow-edges.js +1 -0
- package/dist/esm/interfaces/table-pin-classes.js +1 -0
- package/dist/esm/interfaces/table-reorder-nesting-binding.js +1 -0
- package/dist/esm/interfaces/table-reorder-nesting.js +1 -0
- package/dist/esm/services/ps-table-overflow-service.js +11 -0
- package/dist/esm/services/ps-table-pin-service.js +22 -0
- package/dist/esm/services/ps-table-reorder-service.js +38 -1
- package/dist/hooks/use-ps-table-overflow.d.ts +6 -0
- package/dist/hooks/use-ps-table-overflow.js +23 -0
- package/dist/hooks/use-ps-table-reorder.d.ts +6 -2
- package/dist/hooks/use-ps-table-reorder.js +87 -13
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/interfaces/table-column.d.ts +3 -0
- package/dist/interfaces/table-drop.d.ts +5 -0
- package/dist/interfaces/table-drop.js +2 -0
- package/dist/interfaces/table-nesting-announcements.d.ts +5 -0
- package/dist/interfaces/table-nesting-announcements.js +2 -0
- package/dist/interfaces/table-overflow-edges.d.ts +4 -0
- package/dist/interfaces/table-overflow-edges.js +2 -0
- package/dist/interfaces/table-pin-classes.d.ts +5 -0
- package/dist/interfaces/table-pin-classes.js +2 -0
- package/dist/interfaces/table-reorder-nesting-binding.d.ts +8 -0
- package/dist/interfaces/table-reorder-nesting-binding.js +2 -0
- package/dist/interfaces/table-reorder-nesting.d.ts +8 -0
- package/dist/interfaces/table-reorder-nesting.js +2 -0
- package/dist/interfaces/table-reorder-row-props.d.ts +3 -0
- package/dist/interfaces/table-reorder.d.ts +4 -2
- package/dist/services/ps-table-overflow-service.d.ts +6 -0
- package/dist/services/ps-table-overflow-service.js +15 -0
- package/dist/services/ps-table-pin-service.d.ts +5 -0
- package/dist/services/ps-table-pin-service.js +26 -0
- package/dist/services/ps-table-reorder-service.d.ts +11 -0
- package/dist/services/ps-table-reorder-service.js +38 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { PsDragGrip } from '@pallasoft/ps-core-components';
|
|
3
3
|
import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
|
|
4
|
-
export const PsTableReorderHandle = ({ activatorRef, className, label, ...buttonProps }) => (_jsx("button", { ...buttonProps, "aria-label": label, className: PallasoftClassNameService.merge('ps-focus-ring flex h-7 w-6 shrink-0 cursor-grab touch-none items-center justify-center rounded-ps-control text-ink/40 transition-colors hover:bg-mist hover:text-ink active:cursor-grabbing', className), onClick: (event) => event.stopPropagation(), ref: activatorRef, title: label, type: 'button', children: _jsx(PsDragGrip, {}) }));
|
|
4
|
+
export const PsTableReorderHandle = ({ activatorRef, className, label, ...buttonProps }) => (_jsx("button", { ...buttonProps, "aria-label": label, className: PallasoftClassNameService.merge('ps-focus-ring ps-touch-target relative flex h-7 w-6 shrink-0 cursor-grab touch-none items-center justify-center rounded-ps-control text-ink/40 transition-colors hover:bg-mist hover:text-ink active:cursor-grabbing', className), onClick: (event) => event.stopPropagation(), ref: activatorRef, title: label, type: 'button', children: _jsx(PsDragGrip, {}) }));
|
|
@@ -10,5 +10,5 @@ export const PsTableSortHeader = ({ align, columnId, label, onSort, sort, }) =>
|
|
|
10
10
|
: PsIconKey.SortDescending;
|
|
11
11
|
return (_jsxs("button", { className: PallasoftClassNameService.merge('ps-focus-ring group inline-flex items-center gap-1 rounded-ps-control uppercase tracking-[0.18em] transition-colors hover:text-ink', align === 'right' ? 'flex-row-reverse' : '', isSorted ? 'text-ink' : ''), onClick: () => onSort(columnId), type: 'button', children: [_jsx("span", { children: label }), _jsx(PsIcon, { "aria-hidden": 'true', className: PallasoftClassNameService.merge('block h-3.5 w-3.5 shrink-0', isSorted
|
|
12
12
|
? 'text-primary'
|
|
13
|
-
: 'opacity-0 group-hover:opacity-60 group-focus-visible:opacity-60'), iconKey: iconKey })] }));
|
|
13
|
+
: 'opacity-0 group-hover:opacity-60 group-focus-visible:opacity-60 [@media(hover:none)]:opacity-40'), iconKey: iconKey })] }));
|
|
14
14
|
};
|
|
@@ -2,10 +2,18 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useSortable } from '@dnd-kit/sortable';
|
|
3
3
|
import { CSS } from '@dnd-kit/utilities';
|
|
4
4
|
import { PsDragConfig } from '@pallasoft/ps-core-components';
|
|
5
|
+
import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
|
|
6
|
+
import { PsTableDropClasses } from '../constants/ps-table-drop-classes';
|
|
5
7
|
import { PsTableReorderHandle } from './ps-table-reorder-handle';
|
|
6
|
-
export const PsTableSortableRow = ({ children, className, handleLabel, hasHandle, isDisabled, measureRef, rowId, style, ...rowProps }) => {
|
|
7
|
-
const { attributes, isDragging, listeners, setActivatorNodeRef, setNodeRef, transform, transition, } = useSortable({
|
|
8
|
-
|
|
8
|
+
export const PsTableSortableRow = ({ children, className, dropPlacement = null, handleCellClassName, handleLabel, hasHandle, isDisabled, isDropTarget = false, measureRef, rowId, style, ...rowProps }) => {
|
|
9
|
+
const { attributes, isDragging, listeners, setActivatorNodeRef, setNodeRef, transform, transition, } = useSortable({
|
|
10
|
+
disabled: {
|
|
11
|
+
draggable: isDisabled || !hasHandle,
|
|
12
|
+
droppable: isDisabled || (!hasHandle && !isDropTarget),
|
|
13
|
+
},
|
|
14
|
+
id: rowId,
|
|
15
|
+
});
|
|
16
|
+
return (_jsxs("tr", { ...rowProps, className: PallasoftClassNameService.merge(className, dropPlacement === null ? '' : PsTableDropClasses[dropPlacement]), ref: (element) => {
|
|
9
17
|
setNodeRef(element);
|
|
10
18
|
if (measureRef)
|
|
11
19
|
measureRef(element);
|
|
@@ -14,5 +22,5 @@ export const PsTableSortableRow = ({ children, className, handleLabel, hasHandle
|
|
|
14
22
|
opacity: isDragging ? PsDragConfig.placeholderOpacity : style?.opacity,
|
|
15
23
|
transform: CSS.Translate.toString(transform),
|
|
16
24
|
transition,
|
|
17
|
-
}, children: [_jsx("td", { className: 'w-9 pl-3 pr-0', onClick: (event) => event.stopPropagation(), children: hasHandle ? (_jsx(PsTableReorderHandle, { ...attributes, ...listeners, activatorRef: setActivatorNodeRef, label: handleLabel })) : null }), children] }));
|
|
25
|
+
}, children: [_jsx("td", { className: PallasoftClassNameService.merge('w-9 min-w-9 pl-3 pr-0', handleCellClassName), onClick: (event) => event.stopPropagation(), children: hasHandle ? (_jsx(PsTableReorderHandle, { ...attributes, ...listeners, activatorRef: setActivatorNodeRef, label: handleLabel })) : null }), children] }));
|
|
18
26
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export const PsTableDropClasses = {
|
|
2
|
+
after: '[&>td]:shadow-[inset_0_-2px_0_0_rgb(var(--ps-color-primary-rgb))]',
|
|
3
|
+
before: '[&>td]:shadow-[inset_0_2px_0_0_rgb(var(--ps-color-primary-rgb))]',
|
|
4
|
+
into: 'bg-primary/10 [&>td]:shadow-[inset_0_0_0_2px_rgb(var(--ps-color-primary-rgb)/0.5)]',
|
|
5
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const PsTablePinClasses = {
|
|
2
|
+
cell: 'ps-table-pin',
|
|
3
|
+
edge: 'ps-table-pin-start-edge',
|
|
4
|
+
end: 'ps-table-pin ps-table-pin-end right-0',
|
|
5
|
+
first: {
|
|
6
|
+
both: 'left-[4.75rem]',
|
|
7
|
+
none: 'left-0',
|
|
8
|
+
reorder: 'left-9',
|
|
9
|
+
select: 'left-10',
|
|
10
|
+
},
|
|
11
|
+
reorder: 'left-0',
|
|
12
|
+
select: {
|
|
13
|
+
alone: 'left-0',
|
|
14
|
+
withReorder: 'left-9',
|
|
15
|
+
},
|
|
16
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { PsTableOverflowService } from '../services/ps-table-overflow-service';
|
|
3
|
+
export const usePsTableOverflow = (layoutKey) => {
|
|
4
|
+
const ref = useRef(null);
|
|
5
|
+
const [edges, setEdges] = useState(PsTableOverflowService.none);
|
|
6
|
+
const update = useCallback(() => {
|
|
7
|
+
const element = ref.current;
|
|
8
|
+
if (element === null)
|
|
9
|
+
return;
|
|
10
|
+
const next = PsTableOverflowService.edges(element.scrollLeft, element.clientWidth, element.scrollWidth);
|
|
11
|
+
setEdges((current) => (PsTableOverflowService.isSame(current, next) ? current : next));
|
|
12
|
+
}, []);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
update();
|
|
15
|
+
window.addEventListener('resize', update);
|
|
16
|
+
return () => window.removeEventListener('resize', update);
|
|
17
|
+
}, [layoutKey, update]);
|
|
18
|
+
return { edges, ref, update };
|
|
19
|
+
};
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import { useMemo, useState } from 'react';
|
|
2
|
-
import { closestCenter, } from '@dnd-kit/core';
|
|
1
|
+
import { useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { closestCenter, pointerWithin, } from '@dnd-kit/core';
|
|
3
3
|
import { usePsDragSensors } from '@pallasoft/ps-core-components';
|
|
4
|
+
import { PsTableDropPlacement } from '../constants/ps-table-drop-placement';
|
|
4
5
|
import { PsTableReorderService } from '../services/ps-table-reorder-service';
|
|
5
|
-
|
|
6
|
+
const pointerThenCenter = (args) => {
|
|
7
|
+
const within = pointerWithin(args);
|
|
8
|
+
return within.length > 0 ? within : closestCenter(args);
|
|
9
|
+
};
|
|
10
|
+
export const usePsTableReorder = ({ announcements: texts, enabled, instructions, items, nesting, onReorder, }) => {
|
|
6
11
|
const [activeId, setActiveId] = useState(null);
|
|
12
|
+
const [drop, setDrop] = useState(null);
|
|
13
|
+
const dropRef = useRef(null);
|
|
7
14
|
const sensors = usePsDragSensors();
|
|
8
15
|
const runs = useMemo(() => enabled
|
|
9
16
|
? PsTableReorderService.runs(items, (item) => item.groupKey, (item) => item.id)
|
|
@@ -11,6 +18,7 @@ export const usePsTableReorder = ({ announcements: texts, enabled, instructions,
|
|
|
11
18
|
const placements = useMemo(() => PsTableReorderService.placements(runs, (item) => item.id), [runs]);
|
|
12
19
|
const activePlacement = activeId === null ? undefined : placements.get(activeId);
|
|
13
20
|
const itemById = useMemo(() => new Map(items.map((item) => [item.id, item])), [items]);
|
|
21
|
+
const indexById = useMemo(() => new Map(items.map((item, index) => [item.id, index])), [items]);
|
|
14
22
|
const labelOf = (id) => {
|
|
15
23
|
const item = itemById.get(id);
|
|
16
24
|
return item === undefined ? id : item.label;
|
|
@@ -23,23 +31,83 @@ export const usePsTableReorder = ({ announcements: texts, enabled, instructions,
|
|
|
23
31
|
const placement = placements.get(id);
|
|
24
32
|
return placement === undefined ? 0 : placement.size;
|
|
25
33
|
};
|
|
34
|
+
const edgeFor = (activeKey, overId) => {
|
|
35
|
+
const activeIndex = indexById.get(activeKey);
|
|
36
|
+
const overIndex = indexById.get(overId);
|
|
37
|
+
return activeIndex !== undefined && overIndex !== undefined && activeIndex < overIndex
|
|
38
|
+
? PsTableDropPlacement.after
|
|
39
|
+
: PsTableDropPlacement.before;
|
|
40
|
+
};
|
|
41
|
+
const resolveDrop = (event) => {
|
|
42
|
+
if (nesting === undefined || event.over === null || event.over.id === event.active.id)
|
|
43
|
+
return null;
|
|
44
|
+
const activeKey = String(event.active.id);
|
|
45
|
+
const overId = String(event.over.id);
|
|
46
|
+
const placement = PsTableReorderService.dropPlacement(PsTableReorderService.pointerY(event.activatorEvent, event.delta.y), event.over.rect, edgeFor(activeKey, overId), (candidate) => nesting.canDrop(activeKey, overId, candidate));
|
|
47
|
+
return placement === null ? null : { overId, placement };
|
|
48
|
+
};
|
|
49
|
+
const announcedDrop = (activeKey, overId) => {
|
|
50
|
+
if (nesting === undefined)
|
|
51
|
+
return null;
|
|
52
|
+
const known = dropRef.current;
|
|
53
|
+
if (known !== null && known.overId === overId)
|
|
54
|
+
return known;
|
|
55
|
+
const placement = edgeFor(activeKey, overId);
|
|
56
|
+
return nesting.canDrop(activeKey, overId, placement) ? { overId, placement } : null;
|
|
57
|
+
};
|
|
58
|
+
const describeDrop = (active, target) => nesting === undefined
|
|
59
|
+
? undefined
|
|
60
|
+
: nesting.announcements[target.placement](labelOf(active), labelOf(target.overId));
|
|
26
61
|
const announcements = {
|
|
27
62
|
onDragCancel: ({ active }) => texts.cancelled(labelOf(String(active.id))),
|
|
28
|
-
onDragEnd: ({ active, over }) =>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
63
|
+
onDragEnd: ({ active, over }) => {
|
|
64
|
+
if (nesting !== undefined) {
|
|
65
|
+
const target = over === null ? null : announcedDrop(String(active.id), String(over.id));
|
|
66
|
+
return target === null
|
|
67
|
+
? texts.cancelled(labelOf(String(active.id)))
|
|
68
|
+
: describeDrop(String(active.id), target);
|
|
69
|
+
}
|
|
70
|
+
return over === null
|
|
71
|
+
? texts.cancelled(labelOf(String(active.id)))
|
|
72
|
+
: texts.dropped(labelOf(String(active.id)), positionOf(String(over.id)), countOf(String(over.id)));
|
|
73
|
+
},
|
|
74
|
+
onDragOver: ({ active, over }) => {
|
|
75
|
+
if (over === null)
|
|
76
|
+
return undefined;
|
|
77
|
+
if (nesting !== undefined) {
|
|
78
|
+
const target = announcedDrop(String(active.id), String(over.id));
|
|
79
|
+
return target === null ? undefined : describeDrop(String(active.id), target);
|
|
80
|
+
}
|
|
81
|
+
return texts.moved(labelOf(String(active.id)), positionOf(String(over.id)), countOf(String(over.id)));
|
|
82
|
+
},
|
|
34
83
|
onDragStart: ({ active }) => texts.lifted(labelOf(String(active.id)), positionOf(String(active.id)), countOf(String(active.id))),
|
|
35
84
|
};
|
|
36
|
-
const
|
|
85
|
+
const handleDragMove = (event) => {
|
|
86
|
+
const next = resolveDrop(event);
|
|
87
|
+
dropRef.current = next;
|
|
88
|
+
setDrop((current) => current !== null &&
|
|
89
|
+
next !== null &&
|
|
90
|
+
current.overId === next.overId &&
|
|
91
|
+
current.placement === next.placement
|
|
92
|
+
? current
|
|
93
|
+
: next);
|
|
94
|
+
};
|
|
95
|
+
const handleDragEnd = (event) => {
|
|
96
|
+
const { active, over } = event;
|
|
97
|
+
const target = resolveDrop(event);
|
|
37
98
|
setActiveId(null);
|
|
38
|
-
|
|
99
|
+
setDrop(null);
|
|
100
|
+
dropRef.current = null;
|
|
101
|
+
if (nesting !== undefined) {
|
|
102
|
+
if (target !== null)
|
|
103
|
+
nesting.onMove(String(active.id), target.overId, target.placement);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (over === null || active.id === over.id || onReorder === undefined)
|
|
39
107
|
return;
|
|
40
108
|
const placement = placements.get(String(active.id));
|
|
41
|
-
const
|
|
42
|
-
if (placement === undefined ||
|
|
109
|
+
const sibling = placements.get(String(over.id));
|
|
110
|
+
if (placement === undefined || sibling === undefined || placement.runId !== sibling.runId)
|
|
43
111
|
return;
|
|
44
112
|
const run = runs.find((candidate) => candidate.id === placement.runId);
|
|
45
113
|
if (run === undefined)
|
|
@@ -51,13 +119,19 @@ export const usePsTableReorder = ({ announcements: texts, enabled, instructions,
|
|
|
51
119
|
activeRunId: activePlacement === undefined ? null : activePlacement.runId,
|
|
52
120
|
contextProps: {
|
|
53
121
|
accessibility: { announcements, screenReaderInstructions: { draggable: instructions } },
|
|
54
|
-
collisionDetection: closestCenter,
|
|
122
|
+
collisionDetection: nesting === undefined ? closestCenter : pointerThenCenter,
|
|
55
123
|
modifiers: [PsTableReorderService.lockToVerticalAxis],
|
|
56
|
-
onDragCancel: () =>
|
|
124
|
+
onDragCancel: () => {
|
|
125
|
+
setActiveId(null);
|
|
126
|
+
setDrop(null);
|
|
127
|
+
dropRef.current = null;
|
|
128
|
+
},
|
|
57
129
|
onDragEnd: handleDragEnd,
|
|
130
|
+
onDragMove: nesting === undefined ? undefined : handleDragMove,
|
|
58
131
|
onDragStart: ({ active }) => setActiveId(String(active.id)),
|
|
59
132
|
sensors,
|
|
60
133
|
},
|
|
134
|
+
drop,
|
|
61
135
|
placements,
|
|
62
136
|
};
|
|
63
137
|
};
|
package/dist/esm/index.js
CHANGED
|
@@ -3,7 +3,9 @@ export * from './components/ps-streamed-rows';
|
|
|
3
3
|
export * from './components/ps-table-stream-status';
|
|
4
4
|
export * from './components/ps-table-group-header';
|
|
5
5
|
export * from './components/ps-table-pagination';
|
|
6
|
+
export * from './constants/table-breakpoint';
|
|
6
7
|
export * from './constants/table-card-role';
|
|
8
|
+
export * from './constants/ps-table-pin-classes';
|
|
7
9
|
export * from './constants/table-column-size';
|
|
8
10
|
export * from './constants/table-filter-kind';
|
|
9
11
|
export * from './interfaces/table-column';
|
|
@@ -27,6 +29,11 @@ export * from './services/ps-table-group-service';
|
|
|
27
29
|
export * from './services/ps-table-query-service';
|
|
28
30
|
export * from './services/ps-table-search-service';
|
|
29
31
|
export * from './services/ps-table-scroll-service';
|
|
32
|
+
export * from './services/ps-table-pin-service';
|
|
33
|
+
export * from './services/ps-table-overflow-service';
|
|
34
|
+
export * from './hooks/use-ps-table-overflow';
|
|
35
|
+
export * from './interfaces/table-pin-classes';
|
|
36
|
+
export * from './interfaces/table-overflow-edges';
|
|
30
37
|
export * from './services/ps-table-stream-service';
|
|
31
38
|
export * from './components/ps-table-export-button';
|
|
32
39
|
export * from './constants/ps-table-download-config';
|
|
@@ -36,4 +43,7 @@ export * from './hooks/use-ps-table-page';
|
|
|
36
43
|
export * from './interfaces/ps-table-page-state';
|
|
37
44
|
export * from './interfaces/table-reorder';
|
|
38
45
|
export * from './interfaces/table-reorder-announcements';
|
|
46
|
+
export * from './interfaces/table-reorder-nesting';
|
|
47
|
+
export * from './interfaces/table-nesting-announcements';
|
|
48
|
+
export * from './constants/ps-table-drop-placement';
|
|
39
49
|
export * from './services/ps-table-reorder-service';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export class PsTableOverflowService {
|
|
2
|
+
static edges(scrollLeft, clientWidth, scrollWidth) {
|
|
3
|
+
const start = Math.abs(scrollLeft) > 0.5;
|
|
4
|
+
const end = scrollWidth - clientWidth - Math.abs(scrollLeft) > 0.5;
|
|
5
|
+
return { end, start };
|
|
6
|
+
}
|
|
7
|
+
static isSame(current, next) {
|
|
8
|
+
return current.end === next.end && current.start === next.start;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
PsTableOverflowService.none = { end: false, start: false };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { PsTablePinClasses } from '../constants/ps-table-pin-classes';
|
|
2
|
+
export class PsTablePinService {
|
|
3
|
+
static leading(isPinned, hasReorder, isSelectable) {
|
|
4
|
+
if (!isPinned)
|
|
5
|
+
return { first: '', reorder: '', select: '' };
|
|
6
|
+
const firstOffset = hasReorder && isSelectable
|
|
7
|
+
? PsTablePinClasses.first.both
|
|
8
|
+
: hasReorder
|
|
9
|
+
? PsTablePinClasses.first.reorder
|
|
10
|
+
: isSelectable
|
|
11
|
+
? PsTablePinClasses.first.select
|
|
12
|
+
: PsTablePinClasses.first.none;
|
|
13
|
+
return {
|
|
14
|
+
first: `${PsTablePinClasses.cell} ${PsTablePinClasses.edge} ${firstOffset}`,
|
|
15
|
+
reorder: `${PsTablePinClasses.cell} ${PsTablePinClasses.reorder}`,
|
|
16
|
+
select: `${PsTablePinClasses.cell} ${hasReorder ? PsTablePinClasses.select.withReorder : PsTablePinClasses.select.alone}`,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
static end(isPinned) {
|
|
20
|
+
return isPinned ? PsTablePinClasses.end : '';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PsTableDropPlacement } from '../constants/ps-table-drop-placement';
|
|
1
2
|
export class PsTableReorderService {
|
|
2
3
|
static runs(items, getKey, getId) {
|
|
3
4
|
const runs = [];
|
|
@@ -32,11 +33,47 @@ export class PsTableReorderService {
|
|
|
32
33
|
next.splice(to, 0, moved);
|
|
33
34
|
return next;
|
|
34
35
|
}
|
|
36
|
+
static pointerY(event, deltaY) {
|
|
37
|
+
if (event instanceof MouseEvent)
|
|
38
|
+
return event.clientY + deltaY;
|
|
39
|
+
if (typeof TouchEvent !== 'undefined' &&
|
|
40
|
+
event instanceof TouchEvent &&
|
|
41
|
+
event.touches.length > 0)
|
|
42
|
+
return event.touches[0].clientY + deltaY;
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
static dropPlacement(pointerY, rect, fallback, isAllowed) {
|
|
46
|
+
const allowed = PsTableReorderService.candidates(pointerY, rect, fallback).find(isAllowed);
|
|
47
|
+
return allowed === undefined ? null : allowed;
|
|
48
|
+
}
|
|
49
|
+
static candidates(pointerY, rect, fallback) {
|
|
50
|
+
if (pointerY === null || rect.height <= 0)
|
|
51
|
+
return [fallback];
|
|
52
|
+
const ratio = (pointerY - rect.top) / rect.height;
|
|
53
|
+
if (ratio < PsTableReorderService.edgeRatio)
|
|
54
|
+
return [PsTableDropPlacement.before, PsTableDropPlacement.into];
|
|
55
|
+
if (ratio > 1 - PsTableReorderService.edgeRatio)
|
|
56
|
+
return [PsTableDropPlacement.after, PsTableDropPlacement.into];
|
|
57
|
+
return [
|
|
58
|
+
PsTableDropPlacement.into,
|
|
59
|
+
ratio < 0.5 ? PsTableDropPlacement.before : PsTableDropPlacement.after,
|
|
60
|
+
];
|
|
61
|
+
}
|
|
35
62
|
}
|
|
63
|
+
PsTableReorderService.edgeRatio = 0.25;
|
|
64
|
+
PsTableReorderService.treeKey = 'tree';
|
|
36
65
|
PsTableReorderService.plain = {
|
|
37
66
|
Row: 'tr',
|
|
38
67
|
isActive: false,
|
|
39
|
-
rowProps: (rowId) => ({
|
|
68
|
+
rowProps: (rowId) => ({
|
|
69
|
+
dropPlacement: null,
|
|
70
|
+
handleLabel: '',
|
|
71
|
+
hasHandle: false,
|
|
72
|
+
isDisabled: true,
|
|
73
|
+
isDropTarget: false,
|
|
74
|
+
rowId,
|
|
75
|
+
}),
|
|
40
76
|
run: (_runId, _ids, children) => children,
|
|
41
77
|
};
|
|
78
|
+
PsTableReorderService.still = () => null;
|
|
42
79
|
PsTableReorderService.lockToVerticalAxis = ({ transform }) => ({ ...transform, x: 0 });
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.usePsTableOverflow = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const ps_table_overflow_service_1 = require("../services/ps-table-overflow-service");
|
|
6
|
+
const usePsTableOverflow = (layoutKey) => {
|
|
7
|
+
const ref = (0, react_1.useRef)(null);
|
|
8
|
+
const [edges, setEdges] = (0, react_1.useState)(ps_table_overflow_service_1.PsTableOverflowService.none);
|
|
9
|
+
const update = (0, react_1.useCallback)(() => {
|
|
10
|
+
const element = ref.current;
|
|
11
|
+
if (element === null)
|
|
12
|
+
return;
|
|
13
|
+
const next = ps_table_overflow_service_1.PsTableOverflowService.edges(element.scrollLeft, element.clientWidth, element.scrollWidth);
|
|
14
|
+
setEdges((current) => (ps_table_overflow_service_1.PsTableOverflowService.isSame(current, next) ? current : next));
|
|
15
|
+
}, []);
|
|
16
|
+
(0, react_1.useEffect)(() => {
|
|
17
|
+
update();
|
|
18
|
+
window.addEventListener('resize', update);
|
|
19
|
+
return () => window.removeEventListener('resize', update);
|
|
20
|
+
}, [layoutKey, update]);
|
|
21
|
+
return { edges, ref, update };
|
|
22
|
+
};
|
|
23
|
+
exports.usePsTableOverflow = usePsTableOverflow;
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import { type DndContextProps } from '@dnd-kit/core';
|
|
2
|
+
import type { PsTableDrop } from '../interfaces/table-drop';
|
|
2
3
|
import type { PsTableReorderAnnouncements } from '../interfaces/table-reorder-announcements';
|
|
3
4
|
import type { PsTableReorderItem } from '../interfaces/table-reorder-item';
|
|
5
|
+
import type { PsTableReorderNestingBinding } from '../interfaces/table-reorder-nesting-binding';
|
|
4
6
|
import type { PsTableReorderPlacement } from '../interfaces/table-reorder-placement';
|
|
5
7
|
export interface UsePsTableReorderInput {
|
|
6
8
|
announcements: PsTableReorderAnnouncements;
|
|
7
9
|
enabled: boolean;
|
|
8
10
|
instructions: string;
|
|
9
11
|
items: PsTableReorderItem[];
|
|
10
|
-
|
|
12
|
+
nesting?: PsTableReorderNestingBinding;
|
|
13
|
+
onReorder?: (groupKey: string, orderedIds: string[]) => void;
|
|
11
14
|
}
|
|
12
15
|
export interface PsTableReorderState {
|
|
13
16
|
activeId: string | null;
|
|
14
17
|
activeRunId: string | null;
|
|
15
18
|
contextProps: Omit<DndContextProps, 'children'>;
|
|
19
|
+
drop: PsTableDrop | null;
|
|
16
20
|
placements: Map<string, PsTableReorderPlacement>;
|
|
17
21
|
}
|
|
18
|
-
export declare const usePsTableReorder: ({ announcements: texts, enabled, instructions, items, onReorder, }: UsePsTableReorderInput) => PsTableReorderState;
|
|
22
|
+
export declare const usePsTableReorder: ({ announcements: texts, enabled, instructions, items, nesting, onReorder, }: UsePsTableReorderInput) => PsTableReorderState;
|
|
@@ -4,9 +4,16 @@ exports.usePsTableReorder = void 0;
|
|
|
4
4
|
const react_1 = require("react");
|
|
5
5
|
const core_1 = require("@dnd-kit/core");
|
|
6
6
|
const ps_core_components_1 = require("@pallasoft/ps-core-components");
|
|
7
|
+
const ps_table_drop_placement_1 = require("../constants/ps-table-drop-placement");
|
|
7
8
|
const ps_table_reorder_service_1 = require("../services/ps-table-reorder-service");
|
|
8
|
-
const
|
|
9
|
+
const pointerThenCenter = (args) => {
|
|
10
|
+
const within = (0, core_1.pointerWithin)(args);
|
|
11
|
+
return within.length > 0 ? within : (0, core_1.closestCenter)(args);
|
|
12
|
+
};
|
|
13
|
+
const usePsTableReorder = ({ announcements: texts, enabled, instructions, items, nesting, onReorder, }) => {
|
|
9
14
|
const [activeId, setActiveId] = (0, react_1.useState)(null);
|
|
15
|
+
const [drop, setDrop] = (0, react_1.useState)(null);
|
|
16
|
+
const dropRef = (0, react_1.useRef)(null);
|
|
10
17
|
const sensors = (0, ps_core_components_1.usePsDragSensors)();
|
|
11
18
|
const runs = (0, react_1.useMemo)(() => enabled
|
|
12
19
|
? ps_table_reorder_service_1.PsTableReorderService.runs(items, (item) => item.groupKey, (item) => item.id)
|
|
@@ -14,6 +21,7 @@ const usePsTableReorder = ({ announcements: texts, enabled, instructions, items,
|
|
|
14
21
|
const placements = (0, react_1.useMemo)(() => ps_table_reorder_service_1.PsTableReorderService.placements(runs, (item) => item.id), [runs]);
|
|
15
22
|
const activePlacement = activeId === null ? undefined : placements.get(activeId);
|
|
16
23
|
const itemById = (0, react_1.useMemo)(() => new Map(items.map((item) => [item.id, item])), [items]);
|
|
24
|
+
const indexById = (0, react_1.useMemo)(() => new Map(items.map((item, index) => [item.id, index])), [items]);
|
|
17
25
|
const labelOf = (id) => {
|
|
18
26
|
const item = itemById.get(id);
|
|
19
27
|
return item === undefined ? id : item.label;
|
|
@@ -26,23 +34,83 @@ const usePsTableReorder = ({ announcements: texts, enabled, instructions, items,
|
|
|
26
34
|
const placement = placements.get(id);
|
|
27
35
|
return placement === undefined ? 0 : placement.size;
|
|
28
36
|
};
|
|
37
|
+
const edgeFor = (activeKey, overId) => {
|
|
38
|
+
const activeIndex = indexById.get(activeKey);
|
|
39
|
+
const overIndex = indexById.get(overId);
|
|
40
|
+
return activeIndex !== undefined && overIndex !== undefined && activeIndex < overIndex
|
|
41
|
+
? ps_table_drop_placement_1.PsTableDropPlacement.after
|
|
42
|
+
: ps_table_drop_placement_1.PsTableDropPlacement.before;
|
|
43
|
+
};
|
|
44
|
+
const resolveDrop = (event) => {
|
|
45
|
+
if (nesting === undefined || event.over === null || event.over.id === event.active.id)
|
|
46
|
+
return null;
|
|
47
|
+
const activeKey = String(event.active.id);
|
|
48
|
+
const overId = String(event.over.id);
|
|
49
|
+
const placement = ps_table_reorder_service_1.PsTableReorderService.dropPlacement(ps_table_reorder_service_1.PsTableReorderService.pointerY(event.activatorEvent, event.delta.y), event.over.rect, edgeFor(activeKey, overId), (candidate) => nesting.canDrop(activeKey, overId, candidate));
|
|
50
|
+
return placement === null ? null : { overId, placement };
|
|
51
|
+
};
|
|
52
|
+
const announcedDrop = (activeKey, overId) => {
|
|
53
|
+
if (nesting === undefined)
|
|
54
|
+
return null;
|
|
55
|
+
const known = dropRef.current;
|
|
56
|
+
if (known !== null && known.overId === overId)
|
|
57
|
+
return known;
|
|
58
|
+
const placement = edgeFor(activeKey, overId);
|
|
59
|
+
return nesting.canDrop(activeKey, overId, placement) ? { overId, placement } : null;
|
|
60
|
+
};
|
|
61
|
+
const describeDrop = (active, target) => nesting === undefined
|
|
62
|
+
? undefined
|
|
63
|
+
: nesting.announcements[target.placement](labelOf(active), labelOf(target.overId));
|
|
29
64
|
const announcements = {
|
|
30
65
|
onDragCancel: ({ active }) => texts.cancelled(labelOf(String(active.id))),
|
|
31
|
-
onDragEnd: ({ active, over }) =>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
66
|
+
onDragEnd: ({ active, over }) => {
|
|
67
|
+
if (nesting !== undefined) {
|
|
68
|
+
const target = over === null ? null : announcedDrop(String(active.id), String(over.id));
|
|
69
|
+
return target === null
|
|
70
|
+
? texts.cancelled(labelOf(String(active.id)))
|
|
71
|
+
: describeDrop(String(active.id), target);
|
|
72
|
+
}
|
|
73
|
+
return over === null
|
|
74
|
+
? texts.cancelled(labelOf(String(active.id)))
|
|
75
|
+
: texts.dropped(labelOf(String(active.id)), positionOf(String(over.id)), countOf(String(over.id)));
|
|
76
|
+
},
|
|
77
|
+
onDragOver: ({ active, over }) => {
|
|
78
|
+
if (over === null)
|
|
79
|
+
return undefined;
|
|
80
|
+
if (nesting !== undefined) {
|
|
81
|
+
const target = announcedDrop(String(active.id), String(over.id));
|
|
82
|
+
return target === null ? undefined : describeDrop(String(active.id), target);
|
|
83
|
+
}
|
|
84
|
+
return texts.moved(labelOf(String(active.id)), positionOf(String(over.id)), countOf(String(over.id)));
|
|
85
|
+
},
|
|
37
86
|
onDragStart: ({ active }) => texts.lifted(labelOf(String(active.id)), positionOf(String(active.id)), countOf(String(active.id))),
|
|
38
87
|
};
|
|
39
|
-
const
|
|
88
|
+
const handleDragMove = (event) => {
|
|
89
|
+
const next = resolveDrop(event);
|
|
90
|
+
dropRef.current = next;
|
|
91
|
+
setDrop((current) => current !== null &&
|
|
92
|
+
next !== null &&
|
|
93
|
+
current.overId === next.overId &&
|
|
94
|
+
current.placement === next.placement
|
|
95
|
+
? current
|
|
96
|
+
: next);
|
|
97
|
+
};
|
|
98
|
+
const handleDragEnd = (event) => {
|
|
99
|
+
const { active, over } = event;
|
|
100
|
+
const target = resolveDrop(event);
|
|
40
101
|
setActiveId(null);
|
|
41
|
-
|
|
102
|
+
setDrop(null);
|
|
103
|
+
dropRef.current = null;
|
|
104
|
+
if (nesting !== undefined) {
|
|
105
|
+
if (target !== null)
|
|
106
|
+
nesting.onMove(String(active.id), target.overId, target.placement);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (over === null || active.id === over.id || onReorder === undefined)
|
|
42
110
|
return;
|
|
43
111
|
const placement = placements.get(String(active.id));
|
|
44
|
-
const
|
|
45
|
-
if (placement === undefined ||
|
|
112
|
+
const sibling = placements.get(String(over.id));
|
|
113
|
+
if (placement === undefined || sibling === undefined || placement.runId !== sibling.runId)
|
|
46
114
|
return;
|
|
47
115
|
const run = runs.find((candidate) => candidate.id === placement.runId);
|
|
48
116
|
if (run === undefined)
|
|
@@ -54,13 +122,19 @@ const usePsTableReorder = ({ announcements: texts, enabled, instructions, items,
|
|
|
54
122
|
activeRunId: activePlacement === undefined ? null : activePlacement.runId,
|
|
55
123
|
contextProps: {
|
|
56
124
|
accessibility: { announcements, screenReaderInstructions: { draggable: instructions } },
|
|
57
|
-
collisionDetection: core_1.closestCenter,
|
|
125
|
+
collisionDetection: nesting === undefined ? core_1.closestCenter : pointerThenCenter,
|
|
58
126
|
modifiers: [ps_table_reorder_service_1.PsTableReorderService.lockToVerticalAxis],
|
|
59
|
-
onDragCancel: () =>
|
|
127
|
+
onDragCancel: () => {
|
|
128
|
+
setActiveId(null);
|
|
129
|
+
setDrop(null);
|
|
130
|
+
dropRef.current = null;
|
|
131
|
+
},
|
|
60
132
|
onDragEnd: handleDragEnd,
|
|
133
|
+
onDragMove: nesting === undefined ? undefined : handleDragMove,
|
|
61
134
|
onDragStart: ({ active }) => setActiveId(String(active.id)),
|
|
62
135
|
sensors,
|
|
63
136
|
},
|
|
137
|
+
drop,
|
|
64
138
|
placements,
|
|
65
139
|
};
|
|
66
140
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,9 @@ export * from './components/ps-streamed-rows';
|
|
|
3
3
|
export * from './components/ps-table-stream-status';
|
|
4
4
|
export * from './components/ps-table-group-header';
|
|
5
5
|
export * from './components/ps-table-pagination';
|
|
6
|
+
export * from './constants/table-breakpoint';
|
|
6
7
|
export * from './constants/table-card-role';
|
|
8
|
+
export * from './constants/ps-table-pin-classes';
|
|
7
9
|
export * from './constants/table-column-size';
|
|
8
10
|
export * from './constants/table-filter-kind';
|
|
9
11
|
export * from './interfaces/table-column';
|
|
@@ -27,6 +29,11 @@ export * from './services/ps-table-group-service';
|
|
|
27
29
|
export * from './services/ps-table-query-service';
|
|
28
30
|
export * from './services/ps-table-search-service';
|
|
29
31
|
export * from './services/ps-table-scroll-service';
|
|
32
|
+
export * from './services/ps-table-pin-service';
|
|
33
|
+
export * from './services/ps-table-overflow-service';
|
|
34
|
+
export * from './hooks/use-ps-table-overflow';
|
|
35
|
+
export * from './interfaces/table-pin-classes';
|
|
36
|
+
export * from './interfaces/table-overflow-edges';
|
|
30
37
|
export * from './services/ps-table-stream-service';
|
|
31
38
|
export * from './components/ps-table-export-button';
|
|
32
39
|
export * from './constants/ps-table-download-config';
|
|
@@ -36,4 +43,7 @@ export * from './hooks/use-ps-table-page';
|
|
|
36
43
|
export * from './interfaces/ps-table-page-state';
|
|
37
44
|
export * from './interfaces/table-reorder';
|
|
38
45
|
export * from './interfaces/table-reorder-announcements';
|
|
46
|
+
export * from './interfaces/table-reorder-nesting';
|
|
47
|
+
export * from './interfaces/table-nesting-announcements';
|
|
48
|
+
export * from './constants/ps-table-drop-placement';
|
|
39
49
|
export * from './services/ps-table-reorder-service';
|