@pallasoft/ps-table-components 1.28.1 → 1.28.3

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.
@@ -41,6 +41,7 @@ const ps_design_system_1 = require("@pallasoft/ps-design-system");
41
41
  const ps_input_components_1 = require("@pallasoft/ps-input-components");
42
42
  const ps_motion_components_1 = require("@pallasoft/ps-motion-components");
43
43
  const react_virtual_1 = require("@tanstack/react-virtual");
44
+ const ps_table_body_classes_1 = require("../constants/ps-table-body-classes");
44
45
  const ps_table_control_classes_1 = require("../constants/ps-table-control-classes");
45
46
  const ps_table_pagination_config_1 = require("../constants/ps-table-pagination-config");
46
47
  const ps_table_pagination_position_1 = require("../constants/ps-table-pagination-position");
@@ -99,7 +100,7 @@ const PsDataTable = ({ caption, className, clearSelectionKey, columns, cursorPag
99
100
  const [seenClearKey, setSeenClearKey] = (0, react_1.useState)(clearSelectionKey);
100
101
  const stickyRegionRef = (0, react_1.useRef)(null);
101
102
  const stickySentinelRef = (0, react_1.useRef)(null);
102
- const stickyBackdropRef = (0, react_1.useRef)(null);
103
+ const stickyCardRef = (0, react_1.useRef)(null);
103
104
  const stickyHeadRef = (0, react_1.useRef)(null);
104
105
  const currentQuery = query ? query : uncontrolledQuery;
105
106
  if (seenClearKey !== clearSelectionKey) {
@@ -129,7 +130,7 @@ const PsDataTable = ({ caption, className, clearSelectionKey, columns, cursorPag
129
130
  const placementOf = (column, columnIndex) => ps_design_system_1.PallasoftClassNameService.merge(column.hideBelow === undefined ? '' : table_breakpoint_1.PsTableHideBelowClasses[column.hideBelow], columnIndex === 0 ? pins.first : '', ps_table_pin_service_1.PsTablePinService.end(column.pinEnd === true));
130
131
  const overflow = (0, use_ps_table_overflow_1.usePsTableOverflow)(`${visibleColumns.map((column) => column.id).join(',')}:${rows.length}`);
131
132
  const isStuck = (0, use_ps_sticky_head_1.usePsStickyHead)({
132
- backdropRef: stickyBackdropRef,
133
+ cardRef: stickyCardRef,
133
134
  headRef: stickyHeadRef,
134
135
  layoutKey: `${visibleColumns.map((column) => column.id).join(',')}:${rows.length}:${isLoading}`,
135
136
  regionRef: stickyRegionRef,
@@ -396,18 +397,18 @@ const PsDataTable = ({ caption, className, clearSelectionKey, columns, cursorPag
396
397
  updateQuery({ search: next });
397
398
  resetPage();
398
399
  }, rows: rows, search: search, searchPlaceholder: searchPlaceholder })) : null, banner] }));
399
- return ((0, jsx_runtime_1.jsxs)("div", { ref: containerRef, className: ps_design_system_1.PallasoftClassNameService.merge('flex min-w-0 flex-col gap-3', className), children: [stickyTop === undefined ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [stickyLeading, topContent] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { "aria-hidden": 'true', className: '-mb-3 h-0', ref: stickySentinelRef }), (0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('sticky z-sticky flex flex-col gap-3', stickyClassName), "data-stuck": isStuck, ref: stickyRegionRef, style: { top: stickyTop }, children: [(0, jsx_runtime_1.jsx)("div", { "aria-hidden": 'true', className: 'ps-glass-strong pointer-events-none absolute -inset-x-3 -bottom-3 rounded-b-ps-card border-t-0 opacity-0', ref: stickyBackdropRef, style: { top: `calc(-1 * ${stickyTop})` } }), (0, jsx_runtime_1.jsxs)("div", { className: 'relative flex flex-col gap-3', children: [stickyLeading, topContent] })] })] })), (0, jsx_runtime_1.jsxs)("div", { "aria-busy": isRefreshing, className: 'min-w-0 overflow-hidden rounded-[1.25rem] border border-line bg-surface', children: [showsPagination &&
400
+ return ((0, jsx_runtime_1.jsxs)("div", { ref: containerRef, className: ps_design_system_1.PallasoftClassNameService.merge('flex min-w-0 flex-col gap-3', className), children: [stickyTop === undefined ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [stickyLeading, topContent] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { "aria-hidden": 'true', className: '-mb-3 h-0', ref: stickySentinelRef }), (0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('sticky z-sticky flex flex-col gap-3', stickyClassName), "data-stuck": isStuck, ref: stickyRegionRef, style: { top: stickyTop }, children: [stickyLeading, topContent] })] })), (0, jsx_runtime_1.jsxs)("div", { "aria-busy": isRefreshing, className: 'min-w-0 overflow-hidden rounded-[1.25rem] border border-line bg-surface', ref: stickyCardRef, children: [showsPagination &&
400
401
  paginationPosition !== ps_table_pagination_position_1.PsTablePaginationPosition.bottom &&
401
402
  rowCount > ps_table_pagination_config_1.PsTablePaginationConfig.topMinRows
402
403
  ? renderPagination('border-b border-t-0')
403
- : null, mobileLayout === 'cards' ? ((0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('transition-opacity duration-150 sm:hidden', isRefreshing ? 'opacity-60' : ''), children: [reorder && reorder.cardsReason ? ((0, jsx_runtime_1.jsx)("p", { className: 'border-b border-line px-4 py-2 text-xs text-ink/55', children: reorder.cardsReason })) : null, grouping
404
+ : null, mobileLayout === 'cards' ? ((0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('sm:hidden', isRefreshing ? ps_table_body_classes_1.PsTableBodyClasses.refreshing : ''), children: [reorder && reorder.cardsReason ? ((0, jsx_runtime_1.jsx)("p", { className: 'border-b border-line px-4 py-2 text-xs text-ink/55', children: reorder.cardsReason })) : null, grouping
404
405
  ? groups.map((group, groupIndex) => {
405
406
  const isExpanded = isGroupExpanded(group.key, groupIndex);
406
407
  return ((0, jsx_runtime_1.jsxs)("div", { className: 'border-b border-line last:border-b-0', children: [(0, jsx_runtime_1.jsx)(ps_table_group_header_1.PsTableGroupHeader, { count: group.rows.length, isExpanded: isExpanded, label: grouping.getGroupLabel(group.key, group.rows), onToggle: () => toggleGroup(group.key, isExpanded), summary: grouping.renderGroupSummary
407
408
  ? grouping.renderGroupSummary(group.rows)
408
409
  : undefined }), (0, jsx_runtime_1.jsx)(ps_motion_components_1.PsCollapse, { isOpen: isExpanded && !closingGroupKeys.includes(group.key), children: renderCardList(group.rows, null) })] }, `group-${group.key}`));
409
410
  })
410
- : renderCardList(shouldVirtualize ? visibleRows.slice(0, cards.count) : visibleRows, visibleRows.length === 0 && isSearching ? ((0, jsx_runtime_1.jsx)(ps_table_searching_state_1.PsTableSearchingState, { label: searchingLabel, skeletonRows: table_config_1.PsTableConfig.searchingSkeletonRows })) : visibleRows.length === 0 && isQueried ? ((0, jsx_runtime_1.jsxs)("div", { className: 'px-4 py-10 text-center', children: [(0, jsx_runtime_1.jsx)("p", { className: 'text-sm font-semibold text-ink', children: table_config_1.PsTableConfig.noMatchesTitle }), (0, jsx_runtime_1.jsx)("button", { className: ps_design_system_1.PallasoftClassNameService.merge(ps_table_control_classes_1.PsTableControlClasses.textButton, 'mt-2 text-primary'), onClick: clearFilters, type: 'button', children: "Clear search and filters" })] })) : null), !grouping && shouldVirtualize && cards.count < visibleRows.length ? ((0, jsx_runtime_1.jsx)("div", { "aria-hidden": 'true', className: 'h-px', ref: cards.sentinelRef })) : null] })) : null, (0, jsx_runtime_1.jsx)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('ps-scrollbar overflow-x-auto overflow-y-hidden overscroll-x-contain', 'transition-opacity duration-150', isRefreshing ? 'opacity-60' : '', 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) => ((0, jsx_runtime_1.jsxs)("table", { className: ps_design_system_1.PallasoftClassNameService.merge('w-full border-collapse text-left', layout === 'fixed' ? 'table-fixed' : ''), children: [caption ? (0, jsx_runtime_1.jsx)("caption", { className: 'sr-only', children: caption }) : null, (0, jsx_runtime_1.jsx)("thead", { className: ps_design_system_1.PallasoftClassNameService.merge('bg-mist/70 text-[0.68rem] font-semibold uppercase tracking-[0.18em] text-ink/45', stickyTop === undefined
411
+ : renderCardList(shouldVirtualize ? visibleRows.slice(0, cards.count) : visibleRows, visibleRows.length === 0 && isSearching ? ((0, jsx_runtime_1.jsx)(ps_table_searching_state_1.PsTableSearchingState, { label: searchingLabel, skeletonRows: table_config_1.PsTableConfig.searchingSkeletonRows })) : visibleRows.length === 0 && isQueried ? ((0, jsx_runtime_1.jsxs)("div", { className: 'px-4 py-10 text-center', children: [(0, jsx_runtime_1.jsx)("p", { className: 'text-sm font-semibold text-ink', children: table_config_1.PsTableConfig.noMatchesTitle }), (0, jsx_runtime_1.jsx)("button", { className: ps_design_system_1.PallasoftClassNameService.merge(ps_table_control_classes_1.PsTableControlClasses.textButton, 'mt-2 text-primary'), onClick: clearFilters, type: 'button', children: "Clear search and filters" })] })) : null), !grouping && shouldVirtualize && cards.count < visibleRows.length ? ((0, jsx_runtime_1.jsx)("div", { "aria-hidden": 'true', className: 'h-px', ref: cards.sentinelRef })) : null] })) : null, (0, jsx_runtime_1.jsx)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('ps-scrollbar overflow-x-auto overflow-y-hidden overscroll-x-contain', isRefreshing ? ps_table_body_classes_1.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) => ((0, jsx_runtime_1.jsxs)("table", { className: ps_design_system_1.PallasoftClassNameService.merge('w-full border-collapse text-left', layout === 'fixed' ? 'table-fixed' : ''), children: [caption ? (0, jsx_runtime_1.jsx)("caption", { className: 'sr-only', children: caption }) : null, (0, jsx_runtime_1.jsx)("thead", { className: ps_design_system_1.PallasoftClassNameService.merge('bg-mist/70 text-[0.68rem] font-semibold uppercase tracking-[0.18em] text-ink/45', stickyTop === undefined
411
412
  ? ''
412
413
  : 'relative z-docked bg-surface will-change-transform [&_th]:border-b [&_th]:border-line [&>tr]:bg-mist/70'), ref: stickyHeadRef, children: (0, jsx_runtime_1.jsxs)("tr", { children: [reorder ? ((0, jsx_runtime_1.jsx)("th", { className: ps_design_system_1.PallasoftClassNameService.merge('w-9 min-w-9 pl-3 pr-0', pins.reorder), scope: 'col', children: reorder.enabled ? ((0, jsx_runtime_1.jsx)("span", { className: 'sr-only', children: reorder.columnLabel })) : reorder.disabledReason ? ((0, jsx_runtime_1.jsx)("span", { "aria-label": reorder.disabledReason, className: 'inline-flex cursor-help opacity-40', role: 'img', title: reorder.disabledReason, children: (0, jsx_runtime_1.jsx)(ps_core_components_1.PsDragGrip, {}) })) : null })) : null, isSelectable ? ((0, jsx_runtime_1.jsx)("th", { className: ps_design_system_1.PallasoftClassNameService.merge('w-10 min-w-10 pl-4 pr-0', pins.select), scope: 'col', children: (0, jsx_runtime_1.jsx)(ps_input_components_1.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) => {
413
414
  const align = column.align !== null && column.align !== undefined ? column.align : 'left';
@@ -0,0 +1,3 @@
1
+ export declare const PsTableBodyClasses: {
2
+ readonly refreshing: "opacity-60";
3
+ };
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsTableBodyClasses = void 0;
4
+ exports.PsTableBodyClasses = {
5
+ refreshing: 'opacity-60',
6
+ };
@@ -1,3 +1,4 @@
1
1
  export declare const PsTableStickyConfig: {
2
- readonly backdropFadePx: 16;
2
+ readonly cardGapPx: 12;
3
+ readonly cardRadius: "1.25rem";
3
4
  };
@@ -2,5 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PsTableStickyConfig = void 0;
4
4
  exports.PsTableStickyConfig = {
5
- backdropFadePx: 16,
5
+ cardGapPx: 12,
6
+ cardRadius: '1.25rem',
6
7
  };
@@ -5,6 +5,7 @@ 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
+ import { PsTableBodyClasses } from '../constants/ps-table-body-classes';
8
9
  import { PsTableControlClasses } from '../constants/ps-table-control-classes';
9
10
  import { PsTablePaginationConfig } from '../constants/ps-table-pagination-config';
10
11
  import { PsTablePaginationPosition } from '../constants/ps-table-pagination-position';
@@ -63,7 +64,7 @@ export const PsDataTable = ({ caption, className, clearSelectionKey, columns, cu
63
64
  const [seenClearKey, setSeenClearKey] = useState(clearSelectionKey);
64
65
  const stickyRegionRef = useRef(null);
65
66
  const stickySentinelRef = useRef(null);
66
- const stickyBackdropRef = useRef(null);
67
+ const stickyCardRef = useRef(null);
67
68
  const stickyHeadRef = useRef(null);
68
69
  const currentQuery = query ? query : uncontrolledQuery;
69
70
  if (seenClearKey !== clearSelectionKey) {
@@ -93,7 +94,7 @@ export const PsDataTable = ({ caption, className, clearSelectionKey, columns, cu
93
94
  const placementOf = (column, columnIndex) => PallasoftClassNameService.merge(column.hideBelow === undefined ? '' : PsTableHideBelowClasses[column.hideBelow], columnIndex === 0 ? pins.first : '', PsTablePinService.end(column.pinEnd === true));
94
95
  const overflow = usePsTableOverflow(`${visibleColumns.map((column) => column.id).join(',')}:${rows.length}`);
95
96
  const isStuck = usePsStickyHead({
96
- backdropRef: stickyBackdropRef,
97
+ cardRef: stickyCardRef,
97
98
  headRef: stickyHeadRef,
98
99
  layoutKey: `${visibleColumns.map((column) => column.id).join(',')}:${rows.length}:${isLoading}`,
99
100
  regionRef: stickyRegionRef,
@@ -360,18 +361,18 @@ export const PsDataTable = ({ caption, className, clearSelectionKey, columns, cu
360
361
  updateQuery({ search: next });
361
362
  resetPage();
362
363
  }, rows: rows, search: search, searchPlaceholder: searchPlaceholder })) : null, banner] }));
363
- 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: [_jsx("div", { "aria-hidden": 'true', className: 'ps-glass-strong pointer-events-none absolute -inset-x-3 -bottom-3 rounded-b-ps-card border-t-0 opacity-0', ref: stickyBackdropRef, style: { top: `calc(-1 * ${stickyTop})` } }), _jsxs("div", { className: 'relative flex flex-col gap-3', children: [stickyLeading, topContent] })] })] })), _jsxs("div", { "aria-busy": isRefreshing, className: 'min-w-0 overflow-hidden rounded-[1.25rem] border border-line bg-surface', children: [showsPagination &&
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 &&
364
365
  paginationPosition !== PsTablePaginationPosition.bottom &&
365
366
  rowCount > PsTablePaginationConfig.topMinRows
366
367
  ? renderPagination('border-b border-t-0')
367
- : null, mobileLayout === 'cards' ? (_jsxs("div", { className: PallasoftClassNameService.merge('transition-opacity duration-150 sm:hidden', isRefreshing ? 'opacity-60' : ''), 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
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
368
369
  ? groups.map((group, groupIndex) => {
369
370
  const isExpanded = isGroupExpanded(group.key, groupIndex);
370
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
371
372
  ? grouping.renderGroupSummary(group.rows)
372
373
  : undefined }), _jsx(PsCollapse, { isOpen: isExpanded && !closingGroupKeys.includes(group.key), children: renderCardList(group.rows, null) })] }, `group-${group.key}`));
373
374
  })
374
- : 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', 'transition-opacity duration-150', isRefreshing ? 'opacity-60' : '', 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
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
375
376
  ? ''
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) => {
377
378
  const align = column.align !== null && column.align !== undefined ? column.align : 'left';
@@ -0,0 +1,3 @@
1
+ export const PsTableBodyClasses = {
2
+ refreshing: 'opacity-60',
3
+ };
@@ -1,3 +1,4 @@
1
1
  export const PsTableStickyConfig = {
2
- backdropFadePx: 16,
2
+ cardGapPx: 12,
3
+ cardRadius: '1.25rem',
3
4
  };
@@ -2,18 +2,18 @@ import { useLayoutEffect, useState } 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 = ({ backdropRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop, }) => {
5
+ export const usePsStickyHead = ({ cardRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop, }) => {
6
6
  const [isStuck, setIsStuck] = useState(false);
7
7
  useLayoutEffect(() => {
8
8
  const region = regionRef.current;
9
9
  const sentinel = sentinelRef.current;
10
- const backdrop = backdropRef.current;
10
+ const card = cardRef.current;
11
11
  const head = headRef.current;
12
12
  const table = head === null ? null : head.parentElement;
13
13
  if (stickyTop === undefined ||
14
14
  region === null ||
15
15
  sentinel === null ||
16
- backdrop === null ||
16
+ card === null ||
17
17
  head === null ||
18
18
  table === null)
19
19
  return;
@@ -22,49 +22,40 @@ export const usePsStickyHead = ({ backdropRef, headRef, layoutKey, regionRef, se
22
22
  const isDriven = scroller !== null && Timeline !== undefined;
23
23
  let animations = [];
24
24
  let frame = 0;
25
- const maxShift = () => Math.max(table.offsetHeight - head.offsetHeight, 0);
25
+ const headTravel = () => Math.max(table.offsetHeight - head.offsetHeight, 0);
26
26
  const drive = () => {
27
27
  if (scroller === null || Timeline === undefined)
28
28
  return;
29
- const scrollerTop = scroller.getBoundingClientRect().top;
30
- const regionTop = region.getBoundingClientRect().top;
31
- const pinnedBottom = scrollerTop +
29
+ const pinnedLine = scroller.getBoundingClientRect().top +
32
30
  Number.parseFloat(getComputedStyle(region).top) +
33
- backdrop.getBoundingClientRect().bottom -
34
- regionTop;
35
- const pinScroll = table.getBoundingClientRect().top + scroller.scrollTop - pinnedBottom;
36
- const barPinScroll = sentinel.getBoundingClientRect().top -
37
- scrollerTop +
38
- scroller.scrollTop -
39
- Number.parseFloat(getComputedStyle(region).top);
31
+ region.offsetHeight +
32
+ PsTableStickyConfig.cardGapPx;
40
33
  const scrollRange = scroller.scrollHeight - scroller.clientHeight;
41
34
  const timeline = new Timeline({ axis: 'block', source: scroller });
42
- const headFrames = PsTableStickyHeadService.keyframes(pinScroll, maxShift(), scrollRange);
43
- const backdropFrames = PsTableStickyHeadService.backdropKeyframes(barPinScroll, PsTableStickyConfig.backdropFadePx, scrollRange);
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
37
  animations.forEach((animation) => animation.cancel());
45
- animations =
46
- headFrames.length === 0
47
- ? []
48
- : [
49
- head.animate(headFrames.map((keyframe) => ({
50
- offset: keyframe.offset,
51
- transform: `translateY(${keyframe.shift}px)`,
52
- })), { fill: 'both', timeline }),
53
- backdrop.animate(backdropFrames.map((keyframe) => ({
54
- offset: keyframe.offset,
55
- opacity: keyframe.opacity,
56
- })), { fill: 'both', timeline }),
57
- ];
38
+ animations = [
39
+ head.animate(headFrames.map((keyframe) => ({
40
+ offset: keyframe.offset,
41
+ transform: `translateY(${keyframe.shift}px)`,
42
+ })), { fill: 'both', timeline }),
43
+ card.animate(cardFrames.map((keyframe) => ({
44
+ clipPath: PsTableStickyHeadService.clip(keyframe.shift),
45
+ offset: keyframe.offset,
46
+ })), { fill: 'both', timeline }),
47
+ ];
48
+ };
49
+ const follow = () => {
50
+ const pinnedLine = region.getBoundingClientRect().bottom + PsTableStickyConfig.cardGapPx;
51
+ 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));
58
53
  };
59
- const follow = () => (head.style.transform = `translateY(${PsTableStickyHeadService.offset(backdrop.getBoundingClientRect().bottom, table.getBoundingClientRect().top, table.offsetHeight, head.offsetHeight)}px)`);
60
54
  const check = () => {
61
- const stuck = sentinel.getBoundingClientRect().top < region.getBoundingClientRect().top - 1;
62
55
  frame = 0;
63
- setIsStuck(stuck);
64
- if (isDriven)
65
- return;
66
- backdrop.style.opacity = stuck ? '1' : '0';
67
- follow();
56
+ setIsStuck(sentinel.getBoundingClientRect().top < region.getBoundingClientRect().top - 1);
57
+ if (!isDriven)
58
+ follow();
68
59
  };
69
60
  const schedule = () => {
70
61
  if (frame === 0)
@@ -78,7 +69,7 @@ export const usePsStickyHead = ({ backdropRef, headRef, layoutKey, regionRef, se
78
69
  const observer = new ResizeObserver(measure);
79
70
  measure();
80
71
  observer.observe(region);
81
- observer.observe(table);
72
+ observer.observe(card);
82
73
  if (scroller !== null)
83
74
  Array.from(scroller.children).forEach((child) => observer.observe(child));
84
75
  window.addEventListener('scroll', schedule, { capture: true, passive: true });
@@ -87,12 +78,12 @@ export const usePsStickyHead = ({ backdropRef, headRef, layoutKey, regionRef, se
87
78
  observer.disconnect();
88
79
  animations.forEach((animation) => animation.cancel());
89
80
  head.style.transform = '';
90
- backdrop.style.opacity = '';
81
+ card.style.clipPath = '';
91
82
  window.removeEventListener('scroll', schedule, { capture: true });
92
83
  window.removeEventListener('resize', measure);
93
84
  if (frame !== 0)
94
85
  window.cancelAnimationFrame(frame);
95
86
  };
96
- }, [backdropRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop]);
87
+ }, [cardRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop]);
97
88
  return isStuck;
98
89
  };
@@ -1,3 +1,4 @@
1
+ import { PsTableStickyConfig } from '../constants/ps-table-sticky-config';
1
2
  export class PsTableStickyHeadService {
2
3
  static offset(pinnedBottom, tableTop, tableHeight, headHeight) {
3
4
  return Math.min(Math.max(pinnedBottom - tableTop, 0), Math.max(tableHeight - headHeight, 0));
@@ -11,11 +12,9 @@ export class PsTableStickyHeadService {
11
12
  shift: shiftAt(scroll),
12
13
  }));
13
14
  }
14
- static backdropKeyframes(pinScroll, fade, scrollRange) {
15
- if (scrollRange <= 0)
16
- return [];
17
- const opacityAt = (scroll) => Math.min(Math.max((scroll - pinScroll + fade) / fade, 0), 1);
18
- return PsTableStickyHeadService.stops([0, pinScroll - fade, pinScroll, scrollRange], scrollRange).map((scroll) => ({ offset: scroll / scrollRange, opacity: opacityAt(scroll) }));
15
+ static clip(shift) {
16
+ const radius = PsTableStickyConfig.cardRadius;
17
+ return `inset(${shift}px 0 0 0 round ${radius} ${radius} 0 0)`;
19
18
  }
20
19
  static stops(scrolls, scrollRange) {
21
20
  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: ({ backdropRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop, }: PsStickyHeadRefs) => boolean;
2
+ export declare const usePsStickyHead: ({ cardRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop, }: PsStickyHeadRefs) => boolean;
@@ -5,18 +5,18 @@ const react_1 = require("react");
5
5
  const ps_table_sticky_config_1 = require("../constants/ps-table-sticky-config");
6
6
  const ps_table_scroll_service_1 = require("../services/ps-table-scroll-service");
7
7
  const ps_table_sticky_head_service_1 = require("../services/ps-table-sticky-head-service");
8
- const usePsStickyHead = ({ backdropRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop, }) => {
8
+ const usePsStickyHead = ({ cardRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop, }) => {
9
9
  const [isStuck, setIsStuck] = (0, react_1.useState)(false);
10
10
  (0, react_1.useLayoutEffect)(() => {
11
11
  const region = regionRef.current;
12
12
  const sentinel = sentinelRef.current;
13
- const backdrop = backdropRef.current;
13
+ const card = cardRef.current;
14
14
  const head = headRef.current;
15
15
  const table = head === null ? null : head.parentElement;
16
16
  if (stickyTop === undefined ||
17
17
  region === null ||
18
18
  sentinel === null ||
19
- backdrop === null ||
19
+ card === null ||
20
20
  head === null ||
21
21
  table === null)
22
22
  return;
@@ -25,49 +25,40 @@ const usePsStickyHead = ({ backdropRef, headRef, layoutKey, regionRef, sentinelR
25
25
  const isDriven = scroller !== null && Timeline !== undefined;
26
26
  let animations = [];
27
27
  let frame = 0;
28
- const maxShift = () => Math.max(table.offsetHeight - head.offsetHeight, 0);
28
+ const headTravel = () => Math.max(table.offsetHeight - head.offsetHeight, 0);
29
29
  const drive = () => {
30
30
  if (scroller === null || Timeline === undefined)
31
31
  return;
32
- const scrollerTop = scroller.getBoundingClientRect().top;
33
- const regionTop = region.getBoundingClientRect().top;
34
- const pinnedBottom = scrollerTop +
32
+ const pinnedLine = scroller.getBoundingClientRect().top +
35
33
  Number.parseFloat(getComputedStyle(region).top) +
36
- backdrop.getBoundingClientRect().bottom -
37
- regionTop;
38
- const pinScroll = table.getBoundingClientRect().top + scroller.scrollTop - pinnedBottom;
39
- const barPinScroll = sentinel.getBoundingClientRect().top -
40
- scrollerTop +
41
- scroller.scrollTop -
42
- Number.parseFloat(getComputedStyle(region).top);
34
+ region.offsetHeight +
35
+ ps_table_sticky_config_1.PsTableStickyConfig.cardGapPx;
43
36
  const scrollRange = scroller.scrollHeight - scroller.clientHeight;
44
37
  const timeline = new Timeline({ axis: 'block', source: scroller });
45
- const headFrames = ps_table_sticky_head_service_1.PsTableStickyHeadService.keyframes(pinScroll, maxShift(), scrollRange);
46
- const backdropFrames = ps_table_sticky_head_service_1.PsTableStickyHeadService.backdropKeyframes(barPinScroll, ps_table_sticky_config_1.PsTableStickyConfig.backdropFadePx, scrollRange);
38
+ const headFrames = ps_table_sticky_head_service_1.PsTableStickyHeadService.keyframes(table.getBoundingClientRect().top + scroller.scrollTop - pinnedLine, headTravel(), scrollRange);
39
+ const cardFrames = ps_table_sticky_head_service_1.PsTableStickyHeadService.keyframes(card.getBoundingClientRect().top + scroller.scrollTop - pinnedLine, card.offsetHeight, scrollRange);
47
40
  animations.forEach((animation) => animation.cancel());
48
- animations =
49
- headFrames.length === 0
50
- ? []
51
- : [
52
- head.animate(headFrames.map((keyframe) => ({
53
- offset: keyframe.offset,
54
- transform: `translateY(${keyframe.shift}px)`,
55
- })), { fill: 'both', timeline }),
56
- backdrop.animate(backdropFrames.map((keyframe) => ({
57
- offset: keyframe.offset,
58
- opacity: keyframe.opacity,
59
- })), { fill: 'both', timeline }),
60
- ];
41
+ animations = [
42
+ head.animate(headFrames.map((keyframe) => ({
43
+ offset: keyframe.offset,
44
+ transform: `translateY(${keyframe.shift}px)`,
45
+ })), { fill: 'both', timeline }),
46
+ card.animate(cardFrames.map((keyframe) => ({
47
+ clipPath: ps_table_sticky_head_service_1.PsTableStickyHeadService.clip(keyframe.shift),
48
+ offset: keyframe.offset,
49
+ })), { fill: 'both', timeline }),
50
+ ];
51
+ };
52
+ const follow = () => {
53
+ const pinnedLine = region.getBoundingClientRect().bottom + ps_table_sticky_config_1.PsTableStickyConfig.cardGapPx;
54
+ head.style.transform = `translateY(${ps_table_sticky_head_service_1.PsTableStickyHeadService.offset(pinnedLine, table.getBoundingClientRect().top, table.offsetHeight, head.offsetHeight)}px)`;
55
+ card.style.clipPath = ps_table_sticky_head_service_1.PsTableStickyHeadService.clip(ps_table_sticky_head_service_1.PsTableStickyHeadService.offset(pinnedLine, card.getBoundingClientRect().top, card.offsetHeight, 0));
61
56
  };
62
- const follow = () => (head.style.transform = `translateY(${ps_table_sticky_head_service_1.PsTableStickyHeadService.offset(backdrop.getBoundingClientRect().bottom, table.getBoundingClientRect().top, table.offsetHeight, head.offsetHeight)}px)`);
63
57
  const check = () => {
64
- const stuck = sentinel.getBoundingClientRect().top < region.getBoundingClientRect().top - 1;
65
58
  frame = 0;
66
- setIsStuck(stuck);
67
- if (isDriven)
68
- return;
69
- backdrop.style.opacity = stuck ? '1' : '0';
70
- follow();
59
+ setIsStuck(sentinel.getBoundingClientRect().top < region.getBoundingClientRect().top - 1);
60
+ if (!isDriven)
61
+ follow();
71
62
  };
72
63
  const schedule = () => {
73
64
  if (frame === 0)
@@ -81,7 +72,7 @@ const usePsStickyHead = ({ backdropRef, headRef, layoutKey, regionRef, sentinelR
81
72
  const observer = new ResizeObserver(measure);
82
73
  measure();
83
74
  observer.observe(region);
84
- observer.observe(table);
75
+ observer.observe(card);
85
76
  if (scroller !== null)
86
77
  Array.from(scroller.children).forEach((child) => observer.observe(child));
87
78
  window.addEventListener('scroll', schedule, { capture: true, passive: true });
@@ -90,13 +81,13 @@ const usePsStickyHead = ({ backdropRef, headRef, layoutKey, regionRef, sentinelR
90
81
  observer.disconnect();
91
82
  animations.forEach((animation) => animation.cancel());
92
83
  head.style.transform = '';
93
- backdrop.style.opacity = '';
84
+ card.style.clipPath = '';
94
85
  window.removeEventListener('scroll', schedule, { capture: true });
95
86
  window.removeEventListener('resize', measure);
96
87
  if (frame !== 0)
97
88
  window.cancelAnimationFrame(frame);
98
89
  };
99
- }, [backdropRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop]);
90
+ }, [cardRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop]);
100
91
  return isStuck;
101
92
  };
102
93
  exports.usePsStickyHead = usePsStickyHead;
@@ -1,6 +1,6 @@
1
1
  import type { RefObject } from 'react';
2
2
  export interface PsStickyHeadRefs {
3
- backdropRef: RefObject<HTMLDivElement | null>;
3
+ cardRef: RefObject<HTMLDivElement | null>;
4
4
  headRef: RefObject<HTMLTableSectionElement | null>;
5
5
  layoutKey: string;
6
6
  regionRef: RefObject<HTMLDivElement | null>;
@@ -1,8 +1,7 @@
1
- import type { PsTableStickyBackdropKeyframe } from '../interfaces/ps-table-sticky-backdrop-keyframe';
2
1
  import type { PsTableStickyHeadKeyframe } from '../interfaces/ps-table-sticky-head-keyframe';
3
2
  export declare class PsTableStickyHeadService {
4
3
  static offset(pinnedBottom: number, tableTop: number, tableHeight: number, headHeight: number): number;
5
4
  static keyframes(pinScroll: number, maxShift: number, scrollRange: number): PsTableStickyHeadKeyframe[];
6
- static backdropKeyframes(pinScroll: number, fade: number, scrollRange: number): PsTableStickyBackdropKeyframe[];
5
+ static clip(shift: number): string;
7
6
  private static stops;
8
7
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PsTableStickyHeadService = void 0;
4
+ const ps_table_sticky_config_1 = require("../constants/ps-table-sticky-config");
4
5
  class PsTableStickyHeadService {
5
6
  static offset(pinnedBottom, tableTop, tableHeight, headHeight) {
6
7
  return Math.min(Math.max(pinnedBottom - tableTop, 0), Math.max(tableHeight - headHeight, 0));
@@ -14,11 +15,9 @@ class PsTableStickyHeadService {
14
15
  shift: shiftAt(scroll),
15
16
  }));
16
17
  }
17
- static backdropKeyframes(pinScroll, fade, scrollRange) {
18
- if (scrollRange <= 0)
19
- return [];
20
- const opacityAt = (scroll) => Math.min(Math.max((scroll - pinScroll + fade) / fade, 0), 1);
21
- return PsTableStickyHeadService.stops([0, pinScroll - fade, pinScroll, scrollRange], scrollRange).map((scroll) => ({ offset: scroll / scrollRange, opacity: opacityAt(scroll) }));
18
+ static clip(shift) {
19
+ const radius = ps_table_sticky_config_1.PsTableStickyConfig.cardRadius;
20
+ return `inset(${shift}px 0 0 0 round ${radius} ${radius} 0 0)`;
22
21
  }
23
22
  static stops(scrolls, scrollRange) {
24
23
  const inside = scrolls.filter((scroll) => scroll >= 0 && scroll <= scrollRange);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pallasoft/ps-table-components",
3
- "version": "1.28.1",
3
+ "version": "1.28.3",
4
4
  "private": false,
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -1,4 +0,0 @@
1
- export interface PsTableStickyBackdropKeyframe {
2
- offset: number;
3
- opacity: number;
4
- }
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });