@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.
- package/dist/components/ps-data-table.js +6 -5
- package/dist/constants/ps-table-body-classes.d.ts +3 -0
- package/dist/constants/ps-table-body-classes.js +6 -0
- package/dist/constants/ps-table-sticky-config.d.ts +2 -1
- package/dist/constants/ps-table-sticky-config.js +2 -1
- package/dist/esm/components/ps-data-table.js +6 -5
- package/dist/esm/constants/ps-table-body-classes.js +3 -0
- package/dist/esm/constants/ps-table-sticky-config.js +2 -1
- package/dist/esm/hooks/use-ps-sticky-head.js +30 -39
- package/dist/esm/services/ps-table-sticky-head-service.js +4 -5
- package/dist/hooks/use-ps-sticky-head.d.ts +1 -1
- package/dist/hooks/use-ps-sticky-head.js +30 -39
- package/dist/interfaces/ps-sticky-head-refs.d.ts +1 -1
- package/dist/services/ps-table-sticky-head-service.d.ts +1 -2
- package/dist/services/ps-table-sticky-head-service.js +4 -5
- package/package.json +1 -1
- package/dist/esm/interfaces/ps-table-sticky-backdrop-keyframe.js +0 -1
- package/dist/interfaces/ps-table-sticky-backdrop-keyframe.d.ts +0 -4
- package/dist/interfaces/ps-table-sticky-backdrop-keyframe.js +0 -2
|
@@ -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
|
|
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
|
-
|
|
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: [
|
|
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('
|
|
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',
|
|
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';
|
|
@@ -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
|
|
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
|
-
|
|
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: [
|
|
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('
|
|
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',
|
|
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';
|
|
@@ -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 = ({
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
30
|
-
const regionTop = region.getBoundingClientRect().top;
|
|
31
|
-
const pinnedBottom = scrollerTop +
|
|
29
|
+
const pinnedLine = scroller.getBoundingClientRect().top +
|
|
32
30
|
Number.parseFloat(getComputedStyle(region).top) +
|
|
33
|
-
|
|
34
|
-
|
|
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(
|
|
43
|
-
const
|
|
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.
|
|
47
|
-
|
|
48
|
-
:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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(
|
|
64
|
-
if (isDriven)
|
|
65
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
}, [
|
|
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
|
|
15
|
-
|
|
16
|
-
|
|
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: ({
|
|
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 = ({
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
33
|
-
const regionTop = region.getBoundingClientRect().top;
|
|
34
|
-
const pinnedBottom = scrollerTop +
|
|
32
|
+
const pinnedLine = scroller.getBoundingClientRect().top +
|
|
35
33
|
Number.parseFloat(getComputedStyle(region).top) +
|
|
36
|
-
|
|
37
|
-
|
|
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(
|
|
46
|
-
const
|
|
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.
|
|
50
|
-
|
|
51
|
-
:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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(
|
|
67
|
-
if (isDriven)
|
|
68
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
}, [
|
|
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
|
-
|
|
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
|
|
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
|
|
18
|
-
|
|
19
|
-
|
|
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 +0,0 @@
|
|
|
1
|
-
export {};
|