@pallasoft/ps-table-components 1.23.0 → 1.24.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.
@@ -74,9 +74,9 @@ const densityClassNames = {
74
74
  head: 'px-5 py-3.5',
75
75
  },
76
76
  };
77
- const columnStyle = (column) => ({
78
- maxWidth: ps_table_column_size_service_1.PsTableColumnSizeService.maxWidthOf(column),
79
- minWidth: ps_table_column_size_service_1.PsTableColumnSizeService.minWidthOf(column),
77
+ const columnStyle = (column, fittedMinWidth) => ({
78
+ maxWidth: column.measure === undefined ? ps_table_column_size_service_1.PsTableColumnSizeService.maxWidthOf(column) : undefined,
79
+ minWidth: fittedMinWidth === undefined ? ps_table_column_size_service_1.PsTableColumnSizeService.minWidthOf(column) : fittedMinWidth,
80
80
  width: column.width,
81
81
  });
82
82
  const alignClassNames = {
@@ -95,6 +95,9 @@ const PsDataTable = ({ caption, className, columns, defaultSort, density = 'norm
95
95
  const currentQuery = query ? query : uncontrolledQuery;
96
96
  const { filters, hiddenColumnIds, search, sort } = currentQuery;
97
97
  const visibleColumns = columns.filter((column) => !hiddenColumnIds.includes(column.id));
98
+ const fittedWidths = (0, react_1.useMemo)(() => new Map(columns
99
+ .filter((column) => column.measure !== undefined)
100
+ .map((column) => [column.id, ps_table_column_size_service_1.PsTableColumnSizeService.fittedMinWidthOf(column, rows)])), [columns, rows]);
98
101
  const updateQuery = (patch) => {
99
102
  const next = { ...currentQuery, ...patch };
100
103
  if (!query)
@@ -323,10 +326,11 @@ const PsDataTable = ({ caption, className, columns, defaultSort, density = 'norm
323
326
  }
324
327
  : undefined, style: motion && motion.delayMs !== undefined
325
328
  ? { animationDelay: `${motion.delayMs}ms` }
326
- : undefined, tabIndex: onRowClick ? 0 : undefined, children: [reorder && !api.isActive ? ((0, jsx_runtime_1.jsx)("td", { className: ps_design_system_1.PallasoftClassNameService.merge('w-9 min-w-9 pl-3 pr-0', pins.reorder) })) : null, isSelectable ? ((0, jsx_runtime_1.jsx)("td", { className: ps_design_system_1.PallasoftClassNameService.merge('w-10 min-w-10 pl-4 pr-0', pins.select), onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: (0, jsx_runtime_1.jsx)(ps_input_components_1.PsCheckbox, { isSelected: selectedIdSet.has(rowId), label: `Select ${rowLabel}`, onChange: () => toggleRow(rowId) }) })) : null, visibleColumns.map((column, columnIndex) => ((0, jsx_runtime_1.jsx)("td", { className: ps_design_system_1.PallasoftClassNameService.merge(densityClassNames[density].cell, placementOf(column, columnIndex), alignClassNames[column.align !== null && column.align !== undefined ? column.align : 'left'], column.wrap ? '' : 'whitespace-nowrap', (layout === 'fixed' && !column.wrap) ||
327
- ps_table_column_size_service_1.PsTableColumnSizeService.maxWidthOf(column) !== undefined
329
+ : undefined, tabIndex: onRowClick ? 0 : undefined, children: [reorder && !api.isActive ? ((0, jsx_runtime_1.jsx)("td", { className: ps_design_system_1.PallasoftClassNameService.merge('w-9 min-w-9 pl-3 pr-0', pins.reorder) })) : null, isSelectable ? ((0, jsx_runtime_1.jsx)("td", { className: ps_design_system_1.PallasoftClassNameService.merge('w-10 min-w-10 pl-4 pr-0', pins.select), onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: (0, jsx_runtime_1.jsx)(ps_input_components_1.PsCheckbox, { isSelected: selectedIdSet.has(rowId), label: `Select ${rowLabel}`, onChange: () => toggleRow(rowId) }) })) : null, visibleColumns.map((column, columnIndex) => ((0, jsx_runtime_1.jsx)("td", { className: ps_design_system_1.PallasoftClassNameService.merge(densityClassNames[density].cell, placementOf(column, columnIndex), alignClassNames[column.align !== null && column.align !== undefined ? column.align : 'left'], column.wrap ? '' : 'whitespace-nowrap', column.measure === undefined &&
330
+ ((layout === 'fixed' && !column.wrap) ||
331
+ ps_table_column_size_service_1.PsTableColumnSizeService.maxWidthOf(column) !== undefined)
328
332
  ? 'truncate'
329
- : '', '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));
333
+ : '', 'text-sm text-ink'), style: columnStyle(column, fittedWidths.get(column.id)), 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));
330
334
  };
331
335
  const renderEntries = (api, entries) => reorder
332
336
  ? ps_table_reorder_service_1.PsTableReorderService.runs(entries, (entry) => reorderKey(entry.row), (entry) => getRowId(entry.row)).map((run) => api.run(run.id, run.items.map((entry) => getRowId(entry.row)), run.items.map((entry) => renderRow(api, entry.row, entry.motion, entry.virtualItem))))
@@ -355,7 +359,7 @@ const PsDataTable = ({ caption, className, columns, defaultSort, density = 'norm
355
359
  ? sort.direction
356
360
  : column.sortValue && isQueryable
357
361
  ? 'none'
358
- : undefined, className: ps_design_system_1.PallasoftClassNameService.merge(densityClassNames[density].head, alignClassNames[align], placementOf(column, columnIndex), 'whitespace-nowrap'), scope: 'col', style: columnStyle(column), children: column.sortValue && isQueryable ? ((0, jsx_runtime_1.jsx)(ps_table_sort_header_1.PsTableSortHeader, { align: align, columnId: column.id, label: column.label, onSort: updateSort, sort: sort })) : (column.label) }, column.id));
362
+ : undefined, className: ps_design_system_1.PallasoftClassNameService.merge(densityClassNames[density].head, alignClassNames[align], placementOf(column, columnIndex), 'whitespace-nowrap'), scope: 'col', style: columnStyle(column, fittedWidths.get(column.id)), children: column.sortValue && isQueryable ? ((0, jsx_runtime_1.jsx)(ps_table_sort_header_1.PsTableSortHeader, { align: align, columnId: column.id, label: column.label, onSort: updateSort, sort: sort })) : (column.label) }, column.id));
359
363
  })] }) }), (0, jsx_runtime_1.jsxs)("tbody", { className: 'divide-y divide-line', ref: bodyRef, children: [visibleRows.length === 0 && isSearching ? ((0, jsx_runtime_1.jsx)("tr", { children: (0, jsx_runtime_1.jsx)("td", { className: 'p-0', colSpan: columnCount, children: (0, jsx_runtime_1.jsx)(ps_table_searching_state_1.PsTableSearchingState, { label: searchingLabel, skeletonRows: table_config_1.PsTableConfig.searchingSkeletonRows }) }) })) : null, visibleRows.length === 0 && isQueried && !isSearching ? ((0, jsx_runtime_1.jsx)("tr", { children: (0, jsx_runtime_1.jsxs)("td", { className: 'px-4 py-12 text-center', colSpan: columnCount, 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)("p", { className: 'mt-1 text-sm text-ink/55', children: table_config_1.PsTableConfig.noMatchesDescription }), (0, jsx_runtime_1.jsx)("button", { className: ps_design_system_1.PallasoftClassNameService.merge(ps_table_control_classes_1.PsTableControlClasses.textButton, 'mt-3 text-primary hover:underline'), onClick: clearFilters, type: 'button', children: "Clear search and filters" })] }) })) : null, grouping
360
364
  ? groups.map((group, groupIndex) => {
361
365
  const isExpanded = isGroupExpanded(group.key, groupIndex);
@@ -38,9 +38,9 @@ const densityClassNames = {
38
38
  head: 'px-5 py-3.5',
39
39
  },
40
40
  };
41
- const columnStyle = (column) => ({
42
- maxWidth: PsTableColumnSizeService.maxWidthOf(column),
43
- minWidth: PsTableColumnSizeService.minWidthOf(column),
41
+ const columnStyle = (column, fittedMinWidth) => ({
42
+ maxWidth: column.measure === undefined ? PsTableColumnSizeService.maxWidthOf(column) : undefined,
43
+ minWidth: fittedMinWidth === undefined ? PsTableColumnSizeService.minWidthOf(column) : fittedMinWidth,
44
44
  width: column.width,
45
45
  });
46
46
  const alignClassNames = {
@@ -59,6 +59,9 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
59
59
  const currentQuery = query ? query : uncontrolledQuery;
60
60
  const { filters, hiddenColumnIds, search, sort } = currentQuery;
61
61
  const visibleColumns = columns.filter((column) => !hiddenColumnIds.includes(column.id));
62
+ const fittedWidths = useMemo(() => new Map(columns
63
+ .filter((column) => column.measure !== undefined)
64
+ .map((column) => [column.id, PsTableColumnSizeService.fittedMinWidthOf(column, rows)])), [columns, rows]);
62
65
  const updateQuery = (patch) => {
63
66
  const next = { ...currentQuery, ...patch };
64
67
  if (!query)
@@ -287,10 +290,11 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
287
290
  }
288
291
  : undefined, style: motion && motion.delayMs !== undefined
289
292
  ? { animationDelay: `${motion.delayMs}ms` }
290
- : undefined, tabIndex: onRowClick ? 0 : undefined, children: [reorder && !api.isActive ? (_jsx("td", { className: PallasoftClassNameService.merge('w-9 min-w-9 pl-3 pr-0', pins.reorder) })) : null, isSelectable ? (_jsx("td", { className: PallasoftClassNameService.merge('w-10 min-w-10 pl-4 pr-0', pins.select), onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: _jsx(PsCheckbox, { isSelected: selectedIdSet.has(rowId), label: `Select ${rowLabel}`, onChange: () => toggleRow(rowId) }) })) : null, visibleColumns.map((column, columnIndex) => (_jsx("td", { className: PallasoftClassNameService.merge(densityClassNames[density].cell, placementOf(column, columnIndex), alignClassNames[column.align !== null && column.align !== undefined ? column.align : 'left'], column.wrap ? '' : 'whitespace-nowrap', (layout === 'fixed' && !column.wrap) ||
291
- PsTableColumnSizeService.maxWidthOf(column) !== undefined
293
+ : undefined, tabIndex: onRowClick ? 0 : undefined, children: [reorder && !api.isActive ? (_jsx("td", { className: PallasoftClassNameService.merge('w-9 min-w-9 pl-3 pr-0', pins.reorder) })) : null, isSelectable ? (_jsx("td", { className: PallasoftClassNameService.merge('w-10 min-w-10 pl-4 pr-0', pins.select), onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: _jsx(PsCheckbox, { isSelected: selectedIdSet.has(rowId), label: `Select ${rowLabel}`, onChange: () => toggleRow(rowId) }) })) : null, visibleColumns.map((column, columnIndex) => (_jsx("td", { className: PallasoftClassNameService.merge(densityClassNames[density].cell, placementOf(column, columnIndex), alignClassNames[column.align !== null && column.align !== undefined ? column.align : 'left'], column.wrap ? '' : 'whitespace-nowrap', column.measure === undefined &&
294
+ ((layout === 'fixed' && !column.wrap) ||
295
+ PsTableColumnSizeService.maxWidthOf(column) !== undefined)
292
296
  ? 'truncate'
293
- : '', '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));
297
+ : '', 'text-sm text-ink'), style: columnStyle(column, fittedWidths.get(column.id)), 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));
294
298
  };
295
299
  const renderEntries = (api, entries) => reorder
296
300
  ? PsTableReorderService.runs(entries, (entry) => reorderKey(entry.row), (entry) => getRowId(entry.row)).map((run) => api.run(run.id, run.items.map((entry) => getRowId(entry.row)), run.items.map((entry) => renderRow(api, entry.row, entry.motion, entry.virtualItem))))
@@ -319,7 +323,7 @@ export const PsDataTable = ({ caption, className, columns, defaultSort, density
319
323
  ? sort.direction
320
324
  : column.sortValue && isQueryable
321
325
  ? 'none'
322
- : undefined, className: PallasoftClassNameService.merge(densityClassNames[density].head, alignClassNames[align], placementOf(column, columnIndex), 'whitespace-nowrap'), scope: 'col', style: columnStyle(column), children: column.sortValue && isQueryable ? (_jsx(PsTableSortHeader, { align: align, columnId: column.id, label: column.label, onSort: updateSort, sort: sort })) : (column.label) }, column.id));
326
+ : undefined, className: PallasoftClassNameService.merge(densityClassNames[density].head, alignClassNames[align], placementOf(column, columnIndex), 'whitespace-nowrap'), scope: 'col', style: columnStyle(column, fittedWidths.get(column.id)), children: column.sortValue && isQueryable ? (_jsx(PsTableSortHeader, { align: align, columnId: column.id, label: column.label, onSort: updateSort, sort: sort })) : (column.label) }, column.id));
323
327
  })] }) }), _jsxs("tbody", { className: 'divide-y divide-line', ref: bodyRef, children: [visibleRows.length === 0 && isSearching ? (_jsx("tr", { children: _jsx("td", { className: 'p-0', colSpan: columnCount, children: _jsx(PsTableSearchingState, { label: searchingLabel, skeletonRows: PsTableConfig.searchingSkeletonRows }) }) })) : null, visibleRows.length === 0 && isQueried && !isSearching ? (_jsx("tr", { children: _jsxs("td", { className: 'px-4 py-12 text-center', colSpan: columnCount, children: [_jsx("p", { className: 'text-sm font-semibold text-ink', children: PsTableConfig.noMatchesTitle }), _jsx("p", { className: 'mt-1 text-sm text-ink/55', children: PsTableConfig.noMatchesDescription }), _jsx("button", { className: PallasoftClassNameService.merge(PsTableControlClasses.textButton, 'mt-3 text-primary hover:underline'), onClick: clearFilters, type: 'button', children: "Clear search and filters" })] }) })) : null, grouping
324
328
  ? groups.map((group, groupIndex) => {
325
329
  const isExpanded = isGroupExpanded(group.key, groupIndex);
@@ -1,6 +1,13 @@
1
1
  import { PsTableColumnMaxWidths, PsTableColumnSize, PsTableColumnWidths, } from '../constants/table-column-size';
2
2
  import { PsTableFilterKind } from '../constants/table-filter-kind';
3
3
  export class PsTableColumnSizeService {
4
+ static fittedMinWidthOf(column, rows) {
5
+ const measure = column.measure;
6
+ if (measure === undefined)
7
+ return undefined;
8
+ const longest = rows.reduce((length, row) => Math.max(length, measure(row).length), 0);
9
+ return `max(${PsTableColumnSizeService.minWidthOf(column)}, calc(${(longest * 1.1).toFixed(1)}ch + 3rem))`;
10
+ }
4
11
  static sizeOf(column) {
5
12
  if (column.size !== undefined)
6
13
  return column.size;
@@ -14,6 +14,8 @@ export interface PsTableColumn<RowData> {
14
14
  hideOnCards?: boolean;
15
15
  id: string;
16
16
  label: string;
17
+ /** Formatted text of the cell (for example the money string). The column is widened to fit the longest value, so numbers never truncate. */
18
+ measure?: (row: RowData) => string;
17
19
  minWidth?: string;
18
20
  pinEnd?: boolean;
19
21
  render: (row: RowData) => ReactNode;
@@ -1,6 +1,7 @@
1
1
  import { PsTableColumnSize } from '../constants/table-column-size';
2
2
  import type { PsTableColumn } from '../interfaces/table-column';
3
3
  export declare class PsTableColumnSizeService {
4
+ static fittedMinWidthOf<RowData>(column: PsTableColumn<RowData>, rows: RowData[]): string | undefined;
4
5
  static sizeOf<RowData>(column: PsTableColumn<RowData>): PsTableColumnSize;
5
6
  static minWidthOf<RowData>(column: PsTableColumn<RowData>): string;
6
7
  static maxWidthOf<RowData>(column: PsTableColumn<RowData>): string | undefined;
@@ -4,6 +4,13 @@ exports.PsTableColumnSizeService = void 0;
4
4
  const table_column_size_1 = require("../constants/table-column-size");
5
5
  const table_filter_kind_1 = require("../constants/table-filter-kind");
6
6
  class PsTableColumnSizeService {
7
+ static fittedMinWidthOf(column, rows) {
8
+ const measure = column.measure;
9
+ if (measure === undefined)
10
+ return undefined;
11
+ const longest = rows.reduce((length, row) => Math.max(length, measure(row).length), 0);
12
+ return `max(${PsTableColumnSizeService.minWidthOf(column)}, calc(${(longest * 1.1).toFixed(1)}ch + 3rem))`;
13
+ }
7
14
  static sizeOf(column) {
8
15
  if (column.size !== undefined)
9
16
  return column.size;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pallasoft/ps-table-components",
3
- "version": "1.23.0",
3
+ "version": "1.24.0",
4
4
  "private": false,
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/esm/index.js",