@pallasoft/ps-table-components 1.20.0 → 1.22.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.
Files changed (61) hide show
  1. package/dist/components/ps-data-table.d.ts +5 -1
  2. package/dist/components/ps-data-table.js +80 -12
  3. package/dist/components/ps-table-pagination.d.ts +2 -1
  4. package/dist/components/ps-table-pagination.js +4 -2
  5. package/dist/components/ps-table-reorder-frame.d.ts +8 -0
  6. package/dist/components/ps-table-reorder-frame.js +30 -0
  7. package/dist/components/ps-table-reorder-handle.d.ts +6 -0
  8. package/dist/components/ps-table-reorder-handle.js +8 -0
  9. package/dist/components/ps-table-searching-state.d.ts +6 -0
  10. package/dist/components/ps-table-searching-state.js +7 -0
  11. package/dist/components/ps-table-sortable-row.d.ts +9 -0
  12. package/dist/components/ps-table-sortable-row.js +22 -0
  13. package/dist/constants/table-config.d.ts +2 -0
  14. package/dist/constants/table-config.js +2 -0
  15. package/dist/esm/components/ps-data-table.js +49 -14
  16. package/dist/esm/components/ps-table-pagination.js +4 -2
  17. package/dist/esm/components/ps-table-reorder-frame.js +26 -0
  18. package/dist/esm/components/ps-table-reorder-handle.js +4 -0
  19. package/dist/esm/components/ps-table-searching-state.js +3 -0
  20. package/dist/esm/components/ps-table-sortable-row.js +18 -0
  21. package/dist/esm/constants/table-config.js +2 -0
  22. package/dist/esm/hooks/use-ps-table-page.js +5 -0
  23. package/dist/esm/hooks/use-ps-table-reorder.js +63 -0
  24. package/dist/esm/index.js +5 -0
  25. package/dist/esm/interfaces/ps-table-page-state.js +1 -0
  26. package/dist/esm/interfaces/table-reorder-announcements.js +1 -0
  27. package/dist/esm/interfaces/table-reorder-api.js +1 -0
  28. package/dist/esm/interfaces/table-reorder-item.js +1 -0
  29. package/dist/esm/interfaces/table-reorder-placement.js +1 -0
  30. package/dist/esm/interfaces/table-reorder-row-props.js +1 -0
  31. package/dist/esm/interfaces/table-reorder-run.js +1 -0
  32. package/dist/esm/interfaces/table-reorder.js +1 -0
  33. package/dist/esm/interfaces/table-row-entry.js +1 -0
  34. package/dist/esm/services/ps-table-reorder-service.js +42 -0
  35. package/dist/hooks/use-ps-table-page.d.ts +2 -0
  36. package/dist/hooks/use-ps-table-page.js +9 -0
  37. package/dist/hooks/use-ps-table-reorder.d.ts +18 -0
  38. package/dist/hooks/use-ps-table-reorder.js +67 -0
  39. package/dist/index.d.ts +5 -0
  40. package/dist/index.js +5 -0
  41. package/dist/interfaces/ps-table-page-state.d.ts +4 -0
  42. package/dist/interfaces/ps-table-page-state.js +2 -0
  43. package/dist/interfaces/table-reorder-announcements.d.ts +6 -0
  44. package/dist/interfaces/table-reorder-announcements.js +2 -0
  45. package/dist/interfaces/table-reorder-api.d.ts +8 -0
  46. package/dist/interfaces/table-reorder-api.js +2 -0
  47. package/dist/interfaces/table-reorder-item.d.ts +6 -0
  48. package/dist/interfaces/table-reorder-item.js +2 -0
  49. package/dist/interfaces/table-reorder-placement.d.ts +6 -0
  50. package/dist/interfaces/table-reorder-placement.js +2 -0
  51. package/dist/interfaces/table-reorder-row-props.d.ts +6 -0
  52. package/dist/interfaces/table-reorder-row-props.js +2 -0
  53. package/dist/interfaces/table-reorder-run.d.ts +5 -0
  54. package/dist/interfaces/table-reorder-run.js +2 -0
  55. package/dist/interfaces/table-reorder.d.ts +12 -0
  56. package/dist/interfaces/table-reorder.js +2 -0
  57. package/dist/interfaces/table-row-entry.d.ts +7 -0
  58. package/dist/interfaces/table-row-entry.js +2 -0
  59. package/dist/services/ps-table-reorder-service.d.ts +11 -0
  60. package/dist/services/ps-table-reorder-service.js +46 -0
  61. package/package.json +6 -2
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { Fragment, useDeferredValue, useEffect, useMemo, useRef, useState, } from 'react';
3
- import { PsSkeletonTable } from '@pallasoft/ps-core-components';
2
+ import { Fragment, Suspense, lazy, useDeferredValue, useEffect, useMemo, useRef, useState, } from 'react';
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';
@@ -13,14 +13,17 @@ import { PsTableCellTooltipService } from '../services/ps-table-cell-tooltip-ser
13
13
  import { PsTableColumnSizeService } from '../services/ps-table-column-size-service';
14
14
  import { PsTableGroupService } from '../services/ps-table-group-service';
15
15
  import { PsTableQueryService } from '../services/ps-table-query-service';
16
+ import { PsTableReorderService } from '../services/ps-table-reorder-service';
16
17
  import { PsTableScrollService } from '../services/ps-table-scroll-service';
17
18
  import { PsTableBulkBar } from './ps-table-bulk-bar';
18
19
  import { PsTableCardList } from './ps-table-card-list';
19
20
  import { PsTableColumnPicker } from './ps-table-column-picker';
20
21
  import { PsTableGroupHeader } from './ps-table-group-header';
21
22
  import { PsTablePagination } from './ps-table-pagination';
23
+ import { PsTableSearchingState } from './ps-table-searching-state';
22
24
  import { PsTableSortHeader } from './ps-table-sort-header';
23
25
  import { PsTableToolbar } from './ps-table-toolbar';
26
+ const LazyReorderFrame = lazy(() => import('./ps-table-reorder-frame').then((module) => ({ default: module.PsTableReorderFrame })));
24
27
  const densityClassNames = {
25
28
  compact: {
26
29
  cell: 'px-3 py-1.5 text-[0.8125rem] leading-5',
@@ -41,7 +44,7 @@ const alignClassNames = {
41
44
  left: 'text-left',
42
45
  right: 'text-right tabular-nums',
43
46
  };
44
- export const PsDataTable = ({ caption, className, columns, defaultSort, density = 'normal', expandedRowIds, mobileLayout = 'cards', getBulkActions, getRowId, getRowLabel, getSearchText, grouping, isLoading = false, layout = 'auto', onPageChange, onQueryChange, onRowClick, onRowHover, page, pageSize, query, renderExpandedRow, rows, searchPlaceholder = PsTableConfig.searchPlaceholder, toolbarActions, totalRows, }) => {
47
+ 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, }) => {
45
48
  const containerRef = useRef(null);
46
49
  const [uncontrolledPage, setUncontrolledPage] = useState(1);
47
50
  const [uncontrolledQuery, setUncontrolledQuery] = useState(() => PsTableQueryService.empty(defaultSort ? defaultSort : null));
@@ -65,7 +68,7 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
65
68
  const hasFilters = columns.some((column) => column.filter) && isQueryable;
66
69
  const hasToolbar = isSearchable || hasFilters || Boolean(toolbarActions);
67
70
  const isSelectable = Boolean(getBulkActions);
68
- const columnCount = visibleColumns.length + (isSelectable ? 1 : 0);
71
+ const columnCount = visibleColumns.length + (isSelectable ? 1 : 0) + (reorder ? 1 : 0);
69
72
  const deferredSearch = useDeferredValue(search);
70
73
  const queriedRows = useMemo(() => isServerPaginated
71
74
  ? rows
@@ -73,6 +76,8 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
73
76
  const streamStatus = usePsTableStreamStatus();
74
77
  const isQueried = search.trim() !== '' ||
75
78
  Object.values(filters).some((value) => PsTableQueryService.isActive(value));
79
+ const isPartial = streamStatus !== null && !isServerPaginated && isQueried;
80
+ const isSearching = isPartial || isPending;
76
81
  const currentPage = page !== null && page !== undefined ? page : uncontrolledPage;
77
82
  const loadedRowCount = isServerPaginated ? totalRows : queriedRows.length;
78
83
  const rowCount = streamStatus !== null && !isServerPaginated && !isQueried
@@ -133,6 +138,23 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
133
138
  safePage,
134
139
  toggledGroupKeys,
135
140
  ]);
141
+ const reorderItems = useMemo(() => reorder
142
+ ? visibleRows.map((row) => {
143
+ const rowId = getRowId(row);
144
+ const label = getRowLabel ? getRowLabel(row) : rowId;
145
+ return {
146
+ groupKey: reorder.groupKey(row),
147
+ handleLabel: reorder.getHandleLabel(label),
148
+ id: rowId,
149
+ label,
150
+ };
151
+ })
152
+ : [], [getRowId, getRowLabel, reorder, visibleRows]);
153
+ const renderOverlayRow = (rowId) => {
154
+ const row = visibleRows.find((candidate) => getRowId(candidate) === rowId);
155
+ 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) }) }));
156
+ };
157
+ 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 }) }));
136
158
  const changePage = (next) => {
137
159
  if (onPageChange) {
138
160
  onPageChange(next);
@@ -210,11 +232,15 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
210
232
  }, [shouldVirtualize, visibleRows.length]);
211
233
  const toggleRow = (rowId) => setSelectedIds((current) => current.includes(rowId) ? current.filter((id) => id !== rowId) : [...current, rowId]);
212
234
  const renderCardList = (cardRows, emptyContent) => (_jsx(PsTableCardList, { columns: visibleColumns, emptyContent: emptyContent, expandedRowIds: expandedRowIds, footerColumns: hasFooter ? visibleColumns.filter((column) => column.footer !== undefined) : [], getRowId: getRowId, getRowLabel: (row) => (getRowLabel ? getRowLabel(row) : getRowId(row)), isSelectable: isSelectable, onRowClick: onRowClick, onRowHover: onRowHover, onToggleRow: toggleRow, renderExpandedRow: renderExpandedRow, rows: cardRows, selectedIds: selectedIds }));
213
- const renderRow = (row, motion, virtualItem) => {
235
+ const renderRow = (api, row, motion, virtualItem) => {
214
236
  const rowId = getRowId(row);
215
237
  const isExpanded = expandedRowIds ? expandedRowIds.includes(rowId) : false;
216
238
  const rowLabel = getRowLabel ? getRowLabel(row) : rowId;
217
- return (_jsxs(Fragment, { children: [_jsxs("tr", { "data-index": virtualItem ? virtualItem.index : undefined, ref: virtualItem ? virtualizer.measureElement : 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
239
+ const Row = api.Row;
240
+ const rowExtras = api.isActive
241
+ ? { ...api.rowProps(rowId), measureRef: virtualItem ? virtualizer.measureElement : undefined }
242
+ : { ref: virtualItem ? virtualizer.measureElement : undefined };
243
+ 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
218
244
  ? (event) => {
219
245
  if (event.target !== event.currentTarget)
220
246
  return;
@@ -225,11 +251,14 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
225
251
  }
226
252
  : undefined, style: motion && motion.delayMs !== undefined
227
253
  ? { animationDelay: `${motion.delayMs}ms` }
228
- : undefined, tabIndex: onRowClick ? 0 : undefined, children: [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', (layout === 'fixed' && !column.wrap) ||
254
+ : 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', (layout === 'fixed' && !column.wrap) ||
229
255
  PsTableColumnSizeService.maxWidthOf(column) !== undefined
230
256
  ? 'truncate'
231
257
  : '', '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));
232
258
  };
259
+ const renderEntries = (api, entries) => reorder
260
+ ? PsTableReorderService.runs(entries, (entry) => reorder.groupKey(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))))
261
+ : entries.map((entry) => renderRow(api, entry.row, entry.motion, entry.virtualItem));
233
262
  if (isLoading)
234
263
  return (_jsx(PsSkeletonTable, { className: className, columns: visibleColumns.length, hasToolbar: hasToolbar, rows: PsTableConfig.skeletonRows }));
235
264
  return (_jsxs("div", { ref: containerRef, className: PallasoftClassNameService.merge('flex min-w-0 flex-col gap-3', className), children: [isSelectable && selectedRows.length > 0 && getBulkActions ? (_jsx(PsTableBulkBar, { actions: getBulkActions(selectedRows), onClear: () => setSelectedIds([]), selectedCount: selectedRows.length })) : hasToolbar || columns.some((column) => column.canHide) ? (_jsx(PsTableToolbar, { actions: _jsxs(_Fragment, { children: [toolbarActions, columns.some((column) => column.canHide) ? (_jsx(PsTableColumnPicker, { columns: columns
@@ -240,14 +269,14 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
240
269
  }, onSearchChange: (next) => {
241
270
  updateQuery({ search: next });
242
271
  resetPage();
243
- }, rows: rows, search: search, searchPlaceholder: searchPlaceholder })) : null, _jsxs("div", { className: 'min-w-0 overflow-hidden rounded-[1.25rem] border border-line bg-surface', children: [mobileLayout === 'cards' ? (_jsxs("div", { className: 'sm:hidden', children: [grouping
272
+ }, rows: rows, search: search, searchPlaceholder: searchPlaceholder })) : null, _jsxs("div", { className: 'min-w-0 overflow-hidden rounded-[1.25rem] border border-line bg-surface', children: [mobileLayout === 'cards' ? (_jsxs("div", { className: 'sm:hidden', children: [reorder && reorder.cardsReason ? (_jsx("p", { className: 'border-b border-line px-4 py-2 text-xs text-ink/55', children: reorder.cardsReason })) : null, grouping
244
273
  ? groups.map((group, groupIndex) => {
245
274
  const isExpanded = isGroupExpanded(group.key, groupIndex);
246
275
  return (_jsxs("div", { className: 'border-b border-line last:border-b-0', children: [_jsx(PsTableGroupHeader, { count: group.rows.length, isExpanded: isExpanded, label: grouping.getGroupLabel(group.key, group.rows), onToggle: () => toggleGroup(group.key, isExpanded), summary: grouping.renderGroupSummary
247
276
  ? grouping.renderGroupSummary(group.rows)
248
277
  : undefined }), _jsx(PsCollapse, { isOpen: isExpanded && !closingGroupKeys.includes(group.key), children: renderCardList(group.rows, null) })] }, `group-${group.key}`));
249
278
  })
250
- : renderCardList(shouldVirtualize ? visibleRows.slice(0, cards.count) : visibleRows, 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: 'ps-focus-ring mt-2 rounded-full px-3 py-1.5 text-sm font-semibold 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: _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: [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) => {
279
+ : 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: 'ps-focus-ring mt-2 rounded-full px-3 py-1.5 text-sm font-semibold 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) => {
251
280
  const align = column.align !== null && column.align !== undefined ? column.align : 'left';
252
281
  const isSorted = sort !== null && sort.columnId === column.id;
253
282
  return (_jsx("th", { "aria-sort": isSorted
@@ -255,22 +284,28 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
255
284
  : column.sortValue && isQueryable
256
285
  ? 'none'
257
286
  : 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));
258
- })] }) }), _jsxs("tbody", { className: 'divide-y divide-line', ref: bodyRef, children: [visibleRows.length === 0 && isQueried ? (_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: 'ps-focus-ring mt-3 rounded-full px-3 py-1.5 text-sm font-semibold text-primary hover:underline', onClick: clearFilters, type: 'button', children: "Clear search and filters" })] }) })) : null, grouping
287
+ })] }) }), _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: 'ps-focus-ring mt-3 rounded-full px-3 py-1.5 text-sm font-semibold text-primary hover:underline', onClick: clearFilters, type: 'button', children: "Clear search and filters" })] }) })) : null, grouping
259
288
  ? groups.map((group, groupIndex) => {
260
289
  const isExpanded = isGroupExpanded(group.key, groupIndex);
261
290
  return (_jsxs(Fragment, { children: [_jsx("tr", { children: _jsx("td", { className: 'p-0', colSpan: columnCount, children: _jsx(PsTableGroupHeader, { count: group.rows.length, isExpanded: isExpanded, label: grouping.getGroupLabel(group.key, group.rows), onToggle: () => toggleGroup(group.key, isExpanded), summary: grouping.renderGroupSummary
262
291
  ? grouping.renderGroupSummary(group.rows)
263
292
  : undefined }) }) }), isExpanded
264
- ? group.rows.map((row, rowIndex) => renderRow(row, groupRowMotion(group.key, rowIndex)))
293
+ ? renderEntries(api, group.rows.map((row, rowIndex) => ({
294
+ motion: groupRowMotion(group.key, rowIndex),
295
+ row,
296
+ })))
265
297
  : null] }, `group-${group.key}`));
266
298
  })
267
299
  : shouldVirtualize
268
300
  ? [
269
301
  _jsx("tr", { "aria-hidden": 'true', children: _jsx("td", { className: 'p-0', colSpan: columnCount, style: { height: virtualTop } }) }, 'virtual-top'),
270
- ...virtualItems.map((item) => renderRow(visibleRows[item.index], undefined, item)),
302
+ ...renderEntries(api, virtualItems.map((item) => ({
303
+ row: visibleRows[item.index],
304
+ virtualItem: item,
305
+ }))),
271
306
  _jsx("tr", { "aria-hidden": 'true', children: _jsx("td", { className: 'p-0', colSpan: columnCount, style: { height: virtualBottom } }) }, 'virtual-bottom'),
272
307
  ]
273
- : visibleRows.map((row) => renderRow(row))] }), hasFooter ? (_jsx("tfoot", { className: 'border-t-2 border-line bg-mist/50 text-sm font-semibold text-ink', children: _jsxs("tr", { children: [isSelectable ? _jsx("td", {}) : null, visibleColumns.map((column) => (_jsx("td", { className: PallasoftClassNameService.merge(densityClassNames[density].cell, alignClassNames[column.align !== null && column.align !== undefined
308
+ : 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
274
309
  ? column.align
275
- : 'left'], 'whitespace-nowrap'), children: column.footer }, column.id)))] }) })) : null] }) }), pageSize && (!grouping || isServerPaginated) ? (_jsx(PsTablePagination, { loadedPageCount: pageCountOf(loadedRowCount), onPageChange: changePage, page: safePage, pageCount: pageCount, pageSize: pageSize, totalRows: rowCount })) : null] })] }));
310
+ : '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] })] }));
276
311
  };
@@ -1,9 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
- export const PsTablePagination = ({ className, loadedPageCount, onPageChange, page, pageCount, pageSize, totalRows, }) => {
3
+ export const PsTablePagination = ({ className, isPartial = false, loadedPageCount, onPageChange, page, pageCount, pageSize, totalRows, }) => {
4
4
  const firstRow = totalRows === 0 ? 0 : (page - 1) * pageSize + 1;
5
5
  const lastRow = Math.min(page * pageSize, totalRows);
6
6
  const buttonClassName = 'ps-focus-ring inline-flex min-h-9 items-center rounded-full border border-line px-3.5 text-sm font-semibold text-ink transition-colors disabled:cursor-not-allowed disabled:opacity-40 enabled:hover:border-primary/40';
7
- return (_jsxs("nav", { "aria-label": 'Pagination', className: PallasoftClassNameService.merge('flex flex-wrap items-center justify-between gap-3 border-t border-line px-4 py-3', className), children: [_jsx("p", { className: 'text-sm text-ink/55', children: totalRows === 0 ? 'No rows' : `${firstRow}–${lastRow} of ${totalRows}` }), _jsxs("div", { className: 'flex items-center gap-2', children: [_jsx("button", { className: buttonClassName, disabled: page <= 1, onClick: () => onPageChange(page - 1), type: 'button', children: "Previous" }), _jsxs("span", { className: 'hidden text-sm text-ink/65 sm:inline', children: ["Page ", Math.min(page, pageCount), " of ", pageCount] }), _jsx("button", { className: buttonClassName, disabled: page >=
7
+ return (_jsxs("nav", { "aria-label": 'Pagination', className: PallasoftClassNameService.merge('flex flex-wrap items-center justify-between gap-3 border-t border-line px-4 py-3', className), children: [_jsx("p", { className: 'text-sm text-ink/55', children: totalRows === 0
8
+ ? 'No rows'
9
+ : `${firstRow}–${lastRow} of ${totalRows}${isPartial ? '+' : ''}` }), _jsxs("div", { className: 'flex items-center gap-2', children: [_jsx("button", { className: buttonClassName, disabled: page <= 1, onClick: () => onPageChange(page - 1), type: 'button', children: "Previous" }), _jsxs("span", { className: 'hidden text-sm text-ink/65 sm:inline', children: ["Page ", Math.min(page, pageCount), " of ", pageCount] }), _jsx("button", { className: buttonClassName, disabled: page >=
8
10
  (loadedPageCount === undefined ? pageCount : Math.min(loadedPageCount, pageCount)), onClick: () => onPageChange(page + 1), type: 'button', children: "Next" })] })] }));
9
11
  };
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { DndContext } from '@dnd-kit/core';
3
+ import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
4
+ import { PsDragClasses, PsDragListLiftFrames, PsDragOverlay } from '@pallasoft/ps-core-components';
5
+ import { usePsTableReorder } from '../hooks/use-ps-table-reorder';
6
+ import { PsTableSortableRow } from './ps-table-sortable-row';
7
+ export const PsTableReorderFrame = ({ children, renderOverlay, ...input }) => {
8
+ const { activeId, activeRunId, contextProps, placements } = usePsTableReorder(input);
9
+ const itemById = new Map(input.items.map((item) => [item.id, item]));
10
+ const api = {
11
+ isActive: true,
12
+ Row: PsTableSortableRow,
13
+ rowProps: (rowId) => {
14
+ const item = itemById.get(rowId);
15
+ const placement = placements.get(rowId);
16
+ return {
17
+ handleLabel: item === undefined ? '' : item.handleLabel,
18
+ hasHandle: item !== undefined && input.enabled && placement !== undefined && placement.size > 1,
19
+ isDisabled: activeRunId !== null && (placement === undefined || placement.runId !== activeRunId),
20
+ rowId,
21
+ };
22
+ },
23
+ run: (runId, ids, runChildren) => (_jsx(SortableContext, { items: ids, strategy: verticalListSortingStrategy, children: runChildren }, runId)),
24
+ };
25
+ return (_jsxs(DndContext, { ...contextProps, children: [children(api), _jsx(PsDragOverlay, { className: PsDragClasses.lifted, frames: PsDragListLiftFrames, children: activeId === null ? null : renderOverlay(activeId) })] }));
26
+ };
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { PsDragGrip } from '@pallasoft/ps-core-components';
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-md 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, {}) }));
@@ -0,0 +1,3 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ export const PsTableSearchingState = ({ className, label, skeletonRows = 0, }) => (_jsxs("div", { "aria-live": 'polite', className: PallasoftClassNameService.merge('flex flex-col gap-3 px-4 py-4', className), role: 'status', children: [Array.from({ length: skeletonRows }).map((_, index) => (_jsx("div", { className: 'h-4 w-full animate-pulse rounded-full bg-mist' }, index))), _jsx("p", { className: 'text-sm text-ink/55', children: label })] }));
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useSortable } from '@dnd-kit/sortable';
3
+ import { CSS } from '@dnd-kit/utilities';
4
+ import { PsDragConfig } from '@pallasoft/ps-core-components';
5
+ 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({ disabled: isDisabled || !hasHandle, id: rowId });
8
+ return (_jsxs("tr", { ...rowProps, className: className, ref: (element) => {
9
+ setNodeRef(element);
10
+ if (measureRef)
11
+ measureRef(element);
12
+ }, style: {
13
+ ...style,
14
+ opacity: isDragging ? PsDragConfig.placeholderOpacity : style?.opacity,
15
+ transform: CSS.Translate.toString(transform),
16
+ 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] }));
18
+ };
@@ -4,6 +4,8 @@ export const PsTableConfig = {
4
4
  groupOpenMs: 280,
5
5
  groupRowStaggerMs: 16,
6
6
  groupStaggerLimit: 12,
7
+ searchingLabel: 'Searching all rows…',
8
+ searchingSkeletonRows: 3,
7
9
  noMatchesDescription: 'Try a different search or clear the filters.',
8
10
  noMatchesTitle: 'Nothing matches',
9
11
  rowEstimatePx: { compact: 37, normal: 57 },
@@ -0,0 +1,5 @@
1
+ import { useState } from 'react';
2
+ export const usePsTablePage = () => {
3
+ const [page, setPage] = useState(1);
4
+ return { onPageChange: setPage, page };
5
+ };
@@ -0,0 +1,63 @@
1
+ import { useMemo, useState } from 'react';
2
+ import { closestCenter, } from '@dnd-kit/core';
3
+ import { usePsDragSensors } from '@pallasoft/ps-core-components';
4
+ import { PsTableReorderService } from '../services/ps-table-reorder-service';
5
+ export const usePsTableReorder = ({ announcements: texts, enabled, instructions, items, onReorder, }) => {
6
+ const [activeId, setActiveId] = useState(null);
7
+ const sensors = usePsDragSensors();
8
+ const runs = useMemo(() => enabled
9
+ ? PsTableReorderService.runs(items, (item) => item.groupKey, (item) => item.id)
10
+ : [], [enabled, items]);
11
+ const placements = useMemo(() => PsTableReorderService.placements(runs, (item) => item.id), [runs]);
12
+ const activePlacement = activeId === null ? undefined : placements.get(activeId);
13
+ const itemById = useMemo(() => new Map(items.map((item) => [item.id, item])), [items]);
14
+ const labelOf = (id) => {
15
+ const item = itemById.get(id);
16
+ return item === undefined ? id : item.label;
17
+ };
18
+ const positionOf = (id) => {
19
+ const placement = placements.get(id);
20
+ return placement === undefined ? 0 : placement.index + 1;
21
+ };
22
+ const countOf = (id) => {
23
+ const placement = placements.get(id);
24
+ return placement === undefined ? 0 : placement.size;
25
+ };
26
+ const announcements = {
27
+ onDragCancel: ({ active }) => texts.cancelled(labelOf(String(active.id))),
28
+ onDragEnd: ({ active, over }) => over === null
29
+ ? texts.cancelled(labelOf(String(active.id)))
30
+ : texts.dropped(labelOf(String(active.id)), positionOf(String(over.id)), countOf(String(over.id))),
31
+ onDragOver: ({ active, over }) => over === null
32
+ ? undefined
33
+ : texts.moved(labelOf(String(active.id)), positionOf(String(over.id)), countOf(String(over.id))),
34
+ onDragStart: ({ active }) => texts.lifted(labelOf(String(active.id)), positionOf(String(active.id)), countOf(String(active.id))),
35
+ };
36
+ const handleDragEnd = ({ active, over }) => {
37
+ setActiveId(null);
38
+ if (over === null || active.id === over.id)
39
+ return;
40
+ const placement = placements.get(String(active.id));
41
+ const target = placements.get(String(over.id));
42
+ if (placement === undefined || target === undefined || placement.runId !== target.runId)
43
+ return;
44
+ const run = runs.find((candidate) => candidate.id === placement.runId);
45
+ if (run === undefined)
46
+ return;
47
+ onReorder(run.groupKey, PsTableReorderService.move(run.items.map((item) => item.id), String(active.id), String(over.id)));
48
+ };
49
+ return {
50
+ activeId,
51
+ activeRunId: activePlacement === undefined ? null : activePlacement.runId,
52
+ contextProps: {
53
+ accessibility: { announcements, screenReaderInstructions: { draggable: instructions } },
54
+ collisionDetection: closestCenter,
55
+ modifiers: [PsTableReorderService.lockToVerticalAxis],
56
+ onDragCancel: () => setActiveId(null),
57
+ onDragEnd: handleDragEnd,
58
+ onDragStart: ({ active }) => setActiveId(String(active.id)),
59
+ sensors,
60
+ },
61
+ placements,
62
+ };
63
+ };
package/dist/esm/index.js CHANGED
@@ -32,3 +32,8 @@ export * from './components/ps-table-export-button';
32
32
  export * from './constants/ps-table-download-config';
33
33
  export * from './services/ps-table-download-service';
34
34
  export * from './services/ps-table-scroll-anchor-service';
35
+ export * from './hooks/use-ps-table-page';
36
+ export * from './interfaces/ps-table-page-state';
37
+ export * from './interfaces/table-reorder';
38
+ export * from './interfaces/table-reorder-announcements';
39
+ 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 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,42 @@
1
+ export class PsTableReorderService {
2
+ static runs(items, getKey, getId) {
3
+ const runs = [];
4
+ for (const item of items) {
5
+ const groupKey = getKey(item);
6
+ const last = runs[runs.length - 1];
7
+ if (last !== undefined && last.groupKey === groupKey)
8
+ last.items.push(item);
9
+ else
10
+ runs.push({ groupKey, id: `${groupKey}:${getId(item)}`, items: [item] });
11
+ }
12
+ return runs;
13
+ }
14
+ static placements(runs, getId) {
15
+ const placements = new Map();
16
+ for (const run of runs)
17
+ run.items.forEach((item, index) => placements.set(getId(item), {
18
+ groupKey: run.groupKey,
19
+ index,
20
+ runId: run.id,
21
+ size: run.items.length,
22
+ }));
23
+ return placements;
24
+ }
25
+ static move(ids, activeId, overId) {
26
+ const from = ids.indexOf(activeId);
27
+ const to = ids.indexOf(overId);
28
+ if (from < 0 || to < 0 || from === to)
29
+ return ids;
30
+ const next = [...ids];
31
+ const [moved] = next.splice(from, 1);
32
+ next.splice(to, 0, moved);
33
+ return next;
34
+ }
35
+ }
36
+ PsTableReorderService.plain = {
37
+ Row: 'tr',
38
+ isActive: false,
39
+ rowProps: (rowId) => ({ handleLabel: '', hasHandle: false, isDisabled: true, rowId }),
40
+ run: (_runId, _ids, children) => children,
41
+ };
42
+ PsTableReorderService.lockToVerticalAxis = ({ transform }) => ({ ...transform, x: 0 });
@@ -0,0 +1,2 @@
1
+ import type { PsTablePageState } from '../interfaces/ps-table-page-state';
2
+ export declare const usePsTablePage: () => PsTablePageState;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usePsTablePage = void 0;
4
+ const react_1 = require("react");
5
+ const usePsTablePage = () => {
6
+ const [page, setPage] = (0, react_1.useState)(1);
7
+ return { onPageChange: setPage, page };
8
+ };
9
+ exports.usePsTablePage = usePsTablePage;
@@ -0,0 +1,18 @@
1
+ import { type DndContextProps } from '@dnd-kit/core';
2
+ import type { PsTableReorderAnnouncements } from '../interfaces/table-reorder-announcements';
3
+ import type { PsTableReorderItem } from '../interfaces/table-reorder-item';
4
+ import type { PsTableReorderPlacement } from '../interfaces/table-reorder-placement';
5
+ export interface UsePsTableReorderInput {
6
+ announcements: PsTableReorderAnnouncements;
7
+ enabled: boolean;
8
+ instructions: string;
9
+ items: PsTableReorderItem[];
10
+ onReorder: (groupKey: string, orderedIds: string[]) => void;
11
+ }
12
+ export interface PsTableReorderState {
13
+ activeId: string | null;
14
+ activeRunId: string | null;
15
+ contextProps: Omit<DndContextProps, 'children'>;
16
+ placements: Map<string, PsTableReorderPlacement>;
17
+ }
18
+ export declare const usePsTableReorder: ({ announcements: texts, enabled, instructions, items, onReorder, }: UsePsTableReorderInput) => PsTableReorderState;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usePsTableReorder = void 0;
4
+ const react_1 = require("react");
5
+ const core_1 = require("@dnd-kit/core");
6
+ const ps_core_components_1 = require("@pallasoft/ps-core-components");
7
+ const ps_table_reorder_service_1 = require("../services/ps-table-reorder-service");
8
+ const usePsTableReorder = ({ announcements: texts, enabled, instructions, items, onReorder, }) => {
9
+ const [activeId, setActiveId] = (0, react_1.useState)(null);
10
+ const sensors = (0, ps_core_components_1.usePsDragSensors)();
11
+ const runs = (0, react_1.useMemo)(() => enabled
12
+ ? ps_table_reorder_service_1.PsTableReorderService.runs(items, (item) => item.groupKey, (item) => item.id)
13
+ : [], [enabled, items]);
14
+ const placements = (0, react_1.useMemo)(() => ps_table_reorder_service_1.PsTableReorderService.placements(runs, (item) => item.id), [runs]);
15
+ const activePlacement = activeId === null ? undefined : placements.get(activeId);
16
+ const itemById = (0, react_1.useMemo)(() => new Map(items.map((item) => [item.id, item])), [items]);
17
+ const labelOf = (id) => {
18
+ const item = itemById.get(id);
19
+ return item === undefined ? id : item.label;
20
+ };
21
+ const positionOf = (id) => {
22
+ const placement = placements.get(id);
23
+ return placement === undefined ? 0 : placement.index + 1;
24
+ };
25
+ const countOf = (id) => {
26
+ const placement = placements.get(id);
27
+ return placement === undefined ? 0 : placement.size;
28
+ };
29
+ const announcements = {
30
+ onDragCancel: ({ active }) => texts.cancelled(labelOf(String(active.id))),
31
+ onDragEnd: ({ active, over }) => over === null
32
+ ? texts.cancelled(labelOf(String(active.id)))
33
+ : texts.dropped(labelOf(String(active.id)), positionOf(String(over.id)), countOf(String(over.id))),
34
+ onDragOver: ({ active, over }) => over === null
35
+ ? undefined
36
+ : texts.moved(labelOf(String(active.id)), positionOf(String(over.id)), countOf(String(over.id))),
37
+ onDragStart: ({ active }) => texts.lifted(labelOf(String(active.id)), positionOf(String(active.id)), countOf(String(active.id))),
38
+ };
39
+ const handleDragEnd = ({ active, over }) => {
40
+ setActiveId(null);
41
+ if (over === null || active.id === over.id)
42
+ return;
43
+ const placement = placements.get(String(active.id));
44
+ const target = placements.get(String(over.id));
45
+ if (placement === undefined || target === undefined || placement.runId !== target.runId)
46
+ return;
47
+ const run = runs.find((candidate) => candidate.id === placement.runId);
48
+ if (run === undefined)
49
+ return;
50
+ onReorder(run.groupKey, ps_table_reorder_service_1.PsTableReorderService.move(run.items.map((item) => item.id), String(active.id), String(over.id)));
51
+ };
52
+ return {
53
+ activeId,
54
+ activeRunId: activePlacement === undefined ? null : activePlacement.runId,
55
+ contextProps: {
56
+ accessibility: { announcements, screenReaderInstructions: { draggable: instructions } },
57
+ collisionDetection: core_1.closestCenter,
58
+ modifiers: [ps_table_reorder_service_1.PsTableReorderService.lockToVerticalAxis],
59
+ onDragCancel: () => setActiveId(null),
60
+ onDragEnd: handleDragEnd,
61
+ onDragStart: ({ active }) => setActiveId(String(active.id)),
62
+ sensors,
63
+ },
64
+ placements,
65
+ };
66
+ };
67
+ exports.usePsTableReorder = usePsTableReorder;
package/dist/index.d.ts CHANGED
@@ -32,3 +32,8 @@ export * from './components/ps-table-export-button';
32
32
  export * from './constants/ps-table-download-config';
33
33
  export * from './services/ps-table-download-service';
34
34
  export * from './services/ps-table-scroll-anchor-service';
35
+ export * from './hooks/use-ps-table-page';
36
+ export * from './interfaces/ps-table-page-state';
37
+ export * from './interfaces/table-reorder';
38
+ export * from './interfaces/table-reorder-announcements';
39
+ export * from './services/ps-table-reorder-service';
package/dist/index.js CHANGED
@@ -48,3 +48,8 @@ __exportStar(require("./components/ps-table-export-button"), exports);
48
48
  __exportStar(require("./constants/ps-table-download-config"), exports);
49
49
  __exportStar(require("./services/ps-table-download-service"), exports);
50
50
  __exportStar(require("./services/ps-table-scroll-anchor-service"), exports);
51
+ __exportStar(require("./hooks/use-ps-table-page"), exports);
52
+ __exportStar(require("./interfaces/ps-table-page-state"), exports);
53
+ __exportStar(require("./interfaces/table-reorder"), exports);
54
+ __exportStar(require("./interfaces/table-reorder-announcements"), exports);
55
+ __exportStar(require("./services/ps-table-reorder-service"), exports);
@@ -0,0 +1,4 @@
1
+ export interface PsTablePageState {
2
+ onPageChange: (page: number) => void;
3
+ page: number;
4
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ export interface PsTableReorderAnnouncements {
2
+ cancelled: (rowLabel: string) => string;
3
+ dropped: (rowLabel: string, position: number, count: number) => string;
4
+ lifted: (rowLabel: string, position: number, count: number) => string;
5
+ moved: (rowLabel: string, position: number, count: number) => string;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,8 @@
1
+ import type { ElementType, ReactNode } from 'react';
2
+ import type { PsTableReorderRowProps } from './table-reorder-row-props';
3
+ export interface PsTableReorderApi {
4
+ isActive: boolean;
5
+ Row: ElementType;
6
+ rowProps: (rowId: string) => PsTableReorderRowProps;
7
+ run: (runId: string, ids: string[], children: ReactNode) => ReactNode;
8
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ export interface PsTableReorderItem {
2
+ groupKey: string;
3
+ handleLabel: string;
4
+ id: string;
5
+ label: string;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ export interface PsTableReorderPlacement {
2
+ groupKey: string;
3
+ index: number;
4
+ runId: string;
5
+ size: number;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });