(function initLargeTableColumnResizeModule() { const STORAGE_PREFIX = 'sg:large-table:column-widths:'; const STORAGE_VERSION = 1; const DEFAULT_MIN_WIDTH = 128; const KEYBOARD_STEP = 8; const KEYBOARD_LARGE_STEP = 40; let activeResize = null; const getTables = (root) => root.querySelectorAll('[data-component="large-table"][data-column-resize="true"]'); const getColumnHeaders = (table) => Array.from( table.querySelectorAll('[data-component-part="large-table-header-row"] [role="columnheader"]'), ); const getMinWidth = (table) => { const configured = table.dataset.columnMinWidth; const value = configured || getComputedStyle(table).getPropertyValue('--large-table-column-min-width').trim(); if (!value) { return DEFAULT_MIN_WIDTH; } const probe = document.createElement('span'); probe.style.cssText = `position:absolute;width:${value};visibility:hidden;`; table.appendChild(probe); const width = probe.getBoundingClientRect().width; probe.remove(); return width > 0 ? width : DEFAULT_MIN_WIDTH; }; const parseDefaultWidth = (rawValue, tableWidth) => { if (!rawValue) { return null; } const value = Number.parseFloat(rawValue); if (!Number.isFinite(value) || value <= 0) { return null; } if (rawValue.trim().endsWith('%')) { return tableWidth * value / 100; } if (rawValue.trim().endsWith('fr')) { return value; } return value; }; const normalizeWidths = (widths, tableWidth, minWidth) => { const safeWidths = widths.map((width) => Math.max(minWidth, width)); const total = safeWidths.reduce((sum, width) => sum + width, 0); if (total <= 0) { return Array(widths.length).fill(Math.max(minWidth, tableWidth / widths.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); }; const getDefaultWidths = (table, headers, minWidth) => { const tableWidth = Math.max(table.clientWidth, 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 normalizeWidths(configured, tableWidth, minWidth); }; const getStorageKey = (table) => `${STORAGE_PREFIX}${table.dataset.columnResizeKey || ''}`; const readStoredWidths = (table, count, minWidth) => { const key = getStorageKey(table); if (!table.dataset.columnResizeKey) { return null; } try { if (!window.localStorage) { return null; } const stored = JSON.parse(window.localStorage.getItem(key)); if (stored?.version !== STORAGE_VERSION || !Array.isArray(stored.widths) || stored.widths.length !== count) { return null; } if (stored.widths.some((width) => !Number.isFinite(width) || width < minWidth)) { return null; } return stored.widths; } catch (error) { return null; } }; const writeStoredWidths = (table, widths) => { if (!table.dataset.columnResizeKey) { return; } try { if (!window.localStorage) { return; } window.localStorage.setItem(getStorageKey(table), JSON.stringify({ version: STORAGE_VERSION, widths: widths.map((width) => Math.round(width)), })); } catch (error) { // Storage can be unavailable in privacy-restricted browser contexts. } }; const updateHandleState = (table, widths, minWidth) => { const handles = table.querySelectorAll('[data-large-table-resize-handle]'); handles.forEach((handle) => { const index = Number.parseInt(handle.dataset.largeTableResizeHandle, 10); const current = widths[index]; const maximum = Math.max(minWidth, widths[index] + widths[index + 1] - minWidth); if (table.id) { handle.setAttribute('aria-controls', table.id); } handle.setAttribute('aria-valuemin', String(Math.round(minWidth))); handle.setAttribute('aria-valuemax', String(Math.round(maximum))); handle.setAttribute('aria-valuenow', String(Math.round(current))); handle.setAttribute('aria-valuetext', `${Math.round(current)} Pixel`); }); }; const applyWidths = (table, widths, minWidth) => { const safeWidths = widths.map((width) => Math.max(minWidth, width)); const total = safeWidths.reduce((sum, width) => sum + width, 0); table.style.setProperty('--large-table-grid-template-columns', safeWidths.map((width) => `${width}px`).join(' ')); table.style.setProperty('--large-table-grid-min-width', `${Math.ceil(total)}px`); table._largeTableColumnWidths = safeWidths; updateHandleState(table, safeWidths, minWidth); }; const resizeColumn = (table, index, delta, persist) => { const widths = [...table._largeTableColumnWidths]; 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); if (persist) { writeStoredWidths(table, widths); } }; const initTable = (table) => { const headers = getColumnHeaders(table); if (headers.length < 2) { return; } const minWidth = getMinWidth(table); const stored = readStoredWidths(table, headers.length, minWidth); applyWidths(table, stored || getDefaultWidths(table, headers, minWidth), minWidth); if (table.dataset.largeTableResizeInitialized === 'true') { return; } table.dataset.largeTableResizeInitialized = 'true'; table.addEventListener('pointerdown', (event) => { const handle = event.target.closest('[data-large-table-resize-handle]'); if (!handle || !table.contains(handle)) { return; } event.preventDefault(); activeResize = { table, handle, index: Number.parseInt(handle.dataset.largeTableResizeHandle, 10), startX: event.clientX, startWidths: [...table._largeTableColumnWidths], }; handle.dataset.largeTableResizeActive = 'true'; table.dataset.columnResizeState = 'resizing'; handle.setPointerCapture?.(event.pointerId); }); table.addEventListener('pointermove', (event) => { if (!activeResize || activeResize.table !== table) { return; } applyWidths(table, activeResize.startWidths, getMinWidth(table)); resizeColumn(table, activeResize.index, event.clientX - activeResize.startX, false); }); table.addEventListener('pointerup', () => { if (!activeResize || activeResize.table !== table) { return; } writeStoredWidths(table, table._largeTableColumnWidths); activeResize.handle.dataset.largeTableResizeActive = 'false'; table.dataset.columnResizeState = 'idle'; activeResize = null; }); table.addEventListener('keydown', (event) => { const handle = event.target.closest('[data-large-table-resize-handle]'); if (!handle || !table.contains(handle)) { return; } const index = Number.parseInt(handle.dataset.largeTableResizeHandle, 10); const step = event.shiftKey ? KEYBOARD_LARGE_STEP : KEYBOARD_STEP; if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') { event.preventDefault(); resizeColumn(table, index, event.key === 'ArrowRight' ? step : -step, true); } else if (event.key === 'Home' || event.key === 'End') { event.preventDefault(); const minWidth = getMinWidth(table); const current = table._largeTableColumnWidths[index]; const target = event.key === 'Home' ? minWidth : current + table._largeTableColumnWidths[index + 1] - minWidth; resizeColumn(table, index, target - current, true); } }); }; window.sgInitLargeTableColumnResize = (options = {}) => { const root = options.root || document; getTables(root).forEach(initTable); }; document.addEventListener('DOMContentLoaded', () => window.sgInitLargeTableColumnResize(), { once: true }); })();