diff --git a/scripts/large-table-column-resize.js b/scripts/large-table-column-resize.js
index 791657a..ef73133 100644
--- a/scripts/large-table-column-resize.js
+++ b/scripts/large-table-column-resize.js
@@ -1,6 +1,6 @@
(function initLargeTableColumnResizeModule() {
const STORAGE_PREFIX = 'sg:large-table:column-widths:';
- const STORAGE_VERSION = 2;
+ const STORAGE_VERSION = 3;
const DEFAULT_MIN_WIDTH = 128;
const KEYBOARD_STEP = 8;
const KEYBOARD_LARGE_STEP = 40;
@@ -44,41 +44,27 @@
return value;
};
- const getGridTrackWidth = (table) => {
- const row = table.querySelector('[data-component-part="large-table-header-row"]');
- if (!row) {
- return table.clientWidth;
- }
- const rowStyles = getComputedStyle(row);
- const horizontalPadding = (parseFloat(rowStyles.paddingLeft) || 0)
- + (parseFloat(rowStyles.paddingRight) || 0);
- return Math.max(0, row.clientWidth - horizontalPadding);
- };
-
- const normalizeWidths = (widths, tableWidth, minWidth) => {
- const safeWidths = widths.map((width) => Math.max(minWidth, width));
- const total = safeWidths.reduce((sum, width) => sum + width, 0);
+ const normalizeRatios = (values) => {
+ const safeValues = values.map((value) => (Number.isFinite(value) && value > 0 ? value : 0));
+ const total = safeValues.reduce((sum, value) => sum + value, 0);
if (total <= 0) {
- return Array(widths.length).fill(Math.max(minWidth, tableWidth / widths.length));
+ return Array(values.length).fill(1 / values.length);
}
- if (widths.some((width) => width !== width)) {
- return Array(widths.length).fill(Math.max(minWidth, tableWidth / widths.length));
- }
- return safeWidths.map((width) => width * tableWidth / total);
+ return safeValues.map((value) => value / total);
};
- const getDefaultWidths = (table, headers, minWidth) => {
- const tableWidth = Math.max(getGridTrackWidth(table), minWidth * headers.length);
+ const getDefaultRatios = (table, headers, minWidth) => {
+ const tableWidth = Math.max(table.querySelector('[data-component-part="large-table-viewport"]')?.clientWidth || 0, minWidth * headers.length);
const configured = headers.map((header) => parseDefaultWidth(header.dataset.defaultWidth, tableWidth));
if (configured.some((width) => width === null)) {
- return Array(headers.length).fill(Math.max(minWidth, tableWidth / headers.length));
+ return Array(headers.length).fill(1 / headers.length);
}
- return normalizeWidths(configured, tableWidth, minWidth);
+ return normalizeRatios(configured);
};
const getStorageKey = (table) => `${STORAGE_PREFIX}${table.dataset.columnResizeKey || ''}`;
- const readStoredWidths = (table, count, minWidth) => {
+ const readStoredRatios = (table, count) => {
const key = getStorageKey(table);
if (!table.dataset.columnResizeKey) {
return null;
@@ -88,19 +74,19 @@
return null;
}
const stored = JSON.parse(window.localStorage.getItem(key));
- if (stored?.version !== STORAGE_VERSION || !Array.isArray(stored.widths) || stored.widths.length !== count) {
+ if (stored?.version !== STORAGE_VERSION || !Array.isArray(stored.ratios) || stored.ratios.length !== count) {
return null;
}
- if (stored.widths.some((width) => !Number.isFinite(width) || width < minWidth)) {
+ if (stored.ratios.some((ratio) => !Number.isFinite(ratio) || ratio <= 0)) {
return null;
}
- return stored.widths;
+ return normalizeRatios(stored.ratios);
} catch (error) {
return null;
}
};
- const writeStoredWidths = (table, widths) => {
+ const writeStoredRatios = (table, ratios) => {
if (!table.dataset.columnResizeKey) {
return;
}
@@ -110,7 +96,7 @@
}
window.localStorage.setItem(getStorageKey(table), JSON.stringify({
version: STORAGE_VERSION,
- widths: widths.map((width) => Math.round(width)),
+ ratios: normalizeRatios(ratios),
}));
} catch (error) {
// Storage can be unavailable in privacy-restricted browser contexts.
@@ -133,35 +119,37 @@
});
};
- const applyWidths = (table, widths, minWidth) => {
- const safeWidths = widths.map((width) => Math.max(minWidth, width));
- const baseTotal = safeWidths.reduce((sum, width) => sum + width, 0);
- const effectiveTotal = Math.max(baseTotal, getGridTrackWidth(table));
- const effectiveWidths = safeWidths.map((width, index) => (
- index === safeWidths.length - 1 ? width + effectiveTotal - baseTotal : width
- ));
- const total = effectiveWidths.reduce((sum, width) => sum + width, 0);
- const columnTemplate = effectiveWidths.map((width, index) => (
- index === safeWidths.length - 1
- ? `minmax(${Math.round(width)}px, 1fr)`
- : `${Math.round(width)}px`
- )).join(' ');
- table.style.setProperty('--large-table-grid-template-columns', columnTemplate);
- table.style.setProperty('--large-table-grid-min-width', `${Math.ceil(total)}px`);
- table._largeTableColumnWidths = effectiveWidths;
- updateHandleState(table, effectiveWidths, minWidth);
+ const getRenderedWidths = (table, count, minWidth) => {
+ const headers = getColumnHeaders(table);
+ const widths = headers.map((header) => header.getBoundingClientRect().width);
+ if (widths.length === count && widths.every((width) => width > 0)) {
+ return widths;
+ }
+ return Array(count).fill(minWidth);
};
- const resizeColumn = (table, index, delta, persist) => {
- const widths = [...table._largeTableColumnWidths];
+ const applyRatios = (table, ratios, minWidth) => {
+ const safeRatios = normalizeRatios(ratios);
+ const columnTemplate = safeRatios
+ .map((ratio) => `minmax(${Math.ceil(minWidth)}px, ${ratio}fr)`)
+ .join(' ');
+ table.style.setProperty('--large-table-grid-template-columns', columnTemplate);
+ table.style.setProperty('--large-table-grid-min-width', `${Math.ceil(minWidth * safeRatios.length)}px`);
+ table._largeTableColumnRatios = safeRatios;
+ table._largeTableColumnWidths = getRenderedWidths(table, safeRatios.length, minWidth);
+ updateHandleState(table, table._largeTableColumnWidths, minWidth);
+ };
+
+ const resizeColumn = (table, index, delta, persist, baseWidths = table._largeTableColumnWidths) => {
+ const widths = [...baseWidths];
const minWidth = getMinWidth(table);
const nextLeft = Math.max(minWidth, Math.min(widths[index] + widths[index + 1] - minWidth, widths[index] + delta));
const appliedDelta = nextLeft - widths[index];
widths[index] = nextLeft;
widths[index + 1] -= appliedDelta;
- applyWidths(table, widths, minWidth);
+ applyRatios(table, widths.map((width) => width / widths.reduce((sum, value) => sum + value, 0)), minWidth);
if (persist) {
- writeStoredWidths(table, widths);
+ writeStoredRatios(table, table._largeTableColumnRatios);
}
};
@@ -171,8 +159,8 @@
return;
}
const minWidth = getMinWidth(table);
- const stored = readStoredWidths(table, headers.length, minWidth);
- applyWidths(table, stored || getDefaultWidths(table, headers, minWidth), minWidth);
+ const stored = readStoredRatios(table, headers.length);
+ applyRatios(table, stored || getDefaultRatios(table, headers, minWidth), minWidth);
if (table.dataset.largeTableResizeInitialized === 'true') {
return;
@@ -201,20 +189,32 @@
if (!activeResize || activeResize.table !== table) {
return;
}
- applyWidths(table, activeResize.startWidths, getMinWidth(table));
- resizeColumn(table, activeResize.index, event.clientX - activeResize.startX, false);
+ resizeColumn(
+ table,
+ activeResize.index,
+ event.clientX - activeResize.startX,
+ false,
+ activeResize.startWidths,
+ );
});
table.addEventListener('pointerup', () => {
if (!activeResize || activeResize.table !== table) {
return;
}
- writeStoredWidths(table, table._largeTableColumnWidths);
+ writeStoredRatios(table, table._largeTableColumnRatios);
activeResize.handle.dataset.largeTableResizeActive = 'false';
table.dataset.columnResizeState = 'idle';
activeResize = null;
});
+ if (typeof ResizeObserver === 'function') {
+ table._largeTableResizeObserver = new ResizeObserver(() => {
+ applyRatios(table, table._largeTableColumnRatios, getMinWidth(table));
+ });
+ table._largeTableResizeObserver.observe(table.querySelector('[data-component-part="large-table-viewport"]'));
+ }
+
table.addEventListener('keydown', (event) => {
const handle = event.target.closest('[data-large-table-resize-handle]');
if (!handle || !table.contains(handle)) {
diff --git a/styles/42-components-data-display.css b/styles/42-components-data-display.css
index 91fea68..5a3861a 100644
--- a/styles/42-components-data-display.css
+++ b/styles/42-components-data-display.css
@@ -106,14 +106,7 @@
.sg-large-table[data-column-resize="true"] .sg-large-table__row,
.sg-large-table[data-column-resize="true"] .sg-large-table__title-segment {
- width: max(
- 100%,
- calc(
- var(--large-table-grid-min-width, 0px) +
- var(--card-segment-padding-horizontal) +
- var(--card-segment-padding-horizontal)
- )
- );
+ width: max(100%, var(--large-table-grid-min-width, 0px));
}
.sg-large-table__row--hidden {