@pallasoft/ps-table-components 1.28.4 → 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 +2 -4
  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 -0
  19. package/dist/constants/ps-table-sticky-config.js +1 -0
  20. package/dist/esm/components/ps-data-table.js +2 -4
  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 -0
  30. package/dist/esm/hooks/use-ps-sticky-head.js +22 -19
  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 +13 -0
  37. package/dist/hooks/use-ps-sticky-head.d.ts +1 -1
  38. package/dist/hooks/use-ps-sticky-head.js +21 -18
  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 +0 -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 -0
  51. package/dist/services/ps-table-sticky-head-service.js +13 -0
  52. package/package.json +1 -1
@@ -99,7 +99,6 @@ const PsDataTable = ({ caption, className, clearSelectionKey, columns, cursorPag
99
99
  const [openedGroupKeys, setOpenedGroupKeys] = (0, react_1.useState)([]);
100
100
  const [seenClearKey, setSeenClearKey] = (0, react_1.useState)(clearSelectionKey);
101
101
  const stickyRegionRef = (0, react_1.useRef)(null);
102
- const stickySentinelRef = (0, react_1.useRef)(null);
103
102
  const stickyCardRef = (0, react_1.useRef)(null);
104
103
  const stickyContentRef = (0, react_1.useRef)(null);
105
104
  const stickyHeadRef = (0, react_1.useRef)(null);
@@ -130,13 +129,12 @@ const PsDataTable = ({ caption, className, clearSelectionKey, columns, cursorPag
130
129
  const pins = ps_table_pin_service_1.PsTablePinService.leading(pinFirstColumn, Boolean(reorder), isSelectable);
131
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));
132
131
  const overflow = (0, use_ps_table_overflow_1.usePsTableOverflow)(`${visibleColumns.map((column) => column.id).join(',')}:${rows.length}`);
133
- const isStuck = (0, use_ps_sticky_head_1.usePsStickyHead)({
132
+ (0, use_ps_sticky_head_1.usePsStickyHead)({
134
133
  cardRef: stickyCardRef,
135
134
  contentRef: stickyContentRef,
136
135
  headRef: stickyHeadRef,
137
136
  layoutKey: `${visibleColumns.map((column) => column.id).join(',')}:${rows.length}:${isLoading}`,
138
137
  regionRef: stickyRegionRef,
139
- sentinelRef: stickySentinelRef,
140
138
  stickyTop,
141
139
  });
142
140
  const deferredSearch = (0, react_1.useDeferredValue)(search);
@@ -399,7 +397,7 @@ const PsDataTable = ({ caption, className, clearSelectionKey, columns, cursorPag
399
397
  updateQuery({ search: next });
400
398
  resetPage();
401
399
  }, rows: rows, search: search, searchPlaceholder: searchPlaceholder })) : null, banner] }));
402
- 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.jsx)("div", { className: 'min-w-0 overflow-clip rounded-[1.25rem]', children: (0, jsx_runtime_1.jsx)("div", { "aria-busy": isRefreshing, className: 'min-w-0 overflow-hidden rounded-[1.25rem] border border-line bg-surface', ref: stickyCardRef, children: (0, jsx_runtime_1.jsxs)("div", { ref: stickyContentRef, 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.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('sticky z-sticky flex flex-col gap-3', stickyClassName), ref: stickyRegionRef, style: { top: stickyTop }, children: [stickyLeading, topContent] }) })), (0, jsx_runtime_1.jsx)("div", { className: 'min-w-0 overflow-clip rounded-[1.25rem]', children: (0, jsx_runtime_1.jsx)("div", { "aria-busy": isRefreshing, className: 'min-w-0 overflow-hidden rounded-[1.25rem] border border-line bg-surface', ref: stickyCardRef, children: (0, jsx_runtime_1.jsxs)("div", { ref: stickyContentRef, children: [showsPagination &&
403
401
  paginationPosition !== ps_table_pagination_position_1.PsTablePaginationPosition.bottom &&
404
402
  rowCount > ps_table_pagination_config_1.PsTablePaginationConfig.topMinRows
405
403
  ? renderPagination('border-b border-t-0')
@@ -0,0 +1,10 @@
1
+ import { PsReportTableDensity } from '../constants/ps-report-table-density';
2
+ import type { PsReportColumn } from '../interfaces/ps-report-column';
3
+ export interface PsReportTableSkeletonProps<RowData> {
4
+ className?: string;
5
+ columns: PsReportColumn<RowData>[];
6
+ density?: PsReportTableDensity;
7
+ isFramed?: boolean;
8
+ rows?: number;
9
+ }
10
+ export declare const PsReportTableSkeleton: <RowData>({ className, columns, density, isFramed, rows, }: PsReportTableSkeletonProps<RowData>) => import("react").JSX.Element;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsReportTableSkeleton = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const ps_core_components_1 = require("@pallasoft/ps-core-components");
6
+ const ps_design_system_1 = require("@pallasoft/ps-design-system");
7
+ const ps_report_column_align_1 = require("../constants/ps-report-column-align");
8
+ const ps_report_table_classes_1 = require("../constants/ps-report-table-classes");
9
+ const ps_report_table_config_1 = require("../constants/ps-report-table-config");
10
+ const ps_report_table_density_1 = require("../constants/ps-report-table-density");
11
+ const ps_report_table_service_1 = require("../services/ps-report-table-service");
12
+ const PsReportTableSkeleton = ({ className, columns, density = ps_report_table_density_1.PsReportTableDensity.normal, isFramed = true, rows = ps_report_table_config_1.PsReportTableConfig.skeletonRows, }) => {
13
+ const isEnd = (column) => ps_report_table_service_1.PsReportTableService.alignOf(column) === ps_report_column_align_1.PsReportColumnAlign.right;
14
+ const headClass = (column, index) => {
15
+ if (isEnd(column))
16
+ return ps_report_table_classes_1.PsReportTableClasses.skeleton.headEnd;
17
+ return index === 0
18
+ ? ps_report_table_classes_1.PsReportTableClasses.skeleton.headFirst
19
+ : ps_report_table_classes_1.PsReportTableClasses.skeleton.headOther;
20
+ };
21
+ const cellClass = (column, rowIndex, index) => isEnd(column)
22
+ ? ps_report_table_classes_1.PsReportTableClasses.skeleton.cellEnd
23
+ : ps_report_table_classes_1.PsReportTableClasses.skeleton.cellWidths[(rowIndex + index) % ps_report_table_classes_1.PsReportTableClasses.skeleton.cellWidths.length];
24
+ return ((0, jsx_runtime_1.jsx)(ps_core_components_1.PsSkeletonGroup, { className: ps_design_system_1.PallasoftClassNameService.merge(isFramed ? ps_report_table_classes_1.PsReportTableClasses.frame : ps_report_table_classes_1.PsReportTableClasses.skeleton.plain, className), children: (0, jsx_runtime_1.jsxs)("table", { className: ps_report_table_classes_1.PsReportTableClasses.table, children: [(0, jsx_runtime_1.jsx)("thead", { className: ps_report_table_classes_1.PsReportTableClasses.head, children: (0, jsx_runtime_1.jsx)("tr", { children: columns.map((column, index) => ((0, jsx_runtime_1.jsx)("th", { className: ps_report_table_classes_1.PsReportTableClasses.headCell[density], style: ps_report_table_service_1.PsReportTableService.indent(0, density), children: (0, jsx_runtime_1.jsx)(ps_core_components_1.PsSkeleton, { className: headClass(column, index) }) }, column.id))) }) }), (0, jsx_runtime_1.jsx)("tbody", { className: ps_report_table_classes_1.PsReportTableClasses.body, children: Array.from({ length: rows }, (_, rowIndex) => ((0, jsx_runtime_1.jsx)("tr", { children: columns.map((column, index) => ((0, jsx_runtime_1.jsx)("td", { className: ps_report_table_classes_1.PsReportTableClasses.cell[density], style: {
25
+ ...ps_report_table_service_1.PsReportTableService.columnStyle(column),
26
+ ...ps_report_table_service_1.PsReportTableService.indent(0, density),
27
+ }, children: (0, jsx_runtime_1.jsx)(ps_core_components_1.PsSkeleton, { className: cellClass(column, rowIndex, index) }) }, column.id))) }, rowIndex))) })] }) }));
28
+ };
29
+ exports.PsReportTableSkeleton = PsReportTableSkeleton;
@@ -0,0 +1,28 @@
1
+ import type { ReactNode } from 'react';
2
+ import { PsReportRowKind } from '../constants/ps-report-row-kind';
3
+ import { PsReportRowTone } from '../constants/ps-report-row-tone';
4
+ import { PsReportTableDensity } from '../constants/ps-report-table-density';
5
+ import type { PsReportColumn } from '../interfaces/ps-report-column';
6
+ export interface PsReportTableProps<RowData> {
7
+ caption: string;
8
+ className?: string;
9
+ columns: PsReportColumn<RowData>[];
10
+ density?: PsReportTableDensity;
11
+ emptyState?: ReactNode;
12
+ getLeadSpan?: (row: RowData) => number;
13
+ getRowId: (row: RowData) => string;
14
+ getRowKind?: (row: RowData) => PsReportRowKind;
15
+ getRowLevel?: (row: RowData) => number;
16
+ getRowTone?: (row: RowData) => PsReportRowTone;
17
+ isFirstColumnSticky?: boolean;
18
+ isFramed?: boolean;
19
+ isHeaderHidden?: boolean;
20
+ isHeaderSticky?: boolean;
21
+ isLoading?: boolean;
22
+ isRefreshing?: boolean;
23
+ maxHeight?: string;
24
+ minWidth?: string;
25
+ renderLead?: (row: RowData) => ReactNode;
26
+ rows: RowData[];
27
+ }
28
+ export declare const PsReportTable: <RowData>({ caption, className, columns, density, emptyState, getLeadSpan, getRowId, getRowKind, getRowLevel, getRowTone, isFirstColumnSticky, isFramed, isHeaderHidden, isHeaderSticky, isLoading, isRefreshing, maxHeight, minWidth, renderLead, rows, }: PsReportTableProps<RowData>) => import("react").JSX.Element;
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsReportTable = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const ps_design_system_1 = require("@pallasoft/ps-design-system");
6
+ const ps_report_row_kind_1 = require("../constants/ps-report-row-kind");
7
+ const ps_report_row_tone_1 = require("../constants/ps-report-row-tone");
8
+ const ps_report_table_classes_1 = require("../constants/ps-report-table-classes");
9
+ const ps_report_table_config_1 = require("../constants/ps-report-table-config");
10
+ const ps_report_table_density_1 = require("../constants/ps-report-table-density");
11
+ const use_ps_table_overflow_1 = require("../hooks/use-ps-table-overflow");
12
+ const ps_report_table_service_1 = require("../services/ps-report-table-service");
13
+ const ps_report_table_skeleton_1 = require("./ps-report-table-skeleton");
14
+ const PsReportTable = ({ caption, className, columns, density = ps_report_table_density_1.PsReportTableDensity.normal, emptyState, getLeadSpan, getRowId, getRowKind, getRowLevel, getRowTone, isFirstColumnSticky = false, isFramed = true, isHeaderHidden = false, isHeaderSticky = false, isLoading = false, isRefreshing = false, maxHeight, minWidth, renderLead, rows, }) => {
15
+ const overflow = (0, use_ps_table_overflow_1.usePsTableOverflow)(String(rows.length));
16
+ if (isLoading)
17
+ return ((0, jsx_runtime_1.jsx)(ps_report_table_skeleton_1.PsReportTableSkeleton, { className: className, columns: columns, density: density, isFramed: isFramed }));
18
+ const kindOf = (row) => getRowKind !== undefined ? getRowKind(row) : ps_report_row_kind_1.PsReportRowKind.data;
19
+ const toneOf = (row) => getRowTone !== undefined ? getRowTone(row) : ps_report_row_tone_1.PsReportRowTone.neutral;
20
+ const levelOf = (row) => ps_report_table_service_1.PsReportTableService.levelOf(getRowLevel !== undefined ? getRowLevel(row) : undefined);
21
+ const leadOf = (row) => (getLeadSpan !== undefined ? getLeadSpan(row) : 1);
22
+ const renderRow = (row) => {
23
+ const kind = kindOf(row);
24
+ const tone = toneOf(row);
25
+ const level = levelOf(row);
26
+ return ((0, jsx_runtime_1.jsx)("tr", { className: ps_report_table_classes_1.PsReportTableClasses.kind[kind], children: ps_report_table_service_1.PsReportTableService.cells(columns, leadOf(row)).map((plan) => {
27
+ const className = ps_design_system_1.PallasoftClassNameService.merge(ps_report_table_service_1.PsReportTableService.cellClass(plan.column, plan.index, density, tone, isFirstColumnSticky), plan.index === 0 ? ps_report_table_classes_1.PsReportTableClasses.rowHeader : '');
28
+ const style = {
29
+ ...ps_report_table_service_1.PsReportTableService.columnStyle(plan.column),
30
+ ...(plan.index === 0 ? ps_report_table_service_1.PsReportTableService.indent(level, density) : {}),
31
+ };
32
+ return plan.index === 0 ? ((0, jsx_runtime_1.jsx)("th", { className: className, colSpan: plan.colSpan, scope: kind === ps_report_row_kind_1.PsReportRowKind.group && plan.colSpan === columns.length
33
+ ? 'colgroup'
34
+ : 'row', style: style, children: plan.colSpan > 1 && renderLead !== undefined
35
+ ? renderLead(row)
36
+ : plan.column.render(row) }, plan.column.id)) : ((0, jsx_runtime_1.jsx)("td", { className: className, colSpan: plan.colSpan, style: style, children: plan.column.render(row) }, plan.column.id));
37
+ }) }, getRowId(row)));
38
+ };
39
+ const content = ((0, jsx_runtime_1.jsx)("div", { className: ps_design_system_1.PallasoftClassNameService.merge(ps_report_table_classes_1.PsReportTableClasses.scroll, maxHeight !== undefined ? ps_report_table_classes_1.PsReportTableClasses.scrollBounded : '', isRefreshing ? ps_report_table_classes_1.PsReportTableClasses.refreshing : ''), "data-overflow-end": overflow.edges.end, "data-overflow-start": overflow.edges.start, onScroll: overflow.update, ref: overflow.ref, style: { maxHeight }, children: (0, jsx_runtime_1.jsxs)("table", { className: ps_report_table_classes_1.PsReportTableClasses.table, style: { minWidth }, children: [(0, jsx_runtime_1.jsx)("caption", { className: ps_report_table_classes_1.PsReportTableClasses.caption, children: caption }), (0, jsx_runtime_1.jsx)("thead", { className: ps_design_system_1.PallasoftClassNameService.merge(ps_report_table_classes_1.PsReportTableClasses.head, isHeaderHidden ? ps_report_table_classes_1.PsReportTableClasses.headHidden : ''), children: (0, jsx_runtime_1.jsx)("tr", { children: columns.map((column, index) => ((0, jsx_runtime_1.jsx)("th", { className: ps_report_table_service_1.PsReportTableService.headClass(column, index, density, isHeaderSticky, isFirstColumnSticky), scope: 'col', style: {
40
+ ...ps_report_table_service_1.PsReportTableService.columnStyle(column),
41
+ ...ps_report_table_service_1.PsReportTableService.indent(0, density),
42
+ }, children: column.label }, column.id))) }) }), (0, jsx_runtime_1.jsx)("tbody", { className: ps_report_table_classes_1.PsReportTableClasses.body, children: rows.length === 0 ? ((0, jsx_runtime_1.jsx)("tr", { children: (0, jsx_runtime_1.jsx)("td", { className: ps_report_table_classes_1.PsReportTableClasses.empty, colSpan: columns.length, children: emptyState !== undefined ? emptyState : ps_report_table_config_1.PsReportTableConfig.emptyLabel }) })) : (rows.map(renderRow)) })] }) }));
43
+ return ((0, jsx_runtime_1.jsx)("div", { "aria-busy": isRefreshing, className: ps_design_system_1.PallasoftClassNameService.merge(isFramed ? ps_report_table_classes_1.PsReportTableClasses.frame : ps_report_table_classes_1.PsReportTableClasses.framePlain, className), children: content }));
44
+ };
45
+ exports.PsReportTable = PsReportTable;
@@ -0,0 +1,6 @@
1
+ export declare const PsReportColumnAlign: {
2
+ readonly center: "center";
3
+ readonly left: "left";
4
+ readonly right: "right";
5
+ };
6
+ export type PsReportColumnAlign = (typeof PsReportColumnAlign)[keyof typeof PsReportColumnAlign];
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsReportColumnAlign = void 0;
4
+ exports.PsReportColumnAlign = {
5
+ center: 'center',
6
+ left: 'left',
7
+ right: 'right',
8
+ };
@@ -0,0 +1,7 @@
1
+ export declare const PsReportRowKind: {
2
+ readonly data: "data";
3
+ readonly group: "group";
4
+ readonly subtotal: "subtotal";
5
+ readonly total: "total";
6
+ };
7
+ export type PsReportRowKind = (typeof PsReportRowKind)[keyof typeof PsReportRowKind];
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsReportRowKind = void 0;
4
+ exports.PsReportRowKind = {
5
+ data: 'data',
6
+ group: 'group',
7
+ subtotal: 'subtotal',
8
+ total: 'total',
9
+ };
@@ -0,0 +1,7 @@
1
+ export declare const PsReportRowTone: {
2
+ readonly danger: "danger";
3
+ readonly muted: "muted";
4
+ readonly neutral: "neutral";
5
+ readonly primary: "primary";
6
+ };
7
+ export type PsReportRowTone = (typeof PsReportRowTone)[keyof typeof PsReportRowTone];
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsReportRowTone = void 0;
4
+ exports.PsReportRowTone = {
5
+ danger: 'danger',
6
+ muted: 'muted',
7
+ neutral: 'neutral',
8
+ primary: 'primary',
9
+ };
@@ -0,0 +1,52 @@
1
+ export declare const PsReportTableClasses: {
2
+ readonly align: {
3
+ readonly center: "text-center";
4
+ readonly left: "text-left";
5
+ readonly right: "text-right tabular-nums";
6
+ };
7
+ readonly body: "divide-y divide-line/60";
8
+ readonly caption: "sr-only";
9
+ readonly cell: {
10
+ readonly compact: "py-1.5 pr-3 text-[0.8125rem] leading-5";
11
+ readonly normal: "py-3 pr-5 text-sm";
12
+ };
13
+ readonly empty: "px-4 py-10 text-center text-sm text-ink/55";
14
+ readonly framePlain: "min-w-0";
15
+ readonly frame: "min-w-0 overflow-hidden rounded-[1.25rem] border border-line bg-surface";
16
+ readonly head: "bg-mist/70 text-[0.68rem] font-semibold uppercase tracking-[0.18em] text-ink/45";
17
+ readonly headCell: {
18
+ readonly compact: "py-2 pr-3 whitespace-nowrap";
19
+ readonly normal: "py-3.5 pr-5 whitespace-nowrap";
20
+ };
21
+ readonly headHidden: "sr-only";
22
+ readonly kind: {
23
+ readonly data: "text-ink";
24
+ readonly 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)]";
25
+ readonly subtotal: "border-t border-line font-semibold text-ink";
26
+ readonly 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)]";
27
+ };
28
+ readonly nowrap: "whitespace-nowrap";
29
+ readonly refreshing: "opacity-60";
30
+ readonly rowHeader: "[font-weight:inherit]";
31
+ readonly scroll: "ps-scrollbar overflow-x-auto overscroll-x-contain";
32
+ readonly scrollBounded: "overflow-y-auto overscroll-contain";
33
+ readonly skeleton: {
34
+ readonly cellEnd: "ml-auto w-16";
35
+ readonly cellWidths: readonly ["w-3/4", "w-1/2"];
36
+ readonly headEnd: "ml-auto h-2.5 w-12";
37
+ readonly headFirst: "h-2.5 w-20";
38
+ readonly headOther: "h-2.5 w-14";
39
+ readonly plain: "min-w-0 overflow-hidden";
40
+ };
41
+ readonly stickyFirstBody: "ps-table-pin left-0";
42
+ readonly stickyFirstHead: "ps-table-pin left-0 top-0 z-[3]";
43
+ readonly stickyHead: "ps-table-pin top-0 z-[2]";
44
+ readonly table: "w-full border-collapse text-left";
45
+ readonly tone: {
46
+ readonly 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)]";
47
+ readonly muted: "text-ink/60";
48
+ readonly neutral: "";
49
+ readonly primary: "bg-primary/10 text-primary [--ps-table-pin-fill:inset_0_0_0_100vmax_rgb(var(--ps-color-primary-rgb)/0.1)]";
50
+ };
51
+ readonly truncate: "truncate";
52
+ };
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsReportTableClasses = void 0;
4
+ const ps_report_column_align_1 = require("./ps-report-column-align");
5
+ const ps_report_row_kind_1 = require("./ps-report-row-kind");
6
+ const ps_report_row_tone_1 = require("./ps-report-row-tone");
7
+ const ps_report_table_density_1 = require("./ps-report-table-density");
8
+ exports.PsReportTableClasses = {
9
+ align: {
10
+ [ps_report_column_align_1.PsReportColumnAlign.center]: 'text-center',
11
+ [ps_report_column_align_1.PsReportColumnAlign.left]: 'text-left',
12
+ [ps_report_column_align_1.PsReportColumnAlign.right]: 'text-right tabular-nums',
13
+ },
14
+ body: 'divide-y divide-line/60',
15
+ caption: 'sr-only',
16
+ cell: {
17
+ [ps_report_table_density_1.PsReportTableDensity.compact]: 'py-1.5 pr-3 text-[0.8125rem] leading-5',
18
+ [ps_report_table_density_1.PsReportTableDensity.normal]: 'py-3 pr-5 text-sm',
19
+ },
20
+ empty: 'px-4 py-10 text-center text-sm text-ink/55',
21
+ framePlain: 'min-w-0',
22
+ frame: 'min-w-0 overflow-hidden rounded-[1.25rem] border border-line bg-surface',
23
+ head: 'bg-mist/70 text-[0.68rem] font-semibold uppercase tracking-[0.18em] text-ink/45',
24
+ headCell: {
25
+ [ps_report_table_density_1.PsReportTableDensity.compact]: 'py-2 pr-3 whitespace-nowrap',
26
+ [ps_report_table_density_1.PsReportTableDensity.normal]: 'py-3.5 pr-5 whitespace-nowrap',
27
+ },
28
+ headHidden: 'sr-only',
29
+ kind: {
30
+ [ps_report_row_kind_1.PsReportRowKind.data]: 'text-ink',
31
+ [ps_report_row_kind_1.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)]',
32
+ [ps_report_row_kind_1.PsReportRowKind.subtotal]: 'border-t border-line font-semibold text-ink',
33
+ [ps_report_row_kind_1.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)]',
34
+ },
35
+ nowrap: 'whitespace-nowrap',
36
+ refreshing: 'opacity-60',
37
+ rowHeader: '[font-weight:inherit]',
38
+ scroll: 'ps-scrollbar overflow-x-auto overscroll-x-contain',
39
+ scrollBounded: 'overflow-y-auto overscroll-contain',
40
+ skeleton: {
41
+ cellEnd: 'ml-auto w-16',
42
+ cellWidths: ['w-3/4', 'w-1/2'],
43
+ headEnd: 'ml-auto h-2.5 w-12',
44
+ headFirst: 'h-2.5 w-20',
45
+ headOther: 'h-2.5 w-14',
46
+ plain: 'min-w-0 overflow-hidden',
47
+ },
48
+ stickyFirstBody: 'ps-table-pin left-0',
49
+ stickyFirstHead: 'ps-table-pin left-0 top-0 z-[3]',
50
+ stickyHead: 'ps-table-pin top-0 z-[2]',
51
+ table: 'w-full border-collapse text-left',
52
+ tone: {
53
+ [ps_report_row_tone_1.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)]',
54
+ [ps_report_row_tone_1.PsReportRowTone.muted]: 'text-ink/60',
55
+ [ps_report_row_tone_1.PsReportRowTone.neutral]: '',
56
+ [ps_report_row_tone_1.PsReportRowTone.primary]: 'bg-primary/10 text-primary [--ps-table-pin-fill:inset_0_0_0_100vmax_rgb(var(--ps-color-primary-rgb)/0.1)]',
57
+ },
58
+ truncate: 'truncate',
59
+ };
@@ -0,0 +1,9 @@
1
+ export declare const PsReportTableConfig: {
2
+ readonly baseIndentRem: {
3
+ readonly compact: 0.75;
4
+ readonly normal: 1.25;
5
+ };
6
+ readonly emptyLabel: "Nothing to show";
7
+ readonly indentRem: 1.25;
8
+ readonly skeletonRows: 6;
9
+ };
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsReportTableConfig = void 0;
4
+ exports.PsReportTableConfig = {
5
+ baseIndentRem: { compact: 0.75, normal: 1.25 },
6
+ emptyLabel: 'Nothing to show',
7
+ indentRem: 1.25,
8
+ skeletonRows: 6,
9
+ };
@@ -0,0 +1,5 @@
1
+ export declare const PsReportTableDensity: {
2
+ readonly compact: "compact";
3
+ readonly normal: "normal";
4
+ };
5
+ export type PsReportTableDensity = (typeof PsReportTableDensity)[keyof typeof PsReportTableDensity];
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsReportTableDensity = void 0;
4
+ exports.PsReportTableDensity = {
5
+ compact: 'compact',
6
+ normal: 'normal',
7
+ };
@@ -1,3 +1,4 @@
1
1
  export declare const PsTableStickyConfig: {
2
2
  readonly cardGapPx: 12;
3
+ readonly inputTolerancePx: 0.5;
3
4
  };
@@ -3,4 +3,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PsTableStickyConfig = void 0;
4
4
  exports.PsTableStickyConfig = {
5
5
  cardGapPx: 12,
6
+ inputTolerancePx: 0.5,
6
7
  };
@@ -63,7 +63,6 @@ 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);
68
67
  const stickyContentRef = useRef(null);
69
68
  const stickyHeadRef = useRef(null);
@@ -94,13 +93,12 @@ export const PsDataTable = ({ caption, className, clearSelectionKey, columns, cu
94
93
  const pins = PsTablePinService.leading(pinFirstColumn, Boolean(reorder), isSelectable);
95
94
  const placementOf = (column, columnIndex) => PallasoftClassNameService.merge(column.hideBelow === undefined ? '' : PsTableHideBelowClasses[column.hideBelow], columnIndex === 0 ? pins.first : '', PsTablePinService.end(column.pinEnd === true));
96
95
  const overflow = usePsTableOverflow(`${visibleColumns.map((column) => column.id).join(',')}:${rows.length}`);
97
- const isStuck = usePsStickyHead({
96
+ usePsStickyHead({
98
97
  cardRef: stickyCardRef,
99
98
  contentRef: stickyContentRef,
100
99
  headRef: stickyHeadRef,
101
100
  layoutKey: `${visibleColumns.map((column) => column.id).join(',')}:${rows.length}:${isLoading}`,
102
101
  regionRef: stickyRegionRef,
103
- sentinelRef: stickySentinelRef,
104
102
  stickyTop,
105
103
  });
106
104
  const deferredSearch = useDeferredValue(search);
@@ -363,7 +361,7 @@ export const PsDataTable = ({ caption, className, clearSelectionKey, columns, cu
363
361
  updateQuery({ search: next });
364
362
  resetPage();
365
363
  }, rows: rows, search: search, searchPlaceholder: searchPlaceholder })) : null, banner] }));
366
- 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] })] })), _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 &&
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 &&
367
365
  paginationPosition !== PsTablePaginationPosition.bottom &&
368
366
  rowCount > PsTablePaginationConfig.topMinRows
369
367
  ? renderPagination('border-b border-t-0')
@@ -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,3 +1,4 @@
1
1
  export const PsTableStickyConfig = {
2
2
  cardGapPx: 12,
3
+ inputTolerancePx: 0.5,
3
4
  };
@@ -1,19 +1,16 @@
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, contentRef, 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;
11
9
  const content = contentRef.current;
12
10
  const head = headRef.current;
13
11
  const table = head === null ? null : head.parentElement;
14
12
  if (stickyTop === undefined ||
15
13
  region === null ||
16
- sentinel === null ||
17
14
  card === null ||
18
15
  content === null ||
19
16
  head === null ||
@@ -23,6 +20,7 @@ export const usePsStickyHead = ({ cardRef, contentRef, headRef, layoutKey, regio
23
20
  const Timeline = window.ScrollTimeline;
24
21
  const isDriven = scroller !== null && Timeline !== undefined;
25
22
  let animations = [];
23
+ let measured = null;
26
24
  let frame = 0;
27
25
  const headTravel = () => Math.max(table.offsetHeight - head.offsetHeight, 0);
28
26
  const drive = () => {
@@ -32,10 +30,19 @@ export const usePsStickyHead = ({ cardRef, contentRef, headRef, layoutKey, regio
32
30
  Number.parseFloat(getComputedStyle(region).top) +
33
31
  region.offsetHeight +
34
32
  PsTableStickyConfig.cardGapPx;
35
- 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;
36
43
  const timeline = new Timeline({ axis: 'block', source: scroller });
37
- const headFrames = PsTableStickyHeadService.keyframes(table.getBoundingClientRect().top + scroller.scrollTop - pinnedLine, headTravel(), scrollRange);
38
- const cardFrames = PsTableStickyHeadService.keyframes(content.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);
39
46
  animations.forEach((animation) => animation.cancel());
40
47
  animations = [
41
48
  head.animate(headFrames.map((keyframe) => ({
@@ -53,26 +60,22 @@ export const usePsStickyHead = ({ cardRef, contentRef, headRef, layoutKey, regio
53
60
  ];
54
61
  };
55
62
  const follow = () => {
63
+ frame = 0;
56
64
  const pinnedLine = region.getBoundingClientRect().bottom + PsTableStickyConfig.cardGapPx;
57
65
  head.style.transform = `translateY(${PsTableStickyHeadService.offset(pinnedLine, table.getBoundingClientRect().top, table.offsetHeight, head.offsetHeight)}px)`;
58
66
  const cut = PsTableStickyHeadService.offset(pinnedLine, content.getBoundingClientRect().top, card.offsetHeight, 0);
59
67
  card.style.transform = `translateY(${cut}px)`;
60
68
  content.style.transform = `translateY(${-cut}px)`;
61
69
  };
62
- const check = () => {
63
- frame = 0;
64
- setIsStuck(sentinel.getBoundingClientRect().top < region.getBoundingClientRect().top - 1);
65
- if (!isDriven)
66
- follow();
67
- };
68
70
  const schedule = () => {
69
71
  if (frame === 0)
70
- frame = window.requestAnimationFrame(check);
72
+ frame = window.requestAnimationFrame(follow);
71
73
  };
72
74
  const measure = () => {
73
75
  if (isDriven)
74
76
  drive();
75
- schedule();
77
+ else
78
+ schedule();
76
79
  };
77
80
  const observer = new ResizeObserver(measure);
78
81
  measure();
@@ -80,8 +83,9 @@ export const usePsStickyHead = ({ cardRef, contentRef, headRef, layoutKey, regio
80
83
  observer.observe(card);
81
84
  if (scroller !== null)
82
85
  Array.from(scroller.children).forEach((child) => observer.observe(child));
83
- window.addEventListener('scroll', schedule, { capture: true, passive: true });
84
86
  window.addEventListener('resize', measure);
87
+ if (!isDriven)
88
+ window.addEventListener('scroll', schedule, { capture: true, passive: true });
85
89
  return () => {
86
90
  observer.disconnect();
87
91
  animations.forEach((animation) => animation.cancel());
@@ -93,6 +97,5 @@ export const usePsStickyHead = ({ cardRef, contentRef, headRef, layoutKey, regio
93
97
  if (frame !== 0)
94
98
  window.cancelAnimationFrame(frame);
95
99
  };
96
- }, [cardRef, contentRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop]);
97
- return isStuck;
100
+ }, [cardRef, contentRef, headRef, layoutKey, regionRef, stickyTop]);
98
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
+ }
@@ -1,7 +1,17 @@
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));
4
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
+ }
5
15
  static keyframes(pinScroll, maxShift, scrollRange) {
6
16
  if (scrollRange <= 0)
7
17
  return [];
@@ -11,6 +21,9 @@ export class PsTableStickyHeadService {
11
21
  shift: shiftAt(scroll),
12
22
  }));
13
23
  }
24
+ static close(first, second) {
25
+ return Math.abs(first - second) <= PsTableStickyConfig.inputTolerancePx;
26
+ }
14
27
  static stops(scrolls, scrollRange) {
15
28
  const inside = scrolls.filter((scroll) => scroll >= 0 && scroll <= scrollRange);
16
29
  return inside.filter((scroll, index) => inside.indexOf(scroll) === index);
@@ -1,2 +1,2 @@
1
1
  import type { PsStickyHeadRefs } from '../interfaces/ps-sticky-head-refs';
2
- export declare const usePsStickyHead: ({ cardRef, contentRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop, }: PsStickyHeadRefs) => boolean;
2
+ export declare const usePsStickyHead: ({ cardRef, contentRef, headRef, layoutKey, regionRef, stickyTop, }: PsStickyHeadRefs) => void;
@@ -5,18 +5,15 @@ 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 = ({ cardRef, contentRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop, }) => {
9
- const [isStuck, setIsStuck] = (0, react_1.useState)(false);
8
+ const usePsStickyHead = ({ cardRef, contentRef, headRef, layoutKey, regionRef, stickyTop, }) => {
10
9
  (0, react_1.useLayoutEffect)(() => {
11
10
  const region = regionRef.current;
12
- const sentinel = sentinelRef.current;
13
11
  const card = cardRef.current;
14
12
  const content = contentRef.current;
15
13
  const head = headRef.current;
16
14
  const table = head === null ? null : head.parentElement;
17
15
  if (stickyTop === undefined ||
18
16
  region === null ||
19
- sentinel === null ||
20
17
  card === null ||
21
18
  content === null ||
22
19
  head === null ||
@@ -26,6 +23,7 @@ const usePsStickyHead = ({ cardRef, contentRef, headRef, layoutKey, regionRef, s
26
23
  const Timeline = window.ScrollTimeline;
27
24
  const isDriven = scroller !== null && Timeline !== undefined;
28
25
  let animations = [];
26
+ let measured = null;
29
27
  let frame = 0;
30
28
  const headTravel = () => Math.max(table.offsetHeight - head.offsetHeight, 0);
31
29
  const drive = () => {
@@ -35,10 +33,19 @@ const usePsStickyHead = ({ cardRef, contentRef, headRef, layoutKey, regionRef, s
35
33
  Number.parseFloat(getComputedStyle(region).top) +
36
34
  region.offsetHeight +
37
35
  ps_table_sticky_config_1.PsTableStickyConfig.cardGapPx;
38
- const scrollRange = scroller.scrollHeight - scroller.clientHeight;
36
+ const inputs = {
37
+ cardPin: content.getBoundingClientRect().top + scroller.scrollTop - pinnedLine,
38
+ cardTravel: card.offsetHeight,
39
+ headPin: table.getBoundingClientRect().top + scroller.scrollTop - pinnedLine,
40
+ headTravel: headTravel(),
41
+ scrollRange: scroller.scrollHeight - scroller.clientHeight,
42
+ };
43
+ if (ps_table_sticky_head_service_1.PsTableStickyHeadService.sameInputs(measured, inputs))
44
+ return;
45
+ measured = inputs;
39
46
  const timeline = new Timeline({ axis: 'block', source: scroller });
40
- const headFrames = ps_table_sticky_head_service_1.PsTableStickyHeadService.keyframes(table.getBoundingClientRect().top + scroller.scrollTop - pinnedLine, headTravel(), scrollRange);
41
- const cardFrames = ps_table_sticky_head_service_1.PsTableStickyHeadService.keyframes(content.getBoundingClientRect().top + scroller.scrollTop - pinnedLine, card.offsetHeight, scrollRange);
47
+ const headFrames = ps_table_sticky_head_service_1.PsTableStickyHeadService.keyframes(inputs.headPin, inputs.headTravel, inputs.scrollRange);
48
+ const cardFrames = ps_table_sticky_head_service_1.PsTableStickyHeadService.keyframes(inputs.cardPin, inputs.cardTravel, inputs.scrollRange);
42
49
  animations.forEach((animation) => animation.cancel());
43
50
  animations = [
44
51
  head.animate(headFrames.map((keyframe) => ({
@@ -56,26 +63,22 @@ const usePsStickyHead = ({ cardRef, contentRef, headRef, layoutKey, regionRef, s
56
63
  ];
57
64
  };
58
65
  const follow = () => {
66
+ frame = 0;
59
67
  const pinnedLine = region.getBoundingClientRect().bottom + ps_table_sticky_config_1.PsTableStickyConfig.cardGapPx;
60
68
  head.style.transform = `translateY(${ps_table_sticky_head_service_1.PsTableStickyHeadService.offset(pinnedLine, table.getBoundingClientRect().top, table.offsetHeight, head.offsetHeight)}px)`;
61
69
  const cut = ps_table_sticky_head_service_1.PsTableStickyHeadService.offset(pinnedLine, content.getBoundingClientRect().top, card.offsetHeight, 0);
62
70
  card.style.transform = `translateY(${cut}px)`;
63
71
  content.style.transform = `translateY(${-cut}px)`;
64
72
  };
65
- const check = () => {
66
- frame = 0;
67
- setIsStuck(sentinel.getBoundingClientRect().top < region.getBoundingClientRect().top - 1);
68
- if (!isDriven)
69
- follow();
70
- };
71
73
  const schedule = () => {
72
74
  if (frame === 0)
73
- frame = window.requestAnimationFrame(check);
75
+ frame = window.requestAnimationFrame(follow);
74
76
  };
75
77
  const measure = () => {
76
78
  if (isDriven)
77
79
  drive();
78
- schedule();
80
+ else
81
+ schedule();
79
82
  };
80
83
  const observer = new ResizeObserver(measure);
81
84
  measure();
@@ -83,8 +86,9 @@ const usePsStickyHead = ({ cardRef, contentRef, headRef, layoutKey, regionRef, s
83
86
  observer.observe(card);
84
87
  if (scroller !== null)
85
88
  Array.from(scroller.children).forEach((child) => observer.observe(child));
86
- window.addEventListener('scroll', schedule, { capture: true, passive: true });
87
89
  window.addEventListener('resize', measure);
90
+ if (!isDriven)
91
+ window.addEventListener('scroll', schedule, { capture: true, passive: true });
88
92
  return () => {
89
93
  observer.disconnect();
90
94
  animations.forEach((animation) => animation.cancel());
@@ -96,7 +100,6 @@ const usePsStickyHead = ({ cardRef, contentRef, headRef, layoutKey, regionRef, s
96
100
  if (frame !== 0)
97
101
  window.cancelAnimationFrame(frame);
98
102
  };
99
- }, [cardRef, contentRef, headRef, layoutKey, regionRef, sentinelRef, stickyTop]);
100
- return isStuck;
103
+ }, [cardRef, contentRef, headRef, layoutKey, regionRef, stickyTop]);
101
104
  };
102
105
  exports.usePsStickyHead = usePsStickyHead;
package/dist/index.d.ts 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';
package/dist/index.js CHANGED
@@ -80,3 +80,11 @@ __exportStar(require("./interfaces/ps-server-rows-result"), exports);
80
80
  __exportStar(require("./interfaces/ps-table-cursor-paging"), exports);
81
81
  __exportStar(require("./interfaces/ps-table-select-all-matching"), exports);
82
82
  __exportStar(require("./services/ps-server-rows-service"), exports);
83
+ __exportStar(require("./components/ps-report-table"), exports);
84
+ __exportStar(require("./components/ps-report-table-skeleton"), exports);
85
+ __exportStar(require("./constants/ps-report-column-align"), exports);
86
+ __exportStar(require("./constants/ps-report-row-kind"), exports);
87
+ __exportStar(require("./constants/ps-report-row-tone"), exports);
88
+ __exportStar(require("./constants/ps-report-table-density"), exports);
89
+ __exportStar(require("./interfaces/ps-report-column"), exports);
90
+ __exportStar(require("./services/ps-report-table-service"), exports);
@@ -0,0 +1,6 @@
1
+ import type { PsReportColumn } from './ps-report-column';
2
+ export interface PsReportCellPlan<RowData> {
3
+ colSpan: number;
4
+ column: PsReportColumn<RowData>;
5
+ index: number;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,12 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { PsReportColumnAlign } from '../constants/ps-report-column-align';
3
+ export interface PsReportColumn<RowData> {
4
+ align?: PsReportColumnAlign;
5
+ id: string;
6
+ label: ReactNode;
7
+ maxWidth?: string;
8
+ minWidth?: string;
9
+ render: (row: RowData) => ReactNode;
10
+ width?: string;
11
+ wrap?: boolean;
12
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -5,6 +5,5 @@ export interface PsStickyHeadRefs {
5
5
  headRef: RefObject<HTMLTableSectionElement | null>;
6
6
  layoutKey: string;
7
7
  regionRef: RefObject<HTMLDivElement | null>;
8
- sentinelRef: RefObject<HTMLDivElement | null>;
9
8
  stickyTop?: string;
10
9
  }
@@ -0,0 +1,7 @@
1
+ export interface PsTableStickyHeadInputs {
2
+ cardPin: number;
3
+ cardTravel: number;
4
+ headPin: number;
5
+ headTravel: number;
6
+ scrollRange: number;
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,17 @@
1
+ import type { CSSProperties } from 'react';
2
+ import { PsReportColumnAlign } from '../constants/ps-report-column-align';
3
+ import { PsReportRowTone } from '../constants/ps-report-row-tone';
4
+ import { PsReportTableDensity } from '../constants/ps-report-table-density';
5
+ import type { PsReportCellPlan } from '../interfaces/ps-report-cell-plan';
6
+ import type { PsReportColumn } from '../interfaces/ps-report-column';
7
+ export declare class PsReportTableService {
8
+ static cells<RowData>(columns: PsReportColumn<RowData>[], leadSpan: number): PsReportCellPlan<RowData>[];
9
+ static span(count: number, leadSpan: number): number;
10
+ static indent(level: number, density: PsReportTableDensity): CSSProperties;
11
+ static columnStyle<RowData>(column: PsReportColumn<RowData>): CSSProperties;
12
+ static levelOf(level: number | undefined): number;
13
+ static headClass<RowData>(column: PsReportColumn<RowData>, index: number, density: PsReportTableDensity, isHeaderSticky: boolean, isFirstColumnSticky: boolean): string;
14
+ static headPin(isHeaderSticky: boolean, isPinnedFirst: boolean): string;
15
+ static cellClass<RowData>(column: PsReportColumn<RowData>, index: number, density: PsReportTableDensity, tone: PsReportRowTone, isFirstColumnSticky: boolean): string;
16
+ static alignOf<RowData>(column: PsReportColumn<RowData>): PsReportColumnAlign;
17
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsReportTableService = void 0;
4
+ const ps_report_column_align_1 = require("../constants/ps-report-column-align");
5
+ const ps_report_table_classes_1 = require("../constants/ps-report-table-classes");
6
+ const ps_report_table_config_1 = require("../constants/ps-report-table-config");
7
+ const ps_table_pin_classes_1 = require("../constants/ps-table-pin-classes");
8
+ class PsReportTableService {
9
+ static cells(columns, leadSpan) {
10
+ const span = PsReportTableService.span(columns.length, leadSpan);
11
+ const plan = [{ colSpan: span, column: columns[0], index: 0 }];
12
+ for (let index = span; index < columns.length; index += 1)
13
+ plan.push({ colSpan: 1, column: columns[index], index });
14
+ return plan;
15
+ }
16
+ static span(count, leadSpan) {
17
+ return Math.min(Math.max(leadSpan, 1), count);
18
+ }
19
+ static indent(level, density) {
20
+ const base = ps_report_table_config_1.PsReportTableConfig.baseIndentRem[density];
21
+ return { paddingLeft: `${base + level * ps_report_table_config_1.PsReportTableConfig.indentRem}rem` };
22
+ }
23
+ static columnStyle(column) {
24
+ return {
25
+ maxWidth: column.maxWidth,
26
+ minWidth: column.minWidth,
27
+ width: column.width,
28
+ };
29
+ }
30
+ static levelOf(level) {
31
+ return level !== undefined && level > 0 ? level : 0;
32
+ }
33
+ static headClass(column, index, density, isHeaderSticky, isFirstColumnSticky) {
34
+ const isPinnedFirst = index === 0 && isFirstColumnSticky;
35
+ const pin = PsReportTableService.headPin(isHeaderSticky, isPinnedFirst);
36
+ return [
37
+ ps_report_table_classes_1.PsReportTableClasses.headCell[density],
38
+ ps_report_table_classes_1.PsReportTableClasses.align[PsReportTableService.alignOf(column)],
39
+ pin,
40
+ isPinnedFirst ? ps_table_pin_classes_1.PsTablePinClasses.edge : '',
41
+ ]
42
+ .filter((name) => name !== '')
43
+ .join(' ');
44
+ }
45
+ static headPin(isHeaderSticky, isPinnedFirst) {
46
+ if (isHeaderSticky && isPinnedFirst)
47
+ return ps_report_table_classes_1.PsReportTableClasses.stickyFirstHead;
48
+ if (isHeaderSticky)
49
+ return ps_report_table_classes_1.PsReportTableClasses.stickyHead;
50
+ if (isPinnedFirst)
51
+ return ps_report_table_classes_1.PsReportTableClasses.stickyFirstBody;
52
+ return '';
53
+ }
54
+ static cellClass(column, index, density, tone, isFirstColumnSticky) {
55
+ const isPinnedFirst = index === 0 && isFirstColumnSticky;
56
+ return [
57
+ ps_report_table_classes_1.PsReportTableClasses.cell[density],
58
+ ps_report_table_classes_1.PsReportTableClasses.align[PsReportTableService.alignOf(column)],
59
+ ps_report_table_classes_1.PsReportTableClasses.tone[tone],
60
+ column.wrap === true ? '' : ps_report_table_classes_1.PsReportTableClasses.nowrap,
61
+ column.maxWidth !== undefined ? ps_report_table_classes_1.PsReportTableClasses.truncate : '',
62
+ isPinnedFirst ? `${ps_report_table_classes_1.PsReportTableClasses.stickyFirstBody} ${ps_table_pin_classes_1.PsTablePinClasses.edge}` : '',
63
+ ]
64
+ .filter((name) => name !== '')
65
+ .join(' ');
66
+ }
67
+ static alignOf(column) {
68
+ return column.align !== undefined ? column.align : ps_report_column_align_1.PsReportColumnAlign.left;
69
+ }
70
+ }
71
+ exports.PsReportTableService = PsReportTableService;
@@ -1,6 +1,9 @@
1
+ import type { PsTableStickyHeadInputs } from '../interfaces/ps-table-sticky-head-inputs';
1
2
  import type { PsTableStickyHeadKeyframe } from '../interfaces/ps-table-sticky-head-keyframe';
2
3
  export declare class PsTableStickyHeadService {
3
4
  static offset(pinnedBottom: number, tableTop: number, tableHeight: number, headHeight: number): number;
5
+ static sameInputs(previous: PsTableStickyHeadInputs | null, next: PsTableStickyHeadInputs): boolean;
4
6
  static keyframes(pinScroll: number, maxShift: number, scrollRange: number): PsTableStickyHeadKeyframe[];
7
+ private static close;
5
8
  private static stops;
6
9
  }
@@ -1,10 +1,20 @@
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));
7
8
  }
9
+ static sameInputs(previous, next) {
10
+ if (previous === null)
11
+ return false;
12
+ return (PsTableStickyHeadService.close(previous.headPin, next.headPin) &&
13
+ PsTableStickyHeadService.close(previous.headTravel, next.headTravel) &&
14
+ PsTableStickyHeadService.close(previous.cardPin, next.cardPin) &&
15
+ PsTableStickyHeadService.close(previous.cardTravel, next.cardTravel) &&
16
+ PsTableStickyHeadService.close(previous.scrollRange, next.scrollRange));
17
+ }
8
18
  static keyframes(pinScroll, maxShift, scrollRange) {
9
19
  if (scrollRange <= 0)
10
20
  return [];
@@ -14,6 +24,9 @@ class PsTableStickyHeadService {
14
24
  shift: shiftAt(scroll),
15
25
  }));
16
26
  }
27
+ static close(first, second) {
28
+ return Math.abs(first - second) <= ps_table_sticky_config_1.PsTableStickyConfig.inputTolerancePx;
29
+ }
17
30
  static stops(scrolls, scrollRange) {
18
31
  const inside = scrolls.filter((scroll) => scroll >= 0 && scroll <= scrollRange);
19
32
  return inside.filter((scroll, index) => inside.indexOf(scroll) === index);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pallasoft/ps-table-components",
3
- "version": "1.28.4",
3
+ "version": "1.29.0",
4
4
  "private": false,
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/esm/index.js",