@pallasoft/ps-table-components 1.22.2 → 1.24.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 +54 -15
- 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 +55 -16
- 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-column-size-service.js +7 -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 +5 -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-column-size-service.d.ts +1 -0
- package/dist/services/ps-table-column-size-service.js +7 -0
- 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,18 +1,21 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { Fragment, Suspense, lazy, useDeferredValue, useEffect, useMemo, useRef, useState, } from 'react';
|
|
2
|
+
import { Fragment, Suspense, lazy, useCallback, useDeferredValue, useEffect, useMemo, useRef, useState, } from 'react';
|
|
3
3
|
import { PsDragGrip, PsSkeletonTable } from '@pallasoft/ps-core-components';
|
|
4
4
|
import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
|
|
5
5
|
import { PsCheckbox } from '@pallasoft/ps-input-components';
|
|
6
6
|
import { PsCollapse } from '@pallasoft/ps-motion-components';
|
|
7
7
|
import { useVirtualizer, useWindowVirtualizer } from '@tanstack/react-virtual';
|
|
8
8
|
import { PsTableControlClasses } from '../constants/ps-table-control-classes';
|
|
9
|
+
import { PsTableHideBelowClasses } from '../constants/table-breakpoint';
|
|
9
10
|
import { PsTableConfig } from '../constants/table-config';
|
|
10
11
|
import { usePsIncrementalCount } from '../hooks/use-ps-incremental-count';
|
|
11
12
|
import { usePsScrollAnchor } from '../hooks/use-ps-scroll-anchor';
|
|
13
|
+
import { usePsTableOverflow } from '../hooks/use-ps-table-overflow';
|
|
12
14
|
import { usePsTableStreamStatus } from '../hooks/use-ps-table-stream-status';
|
|
13
15
|
import { PsTableCellTooltipService } from '../services/ps-table-cell-tooltip-service';
|
|
14
16
|
import { PsTableColumnSizeService } from '../services/ps-table-column-size-service';
|
|
15
17
|
import { PsTableGroupService } from '../services/ps-table-group-service';
|
|
18
|
+
import { PsTablePinService } from '../services/ps-table-pin-service';
|
|
16
19
|
import { PsTableQueryService } from '../services/ps-table-query-service';
|
|
17
20
|
import { PsTableReorderService } from '../services/ps-table-reorder-service';
|
|
18
21
|
import { PsTableScrollService } from '../services/ps-table-scroll-service';
|
|
@@ -35,9 +38,9 @@ const densityClassNames = {
|
|
|
35
38
|
head: 'px-5 py-3.5',
|
|
36
39
|
},
|
|
37
40
|
};
|
|
38
|
-
const columnStyle = (column) => ({
|
|
39
|
-
maxWidth: PsTableColumnSizeService.maxWidthOf(column),
|
|
40
|
-
minWidth: PsTableColumnSizeService.minWidthOf(column),
|
|
41
|
+
const columnStyle = (column, fittedMinWidth) => ({
|
|
42
|
+
maxWidth: column.measure === undefined ? PsTableColumnSizeService.maxWidthOf(column) : undefined,
|
|
43
|
+
minWidth: fittedMinWidth === undefined ? PsTableColumnSizeService.minWidthOf(column) : fittedMinWidth,
|
|
41
44
|
width: column.width,
|
|
42
45
|
});
|
|
43
46
|
const alignClassNames = {
|
|
@@ -45,7 +48,7 @@ const alignClassNames = {
|
|
|
45
48
|
left: 'text-left',
|
|
46
49
|
right: 'text-right tabular-nums',
|
|
47
50
|
};
|
|
48
|
-
export const PsDataTable = ({ caption, className, columns, defaultSort, density = 'normal', expandedRowIds, mobileLayout = 'cards', getBulkActions, getRowId, getRowLabel, getSearchText, grouping, isLoading = false, isPending = false, layout = 'auto', onPageChange, onQueryChange, onRowClick, onRowHover, page, pageSize, query, renderExpandedRow, reorder, rows, searchingLabel = PsTableConfig.searchingLabel, searchPlaceholder = PsTableConfig.searchPlaceholder, toolbarActions, totalRows, }) => {
|
|
51
|
+
export const PsDataTable = ({ caption, className, columns, defaultSort, density = 'normal', expandedRowIds, mobileLayout = 'cards', getBulkActions, getRowId, getRowLabel, getSearchText, grouping, isLoading = false, isPending = false, layout = 'auto', onPageChange, onQueryChange, onRowClick, onRowHover, page, pageSize, pinFirstColumn = true, query, renderExpandedRow, reorder, rows, searchingLabel = PsTableConfig.searchingLabel, searchPlaceholder = PsTableConfig.searchPlaceholder, toolbarActions, totalRows, }) => {
|
|
49
52
|
const containerRef = useRef(null);
|
|
50
53
|
const [uncontrolledPage, setUncontrolledPage] = useState(1);
|
|
51
54
|
const [uncontrolledQuery, setUncontrolledQuery] = useState(() => PsTableQueryService.empty(defaultSort ? defaultSort : null));
|
|
@@ -56,6 +59,9 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
|
|
|
56
59
|
const currentQuery = query ? query : uncontrolledQuery;
|
|
57
60
|
const { filters, hiddenColumnIds, search, sort } = currentQuery;
|
|
58
61
|
const visibleColumns = columns.filter((column) => !hiddenColumnIds.includes(column.id));
|
|
62
|
+
const fittedWidths = useMemo(() => new Map(columns
|
|
63
|
+
.filter((column) => column.measure !== undefined)
|
|
64
|
+
.map((column) => [column.id, PsTableColumnSizeService.fittedMinWidthOf(column, rows)])), [columns, rows]);
|
|
59
65
|
const updateQuery = (patch) => {
|
|
60
66
|
const next = { ...currentQuery, ...patch };
|
|
61
67
|
if (!query)
|
|
@@ -70,6 +76,9 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
|
|
|
70
76
|
const hasToolbar = isSearchable || hasFilters || Boolean(toolbarActions);
|
|
71
77
|
const isSelectable = Boolean(getBulkActions);
|
|
72
78
|
const columnCount = visibleColumns.length + (isSelectable ? 1 : 0) + (reorder ? 1 : 0);
|
|
79
|
+
const pins = PsTablePinService.leading(pinFirstColumn, Boolean(reorder), isSelectable);
|
|
80
|
+
const placementOf = (column, columnIndex) => PallasoftClassNameService.merge(column.hideBelow === undefined ? '' : PsTableHideBelowClasses[column.hideBelow], columnIndex === 0 ? pins.first : '', PsTablePinService.end(column.pinEnd === true));
|
|
81
|
+
const overflow = usePsTableOverflow(`${visibleColumns.map((column) => column.id).join(',')}:${rows.length}`);
|
|
73
82
|
const deferredSearch = useDeferredValue(search);
|
|
74
83
|
const queriedRows = useMemo(() => isServerPaginated
|
|
75
84
|
? rows
|
|
@@ -139,23 +148,48 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
|
|
|
139
148
|
safePage,
|
|
140
149
|
toggledGroupKeys,
|
|
141
150
|
]);
|
|
151
|
+
const reorderKey = useCallback((row) => reorder && reorder.groupKey ? reorder.groupKey(row) : PsTableReorderService.treeKey, [reorder]);
|
|
152
|
+
const nestingBinding = useMemo(() => {
|
|
153
|
+
if (reorder === undefined || reorder.nesting === undefined)
|
|
154
|
+
return undefined;
|
|
155
|
+
const { nesting } = reorder;
|
|
156
|
+
const find = (id) => visibleRows.find((candidate) => getRowId(candidate) === id);
|
|
157
|
+
return {
|
|
158
|
+
announcements: nesting.announcements,
|
|
159
|
+
canDrag: (id) => {
|
|
160
|
+
const row = find(id);
|
|
161
|
+
return row !== undefined && nesting.canDrag(row);
|
|
162
|
+
},
|
|
163
|
+
canDrop: (activeId, targetId, placement) => {
|
|
164
|
+
const active = find(activeId);
|
|
165
|
+
const target = find(targetId);
|
|
166
|
+
return (active !== undefined && target !== undefined && nesting.canDrop(active, target, placement));
|
|
167
|
+
},
|
|
168
|
+
onMove: (activeId, targetId, placement) => {
|
|
169
|
+
const active = find(activeId);
|
|
170
|
+
const target = find(targetId);
|
|
171
|
+
if (active !== undefined && target !== undefined)
|
|
172
|
+
nesting.onMove(active, target, placement);
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}, [getRowId, reorder, visibleRows]);
|
|
142
176
|
const reorderItems = useMemo(() => reorder
|
|
143
177
|
? visibleRows.map((row) => {
|
|
144
178
|
const rowId = getRowId(row);
|
|
145
179
|
const label = getRowLabel ? getRowLabel(row) : rowId;
|
|
146
180
|
return {
|
|
147
|
-
groupKey:
|
|
181
|
+
groupKey: reorderKey(row),
|
|
148
182
|
handleLabel: reorder.getHandleLabel(label),
|
|
149
183
|
id: rowId,
|
|
150
184
|
label,
|
|
151
185
|
};
|
|
152
186
|
})
|
|
153
|
-
: [], [getRowId, getRowLabel, reorder, visibleRows]);
|
|
187
|
+
: [], [getRowId, getRowLabel, reorder, reorderKey, visibleRows]);
|
|
154
188
|
const renderOverlayRow = (rowId) => {
|
|
155
189
|
const row = visibleRows.find((candidate) => getRowId(candidate) === rowId);
|
|
156
190
|
return row === undefined ? null : (_jsx("table", { className: 'w-full table-fixed border-collapse bg-surface text-left', children: _jsx("tbody", { children: renderRow(PsTableReorderService.plain, row) }) }));
|
|
157
191
|
};
|
|
158
|
-
const renderReorder = (children) => reorder === undefined ? (children(PsTableReorderService.plain)) : (_jsx(Suspense, { fallback: children(PsTableReorderService.plain), children: _jsx(LazyReorderFrame, { announcements: reorder.announcements, enabled: reorder.enabled, instructions: reorder.instructions, items: reorderItems, onReorder: reorder.onReorder, renderOverlay: renderOverlayRow, children: children }) }));
|
|
192
|
+
const renderReorder = (children) => reorder === undefined ? (children(PsTableReorderService.plain)) : (_jsx(Suspense, { fallback: children(PsTableReorderService.plain), children: _jsx(LazyReorderFrame, { announcements: reorder.announcements, enabled: reorder.enabled, instructions: reorder.instructions, items: reorderItems, nesting: nestingBinding, onReorder: reorder.onReorder, renderOverlay: renderOverlayRow, children: children }) }));
|
|
159
193
|
const changePage = (next) => {
|
|
160
194
|
if (onPageChange) {
|
|
161
195
|
onPageChange(next);
|
|
@@ -239,7 +273,11 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
|
|
|
239
273
|
const rowLabel = getRowLabel ? getRowLabel(row) : rowId;
|
|
240
274
|
const Row = api.Row;
|
|
241
275
|
const rowExtras = api.isActive
|
|
242
|
-
? {
|
|
276
|
+
? {
|
|
277
|
+
...api.rowProps(rowId),
|
|
278
|
+
handleCellClassName: pins.reorder,
|
|
279
|
+
measureRef: virtualItem ? virtualizer.measureElement : undefined,
|
|
280
|
+
}
|
|
243
281
|
: { ref: virtualItem ? virtualizer.measureElement : undefined };
|
|
244
282
|
return (_jsxs(Fragment, { children: [_jsxs(Row, { ...rowExtras, "data-index": virtualItem ? virtualItem.index : undefined, "aria-expanded": renderExpandedRow ? isExpanded : undefined, "aria-label": onRowClick ? rowLabel : undefined, className: PallasoftClassNameService.merge('align-middle transition-colors', motion ? motion.className : '', onRowClick ? 'ps-focus-ring cursor-pointer hover:bg-mist/60' : 'hover:bg-mist/40', isExpanded ? 'bg-mist/40' : ''), onClick: onRowClick ? () => onRowClick(row) : undefined, onFocus: onRowHover ? () => onRowHover(row) : undefined, onPointerEnter: onRowHover ? () => onRowHover(row) : undefined, onKeyDown: onRowClick
|
|
245
283
|
? (event) => {
|
|
@@ -252,13 +290,14 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
|
|
|
252
290
|
}
|
|
253
291
|
: undefined, style: motion && motion.delayMs !== undefined
|
|
254
292
|
? { animationDelay: `${motion.delayMs}ms` }
|
|
255
|
-
: undefined, tabIndex: onRowClick ? 0 : undefined, children: [reorder && !api.isActive ? _jsx("td", { className: 'w-9 pl-3 pr-0' }) : null, isSelectable ? (_jsx("td", { className: 'w-10 pl-4 pr-0', onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: _jsx(PsCheckbox, { isSelected: selectedIdSet.has(rowId), label: `Select ${rowLabel}`, onChange: () => toggleRow(rowId) }) })) : null, visibleColumns.map((column) => (_jsx("td", { className: PallasoftClassNameService.merge(densityClassNames[density].cell, alignClassNames[column.align !== null && column.align !== undefined ? column.align : 'left'], column.wrap ? '' : 'whitespace-nowrap',
|
|
256
|
-
|
|
293
|
+
: undefined, tabIndex: onRowClick ? 0 : undefined, children: [reorder && !api.isActive ? (_jsx("td", { className: PallasoftClassNameService.merge('w-9 min-w-9 pl-3 pr-0', pins.reorder) })) : null, isSelectable ? (_jsx("td", { className: PallasoftClassNameService.merge('w-10 min-w-10 pl-4 pr-0', pins.select), onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: _jsx(PsCheckbox, { isSelected: selectedIdSet.has(rowId), label: `Select ${rowLabel}`, onChange: () => toggleRow(rowId) }) })) : null, visibleColumns.map((column, columnIndex) => (_jsx("td", { className: PallasoftClassNameService.merge(densityClassNames[density].cell, placementOf(column, columnIndex), alignClassNames[column.align !== null && column.align !== undefined ? column.align : 'left'], column.wrap ? '' : 'whitespace-nowrap', column.measure === undefined &&
|
|
294
|
+
((layout === 'fixed' && !column.wrap) ||
|
|
295
|
+
PsTableColumnSizeService.maxWidthOf(column) !== undefined)
|
|
257
296
|
? 'truncate'
|
|
258
|
-
: '', 'text-sm text-ink'), style: columnStyle(column), title: PsTableCellTooltipService.forCell(column, row), children: column.render(row) }, column.id)))] }), renderExpandedRow ? (_jsx("tr", { "aria-hidden": !isExpanded, className: isExpanded ? 'border-t-0' : 'border-0', children: _jsx("td", { className: 'p-0', colSpan: columnCount, children: _jsx(PsCollapse, { isOpen: isExpanded, children: _jsx("div", { className: 'w-0 min-w-full border-l-2 border-primary bg-mist/40 px-4 py-4', children: renderExpandedRow(row) }) }) }) })) : null] }, rowId));
|
|
297
|
+
: '', 'text-sm text-ink'), style: columnStyle(column, fittedWidths.get(column.id)), title: PsTableCellTooltipService.forCell(column, row), children: column.render(row) }, column.id)))] }), renderExpandedRow ? (_jsx("tr", { "aria-hidden": !isExpanded, className: isExpanded ? 'border-t-0' : 'border-0', children: _jsx("td", { className: 'p-0', colSpan: columnCount, children: _jsx(PsCollapse, { isOpen: isExpanded, children: _jsx("div", { className: 'w-0 min-w-full border-l-2 border-primary bg-mist/40 px-4 py-4', children: renderExpandedRow(row) }) }) }) })) : null] }, rowId));
|
|
259
298
|
};
|
|
260
299
|
const renderEntries = (api, entries) => reorder
|
|
261
|
-
? PsTableReorderService.runs(entries, (entry) =>
|
|
300
|
+
? PsTableReorderService.runs(entries, (entry) => reorderKey(entry.row), (entry) => getRowId(entry.row)).map((run) => api.run(run.id, run.items.map((entry) => getRowId(entry.row)), run.items.map((entry) => renderRow(api, entry.row, entry.motion, entry.virtualItem))))
|
|
262
301
|
: entries.map((entry) => renderRow(api, entry.row, entry.motion, entry.virtualItem));
|
|
263
302
|
if (isLoading)
|
|
264
303
|
return (_jsx(PsSkeletonTable, { className: className, columns: visibleColumns.length, hasToolbar: hasToolbar, rows: PsTableConfig.skeletonRows }));
|
|
@@ -277,14 +316,14 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
|
|
|
277
316
|
? grouping.renderGroupSummary(group.rows)
|
|
278
317
|
: undefined }), _jsx(PsCollapse, { isOpen: isExpanded && !closingGroupKeys.includes(group.key), children: renderCardList(group.rows, null) })] }, `group-${group.key}`));
|
|
279
318
|
})
|
|
280
|
-
: renderCardList(shouldVirtualize ? visibleRows.slice(0, cards.count) : visibleRows, visibleRows.length === 0 && isSearching ? (_jsx(PsTableSearchingState, { label: searchingLabel, skeletonRows: PsTableConfig.searchingSkeletonRows })) : visibleRows.length === 0 && isQueried ? (_jsxs("div", { className: 'px-4 py-10 text-center', children: [_jsx("p", { className: 'text-sm font-semibold text-ink', children: PsTableConfig.noMatchesTitle }), _jsx("button", { className: PallasoftClassNameService.merge(PsTableControlClasses.textButton, 'mt-2 text-primary'), onClick: clearFilters, type: 'button', children: "Clear search and filters" })] })) : null), !grouping && shouldVirtualize && cards.count < visibleRows.length ? (_jsx("div", { "aria-hidden": 'true', className: 'h-px', ref: cards.sentinelRef })) : null] })) : null, _jsx("div", { className: PallasoftClassNameService.merge('ps-scrollbar overflow-x-auto overflow-y-hidden', mobileLayout === 'cards' ? 'hidden sm:block' : ''), children: renderReorder((api) => (_jsxs("table", { className: PallasoftClassNameService.merge('w-full border-collapse text-left', layout === 'fixed' ? 'table-fixed' : ''), children: [caption ? _jsx("caption", { className: 'sr-only', children: caption }) : null, _jsx("thead", { className: 'bg-mist/70 text-[0.68rem] font-semibold uppercase tracking-[0.18em] text-ink/45', children: _jsxs("tr", { children: [reorder ? (_jsx("th", { className: 'w-9 pl-3 pr-0', scope: 'col', children: reorder.enabled ? (_jsx("span", { className: 'sr-only', children: reorder.columnLabel })) : reorder.disabledReason ? (_jsx("span", { "aria-label": reorder.disabledReason, className: 'inline-flex cursor-help opacity-40', role: 'img', title: reorder.disabledReason, children: _jsx(PsDragGrip, {}) })) : null })) : null, isSelectable ? (_jsx("th", { className: 'w-10 pl-4 pr-0', scope: 'col', children: _jsx(PsCheckbox, { isIndeterminate: !isPageSelected && pageIds.some((rowId) => selectedIdSet.has(rowId)), isSelected: isPageSelected, label: 'Select all rows on this page', onChange: togglePage }) })) : null, visibleColumns.map((column) => {
|
|
319
|
+
: renderCardList(shouldVirtualize ? visibleRows.slice(0, cards.count) : visibleRows, visibleRows.length === 0 && isSearching ? (_jsx(PsTableSearchingState, { label: searchingLabel, skeletonRows: PsTableConfig.searchingSkeletonRows })) : visibleRows.length === 0 && isQueried ? (_jsxs("div", { className: 'px-4 py-10 text-center', children: [_jsx("p", { className: 'text-sm font-semibold text-ink', children: PsTableConfig.noMatchesTitle }), _jsx("button", { className: PallasoftClassNameService.merge(PsTableControlClasses.textButton, 'mt-2 text-primary'), onClick: clearFilters, type: 'button', children: "Clear search and filters" })] })) : null), !grouping && shouldVirtualize && cards.count < visibleRows.length ? (_jsx("div", { "aria-hidden": 'true', className: 'h-px', ref: cards.sentinelRef })) : null] })) : null, _jsx("div", { className: PallasoftClassNameService.merge('ps-scrollbar overflow-x-auto overflow-y-hidden overscroll-x-contain', mobileLayout === 'cards' ? 'hidden sm:block' : ''), "data-overflow-end": overflow.edges.end, "data-overflow-start": overflow.edges.start, onScroll: overflow.update, ref: overflow.ref, children: renderReorder((api) => (_jsxs("table", { className: PallasoftClassNameService.merge('w-full border-collapse text-left', layout === 'fixed' ? 'table-fixed' : ''), children: [caption ? _jsx("caption", { className: 'sr-only', children: caption }) : null, _jsx("thead", { className: 'bg-mist/70 text-[0.68rem] font-semibold uppercase tracking-[0.18em] text-ink/45', children: _jsxs("tr", { children: [reorder ? (_jsx("th", { className: PallasoftClassNameService.merge('w-9 min-w-9 pl-3 pr-0', pins.reorder), scope: 'col', children: reorder.enabled ? (_jsx("span", { className: 'sr-only', children: reorder.columnLabel })) : reorder.disabledReason ? (_jsx("span", { "aria-label": reorder.disabledReason, className: 'inline-flex cursor-help opacity-40', role: 'img', title: reorder.disabledReason, children: _jsx(PsDragGrip, {}) })) : null })) : null, isSelectable ? (_jsx("th", { className: PallasoftClassNameService.merge('w-10 min-w-10 pl-4 pr-0', pins.select), scope: 'col', children: _jsx(PsCheckbox, { isIndeterminate: !isPageSelected && pageIds.some((rowId) => selectedIdSet.has(rowId)), isSelected: isPageSelected, label: 'Select all rows on this page', onChange: togglePage }) })) : null, visibleColumns.map((column, columnIndex) => {
|
|
281
320
|
const align = column.align !== null && column.align !== undefined ? column.align : 'left';
|
|
282
321
|
const isSorted = sort !== null && sort.columnId === column.id;
|
|
283
322
|
return (_jsx("th", { "aria-sort": isSorted
|
|
284
323
|
? sort.direction
|
|
285
324
|
: column.sortValue && isQueryable
|
|
286
325
|
? 'none'
|
|
287
|
-
: undefined, className: PallasoftClassNameService.merge(densityClassNames[density].head, alignClassNames[align], 'whitespace-nowrap'), scope: 'col', style: columnStyle(column), children: column.sortValue && isQueryable ? (_jsx(PsTableSortHeader, { align: align, columnId: column.id, label: column.label, onSort: updateSort, sort: sort })) : (column.label) }, column.id));
|
|
326
|
+
: undefined, className: PallasoftClassNameService.merge(densityClassNames[density].head, alignClassNames[align], placementOf(column, columnIndex), 'whitespace-nowrap'), scope: 'col', style: columnStyle(column, fittedWidths.get(column.id)), children: column.sortValue && isQueryable ? (_jsx(PsTableSortHeader, { align: align, columnId: column.id, label: column.label, onSort: updateSort, sort: sort })) : (column.label) }, column.id));
|
|
288
327
|
})] }) }), _jsxs("tbody", { className: 'divide-y divide-line', ref: bodyRef, children: [visibleRows.length === 0 && isSearching ? (_jsx("tr", { children: _jsx("td", { className: 'p-0', colSpan: columnCount, children: _jsx(PsTableSearchingState, { label: searchingLabel, skeletonRows: PsTableConfig.searchingSkeletonRows }) }) })) : null, visibleRows.length === 0 && isQueried && !isSearching ? (_jsx("tr", { children: _jsxs("td", { className: 'px-4 py-12 text-center', colSpan: columnCount, children: [_jsx("p", { className: 'text-sm font-semibold text-ink', children: PsTableConfig.noMatchesTitle }), _jsx("p", { className: 'mt-1 text-sm text-ink/55', children: PsTableConfig.noMatchesDescription }), _jsx("button", { className: PallasoftClassNameService.merge(PsTableControlClasses.textButton, 'mt-3 text-primary hover:underline'), onClick: clearFilters, type: 'button', children: "Clear search and filters" })] }) })) : null, grouping
|
|
289
328
|
? groups.map((group, groupIndex) => {
|
|
290
329
|
const isExpanded = isGroupExpanded(group.key, groupIndex);
|
|
@@ -306,7 +345,7 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
|
|
|
306
345
|
}))),
|
|
307
346
|
_jsx("tr", { "aria-hidden": 'true', children: _jsx("td", { className: 'p-0', colSpan: columnCount, style: { height: virtualBottom } }) }, 'virtual-bottom'),
|
|
308
347
|
]
|
|
309
|
-
: renderEntries(api, visibleRows.map((row) => ({ row })))] }), hasFooter ? (_jsx("tfoot", { className: 'border-t-2 border-line bg-mist/50 text-sm font-semibold text-ink', children: _jsxs("tr", { children: [reorder ? _jsx("td", {}) : null, isSelectable ? _jsx("td", {}) : null, visibleColumns.map((column) => (_jsx("td", { className: PallasoftClassNameService.merge(densityClassNames[density].cell, alignClassNames[column.align !== null && column.align !== undefined
|
|
348
|
+
: renderEntries(api, visibleRows.map((row) => ({ row })))] }), hasFooter ? (_jsx("tfoot", { className: 'border-t-2 border-line bg-mist/50 text-sm font-semibold text-ink', children: _jsxs("tr", { children: [reorder ? _jsx("td", { className: pins.reorder }) : null, isSelectable ? _jsx("td", { className: pins.select }) : null, visibleColumns.map((column, columnIndex) => (_jsx("td", { className: PallasoftClassNameService.merge(densityClassNames[density].cell, placementOf(column, columnIndex), alignClassNames[column.align !== null && column.align !== undefined
|
|
310
349
|
? column.align
|
|
311
350
|
: 'left'], 'whitespace-nowrap'), children: column.footer }, column.id)))] }) })) : null] }))) }), visibleRows.length > 0 && isSearching ? (_jsx(PsTableSearchingState, { className: 'border-t border-line py-3', label: searchingLabel })) : null, pageSize && (!grouping || isServerPaginated) ? (_jsx(PsTablePagination, { isPartial: isPartial, loadedPageCount: pageCountOf(loadedRowCount), onPageChange: changePage, page: safePage, pageCount: pageCount, pageSize: pageSize, totalRows: rowCount })) : null] })] }));
|
|
312
351
|
};
|
|
@@ -3,24 +3,37 @@ import { DndContext } from '@dnd-kit/core';
|
|
|
3
3
|
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
|
4
4
|
import { PsDragClasses, PsDragListLiftFrames, PsDragOverlay } from '@pallasoft/ps-core-components';
|
|
5
5
|
import { usePsTableReorder } from '../hooks/use-ps-table-reorder';
|
|
6
|
+
import { PsTableReorderService } from '../services/ps-table-reorder-service';
|
|
6
7
|
import { PsTableSortableRow } from './ps-table-sortable-row';
|
|
7
8
|
export const PsTableReorderFrame = ({ children, renderOverlay, ...input }) => {
|
|
8
|
-
const { activeId, activeRunId, contextProps, placements } = usePsTableReorder(input);
|
|
9
|
+
const { activeId, activeRunId, contextProps, drop, placements } = usePsTableReorder(input);
|
|
9
10
|
const itemById = new Map(input.items.map((item) => [item.id, item]));
|
|
11
|
+
const { nesting } = input;
|
|
10
12
|
const api = {
|
|
11
13
|
isActive: true,
|
|
12
14
|
Row: PsTableSortableRow,
|
|
13
15
|
rowProps: (rowId) => {
|
|
14
16
|
const item = itemById.get(rowId);
|
|
15
17
|
const placement = placements.get(rowId);
|
|
18
|
+
if (nesting !== undefined)
|
|
19
|
+
return {
|
|
20
|
+
dropPlacement: drop !== null && drop.overId === rowId ? drop.placement : null,
|
|
21
|
+
handleLabel: item === undefined ? '' : item.handleLabel,
|
|
22
|
+
hasHandle: item !== undefined && input.enabled && nesting.canDrag(rowId),
|
|
23
|
+
isDisabled: !input.enabled,
|
|
24
|
+
isDropTarget: item !== undefined,
|
|
25
|
+
rowId,
|
|
26
|
+
};
|
|
16
27
|
return {
|
|
28
|
+
dropPlacement: null,
|
|
17
29
|
handleLabel: item === undefined ? '' : item.handleLabel,
|
|
18
30
|
hasHandle: item !== undefined && input.enabled && placement !== undefined && placement.size > 1,
|
|
19
31
|
isDisabled: activeRunId !== null && (placement === undefined || placement.runId !== activeRunId),
|
|
32
|
+
isDropTarget: false,
|
|
20
33
|
rowId,
|
|
21
34
|
};
|
|
22
35
|
},
|
|
23
|
-
run: (runId, ids, runChildren) => (_jsx(SortableContext, { items: ids, strategy: verticalListSortingStrategy, children: runChildren }, runId)),
|
|
36
|
+
run: (runId, ids, runChildren) => (_jsx(SortableContext, { items: ids, strategy: nesting === undefined ? verticalListSortingStrategy : PsTableReorderService.still, children: runChildren }, runId)),
|
|
24
37
|
};
|
|
25
38
|
return (_jsxs(DndContext, { ...contextProps, children: [children(api), _jsx(PsDragOverlay, { className: PsDragClasses.lifted, frames: PsDragListLiftFrames, children: activeId === null ? null : renderOverlay(activeId) })] }));
|
|
26
39
|
};
|
|
@@ -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 {};
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { PsTableColumnMaxWidths, PsTableColumnSize, PsTableColumnWidths, } from '../constants/table-column-size';
|
|
2
2
|
import { PsTableFilterKind } from '../constants/table-filter-kind';
|
|
3
3
|
export class PsTableColumnSizeService {
|
|
4
|
+
static fittedMinWidthOf(column, rows) {
|
|
5
|
+
const measure = column.measure;
|
|
6
|
+
if (measure === undefined)
|
|
7
|
+
return undefined;
|
|
8
|
+
const longest = rows.reduce((length, row) => Math.max(length, measure(row).length), 0);
|
|
9
|
+
return `max(${PsTableColumnSizeService.minWidthOf(column)}, calc(${(longest * 1.1).toFixed(1)}ch + 3rem))`;
|
|
10
|
+
}
|
|
4
11
|
static sizeOf(column) {
|
|
5
12
|
if (column.size !== undefined)
|
|
6
13
|
return column.size;
|
|
@@ -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
|
+
}
|