@pallasoft/ps-table-components 1.15.0 → 1.16.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.
@@ -8,6 +8,7 @@ const ps_design_system_1 = require("@pallasoft/ps-design-system");
8
8
  const ps_input_components_1 = require("@pallasoft/ps-input-components");
9
9
  const ps_motion_components_1 = require("@pallasoft/ps-motion-components");
10
10
  const table_config_1 = require("../constants/table-config");
11
+ const ps_table_cell_tooltip_service_1 = require("../services/ps-table-cell-tooltip-service");
11
12
  const ps_table_column_size_service_1 = require("../services/ps-table-column-size-service");
12
13
  const ps_table_group_service_1 = require("../services/ps-table-group-service");
13
14
  const ps_table_query_service_1 = require("../services/ps-table-query-service");
@@ -174,7 +175,7 @@ const PsDataTable = ({ caption, className, columns, defaultSort, density = 'norm
174
175
  : undefined, tabIndex: onRowClick ? 0 : undefined, children: [isSelectable ? ((0, jsx_runtime_1.jsx)("td", { className: 'w-10 pl-4 pr-0', onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: (0, jsx_runtime_1.jsx)(ps_input_components_1.PsCheckbox, { isSelected: selectedIds.includes(rowId), label: `Select ${rowLabel}`, onChange: () => toggleRow(rowId) }) })) : null, visibleColumns.map((column) => ((0, jsx_runtime_1.jsx)("td", { className: ps_design_system_1.PallasoftClassNameService.merge(densityClassNames[density].cell, alignClassNames[column.align !== null && column.align !== undefined ? column.align : 'left'], column.wrap ? '' : 'whitespace-nowrap', (layout === 'fixed' && !column.wrap) ||
175
176
  ps_table_column_size_service_1.PsTableColumnSizeService.maxWidthOf(column) !== undefined
176
177
  ? 'truncate'
177
- : '', 'text-sm text-ink'), style: columnStyle(column), children: column.render(row) }, column.id)))] }), renderExpandedRow ? ((0, jsx_runtime_1.jsx)("tr", { "aria-hidden": !isExpanded, className: isExpanded ? 'border-t-0' : 'border-0', children: (0, jsx_runtime_1.jsx)("td", { className: 'p-0', colSpan: columnCount, children: (0, jsx_runtime_1.jsx)(ps_motion_components_1.PsCollapse, { isOpen: isExpanded, children: (0, jsx_runtime_1.jsx)("div", { className: 'w-0 min-w-full border-l-2 border-primary bg-mist/40 px-4 py-4', children: renderExpandedRow(row) }) }) }) })) : null] }, rowId));
178
+ : '', 'text-sm text-ink'), style: columnStyle(column), title: ps_table_cell_tooltip_service_1.PsTableCellTooltipService.forCell(column, row), children: column.render(row) }, column.id)))] }), renderExpandedRow ? ((0, jsx_runtime_1.jsx)("tr", { "aria-hidden": !isExpanded, className: isExpanded ? 'border-t-0' : 'border-0', children: (0, jsx_runtime_1.jsx)("td", { className: 'p-0', colSpan: columnCount, children: (0, jsx_runtime_1.jsx)(ps_motion_components_1.PsCollapse, { isOpen: isExpanded, children: (0, jsx_runtime_1.jsx)("div", { className: 'w-0 min-w-full border-l-2 border-primary bg-mist/40 px-4 py-4', children: renderExpandedRow(row) }) }) }) })) : null] }, rowId));
178
179
  };
179
180
  if (isLoading)
180
181
  return ((0, jsx_runtime_1.jsx)(ps_core_components_1.PsSkeletonTable, { className: className, columns: visibleColumns.length, hasToolbar: hasToolbar, rows: table_config_1.PsTableConfig.skeletonRows }));
@@ -193,7 +194,7 @@ const PsDataTable = ({ caption, className, columns, defaultSort, density = 'norm
193
194
  ? grouping.renderGroupSummary(group.rows)
194
195
  : 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}`));
195
196
  })
196
- : renderCardList(visibleRows, 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-focus-ring mt-2 rounded-full px-3 py-1.5 text-sm font-semibold text-primary', onClick: clearFilters, type: 'button', children: "Clear search and filters" })] })) : null) })) : null, (0, jsx_runtime_1.jsx)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('ps-scrollbar overflow-x-auto overflow-y-hidden', mobileLayout === 'cards' ? 'hidden sm:block' : ''), children: (0, jsx_runtime_1.jsxs)("table", { className: ps_design_system_1.PallasoftClassNameService.merge('w-full min-w-max 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: 'bg-mist/70 text-[0.68rem] font-semibold uppercase tracking-[0.18em] text-ink/45', children: (0, jsx_runtime_1.jsxs)("tr", { children: [isSelectable ? ((0, jsx_runtime_1.jsx)("th", { className: 'w-10 pl-4 pr-0', scope: 'col', children: (0, jsx_runtime_1.jsx)(ps_input_components_1.PsCheckbox, { isIndeterminate: !isPageSelected && pageIds.some((rowId) => selectedIds.includes(rowId)), isSelected: isPageSelected, label: 'Select all rows on this page', onChange: togglePage }) })) : null, visibleColumns.map((column) => {
197
+ : renderCardList(visibleRows, 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-focus-ring mt-2 rounded-full px-3 py-1.5 text-sm font-semibold text-primary', onClick: clearFilters, type: 'button', children: "Clear search and filters" })] })) : null) })) : null, (0, jsx_runtime_1.jsx)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('ps-scrollbar overflow-x-auto overflow-y-hidden', mobileLayout === 'cards' ? 'hidden sm:block' : ''), children: (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: 'bg-mist/70 text-[0.68rem] font-semibold uppercase tracking-[0.18em] text-ink/45', children: (0, jsx_runtime_1.jsxs)("tr", { children: [isSelectable ? ((0, jsx_runtime_1.jsx)("th", { className: 'w-10 pl-4 pr-0', scope: 'col', children: (0, jsx_runtime_1.jsx)(ps_input_components_1.PsCheckbox, { isIndeterminate: !isPageSelected && pageIds.some((rowId) => selectedIds.includes(rowId)), isSelected: isPageSelected, label: 'Select all rows on this page', onChange: togglePage }) })) : null, visibleColumns.map((column) => {
197
198
  const align = column.align !== null && column.align !== undefined ? column.align : 'left';
198
199
  const isSorted = sort !== null && sort.columnId === column.id;
199
200
  return ((0, jsx_runtime_1.jsx)("th", { "aria-sort": isSorted
@@ -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 { PsTableConfig } from '../constants/table-config';
8
+ import { PsTableCellTooltipService } from '../services/ps-table-cell-tooltip-service';
8
9
  import { PsTableColumnSizeService } from '../services/ps-table-column-size-service';
9
10
  import { PsTableGroupService } from '../services/ps-table-group-service';
10
11
  import { PsTableQueryService } from '../services/ps-table-query-service';
@@ -171,7 +172,7 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
171
172
  : undefined, tabIndex: onRowClick ? 0 : undefined, children: [isSelectable ? (_jsx("td", { className: 'w-10 pl-4 pr-0', onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: _jsx(PsCheckbox, { isSelected: selectedIds.includes(rowId), label: `Select ${rowLabel}`, onChange: () => toggleRow(rowId) }) })) : null, visibleColumns.map((column) => (_jsx("td", { className: PallasoftClassNameService.merge(densityClassNames[density].cell, alignClassNames[column.align !== null && column.align !== undefined ? column.align : 'left'], column.wrap ? '' : 'whitespace-nowrap', (layout === 'fixed' && !column.wrap) ||
172
173
  PsTableColumnSizeService.maxWidthOf(column) !== undefined
173
174
  ? 'truncate'
174
- : '', 'text-sm text-ink'), style: columnStyle(column), children: column.render(row) }, column.id)))] }), renderExpandedRow ? (_jsx("tr", { "aria-hidden": !isExpanded, className: isExpanded ? 'border-t-0' : 'border-0', children: _jsx("td", { className: 'p-0', colSpan: columnCount, children: _jsx(PsCollapse, { isOpen: isExpanded, children: _jsx("div", { className: 'w-0 min-w-full border-l-2 border-primary bg-mist/40 px-4 py-4', children: renderExpandedRow(row) }) }) }) })) : null] }, rowId));
175
+ : '', 'text-sm text-ink'), style: columnStyle(column), title: PsTableCellTooltipService.forCell(column, row), children: column.render(row) }, column.id)))] }), renderExpandedRow ? (_jsx("tr", { "aria-hidden": !isExpanded, className: isExpanded ? 'border-t-0' : 'border-0', children: _jsx("td", { className: 'p-0', colSpan: columnCount, children: _jsx(PsCollapse, { isOpen: isExpanded, children: _jsx("div", { className: 'w-0 min-w-full border-l-2 border-primary bg-mist/40 px-4 py-4', children: renderExpandedRow(row) }) }) }) })) : null] }, rowId));
175
176
  };
176
177
  if (isLoading)
177
178
  return (_jsx(PsSkeletonTable, { className: className, columns: visibleColumns.length, hasToolbar: hasToolbar, rows: PsTableConfig.skeletonRows }));
@@ -190,7 +191,7 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
190
191
  ? grouping.renderGroupSummary(group.rows)
191
192
  : undefined }), _jsx(PsCollapse, { isOpen: isExpanded && !closingGroupKeys.includes(group.key), children: renderCardList(group.rows, null) })] }, `group-${group.key}`));
192
193
  })
193
- : renderCardList(visibleRows, visibleRows.length === 0 && isQueried ? (_jsxs("div", { className: 'px-4 py-10 text-center', children: [_jsx("p", { className: 'text-sm font-semibold text-ink', children: PsTableConfig.noMatchesTitle }), _jsx("button", { className: 'ps-focus-ring mt-2 rounded-full px-3 py-1.5 text-sm font-semibold text-primary', onClick: clearFilters, type: 'button', children: "Clear search and filters" })] })) : null) })) : null, _jsx("div", { className: PallasoftClassNameService.merge('ps-scrollbar overflow-x-auto overflow-y-hidden', mobileLayout === 'cards' ? 'hidden sm:block' : ''), children: _jsxs("table", { className: PallasoftClassNameService.merge('w-full min-w-max border-collapse text-left', layout === 'fixed' ? 'table-fixed' : ''), children: [caption ? _jsx("caption", { className: 'sr-only', children: caption }) : null, _jsx("thead", { className: 'bg-mist/70 text-[0.68rem] font-semibold uppercase tracking-[0.18em] text-ink/45', children: _jsxs("tr", { children: [isSelectable ? (_jsx("th", { className: 'w-10 pl-4 pr-0', scope: 'col', children: _jsx(PsCheckbox, { isIndeterminate: !isPageSelected && pageIds.some((rowId) => selectedIds.includes(rowId)), isSelected: isPageSelected, label: 'Select all rows on this page', onChange: togglePage }) })) : null, visibleColumns.map((column) => {
194
+ : renderCardList(visibleRows, visibleRows.length === 0 && isQueried ? (_jsxs("div", { className: 'px-4 py-10 text-center', children: [_jsx("p", { className: 'text-sm font-semibold text-ink', children: PsTableConfig.noMatchesTitle }), _jsx("button", { className: 'ps-focus-ring mt-2 rounded-full px-3 py-1.5 text-sm font-semibold text-primary', onClick: clearFilters, type: 'button', children: "Clear search and filters" })] })) : null) })) : null, _jsx("div", { className: PallasoftClassNameService.merge('ps-scrollbar overflow-x-auto overflow-y-hidden', mobileLayout === 'cards' ? 'hidden sm:block' : ''), children: _jsxs("table", { className: PallasoftClassNameService.merge('w-full border-collapse text-left', layout === 'fixed' ? 'table-fixed' : ''), children: [caption ? _jsx("caption", { className: 'sr-only', children: caption }) : null, _jsx("thead", { className: 'bg-mist/70 text-[0.68rem] font-semibold uppercase tracking-[0.18em] text-ink/45', children: _jsxs("tr", { children: [isSelectable ? (_jsx("th", { className: 'w-10 pl-4 pr-0', scope: 'col', children: _jsx(PsCheckbox, { isIndeterminate: !isPageSelected && pageIds.some((rowId) => selectedIds.includes(rowId)), isSelected: isPageSelected, label: 'Select all rows on this page', onChange: togglePage }) })) : null, visibleColumns.map((column) => {
194
195
  const align = column.align !== null && column.align !== undefined ? column.align : 'left';
195
196
  const isSorted = sort !== null && sort.columnId === column.id;
196
197
  return (_jsx("th", { "aria-sort": isSorted
package/dist/esm/index.js CHANGED
@@ -13,6 +13,7 @@ export * from './interfaces/table-query';
13
13
  export * from './interfaces/table-row-action';
14
14
  export * from './interfaces/table-row-group';
15
15
  export * from './interfaces/table-sort';
16
+ export * from './services/ps-table-cell-tooltip-service';
16
17
  export * from './services/ps-table-column-size-service';
17
18
  export * from './services/ps-table-group-service';
18
19
  export * from './services/ps-table-query-service';
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,17 @@
1
+ export class PsTableCellTooltipService {
2
+ /**
3
+ * A truncated cell hides the rest of its text, so it carries the full value as a native
4
+ * tooltip. A column can name that text itself; otherwise a string sortValue is already the
5
+ * cell's text in every column that sorts on what it shows.
6
+ */
7
+ static forCell(column, row) {
8
+ if (column.tooltip) {
9
+ const explicit = column.tooltip(row);
10
+ return explicit === null || explicit === '' ? undefined : explicit;
11
+ }
12
+ if (!column.sortValue)
13
+ return undefined;
14
+ const value = column.sortValue(row);
15
+ return typeof value === 'string' && value !== '' ? value : undefined;
16
+ }
17
+ }
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export * from './interfaces/table-query';
13
13
  export * from './interfaces/table-row-action';
14
14
  export * from './interfaces/table-row-group';
15
15
  export * from './interfaces/table-sort';
16
+ export * from './services/ps-table-cell-tooltip-service';
16
17
  export * from './services/ps-table-column-size-service';
17
18
  export * from './services/ps-table-group-service';
18
19
  export * from './services/ps-table-query-service';
package/dist/index.js CHANGED
@@ -29,6 +29,7 @@ __exportStar(require("./interfaces/table-query"), exports);
29
29
  __exportStar(require("./interfaces/table-row-action"), exports);
30
30
  __exportStar(require("./interfaces/table-row-group"), exports);
31
31
  __exportStar(require("./interfaces/table-sort"), exports);
32
+ __exportStar(require("./services/ps-table-cell-tooltip-service"), exports);
32
33
  __exportStar(require("./services/ps-table-column-size-service"), exports);
33
34
  __exportStar(require("./services/ps-table-group-service"), exports);
34
35
  __exportStar(require("./services/ps-table-query-service"), exports);
@@ -16,6 +16,8 @@ export interface PsTableColumn<RowData> {
16
16
  render: (row: RowData) => ReactNode;
17
17
  size?: PsTableColumnSize;
18
18
  sortValue?: (row: RowData) => string | number | null;
19
+ /** Text shown on hover when the cell is too narrow. Defaults to the column's string sortValue. */
20
+ tooltip?: (row: RowData) => string | null;
19
21
  width?: string;
20
22
  wrap?: boolean;
21
23
  }
@@ -0,0 +1,9 @@
1
+ import type { PsTableColumn } from '../interfaces/table-column';
2
+ export declare class PsTableCellTooltipService {
3
+ /**
4
+ * A truncated cell hides the rest of its text, so it carries the full value as a native
5
+ * tooltip. A column can name that text itself; otherwise a string sortValue is already the
6
+ * cell's text in every column that sorts on what it shows.
7
+ */
8
+ static forCell<RowData>(column: PsTableColumn<RowData>, row: RowData): string | undefined;
9
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsTableCellTooltipService = void 0;
4
+ class PsTableCellTooltipService {
5
+ /**
6
+ * A truncated cell hides the rest of its text, so it carries the full value as a native
7
+ * tooltip. A column can name that text itself; otherwise a string sortValue is already the
8
+ * cell's text in every column that sorts on what it shows.
9
+ */
10
+ static forCell(column, row) {
11
+ if (column.tooltip) {
12
+ const explicit = column.tooltip(row);
13
+ return explicit === null || explicit === '' ? undefined : explicit;
14
+ }
15
+ if (!column.sortValue)
16
+ return undefined;
17
+ const value = column.sortValue(row);
18
+ return typeof value === 'string' && value !== '' ? value : undefined;
19
+ }
20
+ }
21
+ exports.PsTableCellTooltipService = PsTableCellTooltipService;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pallasoft/ps-table-components",
3
- "version": "1.15.0",
3
+ "version": "1.16.0",
4
4
  "private": false,
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -9,6 +9,7 @@
9
9
  "exports": {
10
10
  ".": {
11
11
  "types": "./dist/index.d.ts",
12
+ "import": "./dist/esm/index.js",
12
13
  "module": "./dist/esm/index.js",
13
14
  "require": "./dist/index.js",
14
15
  "default": "./dist/index.js"
@@ -19,7 +20,7 @@
19
20
  ],
20
21
  "scripts": {
21
22
  "husky:prepare": "npx husky",
22
- "build": "tsc && tsc -p tsconfig.esm.json",
23
+ "build": "tsc && tsc -p tsconfig.esm.json && node -e \"require('fs').writeFileSync('dist/esm/package.json', JSON.stringify({ type: 'module' }))\"",
23
24
  "setup:graphify": "sh scripts/graphify-setup.sh",
24
25
  "update:graphify": "sh scripts/graphify-update.sh",
25
26
  "lint": "npm run lint:eslint",
@@ -28,7 +29,8 @@
28
29
  "format:prettier": "npx prettier --write \"src/**/*.{ts,tsx,json,md}\"",
29
30
  "lint:eslint": "npx eslint \"src/**/*.{ts,tsx}\"",
30
31
  "lint:eslint:fix": "npx eslint --fix \"src/**/*.{ts,tsx}\"",
31
- "release": "semantic-release"
32
+ "release": "semantic-release",
33
+ "test": "vitest run"
32
34
  },
33
35
  "peerDependencies": {
34
36
  "react": "^18 || ^19"
@@ -60,7 +62,8 @@
60
62
  "react-dom": "^19.3.0",
61
63
  "semantic-release": "^24.2.0",
62
64
  "ts-node": "^10.9.2",
63
- "typescript": "^5.9.3"
65
+ "typescript": "^5.9.3",
66
+ "vitest": "^3.2.4"
64
67
  },
65
68
  "publishConfig": {
66
69
  "access": "public",