@pallasoft/ps-table-components 1.28.3 → 1.29.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 (52) hide show
  1. package/dist/components/ps-data-table.js +52 -50
  2. package/dist/components/ps-report-table-skeleton.d.ts +10 -0
  3. package/dist/components/ps-report-table-skeleton.js +29 -0
  4. package/dist/components/ps-report-table.d.ts +28 -0
  5. package/dist/components/ps-report-table.js +45 -0
  6. package/dist/constants/ps-report-column-align.d.ts +6 -0
  7. package/dist/constants/ps-report-column-align.js +8 -0
  8. package/dist/constants/ps-report-row-kind.d.ts +7 -0
  9. package/dist/constants/ps-report-row-kind.js +9 -0
  10. package/dist/constants/ps-report-row-tone.d.ts +7 -0
  11. package/dist/constants/ps-report-row-tone.js +9 -0
  12. package/dist/constants/ps-report-table-classes.d.ts +52 -0
  13. package/dist/constants/ps-report-table-classes.js +59 -0
  14. package/dist/constants/ps-report-table-config.d.ts +9 -0
  15. package/dist/constants/ps-report-table-config.js +9 -0
  16. package/dist/constants/ps-report-table-density.d.ts +5 -0
  17. package/dist/constants/ps-report-table-density.js +7 -0
  18. package/dist/constants/ps-table-sticky-config.d.ts +1 -1
  19. package/dist/constants/ps-table-sticky-config.js +1 -1
  20. package/dist/esm/components/ps-data-table.js +52 -50
  21. package/dist/esm/components/ps-report-table-skeleton.js +25 -0
  22. package/dist/esm/components/ps-report-table.js +41 -0
  23. package/dist/esm/constants/ps-report-column-align.js +5 -0
  24. package/dist/esm/constants/ps-report-row-kind.js +6 -0
  25. package/dist/esm/constants/ps-report-row-tone.js +6 -0
  26. package/dist/esm/constants/ps-report-table-classes.js +56 -0
  27. package/dist/esm/constants/ps-report-table-config.js +6 -0
  28. package/dist/esm/constants/ps-report-table-density.js +4 -0
  29. package/dist/esm/constants/ps-table-sticky-config.js +1 -1
  30. package/dist/esm/hooks/use-ps-sticky-head.js +34 -22
  31. package/dist/esm/index.js +8 -0
  32. package/dist/esm/interfaces/ps-report-cell-plan.js +1 -0
  33. package/dist/esm/interfaces/ps-report-column.js +1 -0
  34. package/dist/esm/interfaces/ps-table-sticky-head-inputs.js +1 -0
  35. package/dist/esm/services/ps-report-table-service.js +67 -0
  36. package/dist/esm/services/ps-table-sticky-head-service.js +11 -3
  37. package/dist/hooks/use-ps-sticky-head.d.ts +1 -1
  38. package/dist/hooks/use-ps-sticky-head.js +33 -21
  39. package/dist/index.d.ts +8 -0
  40. package/dist/index.js +8 -0
  41. package/dist/interfaces/ps-report-cell-plan.d.ts +6 -0
  42. package/dist/interfaces/ps-report-cell-plan.js +2 -0
  43. package/dist/interfaces/ps-report-column.d.ts +12 -0
  44. package/dist/interfaces/ps-report-column.js +2 -0
  45. package/dist/interfaces/ps-sticky-head-refs.d.ts +1 -1
  46. package/dist/interfaces/ps-table-sticky-head-inputs.d.ts +7 -0
  47. package/dist/interfaces/ps-table-sticky-head-inputs.js +2 -0
  48. package/dist/services/ps-report-table-service.d.ts +17 -0
  49. package/dist/services/ps-report-table-service.js +71 -0
  50. package/dist/services/ps-table-sticky-head-service.d.ts +3 -1
  51. package/dist/services/ps-table-sticky-head-service.js +11 -3
  52. package/package.json +1 -1
@@ -63,8 +63,8 @@ export const PsDataTable = ({ caption, className, clearSelectionKey, columns, cu
63
63
  const [openedGroupKeys, setOpenedGroupKeys] = useState([]);
64
64
  const [seenClearKey, setSeenClearKey] = useState(clearSelectionKey);
65
65
  const stickyRegionRef = useRef(null);
66
- const stickySentinelRef = useRef(null);
67
66
  const stickyCardRef = useRef(null);
67
+ const stickyContentRef = useRef(null);
68
68
  const stickyHeadRef = useRef(null);
69
69
  const currentQuery = query ? query : uncontrolledQuery;
70
70
  if (seenClearKey !== clearSelectionKey) {
@@ -93,12 +93,12 @@ export const PsDataTable = ({ caption, className, clearSelectionKey, columns, cu
93
93
  const pins = PsTablePinService.leading(pinFirstColumn, Boolean(reorder), isSelectable);
94
94
  const placementOf = (column, columnIndex) => PallasoftClassNameService.merge(column.hideBelow === undefined ? '' : PsTableHideBelowClasses[column.hideBelow], columnIndex === 0 ? pins.first : '', PsTablePinService.end(column.pinEnd === true));
95
95
  const overflow = usePsTableOverflow(`${visibleColumns.map((column) => column.id).join(',')}:${rows.length}`);
96
- const isStuck = usePsStickyHead({
96
+ usePsStickyHead({
97
97
  cardRef: stickyCardRef,
98
+ contentRef: stickyContentRef,
98
99
  headRef: stickyHeadRef,
99
100
  layoutKey: `${visibleColumns.map((column) => column.id).join(',')}:${rows.length}:${isLoading}`,
100
101
  regionRef: stickyRegionRef,
101
- sentinelRef: stickySentinelRef,
102
102
  stickyTop,
103
103
  });
104
104
  const deferredSearch = useDeferredValue(search);
@@ -361,51 +361,53 @@ export const PsDataTable = ({ caption, className, clearSelectionKey, columns, cu
361
361
  updateQuery({ search: next });
362
362
  resetPage();
363
363
  }, rows: rows, search: search, searchPlaceholder: searchPlaceholder })) : null, banner] }));
364
- return (_jsxs("div", { ref: containerRef, className: PallasoftClassNameService.merge('flex min-w-0 flex-col gap-3', className), children: [stickyTop === undefined ? (_jsxs(_Fragment, { children: [stickyLeading, topContent] })) : (_jsxs(_Fragment, { children: [_jsx("div", { "aria-hidden": 'true', className: '-mb-3 h-0', ref: stickySentinelRef }), _jsxs("div", { className: PallasoftClassNameService.merge('sticky z-sticky flex flex-col gap-3', stickyClassName), "data-stuck": isStuck, ref: stickyRegionRef, style: { top: stickyTop }, children: [stickyLeading, topContent] })] })), _jsxs("div", { "aria-busy": isRefreshing, className: 'min-w-0 overflow-hidden rounded-[1.25rem] border border-line bg-surface', ref: stickyCardRef, children: [showsPagination &&
365
- paginationPosition !== PsTablePaginationPosition.bottom &&
366
- rowCount > PsTablePaginationConfig.topMinRows
367
- ? renderPagination('border-b border-t-0')
368
- : null, mobileLayout === 'cards' ? (_jsxs("div", { className: PallasoftClassNameService.merge('sm:hidden', isRefreshing ? PsTableBodyClasses.refreshing : ''), 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
369
- ? groups.map((group, groupIndex) => {
370
- const isExpanded = isGroupExpanded(group.key, groupIndex);
371
- 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
372
- ? grouping.renderGroupSummary(group.rows)
373
- : undefined }), _jsx(PsCollapse, { isOpen: isExpanded && !closingGroupKeys.includes(group.key), children: renderCardList(group.rows, null) })] }, `group-${group.key}`));
374
- })
375
- : 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', isRefreshing ? PsTableBodyClasses.refreshing : '', 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: PallasoftClassNameService.merge('bg-mist/70 text-[0.68rem] font-semibold uppercase tracking-[0.18em] text-ink/45', stickyTop === undefined
376
- ? ''
377
- : 'relative z-docked bg-surface will-change-transform [&_th]:border-b [&_th]:border-line [&>tr]:bg-mist/70'), ref: stickyHeadRef, 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) => {
378
- const align = column.align !== null && column.align !== undefined ? column.align : 'left';
379
- const isSorted = sort !== null && sort.columnId === column.id;
380
- return (_jsx("th", { "aria-sort": isSorted
381
- ? sort.direction
382
- : column.sortValue && isQueryable
383
- ? 'none'
384
- : 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));
385
- })] }) }), _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
386
- ? groups.map((group, groupIndex) => {
387
- const isExpanded = isGroupExpanded(group.key, groupIndex);
388
- 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
389
- ? grouping.renderGroupSummary(group.rows)
390
- : undefined }) }) }), isExpanded
391
- ? renderEntries(api, group.rows.map((row, rowIndex) => ({
392
- motion: groupRowMotion(group.key, rowIndex),
393
- row,
394
- })))
395
- : null] }, `group-${group.key}`));
396
- })
397
- : shouldVirtualize
398
- ? [
399
- _jsx("tr", { "aria-hidden": 'true', children: _jsx("td", { className: 'p-0', colSpan: columnCount, style: { height: virtualTop } }) }, 'virtual-top'),
400
- ...renderEntries(api, virtualItems.map((item) => ({
401
- row: visibleRows[item.index],
402
- virtualItem: item,
403
- }))),
404
- _jsx("tr", { "aria-hidden": 'true', children: _jsx("td", { className: 'p-0', colSpan: columnCount, style: { height: virtualBottom } }) }, 'virtual-bottom'),
405
- ]
406
- : 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
407
- ? column.align
408
- : '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, showsPagination && paginationPosition !== PsTablePaginationPosition.top
409
- ? renderPagination('')
410
- : null] })] }));
364
+ return (_jsxs("div", { ref: containerRef, className: PallasoftClassNameService.merge('flex min-w-0 flex-col gap-3', className), children: [stickyTop === undefined ? (_jsxs(_Fragment, { children: [stickyLeading, topContent] })) : (_jsx(_Fragment, { children: _jsxs("div", { className: PallasoftClassNameService.merge('sticky z-sticky flex flex-col gap-3', stickyClassName), ref: stickyRegionRef, style: { top: stickyTop }, children: [stickyLeading, topContent] }) })), _jsx("div", { className: 'min-w-0 overflow-clip rounded-[1.25rem]', children: _jsx("div", { "aria-busy": isRefreshing, className: 'min-w-0 overflow-hidden rounded-[1.25rem] border border-line bg-surface', ref: stickyCardRef, children: _jsxs("div", { ref: stickyContentRef, children: [showsPagination &&
365
+ paginationPosition !== PsTablePaginationPosition.bottom &&
366
+ rowCount > PsTablePaginationConfig.topMinRows
367
+ ? renderPagination('border-b border-t-0')
368
+ : null, mobileLayout === 'cards' ? (_jsxs("div", { className: PallasoftClassNameService.merge('sm:hidden', isRefreshing ? PsTableBodyClasses.refreshing : ''), 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
369
+ ? groups.map((group, groupIndex) => {
370
+ const isExpanded = isGroupExpanded(group.key, groupIndex);
371
+ 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
372
+ ? grouping.renderGroupSummary(group.rows)
373
+ : undefined }), _jsx(PsCollapse, { isOpen: isExpanded && !closingGroupKeys.includes(group.key), children: renderCardList(group.rows, null) })] }, `group-${group.key}`));
374
+ })
375
+ : 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', isRefreshing ? PsTableBodyClasses.refreshing : '', 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: PallasoftClassNameService.merge('bg-mist/70 text-[0.68rem] font-semibold uppercase tracking-[0.18em] text-ink/45', stickyTop === undefined
376
+ ? ''
377
+ : 'relative z-docked bg-surface will-change-transform [&_th]:border-b [&_th]:border-line [&>tr]:bg-mist/70'), ref: stickyHeadRef, 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) => {
378
+ const align = column.align !== null && column.align !== undefined
379
+ ? column.align
380
+ : 'left';
381
+ const isSorted = sort !== null && sort.columnId === column.id;
382
+ return (_jsx("th", { "aria-sort": isSorted
383
+ ? sort.direction
384
+ : column.sortValue && isQueryable
385
+ ? 'none'
386
+ : 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));
387
+ })] }) }), _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
388
+ ? groups.map((group, groupIndex) => {
389
+ const isExpanded = isGroupExpanded(group.key, groupIndex);
390
+ 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
391
+ ? grouping.renderGroupSummary(group.rows)
392
+ : undefined }) }) }), isExpanded
393
+ ? renderEntries(api, group.rows.map((row, rowIndex) => ({
394
+ motion: groupRowMotion(group.key, rowIndex),
395
+ row,
396
+ })))
397
+ : null] }, `group-${group.key}`));
398
+ })
399
+ : shouldVirtualize
400
+ ? [
401
+ _jsx("tr", { "aria-hidden": 'true', children: _jsx("td", { className: 'p-0', colSpan: columnCount, style: { height: virtualTop } }) }, 'virtual-top'),
402
+ ...renderEntries(api, virtualItems.map((item) => ({
403
+ row: visibleRows[item.index],
404
+ virtualItem: item,
405
+ }))),
406
+ _jsx("tr", { "aria-hidden": 'true', children: _jsx("td", { className: 'p-0', colSpan: columnCount, style: { height: virtualBottom } }) }, 'virtual-bottom'),
407
+ ]
408
+ : 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
409
+ ? column.align
410
+ : '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, showsPagination && paginationPosition !== PsTablePaginationPosition.top
411
+ ? renderPagination('')
412
+ : null] }) }) })] }));
411
413
  };
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PsSkeleton, PsSkeletonGroup } from '@pallasoft/ps-core-components';
3
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
4
+ import { PsReportColumnAlign } from '../constants/ps-report-column-align';
5
+ import { PsReportTableClasses } from '../constants/ps-report-table-classes';
6
+ import { PsReportTableConfig } from '../constants/ps-report-table-config';
7
+ import { PsReportTableDensity } from '../constants/ps-report-table-density';
8
+ import { PsReportTableService } from '../services/ps-report-table-service';
9
+ export const PsReportTableSkeleton = ({ className, columns, density = PsReportTableDensity.normal, isFramed = true, rows = PsReportTableConfig.skeletonRows, }) => {
10
+ const isEnd = (column) => PsReportTableService.alignOf(column) === PsReportColumnAlign.right;
11
+ const headClass = (column, index) => {
12
+ if (isEnd(column))
13
+ return PsReportTableClasses.skeleton.headEnd;
14
+ return index === 0
15
+ ? PsReportTableClasses.skeleton.headFirst
16
+ : PsReportTableClasses.skeleton.headOther;
17
+ };
18
+ const cellClass = (column, rowIndex, index) => isEnd(column)
19
+ ? PsReportTableClasses.skeleton.cellEnd
20
+ : PsReportTableClasses.skeleton.cellWidths[(rowIndex + index) % PsReportTableClasses.skeleton.cellWidths.length];
21
+ return (_jsx(PsSkeletonGroup, { className: PallasoftClassNameService.merge(isFramed ? PsReportTableClasses.frame : PsReportTableClasses.skeleton.plain, className), children: _jsxs("table", { className: PsReportTableClasses.table, children: [_jsx("thead", { className: PsReportTableClasses.head, children: _jsx("tr", { children: columns.map((column, index) => (_jsx("th", { className: PsReportTableClasses.headCell[density], style: PsReportTableService.indent(0, density), children: _jsx(PsSkeleton, { className: headClass(column, index) }) }, column.id))) }) }), _jsx("tbody", { className: PsReportTableClasses.body, children: Array.from({ length: rows }, (_, rowIndex) => (_jsx("tr", { children: columns.map((column, index) => (_jsx("td", { className: PsReportTableClasses.cell[density], style: {
22
+ ...PsReportTableService.columnStyle(column),
23
+ ...PsReportTableService.indent(0, density),
24
+ }, children: _jsx(PsSkeleton, { className: cellClass(column, rowIndex, index) }) }, column.id))) }, rowIndex))) })] }) }));
25
+ };
@@ -0,0 +1,41 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ import { PsReportRowKind } from '../constants/ps-report-row-kind';
4
+ import { PsReportRowTone } from '../constants/ps-report-row-tone';
5
+ import { PsReportTableClasses } from '../constants/ps-report-table-classes';
6
+ import { PsReportTableConfig } from '../constants/ps-report-table-config';
7
+ import { PsReportTableDensity } from '../constants/ps-report-table-density';
8
+ import { usePsTableOverflow } from '../hooks/use-ps-table-overflow';
9
+ import { PsReportTableService } from '../services/ps-report-table-service';
10
+ import { PsReportTableSkeleton } from './ps-report-table-skeleton';
11
+ export const PsReportTable = ({ caption, className, columns, density = PsReportTableDensity.normal, emptyState, getLeadSpan, getRowId, getRowKind, getRowLevel, getRowTone, isFirstColumnSticky = false, isFramed = true, isHeaderHidden = false, isHeaderSticky = false, isLoading = false, isRefreshing = false, maxHeight, minWidth, renderLead, rows, }) => {
12
+ const overflow = usePsTableOverflow(String(rows.length));
13
+ if (isLoading)
14
+ return (_jsx(PsReportTableSkeleton, { className: className, columns: columns, density: density, isFramed: isFramed }));
15
+ const kindOf = (row) => getRowKind !== undefined ? getRowKind(row) : PsReportRowKind.data;
16
+ const toneOf = (row) => getRowTone !== undefined ? getRowTone(row) : PsReportRowTone.neutral;
17
+ const levelOf = (row) => PsReportTableService.levelOf(getRowLevel !== undefined ? getRowLevel(row) : undefined);
18
+ const leadOf = (row) => (getLeadSpan !== undefined ? getLeadSpan(row) : 1);
19
+ const renderRow = (row) => {
20
+ const kind = kindOf(row);
21
+ const tone = toneOf(row);
22
+ const level = levelOf(row);
23
+ return (_jsx("tr", { className: PsReportTableClasses.kind[kind], children: PsReportTableService.cells(columns, leadOf(row)).map((plan) => {
24
+ const className = PallasoftClassNameService.merge(PsReportTableService.cellClass(plan.column, plan.index, density, tone, isFirstColumnSticky), plan.index === 0 ? PsReportTableClasses.rowHeader : '');
25
+ const style = {
26
+ ...PsReportTableService.columnStyle(plan.column),
27
+ ...(plan.index === 0 ? PsReportTableService.indent(level, density) : {}),
28
+ };
29
+ return plan.index === 0 ? (_jsx("th", { className: className, colSpan: plan.colSpan, scope: kind === PsReportRowKind.group && plan.colSpan === columns.length
30
+ ? 'colgroup'
31
+ : 'row', style: style, children: plan.colSpan > 1 && renderLead !== undefined
32
+ ? renderLead(row)
33
+ : plan.column.render(row) }, plan.column.id)) : (_jsx("td", { className: className, colSpan: plan.colSpan, style: style, children: plan.column.render(row) }, plan.column.id));
34
+ }) }, getRowId(row)));
35
+ };
36
+ const content = (_jsx("div", { className: PallasoftClassNameService.merge(PsReportTableClasses.scroll, maxHeight !== undefined ? PsReportTableClasses.scrollBounded : '', isRefreshing ? PsReportTableClasses.refreshing : ''), "data-overflow-end": overflow.edges.end, "data-overflow-start": overflow.edges.start, onScroll: overflow.update, ref: overflow.ref, style: { maxHeight }, children: _jsxs("table", { className: PsReportTableClasses.table, style: { minWidth }, children: [_jsx("caption", { className: PsReportTableClasses.caption, children: caption }), _jsx("thead", { className: PallasoftClassNameService.merge(PsReportTableClasses.head, isHeaderHidden ? PsReportTableClasses.headHidden : ''), children: _jsx("tr", { children: columns.map((column, index) => (_jsx("th", { className: PsReportTableService.headClass(column, index, density, isHeaderSticky, isFirstColumnSticky), scope: 'col', style: {
37
+ ...PsReportTableService.columnStyle(column),
38
+ ...PsReportTableService.indent(0, density),
39
+ }, children: column.label }, column.id))) }) }), _jsx("tbody", { className: PsReportTableClasses.body, children: rows.length === 0 ? (_jsx("tr", { children: _jsx("td", { className: PsReportTableClasses.empty, colSpan: columns.length, children: emptyState !== undefined ? emptyState : PsReportTableConfig.emptyLabel }) })) : (rows.map(renderRow)) })] }) }));
40
+ return (_jsx("div", { "aria-busy": isRefreshing, className: PallasoftClassNameService.merge(isFramed ? PsReportTableClasses.frame : PsReportTableClasses.framePlain, className), children: content }));
41
+ };
@@ -0,0 +1,5 @@
1
+ export const PsReportColumnAlign = {
2
+ center: 'center',
3
+ left: 'left',
4
+ right: 'right',
5
+ };
@@ -0,0 +1,6 @@
1
+ export const PsReportRowKind = {
2
+ data: 'data',
3
+ group: 'group',
4
+ subtotal: 'subtotal',
5
+ total: 'total',
6
+ };
@@ -0,0 +1,6 @@
1
+ export const PsReportRowTone = {
2
+ danger: 'danger',
3
+ muted: 'muted',
4
+ neutral: 'neutral',
5
+ primary: 'primary',
6
+ };
@@ -0,0 +1,56 @@
1
+ import { PsReportColumnAlign } from './ps-report-column-align';
2
+ import { PsReportRowKind } from './ps-report-row-kind';
3
+ import { PsReportRowTone } from './ps-report-row-tone';
4
+ import { PsReportTableDensity } from './ps-report-table-density';
5
+ export const PsReportTableClasses = {
6
+ align: {
7
+ [PsReportColumnAlign.center]: 'text-center',
8
+ [PsReportColumnAlign.left]: 'text-left',
9
+ [PsReportColumnAlign.right]: 'text-right tabular-nums',
10
+ },
11
+ body: 'divide-y divide-line/60',
12
+ caption: 'sr-only',
13
+ cell: {
14
+ [PsReportTableDensity.compact]: 'py-1.5 pr-3 text-[0.8125rem] leading-5',
15
+ [PsReportTableDensity.normal]: 'py-3 pr-5 text-sm',
16
+ },
17
+ empty: 'px-4 py-10 text-center text-sm text-ink/55',
18
+ framePlain: 'min-w-0',
19
+ frame: 'min-w-0 overflow-hidden rounded-[1.25rem] border border-line bg-surface',
20
+ head: 'bg-mist/70 text-[0.68rem] font-semibold uppercase tracking-[0.18em] text-ink/45',
21
+ headCell: {
22
+ [PsReportTableDensity.compact]: 'py-2 pr-3 whitespace-nowrap',
23
+ [PsReportTableDensity.normal]: 'py-3.5 pr-5 whitespace-nowrap',
24
+ },
25
+ headHidden: 'sr-only',
26
+ kind: {
27
+ [PsReportRowKind.data]: 'text-ink',
28
+ [PsReportRowKind.group]: 'bg-mist/40 font-semibold text-ink [--ps-table-pin-fill:inset_0_0_0_100vmax_rgb(var(--ps-color-mist-rgb)/0.4)]',
29
+ [PsReportRowKind.subtotal]: 'border-t border-line font-semibold text-ink',
30
+ [PsReportRowKind.total]: 'border-t-2 border-line bg-mist/50 font-semibold text-ink [--ps-table-pin-fill:inset_0_0_0_100vmax_rgb(var(--ps-color-mist-rgb)/0.5)]',
31
+ },
32
+ nowrap: 'whitespace-nowrap',
33
+ refreshing: 'opacity-60',
34
+ rowHeader: '[font-weight:inherit]',
35
+ scroll: 'ps-scrollbar overflow-x-auto overscroll-x-contain',
36
+ scrollBounded: 'overflow-y-auto overscroll-contain',
37
+ skeleton: {
38
+ cellEnd: 'ml-auto w-16',
39
+ cellWidths: ['w-3/4', 'w-1/2'],
40
+ headEnd: 'ml-auto h-2.5 w-12',
41
+ headFirst: 'h-2.5 w-20',
42
+ headOther: 'h-2.5 w-14',
43
+ plain: 'min-w-0 overflow-hidden',
44
+ },
45
+ stickyFirstBody: 'ps-table-pin left-0',
46
+ stickyFirstHead: 'ps-table-pin left-0 top-0 z-[3]',
47
+ stickyHead: 'ps-table-pin top-0 z-[2]',
48
+ table: 'w-full border-collapse text-left',
49
+ tone: {
50
+ [PsReportRowTone.danger]: 'bg-danger-soft/60 text-danger [--ps-table-pin-fill:inset_0_0_0_100vmax_rgb(var(--ps-color-danger-soft-rgb)/0.6)]',
51
+ [PsReportRowTone.muted]: 'text-ink/60',
52
+ [PsReportRowTone.neutral]: '',
53
+ [PsReportRowTone.primary]: 'bg-primary/10 text-primary [--ps-table-pin-fill:inset_0_0_0_100vmax_rgb(var(--ps-color-primary-rgb)/0.1)]',
54
+ },
55
+ truncate: 'truncate',
56
+ };
@@ -0,0 +1,6 @@
1
+ export const PsReportTableConfig = {
2
+ baseIndentRem: { compact: 0.75, normal: 1.25 },
3
+ emptyLabel: 'Nothing to show',
4
+ indentRem: 1.25,
5
+ skeletonRows: 6,
6
+ };
@@ -0,0 +1,4 @@
1
+ export const PsReportTableDensity = {
2
+ compact: 'compact',
3
+ normal: 'normal',
4
+ };
@@ -1,4 +1,4 @@
1
1
  export const PsTableStickyConfig = {
2
2
  cardGapPx: 12,
3
- cardRadius: '1.25rem',
3
+ inputTolerancePx: 0.5,
4
4
  };
@@ -1,19 +1,18 @@
1
- import { useLayoutEffect, useState } from 'react';
1
+ import { useLayoutEffect } from 'react';
2
2
  import { PsTableStickyConfig } from '../constants/ps-table-sticky-config';
3
3
  import { PsTableScrollService } from '../services/ps-table-scroll-service';
4
4
  import { PsTableStickyHeadService } from '../services/ps-table-sticky-head-service';
5
- export const usePsStickyHead = ({ cardRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop, }) => {
6
- const [isStuck, setIsStuck] = useState(false);
5
+ export const usePsStickyHead = ({ cardRef, contentRef, headRef, layoutKey, regionRef, stickyTop, }) => {
7
6
  useLayoutEffect(() => {
8
7
  const region = regionRef.current;
9
- const sentinel = sentinelRef.current;
10
8
  const card = cardRef.current;
9
+ const content = contentRef.current;
11
10
  const head = headRef.current;
12
11
  const table = head === null ? null : head.parentElement;
13
12
  if (stickyTop === undefined ||
14
13
  region === null ||
15
- sentinel === null ||
16
14
  card === null ||
15
+ content === null ||
17
16
  head === null ||
18
17
  table === null)
19
18
  return;
@@ -21,6 +20,7 @@ export const usePsStickyHead = ({ cardRef, headRef, layoutKey, regionRef, sentin
21
20
  const Timeline = window.ScrollTimeline;
22
21
  const isDriven = scroller !== null && Timeline !== undefined;
23
22
  let animations = [];
23
+ let measured = null;
24
24
  let frame = 0;
25
25
  const headTravel = () => Math.max(table.offsetHeight - head.offsetHeight, 0);
26
26
  const drive = () => {
@@ -30,10 +30,19 @@ export const usePsStickyHead = ({ cardRef, headRef, layoutKey, regionRef, sentin
30
30
  Number.parseFloat(getComputedStyle(region).top) +
31
31
  region.offsetHeight +
32
32
  PsTableStickyConfig.cardGapPx;
33
- const scrollRange = scroller.scrollHeight - scroller.clientHeight;
33
+ const inputs = {
34
+ cardPin: content.getBoundingClientRect().top + scroller.scrollTop - pinnedLine,
35
+ cardTravel: card.offsetHeight,
36
+ headPin: table.getBoundingClientRect().top + scroller.scrollTop - pinnedLine,
37
+ headTravel: headTravel(),
38
+ scrollRange: scroller.scrollHeight - scroller.clientHeight,
39
+ };
40
+ if (PsTableStickyHeadService.sameInputs(measured, inputs))
41
+ return;
42
+ measured = inputs;
34
43
  const timeline = new Timeline({ axis: 'block', source: scroller });
35
- const headFrames = PsTableStickyHeadService.keyframes(table.getBoundingClientRect().top + scroller.scrollTop - pinnedLine, headTravel(), scrollRange);
36
- const cardFrames = PsTableStickyHeadService.keyframes(card.getBoundingClientRect().top + scroller.scrollTop - pinnedLine, card.offsetHeight, scrollRange);
44
+ const headFrames = PsTableStickyHeadService.keyframes(inputs.headPin, inputs.headTravel, inputs.scrollRange);
45
+ const cardFrames = PsTableStickyHeadService.keyframes(inputs.cardPin, inputs.cardTravel, inputs.scrollRange);
37
46
  animations.forEach((animation) => animation.cancel());
38
47
  animations = [
39
48
  head.animate(headFrames.map((keyframe) => ({
@@ -41,30 +50,32 @@ export const usePsStickyHead = ({ cardRef, headRef, layoutKey, regionRef, sentin
41
50
  transform: `translateY(${keyframe.shift}px)`,
42
51
  })), { fill: 'both', timeline }),
43
52
  card.animate(cardFrames.map((keyframe) => ({
44
- clipPath: PsTableStickyHeadService.clip(keyframe.shift),
45
53
  offset: keyframe.offset,
54
+ transform: `translateY(${keyframe.shift}px)`,
55
+ })), { fill: 'both', timeline }),
56
+ content.animate(cardFrames.map((keyframe) => ({
57
+ offset: keyframe.offset,
58
+ transform: `translateY(${-keyframe.shift}px)`,
46
59
  })), { fill: 'both', timeline }),
47
60
  ];
48
61
  };
49
62
  const follow = () => {
63
+ frame = 0;
50
64
  const pinnedLine = region.getBoundingClientRect().bottom + PsTableStickyConfig.cardGapPx;
51
65
  head.style.transform = `translateY(${PsTableStickyHeadService.offset(pinnedLine, table.getBoundingClientRect().top, table.offsetHeight, head.offsetHeight)}px)`;
52
- card.style.clipPath = PsTableStickyHeadService.clip(PsTableStickyHeadService.offset(pinnedLine, card.getBoundingClientRect().top, card.offsetHeight, 0));
53
- };
54
- const check = () => {
55
- frame = 0;
56
- setIsStuck(sentinel.getBoundingClientRect().top < region.getBoundingClientRect().top - 1);
57
- if (!isDriven)
58
- follow();
66
+ const cut = PsTableStickyHeadService.offset(pinnedLine, content.getBoundingClientRect().top, card.offsetHeight, 0);
67
+ card.style.transform = `translateY(${cut}px)`;
68
+ content.style.transform = `translateY(${-cut}px)`;
59
69
  };
60
70
  const schedule = () => {
61
71
  if (frame === 0)
62
- frame = window.requestAnimationFrame(check);
72
+ frame = window.requestAnimationFrame(follow);
63
73
  };
64
74
  const measure = () => {
65
75
  if (isDriven)
66
76
  drive();
67
- schedule();
77
+ else
78
+ schedule();
68
79
  };
69
80
  const observer = new ResizeObserver(measure);
70
81
  measure();
@@ -72,18 +83,19 @@ export const usePsStickyHead = ({ cardRef, headRef, layoutKey, regionRef, sentin
72
83
  observer.observe(card);
73
84
  if (scroller !== null)
74
85
  Array.from(scroller.children).forEach((child) => observer.observe(child));
75
- window.addEventListener('scroll', schedule, { capture: true, passive: true });
76
86
  window.addEventListener('resize', measure);
87
+ if (!isDriven)
88
+ window.addEventListener('scroll', schedule, { capture: true, passive: true });
77
89
  return () => {
78
90
  observer.disconnect();
79
91
  animations.forEach((animation) => animation.cancel());
80
92
  head.style.transform = '';
81
- card.style.clipPath = '';
93
+ card.style.transform = '';
94
+ content.style.transform = '';
82
95
  window.removeEventListener('scroll', schedule, { capture: true });
83
96
  window.removeEventListener('resize', measure);
84
97
  if (frame !== 0)
85
98
  window.cancelAnimationFrame(frame);
86
99
  };
87
- }, [cardRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop]);
88
- return isStuck;
100
+ }, [cardRef, contentRef, headRef, layoutKey, regionRef, stickyTop]);
89
101
  };
package/dist/esm/index.js CHANGED
@@ -64,3 +64,11 @@ export * from './interfaces/ps-server-rows-result';
64
64
  export * from './interfaces/ps-table-cursor-paging';
65
65
  export * from './interfaces/ps-table-select-all-matching';
66
66
  export * from './services/ps-server-rows-service';
67
+ export * from './components/ps-report-table';
68
+ export * from './components/ps-report-table-skeleton';
69
+ export * from './constants/ps-report-column-align';
70
+ export * from './constants/ps-report-row-kind';
71
+ export * from './constants/ps-report-row-tone';
72
+ export * from './constants/ps-report-table-density';
73
+ export * from './interfaces/ps-report-column';
74
+ export * from './services/ps-report-table-service';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,67 @@
1
+ import { PsReportColumnAlign } from '../constants/ps-report-column-align';
2
+ import { PsReportTableClasses } from '../constants/ps-report-table-classes';
3
+ import { PsReportTableConfig } from '../constants/ps-report-table-config';
4
+ import { PsTablePinClasses } from '../constants/ps-table-pin-classes';
5
+ export class PsReportTableService {
6
+ static cells(columns, leadSpan) {
7
+ const span = PsReportTableService.span(columns.length, leadSpan);
8
+ const plan = [{ colSpan: span, column: columns[0], index: 0 }];
9
+ for (let index = span; index < columns.length; index += 1)
10
+ plan.push({ colSpan: 1, column: columns[index], index });
11
+ return plan;
12
+ }
13
+ static span(count, leadSpan) {
14
+ return Math.min(Math.max(leadSpan, 1), count);
15
+ }
16
+ static indent(level, density) {
17
+ const base = PsReportTableConfig.baseIndentRem[density];
18
+ return { paddingLeft: `${base + level * PsReportTableConfig.indentRem}rem` };
19
+ }
20
+ static columnStyle(column) {
21
+ return {
22
+ maxWidth: column.maxWidth,
23
+ minWidth: column.minWidth,
24
+ width: column.width,
25
+ };
26
+ }
27
+ static levelOf(level) {
28
+ return level !== undefined && level > 0 ? level : 0;
29
+ }
30
+ static headClass(column, index, density, isHeaderSticky, isFirstColumnSticky) {
31
+ const isPinnedFirst = index === 0 && isFirstColumnSticky;
32
+ const pin = PsReportTableService.headPin(isHeaderSticky, isPinnedFirst);
33
+ return [
34
+ PsReportTableClasses.headCell[density],
35
+ PsReportTableClasses.align[PsReportTableService.alignOf(column)],
36
+ pin,
37
+ isPinnedFirst ? PsTablePinClasses.edge : '',
38
+ ]
39
+ .filter((name) => name !== '')
40
+ .join(' ');
41
+ }
42
+ static headPin(isHeaderSticky, isPinnedFirst) {
43
+ if (isHeaderSticky && isPinnedFirst)
44
+ return PsReportTableClasses.stickyFirstHead;
45
+ if (isHeaderSticky)
46
+ return PsReportTableClasses.stickyHead;
47
+ if (isPinnedFirst)
48
+ return PsReportTableClasses.stickyFirstBody;
49
+ return '';
50
+ }
51
+ static cellClass(column, index, density, tone, isFirstColumnSticky) {
52
+ const isPinnedFirst = index === 0 && isFirstColumnSticky;
53
+ return [
54
+ PsReportTableClasses.cell[density],
55
+ PsReportTableClasses.align[PsReportTableService.alignOf(column)],
56
+ PsReportTableClasses.tone[tone],
57
+ column.wrap === true ? '' : PsReportTableClasses.nowrap,
58
+ column.maxWidth !== undefined ? PsReportTableClasses.truncate : '',
59
+ isPinnedFirst ? `${PsReportTableClasses.stickyFirstBody} ${PsTablePinClasses.edge}` : '',
60
+ ]
61
+ .filter((name) => name !== '')
62
+ .join(' ');
63
+ }
64
+ static alignOf(column) {
65
+ return column.align !== undefined ? column.align : PsReportColumnAlign.left;
66
+ }
67
+ }
@@ -3,6 +3,15 @@ export class PsTableStickyHeadService {
3
3
  static offset(pinnedBottom, tableTop, tableHeight, headHeight) {
4
4
  return Math.min(Math.max(pinnedBottom - tableTop, 0), Math.max(tableHeight - headHeight, 0));
5
5
  }
6
+ static sameInputs(previous, next) {
7
+ if (previous === null)
8
+ return false;
9
+ return (PsTableStickyHeadService.close(previous.headPin, next.headPin) &&
10
+ PsTableStickyHeadService.close(previous.headTravel, next.headTravel) &&
11
+ PsTableStickyHeadService.close(previous.cardPin, next.cardPin) &&
12
+ PsTableStickyHeadService.close(previous.cardTravel, next.cardTravel) &&
13
+ PsTableStickyHeadService.close(previous.scrollRange, next.scrollRange));
14
+ }
6
15
  static keyframes(pinScroll, maxShift, scrollRange) {
7
16
  if (scrollRange <= 0)
8
17
  return [];
@@ -12,9 +21,8 @@ export class PsTableStickyHeadService {
12
21
  shift: shiftAt(scroll),
13
22
  }));
14
23
  }
15
- static clip(shift) {
16
- const radius = PsTableStickyConfig.cardRadius;
17
- return `inset(${shift}px 0 0 0 round ${radius} ${radius} 0 0)`;
24
+ static close(first, second) {
25
+ return Math.abs(first - second) <= PsTableStickyConfig.inputTolerancePx;
18
26
  }
19
27
  static stops(scrolls, scrollRange) {
20
28
  const inside = scrolls.filter((scroll) => scroll >= 0 && scroll <= scrollRange);
@@ -1,2 +1,2 @@
1
1
  import type { PsStickyHeadRefs } from '../interfaces/ps-sticky-head-refs';
2
- export declare const usePsStickyHead: ({ cardRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop, }: PsStickyHeadRefs) => boolean;
2
+ export declare const usePsStickyHead: ({ cardRef, contentRef, headRef, layoutKey, regionRef, stickyTop, }: PsStickyHeadRefs) => void;