@dbcdk/react-components 0.0.197 → 0.0.199

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 (68) hide show
  1. package/dist/components/json-viewer/JsonViewer.module.css +53 -0
  2. package/dist/components/json-viewer/JsonViewerShell.cjs +147 -143
  3. package/dist/components/json-viewer/JsonViewerShell.js +149 -145
  4. package/dist/components/line-viewer/LineViewer.cjs +15 -21
  5. package/dist/components/line-viewer/LineViewer.d.ts +1 -1
  6. package/dist/components/line-viewer/LineViewer.js +16 -22
  7. package/dist/components/line-viewer/LineViewer.module.css +58 -3
  8. package/dist/components/page-layout/PageLayout.module.css +1 -1
  9. package/dist/components/scroll-fade/ScrollFade.cjs +42 -0
  10. package/dist/components/scroll-fade/ScrollFade.d.ts +18 -0
  11. package/dist/components/scroll-fade/ScrollFade.js +36 -0
  12. package/dist/components/scroll-fade/ScrollFade.module.css +71 -0
  13. package/dist/components/search-box/SearchBox.cjs +39 -35
  14. package/dist/components/search-box/SearchBox.d.ts +2 -0
  15. package/dist/components/search-box/SearchBox.js +39 -35
  16. package/dist/components/table/Table.cjs +52 -23
  17. package/dist/components/table/Table.d.ts +1 -1
  18. package/dist/components/table/Table.js +53 -24
  19. package/dist/components/table/Table.module.css +4 -0
  20. package/dist/components/table/Table.types.d.ts +27 -0
  21. package/dist/components/table/TanstackTable.cjs +63 -106
  22. package/dist/components/table/TanstackTable.d.ts +5 -0
  23. package/dist/components/table/TanstackTable.js +66 -106
  24. package/dist/components/table/columnLayout.utils.cjs +146 -0
  25. package/dist/components/table/columnLayout.utils.d.ts +44 -0
  26. package/dist/components/table/columnLayout.utils.js +141 -0
  27. package/dist/components/table/components/TableHeader.cjs +3 -1
  28. package/dist/components/table/components/TableHeader.d.ts +2 -1
  29. package/dist/components/table/components/TableHeader.js +3 -1
  30. package/dist/components/table/components/TableHeaderCell.cjs +29 -19
  31. package/dist/components/table/components/TableHeaderCell.d.ts +2 -1
  32. package/dist/components/table/components/TableHeaderCell.js +29 -19
  33. package/dist/components/table/hooks/useClientPagination.cjs +66 -0
  34. package/dist/components/table/hooks/useClientPagination.d.ts +32 -0
  35. package/dist/components/table/hooks/useClientPagination.js +64 -0
  36. package/dist/components/table/hooks/useDistributedLayout.cjs +44 -0
  37. package/dist/components/table/hooks/useDistributedLayout.d.ts +16 -0
  38. package/dist/components/table/hooks/useDistributedLayout.js +42 -0
  39. package/dist/components/table/hooks/useElementWidth.cjs +40 -0
  40. package/dist/components/table/hooks/useElementWidth.d.ts +7 -0
  41. package/dist/components/table/hooks/useElementWidth.js +38 -0
  42. package/dist/components/table/hooks/useResizeHeaderExtras.cjs +87 -0
  43. package/dist/components/table/hooks/useResizeHeaderExtras.d.ts +17 -0
  44. package/dist/components/table/hooks/useResizeHeaderExtras.js +62 -0
  45. package/dist/components/table/hooks/useUiSorting.cjs +18 -0
  46. package/dist/components/table/hooks/useUiSorting.d.ts +3 -0
  47. package/dist/components/table/hooks/useUiSorting.js +16 -0
  48. package/dist/components/table/table.utils.cjs +24 -2
  49. package/dist/components/table/table.utils.d.ts +40 -2
  50. package/dist/components/table/table.utils.js +20 -2
  51. package/dist/components/table/tanstackTable.utils.cjs +33 -97
  52. package/dist/components/table/tanstackTable.utils.d.ts +24 -8
  53. package/dist/components/table/tanstackTable.utils.js +34 -99
  54. package/dist/components/xml-viewer/XmlViewer.cjs +15 -21
  55. package/dist/components/xml-viewer/XmlViewer.d.ts +1 -1
  56. package/dist/components/xml-viewer/XmlViewer.js +16 -22
  57. package/dist/components/xml-viewer/XmlViewer.module.css +58 -3
  58. package/dist/hooks/useScrollOverflow.cjs +71 -0
  59. package/dist/hooks/useScrollOverflow.d.ts +23 -0
  60. package/dist/hooks/useScrollOverflow.js +69 -0
  61. package/dist/hooks/useTableSettings.cjs +2 -1
  62. package/dist/hooks/useTableSettings.d.ts +1 -0
  63. package/dist/hooks/useTableSettings.js +2 -1
  64. package/dist/index.css +1 -0
  65. package/dist/utils/refs.utils.cjs +13 -0
  66. package/dist/utils/refs.utils.d.ts +7 -0
  67. package/dist/utils/refs.utils.js +11 -0
  68. package/package.json +1 -1
@@ -0,0 +1,62 @@
1
+ 'use client';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import * as React from 'react';
4
+ import ColumnResizer from '../components/column-resizer/ColumnResizer';
5
+
6
+ function useResizeHeaderExtras({
7
+ table,
8
+ widths,
9
+ actionReservePx,
10
+ neighborResizeRef,
11
+ setColumnSizing
12
+ }) {
13
+ return React.useCallback(
14
+ ({ index }) => {
15
+ var _a, _b, _c, _d;
16
+ const headerGroups = table.getHeaderGroups();
17
+ const leafHeaders = headerGroups.length > 0 ? headerGroups[headerGroups.length - 1].headers : [];
18
+ const header = leafHeaders[index];
19
+ const neighbor = leafHeaders[index + 1];
20
+ if (!header || !neighbor) return null;
21
+ const canResize = (_c = (_b = (_a = header.column).getCanResize) == null ? void 0 : _b.call(_a)) != null ? _c : false;
22
+ const handler = (_d = header.getResizeHandler) == null ? void 0 : _d.call(header);
23
+ if (!canResize || !handler) return null;
24
+ const handleResizeStart = (event) => {
25
+ var _a2, _b2, _c2, _d2;
26
+ const startWidth = widths == null ? void 0 : widths[header.column.id];
27
+ const neighborStartWidth = widths == null ? void 0 : widths[neighbor.column.id];
28
+ if (startWidth == null || neighborStartWidth == null) return;
29
+ const neighborReserve = index + 1 === leafHeaders.length - 1 ? actionReservePx : 0;
30
+ const { columnDef } = header.column;
31
+ const neighborDef = neighbor.column.columnDef;
32
+ neighborResizeRef.current = {
33
+ columnId: header.column.id,
34
+ neighborId: neighbor.column.id,
35
+ // TanStack drags from its own size (columnDef.size), not the width on
36
+ // screen; applyNeighborResize only uses its offset from this.
37
+ tanstackStartWidth: header.getSize(),
38
+ startWidth,
39
+ neighborStartWidth,
40
+ min: (_a2 = columnDef.minSize) != null ? _a2 : 0,
41
+ max: (_b2 = columnDef.maxSize) != null ? _b2 : Infinity,
42
+ neighborMin: ((_c2 = neighborDef.minSize) != null ? _c2 : 0) + neighborReserve,
43
+ neighborMax: ((_d2 = neighborDef.maxSize) != null ? _d2 : Infinity) + neighborReserve
44
+ };
45
+ const displayedWidths = widths != null ? widths : {};
46
+ setColumnSizing(
47
+ (prev) => Object.fromEntries(
48
+ Object.entries(prev).map(([id, width]) => {
49
+ var _a3;
50
+ return [id, (_a3 = displayedWidths[id]) != null ? _a3 : width];
51
+ })
52
+ )
53
+ );
54
+ handler(event);
55
+ };
56
+ return /* @__PURE__ */ jsx(ColumnResizer, { id: header.column.id, handler: handleResizeStart });
57
+ },
58
+ [table, widths, actionReservePx, neighborResizeRef, setColumnSizing]
59
+ );
60
+ }
61
+
62
+ export { useResizeHeaderExtras };
@@ -0,0 +1,18 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ var react = require('react');
5
+ var tanstackTable_utils = require('../tanstackTable.utils');
6
+
7
+ function useUiSorting(controlledSorting) {
8
+ const isControlled = controlledSorting != null;
9
+ const [uiSorting, setUiSorting] = react.useState(controlledSorting != null ? controlledSorting : []);
10
+ react.useEffect(() => {
11
+ if (!isControlled) return;
12
+ if (tanstackTable_utils.sortingEqual(uiSorting, controlledSorting)) return;
13
+ setUiSorting(controlledSorting);
14
+ }, [isControlled, controlledSorting, uiSorting]);
15
+ return [uiSorting, setUiSorting];
16
+ }
17
+
18
+ exports.useUiSorting = useUiSorting;
@@ -0,0 +1,3 @@
1
+ import type { SortingState } from '@tanstack/react-table';
2
+ /** Sorting shown in the header; follows `controlledSorting` when given, but can be set ahead of it. */
3
+ export declare function useUiSorting(controlledSorting: SortingState | undefined): readonly [SortingState, import("react").Dispatch<import("react").SetStateAction<SortingState>>];
@@ -0,0 +1,16 @@
1
+ 'use client';
2
+ import { useState, useEffect } from 'react';
3
+ import { sortingEqual } from '../tanstackTable.utils';
4
+
5
+ function useUiSorting(controlledSorting) {
6
+ const isControlled = controlledSorting != null;
7
+ const [uiSorting, setUiSorting] = useState(controlledSorting != null ? controlledSorting : []);
8
+ useEffect(() => {
9
+ if (!isControlled) return;
10
+ if (sortingEqual(uiSorting, controlledSorting)) return;
11
+ setUiSorting(controlledSorting);
12
+ }, [isControlled, controlledSorting, uiSorting]);
13
+ return [uiSorting, setUiSorting];
14
+ }
15
+
16
+ export { useUiSorting };
@@ -1,9 +1,27 @@
1
1
  'use strict';
2
2
 
3
3
  const SELECTION_COLUMN_PX = 32;
4
- const ACTIONS_COLUMN_PX = 0;
4
+ const HEADER_ACTIONS_RESERVE_PX = 20;
5
5
  const ROW_ACTIONS_RESERVE_PX = 32;
6
6
  const DEFAULT_COLUMN_PX = 150;
7
+ const DEFAULT_VIEW_MODE = "wrapped";
8
+ function showsExpandToggle(expandableRows, viewMode) {
9
+ return Boolean(expandableRows) && viewMode !== "wrapped";
10
+ }
11
+ function reservesRowActionsSpace(args) {
12
+ return args.hasRowActions || args.showHeader && args.hasHeaderActions;
13
+ }
14
+ function getActionsReserve(args) {
15
+ const { hasRowActions, hasSettings, hasOtherHeaderActions, showHeader } = args;
16
+ const reserves = reservesRowActionsSpace({
17
+ hasRowActions,
18
+ hasHeaderActions: hasSettings || hasOtherHeaderActions,
19
+ showHeader
20
+ });
21
+ if (!reserves) return { px: 0, compactHeader: false };
22
+ const compactHeader = showHeader && hasSettings && !hasOtherHeaderActions && !hasRowActions;
23
+ return { px: compactHeader ? HEADER_ACTIONS_RESERVE_PX : ROW_ACTIONS_RESERVE_PX, compactHeader };
24
+ }
7
25
  function getVisibleColumns(columns) {
8
26
  return columns.filter((column) => !column.hidden);
9
27
  }
@@ -46,10 +64,12 @@ function getCellDisplayValue(row, column) {
46
64
  return empty;
47
65
  }
48
66
 
49
- exports.ACTIONS_COLUMN_PX = ACTIONS_COLUMN_PX;
50
67
  exports.DEFAULT_COLUMN_PX = DEFAULT_COLUMN_PX;
68
+ exports.DEFAULT_VIEW_MODE = DEFAULT_VIEW_MODE;
69
+ exports.HEADER_ACTIONS_RESERVE_PX = HEADER_ACTIONS_RESERVE_PX;
51
70
  exports.ROW_ACTIONS_RESERVE_PX = ROW_ACTIONS_RESERVE_PX;
52
71
  exports.SELECTION_COLUMN_PX = SELECTION_COLUMN_PX;
72
+ exports.getActionsReserve = getActionsReserve;
53
73
  exports.getAriaSort = getAriaSort;
54
74
  exports.getCellDisplayValue = getCellDisplayValue;
55
75
  exports.getHeaderLabel = getHeaderLabel;
@@ -57,5 +77,7 @@ exports.getNextSortDirection = getNextSortDirection;
57
77
  exports.getVisibleColumns = getVisibleColumns;
58
78
  exports.isActiveSort = isActiveSort;
59
79
  exports.isModifierClick = isModifierClick;
80
+ exports.reservesRowActionsSpace = reservesRowActionsSpace;
60
81
  exports.shouldAllowWrap = shouldAllowWrap;
61
82
  exports.shouldToggleOnKey = shouldToggleOnKey;
83
+ exports.showsExpandToggle = showsExpandToggle;
@@ -1,7 +1,13 @@
1
1
  import type { ReactNode } from 'react';
2
- import type { ColumnItem } from './Table.types';
2
+ import type { ColumnItem, ViewMode } from './Table.types';
3
3
  export declare const SELECTION_COLUMN_PX: 32;
4
- export declare const ACTIONS_COLUMN_PX: 0;
4
+ /**
5
+ * Smaller reserve used when the only action is the header's settings button:
6
+ * the button overlaps the header cell's own padding. Must match
7
+ * `.thMainWithHeaderActionsReserve` in Table.module.css
8
+ * (component-size-sm 30px - spacing-sm 12px + spacing-2xs 2px).
9
+ */
10
+ export declare const HEADER_ACTIONS_RESERVE_PX: 20;
5
11
  /**
6
12
  * Space kept free at the inline end of the last column for the row actions
7
13
  * button and header actions. Must match `--table-row-actions-reserve-inline`
@@ -9,7 +15,39 @@ export declare const ACTIONS_COLUMN_PX: 0;
9
15
  */
10
16
  export declare const ROW_ACTIONS_RESERVE_PX: 32;
11
17
  export declare const DEFAULT_COLUMN_PX: 150;
18
+ /** View mode when neither the `viewMode` prop nor table settings set one. */
19
+ export declare const DEFAULT_VIEW_MODE: ViewMode;
20
+ /**
21
+ * Whether rows show the expand toggle: only in compact mode, since wrapped
22
+ * rows already show their full content.
23
+ */
24
+ export declare function showsExpandToggle(expandableRows: boolean | undefined, viewMode: ViewMode): boolean;
12
25
  export type SortDirection = 'asc' | 'desc' | null;
26
+ /**
27
+ * Whether the last column reserves `ROW_ACTIONS_RESERVE_PX` at its inline end:
28
+ * row actions (context menu, expand toggle) always do, header actions (e.g.
29
+ * the settings menu) only while the header row that holds them is shown.
30
+ */
31
+ export declare function reservesRowActionsSpace(args: {
32
+ hasRowActions: boolean;
33
+ hasHeaderActions: boolean;
34
+ showHeader: boolean;
35
+ }): boolean;
36
+ /**
37
+ * How much space the last column reserves for actions: none, the smaller
38
+ * `HEADER_ACTIONS_RESERVE_PX` when the header's settings button is the only
39
+ * action, or the full `ROW_ACTIONS_RESERVE_PX`. Shared by Table and
40
+ * TanstackTable so the computed widths match the header's padding.
41
+ */
42
+ export declare function getActionsReserve(args: {
43
+ hasRowActions: boolean;
44
+ hasSettings: boolean;
45
+ hasOtherHeaderActions: boolean;
46
+ showHeader: boolean;
47
+ }): {
48
+ px: number;
49
+ compactHeader: boolean;
50
+ };
13
51
  export declare function getVisibleColumns<T>(columns: Array<ColumnItem<T>>): Array<ColumnItem<T>>;
14
52
  export declare function getHeaderLabel(header: string | (() => ReactNode)): ReactNode;
15
53
  export declare function isActiveSort(sortById: string | undefined, columnId: string): boolean;
@@ -1,7 +1,25 @@
1
1
  const SELECTION_COLUMN_PX = 32;
2
- const ACTIONS_COLUMN_PX = 0;
2
+ const HEADER_ACTIONS_RESERVE_PX = 20;
3
3
  const ROW_ACTIONS_RESERVE_PX = 32;
4
4
  const DEFAULT_COLUMN_PX = 150;
5
+ const DEFAULT_VIEW_MODE = "wrapped";
6
+ function showsExpandToggle(expandableRows, viewMode) {
7
+ return Boolean(expandableRows) && viewMode !== "wrapped";
8
+ }
9
+ function reservesRowActionsSpace(args) {
10
+ return args.hasRowActions || args.showHeader && args.hasHeaderActions;
11
+ }
12
+ function getActionsReserve(args) {
13
+ const { hasRowActions, hasSettings, hasOtherHeaderActions, showHeader } = args;
14
+ const reserves = reservesRowActionsSpace({
15
+ hasRowActions,
16
+ hasHeaderActions: hasSettings || hasOtherHeaderActions,
17
+ showHeader
18
+ });
19
+ if (!reserves) return { px: 0, compactHeader: false };
20
+ const compactHeader = showHeader && hasSettings && !hasOtherHeaderActions && !hasRowActions;
21
+ return { px: compactHeader ? HEADER_ACTIONS_RESERVE_PX : ROW_ACTIONS_RESERVE_PX, compactHeader };
22
+ }
5
23
  function getVisibleColumns(columns) {
6
24
  return columns.filter((column) => !column.hidden);
7
25
  }
@@ -44,4 +62,4 @@ function getCellDisplayValue(row, column) {
44
62
  return empty;
45
63
  }
46
64
 
47
- export { ACTIONS_COLUMN_PX, DEFAULT_COLUMN_PX, ROW_ACTIONS_RESERVE_PX, SELECTION_COLUMN_PX, getAriaSort, getCellDisplayValue, getHeaderLabel, getNextSortDirection, getVisibleColumns, isActiveSort, isModifierClick, shouldAllowWrap, shouldToggleOnKey };
65
+ export { DEFAULT_COLUMN_PX, DEFAULT_VIEW_MODE, HEADER_ACTIONS_RESERVE_PX, ROW_ACTIONS_RESERVE_PX, SELECTION_COLUMN_PX, getActionsReserve, getAriaSort, getCellDisplayValue, getHeaderLabel, getNextSortDirection, getVisibleColumns, isActiveSort, isModifierClick, reservesRowActionsSpace, shouldAllowWrap, shouldToggleOnKey, showsExpandToggle };
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var columnLayout_utils = require('./columnLayout.utils');
3
4
  var table_utils = require('./table.utils');
4
5
 
5
6
  function getColumnId(def, index) {
@@ -74,124 +75,59 @@ function getSortPropsFromSorting(sorting) {
74
75
  };
75
76
  }
76
77
  function clamp(value, min, max) {
77
- const lowerBounded = Math.max(min, value);
78
- if (max == null || !Number.isFinite(max)) return lowerBounded;
79
- return Math.min(lowerBounded, max);
78
+ return Math.min(Math.max(value, min), max);
80
79
  }
81
- function toIntegerTrackWidths(tracks, targetWidth) {
82
- const floored = tracks.map((track) => ({
83
- id: track.id,
84
- width: Math.floor(track.width),
85
- fraction: track.width - Math.floor(track.width)
86
- }));
87
- const baseTotal = floored.reduce((sum, track) => sum + track.width, 0);
88
- let remainder = Math.max(0, targetWidth - baseTotal);
89
- floored.slice().sort((a, b) => b.fraction - a.fraction).forEach((track) => {
90
- if (remainder <= 0) return;
91
- track.width += 1;
92
- remainder -= 1;
93
- });
94
- return Object.fromEntries(floored.map((track) => [track.id, track.width]));
80
+ function applyNeighborResize(next, resize) {
81
+ const proposed = next[resize.columnId];
82
+ if (proposed == null) return next;
83
+ const total = resize.startWidth + resize.neighborStartWidth;
84
+ const min = Math.min(resize.min, resize.startWidth);
85
+ const max = Math.max(resize.max, resize.startWidth);
86
+ const neighborMin = Math.min(resize.neighborMin, resize.neighborStartWidth);
87
+ const neighborMax = Math.max(resize.neighborMax, resize.neighborStartWidth);
88
+ const width = Math.round(
89
+ clamp(
90
+ resize.startWidth + proposed - resize.tanstackStartWidth,
91
+ Math.max(min, total - neighborMax),
92
+ Math.min(max, total - neighborMin)
93
+ )
94
+ );
95
+ return { ...next, [resize.columnId]: width, [resize.neighborId]: total - width };
95
96
  }
96
97
  function buildDistributedColumnWidths(args) {
97
98
  const {
98
99
  table,
99
100
  hasSelection,
100
- hasContextMenu = false,
101
+ hasContextMenu,
102
+ contextMenuReservePx = table_utils.ROW_ACTIONS_RESERVE_PX,
101
103
  defaultMinPx,
102
104
  columnSizing,
103
105
  availableWidth
104
106
  } = args;
105
- const leaf = table.getVisibleLeafColumns();
106
- const selectionWidth = hasSelection ? table_utils.SELECTION_COLUMN_PX : 0;
107
- const contextMenuWidth = hasContextMenu ? 0 : 0;
108
- const tracks = leaf.map((c) => {
107
+ const visibleColumns = table.getVisibleLeafColumns();
108
+ const tracks = visibleColumns.map((c, index) => {
109
109
  var _a, _b, _c, _d;
110
110
  const def = c.columnDef;
111
111
  const meta = (_a = def.meta) != null ? _a : {};
112
112
  const min = Math.max(1, Number((_b = def.minSize) != null ? _b : defaultMinPx));
113
113
  const max = def.maxSize != null ? Math.max(min, Number(def.maxSize)) : void 0;
114
114
  const resizedPxRaw = columnSizing[c.id];
115
- const resizedPx = resizedPxRaw != null ? Math.round(clamp(Number(resizedPxRaw), min, max)) : void 0;
116
- if (resizedPx != null) {
117
- return {
118
- id: c.id,
119
- width: resizedPx,
120
- weight: 0,
121
- min,
122
- max: resizedPx,
123
- fixed: true
124
- };
125
- }
115
+ const reserve = hasContextMenu && index === visibleColumns.length - 1 ? contextMenuReservePx : 0;
116
+ const fixedWidth = resizedPxRaw != null ? Math.round(clamp(Number(resizedPxRaw), min + reserve, (max != null ? max : Infinity) + reserve)) : void 0;
126
117
  const rawWeight = Number((_d = (_c = meta.weight) != null ? _c : def.size) != null ? _d : table_utils.DEFAULT_COLUMN_PX);
127
118
  const weight = Number.isFinite(rawWeight) && rawWeight > 0 ? rawWeight : table_utils.DEFAULT_COLUMN_PX;
128
- return {
129
- id: c.id,
130
- width: min,
131
- weight,
132
- min,
133
- max,
134
- fixed: false
135
- };
119
+ return { id: c.id, min, max, weight, fixedWidth };
120
+ });
121
+ return columnLayout_utils.distributeColumnWidths({
122
+ tracks,
123
+ hasSelection,
124
+ hasContextMenu,
125
+ contextMenuReservePx,
126
+ availableWidth
136
127
  });
137
- const lastTrack = tracks[tracks.length - 1];
138
- if (hasContextMenu && lastTrack && !lastTrack.fixed) {
139
- lastTrack.min += table_utils.ROW_ACTIONS_RESERVE_PX;
140
- lastTrack.width += table_utils.ROW_ACTIONS_RESERVE_PX;
141
- if (lastTrack.max != null) lastTrack.max += table_utils.ROW_ACTIONS_RESERVE_PX;
142
- }
143
- const fixedWidth = selectionWidth + contextMenuWidth + tracks.reduce((sum, track) => sum + track.width, 0);
144
- let remaining = Math.max(0, availableWidth - fixedWidth);
145
- let active = tracks.filter(
146
- (track) => !track.fixed && (track.max == null || track.width < track.max)
147
- );
148
- while (remaining > 0.5 && active.length > 0) {
149
- const totalWeight = active.reduce((sum, track) => sum + track.weight, 0);
150
- if (totalWeight <= 0) break;
151
- let consumed = 0;
152
- const nextActive = [];
153
- for (const track of active) {
154
- const share = remaining * track.weight / totalWeight;
155
- const maxGrow = track.max == null ? share : Math.max(0, track.max - track.width);
156
- const growth = Math.min(share, maxGrow);
157
- track.width += growth;
158
- consumed += growth;
159
- if (track.max == null || track.width < track.max - 0.5) {
160
- nextActive.push(track);
161
- }
162
- }
163
- if (consumed <= 0.5) break;
164
- remaining -= consumed;
165
- active = nextActive;
166
- }
167
- const flexible = tracks.filter((track) => !track.fixed);
168
- if (remaining > 0.5 && flexible.length > 0 && flexible.every((track) => track.max != null)) {
169
- const stretchable = flexible.filter((track) => track.max > track.min);
170
- const totalWeight = stretchable.reduce((sum, track) => sum + track.weight, 0);
171
- if (totalWeight > 0) {
172
- for (const track of stretchable) {
173
- track.width += remaining * track.weight / totalWeight;
174
- }
175
- }
176
- }
177
- const floatTrackTotal = tracks.reduce((sum, track) => sum + track.width, 0);
178
- const maxTrackWidth = availableWidth - selectionWidth - contextMenuWidth;
179
- const targetTrackWidth = Math.min(
180
- floatTrackTotal <= maxTrackWidth ? Math.floor(floatTrackTotal) : Math.ceil(floatTrackTotal),
181
- maxTrackWidth
182
- );
183
- const widths = toIntegerTrackWidths(tracks, targetTrackWidth);
184
- const totalWidth = selectionWidth + contextMenuWidth + Object.values(widths).reduce((sum, width) => sum + width, 0);
185
- return {
186
- selectionWidth: hasSelection ? table_utils.SELECTION_COLUMN_PX : void 0,
187
- contextMenuWidth: hasContextMenu ? 0 : void 0,
188
- widths,
189
- totalWidth,
190
- availableWidth,
191
- shouldOverflow: totalWidth > availableWidth
192
- };
193
128
  }
194
129
 
130
+ exports.applyNeighborResize = applyNeighborResize;
195
131
  exports.buildColumnVisibilityFromVisibleIds = buildColumnVisibilityFromVisibleIds;
196
132
  exports.buildDistributedColumnWidths = buildDistributedColumnWidths;
197
133
  exports.getColumnId = getColumnId;
@@ -1,4 +1,5 @@
1
1
  import type { ColumnDef, ColumnSizingState, SortingState, VisibilityState } from '@tanstack/react-table';
2
+ import { type DistributedColumnWidths } from './columnLayout.utils';
2
3
  import { ColumnItem } from './Table.types';
3
4
  type AnyRecord = Record<string, any>;
4
5
  export declare function getColumnId<T>(def: ColumnDef<T, any>, index: number): string;
@@ -11,19 +12,34 @@ export declare function getSortPropsFromSorting(sorting: SortingState): {
11
12
  sortById?: string;
12
13
  sortDirection: 'asc' | 'desc' | null;
13
14
  };
15
+ /** The two columns a drag moves width between, as captured on resize start. */
16
+ export type NeighborResize = {
17
+ columnId: string;
18
+ neighborId: string;
19
+ /** TanStack's own start size; its updates are this plus the drag offset. */
20
+ tanstackStartWidth: number;
21
+ startWidth: number;
22
+ neighborStartWidth: number;
23
+ min: number;
24
+ max: number;
25
+ neighborMin: number;
26
+ neighborMax: number;
27
+ };
28
+ /**
29
+ * Applies a TanStack resize update as a move of width between the dragged
30
+ * column and its right neighbour, so their sum (and every other column) stays
31
+ * put. Both columns stay within their bounds, widened to their start widths
32
+ * so a column already outside its bounds doesn't jump when grabbed.
33
+ */
34
+ export declare function applyNeighborResize(next: ColumnSizingState, resize: NeighborResize): ColumnSizingState;
14
35
  export declare function buildDistributedColumnWidths(args: {
15
36
  table: any;
16
37
  hasSelection: boolean;
17
38
  hasContextMenu?: boolean;
39
+ /** Space the last column reserves for actions; see `getActionsReserve`. */
40
+ contextMenuReservePx?: number;
18
41
  defaultMinPx: number;
19
42
  columnSizing: ColumnSizingState;
20
43
  availableWidth: number;
21
- }): {
22
- selectionWidth?: number;
23
- contextMenuWidth?: number;
24
- widths: Record<string, number>;
25
- totalWidth: number;
26
- availableWidth: number;
27
- shouldOverflow: boolean;
28
- };
44
+ }): DistributedColumnWidths;
29
45
  export {};
@@ -1,4 +1,5 @@
1
- import { DEFAULT_COLUMN_PX, ROW_ACTIONS_RESERVE_PX, SELECTION_COLUMN_PX } from './table.utils';
1
+ import { distributeColumnWidths } from './columnLayout.utils';
2
+ import { ROW_ACTIONS_RESERVE_PX, DEFAULT_COLUMN_PX } from './table.utils';
2
3
 
3
4
  function getColumnId(def, index) {
4
5
  const d = def;
@@ -72,122 +73,56 @@ function getSortPropsFromSorting(sorting) {
72
73
  };
73
74
  }
74
75
  function clamp(value, min, max) {
75
- const lowerBounded = Math.max(min, value);
76
- if (max == null || !Number.isFinite(max)) return lowerBounded;
77
- return Math.min(lowerBounded, max);
76
+ return Math.min(Math.max(value, min), max);
78
77
  }
79
- function toIntegerTrackWidths(tracks, targetWidth) {
80
- const floored = tracks.map((track) => ({
81
- id: track.id,
82
- width: Math.floor(track.width),
83
- fraction: track.width - Math.floor(track.width)
84
- }));
85
- const baseTotal = floored.reduce((sum, track) => sum + track.width, 0);
86
- let remainder = Math.max(0, targetWidth - baseTotal);
87
- floored.slice().sort((a, b) => b.fraction - a.fraction).forEach((track) => {
88
- if (remainder <= 0) return;
89
- track.width += 1;
90
- remainder -= 1;
91
- });
92
- return Object.fromEntries(floored.map((track) => [track.id, track.width]));
78
+ function applyNeighborResize(next, resize) {
79
+ const proposed = next[resize.columnId];
80
+ if (proposed == null) return next;
81
+ const total = resize.startWidth + resize.neighborStartWidth;
82
+ const min = Math.min(resize.min, resize.startWidth);
83
+ const max = Math.max(resize.max, resize.startWidth);
84
+ const neighborMin = Math.min(resize.neighborMin, resize.neighborStartWidth);
85
+ const neighborMax = Math.max(resize.neighborMax, resize.neighborStartWidth);
86
+ const width = Math.round(
87
+ clamp(
88
+ resize.startWidth + proposed - resize.tanstackStartWidth,
89
+ Math.max(min, total - neighborMax),
90
+ Math.min(max, total - neighborMin)
91
+ )
92
+ );
93
+ return { ...next, [resize.columnId]: width, [resize.neighborId]: total - width };
93
94
  }
94
95
  function buildDistributedColumnWidths(args) {
95
96
  const {
96
97
  table,
97
98
  hasSelection,
98
- hasContextMenu = false,
99
+ hasContextMenu,
100
+ contextMenuReservePx = ROW_ACTIONS_RESERVE_PX,
99
101
  defaultMinPx,
100
102
  columnSizing,
101
103
  availableWidth
102
104
  } = args;
103
- const leaf = table.getVisibleLeafColumns();
104
- const selectionWidth = hasSelection ? SELECTION_COLUMN_PX : 0;
105
- const contextMenuWidth = hasContextMenu ? 0 : 0;
106
- const tracks = leaf.map((c) => {
105
+ const visibleColumns = table.getVisibleLeafColumns();
106
+ const tracks = visibleColumns.map((c, index) => {
107
107
  var _a, _b, _c, _d;
108
108
  const def = c.columnDef;
109
109
  const meta = (_a = def.meta) != null ? _a : {};
110
110
  const min = Math.max(1, Number((_b = def.minSize) != null ? _b : defaultMinPx));
111
111
  const max = def.maxSize != null ? Math.max(min, Number(def.maxSize)) : void 0;
112
112
  const resizedPxRaw = columnSizing[c.id];
113
- const resizedPx = resizedPxRaw != null ? Math.round(clamp(Number(resizedPxRaw), min, max)) : void 0;
114
- if (resizedPx != null) {
115
- return {
116
- id: c.id,
117
- width: resizedPx,
118
- weight: 0,
119
- min,
120
- max: resizedPx,
121
- fixed: true
122
- };
123
- }
113
+ const reserve = hasContextMenu && index === visibleColumns.length - 1 ? contextMenuReservePx : 0;
114
+ const fixedWidth = resizedPxRaw != null ? Math.round(clamp(Number(resizedPxRaw), min + reserve, (max != null ? max : Infinity) + reserve)) : void 0;
124
115
  const rawWeight = Number((_d = (_c = meta.weight) != null ? _c : def.size) != null ? _d : DEFAULT_COLUMN_PX);
125
116
  const weight = Number.isFinite(rawWeight) && rawWeight > 0 ? rawWeight : DEFAULT_COLUMN_PX;
126
- return {
127
- id: c.id,
128
- width: min,
129
- weight,
130
- min,
131
- max,
132
- fixed: false
133
- };
117
+ return { id: c.id, min, max, weight, fixedWidth };
118
+ });
119
+ return distributeColumnWidths({
120
+ tracks,
121
+ hasSelection,
122
+ hasContextMenu,
123
+ contextMenuReservePx,
124
+ availableWidth
134
125
  });
135
- const lastTrack = tracks[tracks.length - 1];
136
- if (hasContextMenu && lastTrack && !lastTrack.fixed) {
137
- lastTrack.min += ROW_ACTIONS_RESERVE_PX;
138
- lastTrack.width += ROW_ACTIONS_RESERVE_PX;
139
- if (lastTrack.max != null) lastTrack.max += ROW_ACTIONS_RESERVE_PX;
140
- }
141
- const fixedWidth = selectionWidth + contextMenuWidth + tracks.reduce((sum, track) => sum + track.width, 0);
142
- let remaining = Math.max(0, availableWidth - fixedWidth);
143
- let active = tracks.filter(
144
- (track) => !track.fixed && (track.max == null || track.width < track.max)
145
- );
146
- while (remaining > 0.5 && active.length > 0) {
147
- const totalWeight = active.reduce((sum, track) => sum + track.weight, 0);
148
- if (totalWeight <= 0) break;
149
- let consumed = 0;
150
- const nextActive = [];
151
- for (const track of active) {
152
- const share = remaining * track.weight / totalWeight;
153
- const maxGrow = track.max == null ? share : Math.max(0, track.max - track.width);
154
- const growth = Math.min(share, maxGrow);
155
- track.width += growth;
156
- consumed += growth;
157
- if (track.max == null || track.width < track.max - 0.5) {
158
- nextActive.push(track);
159
- }
160
- }
161
- if (consumed <= 0.5) break;
162
- remaining -= consumed;
163
- active = nextActive;
164
- }
165
- const flexible = tracks.filter((track) => !track.fixed);
166
- if (remaining > 0.5 && flexible.length > 0 && flexible.every((track) => track.max != null)) {
167
- const stretchable = flexible.filter((track) => track.max > track.min);
168
- const totalWeight = stretchable.reduce((sum, track) => sum + track.weight, 0);
169
- if (totalWeight > 0) {
170
- for (const track of stretchable) {
171
- track.width += remaining * track.weight / totalWeight;
172
- }
173
- }
174
- }
175
- const floatTrackTotal = tracks.reduce((sum, track) => sum + track.width, 0);
176
- const maxTrackWidth = availableWidth - selectionWidth - contextMenuWidth;
177
- const targetTrackWidth = Math.min(
178
- floatTrackTotal <= maxTrackWidth ? Math.floor(floatTrackTotal) : Math.ceil(floatTrackTotal),
179
- maxTrackWidth
180
- );
181
- const widths = toIntegerTrackWidths(tracks, targetTrackWidth);
182
- const totalWidth = selectionWidth + contextMenuWidth + Object.values(widths).reduce((sum, width) => sum + width, 0);
183
- return {
184
- selectionWidth: hasSelection ? SELECTION_COLUMN_PX : void 0,
185
- contextMenuWidth: hasContextMenu ? 0 : void 0,
186
- widths,
187
- totalWidth,
188
- availableWidth,
189
- shouldOverflow: totalWidth > availableWidth
190
- };
191
126
  }
192
127
 
193
- export { buildColumnVisibilityFromVisibleIds, buildDistributedColumnWidths, getColumnId, getSortPropsFromSorting, mapDefsToColumnItems, sortingEqual };
128
+ export { applyNeighborResize, buildColumnVisibilityFromVisibleIds, buildDistributedColumnWidths, getColumnId, getSortPropsFromSorting, mapDefsToColumnItems, sortingEqual };