diff --git a/docs/styleguide/components/data-display.html b/docs/styleguide/components/data-display.html index be76b74..8ed802d 100644 --- a/docs/styleguide/components/data-display.html +++ b/docs/styleguide/components/data-display.html @@ -77,7 +77,7 @@

Component: Large Table

Suche, Sortierung und „Mehr laden“ sind hier Demo-Markup. Produktions-Implementierungen müssen Treffer serverseitig neu rendern.

-

Optionale Spaltenbreiten-Anpassung: data-column-resize="true" aktiviert die Funktion. Die Tabelle benötigt dafür eine stabile, portalweit eindeutige data-column-resize-key. Die Header-Zellen können mit data-default-width (Prozent, Pixel oder relative fr-Werte) und die Tabelle mit data-column-min-width konfiguriert werden. Die Runtime wird nach dynamischem Nachladen über window.sgInitLargeTableColumnResize({ root }) erneut aufgerufen. Gespeicherte Werte liegen als { version: 1, widths: number[] } unter sg:large-table:column-widths:<key> in localStorage.

+

Optionale Spaltenbreiten-Anpassung: data-column-resize="true" aktiviert die Funktion. Die Tabelle benötigt dafür eine stabile, portalweit eindeutige data-column-resize-key. Die Header-Zellen können mit data-default-width (Prozent, Pixel oder relative fr-Werte) und die Tabelle mit data-column-min-width konfiguriert werden. Die Runtime wird nach dynamischem Nachladen über window.sgInitLargeTableColumnResize({ root }) erneut aufgerufen. Gespeicherte Werte liegen als { version: 3, ratios: number[] } unter sg:large-table:column-widths:<key> in localStorage; die Werte sind proportionale Anteile der verfügbaren Tabellenbreite.

diff --git a/docs/styleguide/styles/42-components-data-display.css b/docs/styleguide/styles/42-components-data-display.css index 91fea68..5a3861a 100644 --- a/docs/styleguide/styles/42-components-data-display.css +++ b/docs/styleguide/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 { diff --git a/public/assets/styleguide.upstream.css b/public/assets/styleguide.upstream.css index 013e901..1d22391 100644 --- a/public/assets/styleguide.upstream.css +++ b/public/assets/styleguide.upstream.css @@ -4981,14 +4981,7 @@ main { .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 { diff --git a/public/assets/styleguide.upstream.meta.json b/public/assets/styleguide.upstream.meta.json index 9704198..fa186c6 100644 --- a/public/assets/styleguide.upstream.meta.json +++ b/public/assets/styleguide.upstream.meta.json @@ -1,7 +1,7 @@ { "styleguideVersion": "2026.05.18.2", - "styleguideCommit": "0165b6c", - "syncedAtUtc": "2026-09-28T08:50:34Z", + "styleguideCommit": "d88540d", + "syncedAtUtc": "2026-09-28T09:06:53Z", "sourceRepo": "/Users/mathias/Documents/Dokumente Chouchou/Codebases/Styleguide", "mirroredDocsPath": "docs/styleguide" } diff --git a/public/assets/styles.css b/public/assets/styles.css index 013e901..1d22391 100644 --- a/public/assets/styles.css +++ b/public/assets/styles.css @@ -4981,14 +4981,7 @@ main { .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 { diff --git a/public/scripts/large-table-column-resize.js b/public/scripts/large-table-column-resize.js index 791657a..ef73133 100644 --- a/public/scripts/large-table-column-resize.js +++ b/public/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)) {