From a9eec08d8fffc6ed20c1d2bce9de1c671614918c Mon Sep 17 00:00:00 2001 From: bendera Date: Tue, 6 Jan 2026 14:18:54 +0100 Subject: [PATCH 1/7] Fix logger message --- src/includes/VscElement.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/includes/VscElement.ts b/src/includes/VscElement.ts index a08762f8..13f8db00 100644 --- a/src/includes/VscElement.ts +++ b/src/includes/VscElement.ts @@ -11,7 +11,7 @@ const warn = (message: string, componentInstance?: VscElement) => { console.warn(`${prefix}${message}\n%o`, componentInstance); } else { // eslint-disable-next-line no-console - console.warn(`${message}\n%o`, componentInstance); + console.warn(`${prefix}${message}`); } }; From 4ccc2ab83b1cfce83e5ccfe5627f38084b275a54 Mon Sep 17 00:00:00 2001 From: bendera Date: Tue, 6 Jan 2026 14:23:49 +0100 Subject: [PATCH 2/7] Calculate initial sizes from header attributes --- dev/vscode-table/shift-table-columns.html | 18 ++---- .../vscode-table-header-cell.ts | 19 ++++++ src/vscode-table/initial-column-widths.ts | 61 +++++++++++++++++++ src/vscode-table/vscode-table.ts | 48 +++++++++++++-- 4 files changed, 130 insertions(+), 16 deletions(-) create mode 100644 src/vscode-table/initial-column-widths.ts diff --git a/dev/vscode-table/shift-table-columns.html b/dev/vscode-table/shift-table-columns.html index 547e680a..a459b8a9 100644 --- a/dev/vscode-table/shift-table-columns.html +++ b/dev/vscode-table/shift-table-columns.html @@ -37,27 +37,21 @@

Basic example

- + - Id - First name - Last name - Email - Company diff --git a/src/vscode-table-header-cell/vscode-table-header-cell.ts b/src/vscode-table-header-cell/vscode-table-header-cell.ts index 30b77b2e..29c42ccb 100644 --- a/src/vscode-table-header-cell/vscode-table-header-cell.ts +++ b/src/vscode-table-header-cell/vscode-table-header-cell.ts @@ -8,6 +8,11 @@ export type VscTableChangeMinColumnWidthEvent = CustomEvent<{ propertyValue: string; }>; +export type VscTableChangePreferredColumnWidthEvent = CustomEvent<{ + columnIndex: number; + propertyValue: string; +}>; + /** * @tag vscode-table-header-cell * @@ -22,6 +27,9 @@ export class VscodeTableHeaderCell extends VscElement { @property({attribute: 'min-width'}) minWidth = '0'; + @property({attribute: 'preferred-width'}) + preferredWidth = 'auto'; + /** @internal */ @property({type: Number}) index = -1; @@ -40,6 +48,16 @@ export class VscodeTableHeaderCell extends VscElement { }) as VscTableChangeMinColumnWidthEvent ); } + + if (changedProperties.has('preferredWidth') && this.index > -1) { + /** @internal */ + this.dispatchEvent( + new CustomEvent('vsc-table-change-preferred-column-width', { + detail: {columnIndex: this.index, propertyValue: this.preferredWidth}, + bubbles: true, + }) as VscTableChangePreferredColumnWidthEvent + ); + } } override render(): TemplateResult { @@ -58,5 +76,6 @@ declare global { interface GlobalEventHandlersEventMap { 'vsc-table-change-min-column-width': VscTableChangeMinColumnWidthEvent; + 'vsc-table-change-preferred-column-width': VscTableChangePreferredColumnWidthEvent; } } diff --git a/src/vscode-table/initial-column-widths.ts b/src/vscode-table/initial-column-widths.ts new file mode 100644 index 00000000..3cb09a97 --- /dev/null +++ b/src/vscode-table/initial-column-widths.ts @@ -0,0 +1,61 @@ +import {percent, Percent} from '../includes/sizes.js'; + +const PERCENT_FULL = percent(100); + +export type ColumnWidth = Percent | 'auto'; + +export interface Column { + preferredWidth: ColumnWidth; + minWidth: Percent; +} + +export function calculateInitialWidths(columns: Column[]): Percent[] { + const finalWidths: Percent[] = columns.map( + (c) => + typeof c.preferredWidth === 'number' + ? percent(Math.max(c.preferredWidth, c.minWidth)) + : percent(0) // auto placeholder + ); + + const autoIndices = columns + .map((c, i) => (c.preferredWidth === 'auto' ? i : -1)) + .filter((i) => i >= 0); + + const totalMinWidth = columns.reduce( + (sum, c) => percent(sum + c.minWidth), + percent(0) + ); + + if (totalMinWidth > PERCENT_FULL) { + const scale = PERCENT_FULL / totalMinWidth; + return columns.map((c) => percent(c.minWidth * scale)); + } + + const fixedWidthSum = finalWidths.reduce( + (sum, w) => percent(sum + w), + percent(0) + ); + const remainingSpace = percent(PERCENT_FULL - fixedWidthSum); + + if (remainingSpace > 0 && autoIndices.length > 0) { + const extraPerAuto = remainingSpace / autoIndices.length; + for (const i of autoIndices) { + finalWidths[i] = percent(Math.max(columns[i].minWidth, extraPerAuto)); + } + return finalWidths; + } + + if (autoIndices.length > 0) { + for (const i of autoIndices) { + finalWidths[i] = columns[i].minWidth; + } + return finalWidths; + } + + if (remainingSpace > 0 && autoIndices.length === 0) { + const scale = PERCENT_FULL / fixedWidthSum; + return finalWidths.map((w) => percent(w * scale)); + } + + return finalWidths; +} diff --git a/src/vscode-table/vscode-table.ts b/src/vscode-table/vscode-table.ts index d8098c79..6ece3c1e 100644 --- a/src/vscode-table/vscode-table.ts +++ b/src/vscode-table/vscode-table.ts @@ -22,7 +22,11 @@ import { } from '../includes/sizes.js'; import styles from './vscode-table.styles.js'; import {ColumnResizeController} from './ColumnResizeController.js'; -import {VscTableChangeMinColumnWidthEvent} from '../vscode-table-header-cell/vscode-table-header-cell.js'; +import { + VscTableChangeMinColumnWidthEvent, + VscTableChangePreferredColumnWidthEvent, +} from '../vscode-table-header-cell/vscode-table-header-cell.js'; +import {calculateInitialWidths, Column} from './initial-column-widths.js'; /** * @tag vscode-table @@ -199,6 +203,10 @@ export class VscodeTable extends VscElement { 'vsc-table-change-min-column-width', this._handleMinColumnWidthChange ); + this.addEventListener( + 'vsc-table-change-preferred-column-width', + this._handlePreferredColumnWidthChange + ); } override connectedCallback(): void { @@ -519,7 +527,9 @@ export class VscodeTable extends VscElement { private _onHeaderSlotChange() { this._headerCells = this._queryHeaderCells(); const minWidths: Percent[] = []; + const preferredWidths: Percent[] = []; minWidths.fill(percent(0), 0, this._headerCells.length - 1); + preferredWidths.fill(percent(0), 0, this._headerCells.length - 1); this._headerCells.forEach((c, i) => { c.index = i; @@ -531,10 +541,28 @@ export class VscodeTable extends VscElement { this._columnResizeController.setColumnMinWidthAt(i, minWidth); } }); + + const columns = this._headerCells.map((cell) => { + const preferredWidth = + cell.preferredWidth !== 'auto' + ? parseSizeAttributeToPercent(cell.preferredWidth, this._componentW) + : cell.preferredWidth; + const minWidth = parseSizeAttributeToPercent( + cell.minWidth, + this._componentW + ); + + return {preferredWidth, minWidth} as Column; + }); + const calculatedWidths = calculateInitialWidths(columns); + + this._columnResizeController.setColumWidths(calculatedWidths); + this._resizeColumns(true); } private _onBodySlotChange() { - this._initDefaultColumnSizes(); + // this._initDefaultColumnSizes(); + this._updateBodyColumnWidths(); this._initResizeObserver(); this._updateResizeHandlersSize(); @@ -574,6 +602,12 @@ export class VscodeTable extends VscElement { this.requestUpdate(); } + private _updateBodyColumnWidths() { + const widths = this._columnResizeController.columnWidths; + const firstRowCells = this._getCellsOfFirstRow(); + firstRowCells.forEach((c, i) => (c.style.width = `${widths[i]}%`)); + } + private _resizeColumns(resizeBodyCells = true) { const widths = this._columnResizeController.columnWidths; @@ -581,8 +615,7 @@ export class VscodeTable extends VscElement { headerCells.forEach((h, i) => (h.style.width = `${widths[i]}%`)); if (resizeBodyCells) { - const firstRowCells = this._getCellsOfFirstRow(); - firstRowCells.forEach((c, i) => (c.style.width = `${widths[i]}%`)); + this._updateBodyColumnWidths(); } } @@ -639,7 +672,14 @@ export class VscodeTable extends VscElement { } }; + private _handlePreferredColumnWidthChange = ( + event: VscTableChangePreferredColumnWidthEvent + ) => { + console.log(event); + }; + override render(): TemplateResult { + console.log('render'); const splitterPositions = this._columnResizeController.splitterPositions; const sashes = splitterPositions.map((val, index) => { From b03433e2f1735b314033c51d8c9918d2a626797e Mon Sep 17 00:00:00 2001 From: bendera Date: Tue, 6 Jan 2026 15:01:33 +0100 Subject: [PATCH 3/7] Update table when preferredWidth change --- src/vscode-table/vscode-table.ts | 35 ++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/vscode-table/vscode-table.ts b/src/vscode-table/vscode-table.ts index 6ece3c1e..384efc30 100644 --- a/src/vscode-table/vscode-table.ts +++ b/src/vscode-table/vscode-table.ts @@ -510,21 +510,7 @@ export class VscodeTable extends VscElement { this._activeSashElementIndex = -1; } - private _onDefaultSlotChange() { - this._assignedElements.forEach((el) => { - if (el.tagName.toLowerCase() === 'vscode-table-header') { - el.slot = 'header'; - return; - } - - if (el.tagName.toLowerCase() === 'vscode-table-body') { - el.slot = 'body'; - return; - } - }); - } - - private _onHeaderSlotChange() { + private _updateColumnWidths() { this._headerCells = this._queryHeaderCells(); const minWidths: Percent[] = []; const preferredWidths: Percent[] = []; @@ -560,6 +546,24 @@ export class VscodeTable extends VscElement { this._resizeColumns(true); } + private _onDefaultSlotChange() { + this._assignedElements.forEach((el) => { + if (el.tagName.toLowerCase() === 'vscode-table-header') { + el.slot = 'header'; + return; + } + + if (el.tagName.toLowerCase() === 'vscode-table-body') { + el.slot = 'body'; + return; + } + }); + } + + private _onHeaderSlotChange() { + this._updateColumnWidths(); + } + private _onBodySlotChange() { // this._initDefaultColumnSizes(); this._updateBodyColumnWidths(); @@ -676,6 +680,7 @@ export class VscodeTable extends VscElement { event: VscTableChangePreferredColumnWidthEvent ) => { console.log(event); + this._updateColumnWidths(); }; override render(): TemplateResult { From 98c642696af69049336e29cfce1ccd6164491d17 Mon Sep 17 00:00:00 2001 From: bendera Date: Tue, 6 Jan 2026 23:26:30 +0100 Subject: [PATCH 4/7] Update table when minWidth changed --- src/vscode-table/vscode-table.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vscode-table/vscode-table.ts b/src/vscode-table/vscode-table.ts index 384efc30..2c79443b 100644 --- a/src/vscode-table/vscode-table.ts +++ b/src/vscode-table/vscode-table.ts @@ -673,6 +673,7 @@ export class VscodeTable extends VscElement { if (value) { this._columnResizeController.setColumnMinWidthAt(columnIndex, value); + this._updateColumnWidths(); } }; From cebae580394e9f450e592589e31f358d499c8c23 Mon Sep 17 00:00:00 2001 From: bendera Date: Tue, 6 Jan 2026 23:44:22 +0100 Subject: [PATCH 5/7] Refactor --- src/vscode-table/vscode-table.ts | 58 +++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/src/vscode-table/vscode-table.ts b/src/vscode-table/vscode-table.ts index 2c79443b..e342ab2c 100644 --- a/src/vscode-table/vscode-table.ts +++ b/src/vscode-table/vscode-table.ts @@ -39,6 +39,8 @@ import {calculateInitialWidths, Column} from './initial-column-widths.js'; export class VscodeTable extends VscElement { static override styles = styles; + //#region properties + /** @internal */ @property({reflect: true}) override role = 'table'; @@ -132,6 +134,10 @@ export class VscodeTable extends VscElement { @property({type: Boolean, reflect: true, attribute: 'zebra-odd'}) zebraOdd = false; + //#endregion + + //#region private variables + @query('.header') private _headerElement!: HTMLDivElement; @@ -196,6 +202,10 @@ export class VscodeTable extends VscElement { private _columnResizeController = new ColumnResizeController(this); + //#endregion + + //#region lifecycle methods + constructor() { super(); @@ -243,6 +253,10 @@ export class VscodeTable extends VscElement { } } + //#endregion + + //#region private methods + private _memoizeComponentDimensions() { const cr = this.getBoundingClientRect(); @@ -546,6 +560,27 @@ export class VscodeTable extends VscElement { this._resizeColumns(true); } + private _updateBodyColumnWidths() { + const widths = this._columnResizeController.columnWidths; + const firstRowCells = this._getCellsOfFirstRow(); + firstRowCells.forEach((c, i) => (c.style.width = `${widths[i]}%`)); + } + + private _resizeColumns(resizeBodyCells = true) { + const widths = this._columnResizeController.columnWidths; + + const headerCells = this._getHeaderCells(); + headerCells.forEach((h, i) => (h.style.width = `${widths[i]}%`)); + + if (resizeBodyCells) { + this._updateBodyColumnWidths(); + } + } + + //#endregion + + //#region event handlers + private _onDefaultSlotChange() { this._assignedElements.forEach((el) => { if (el.tagName.toLowerCase() === 'vscode-table-header') { @@ -606,23 +641,6 @@ export class VscodeTable extends VscElement { this.requestUpdate(); } - private _updateBodyColumnWidths() { - const widths = this._columnResizeController.columnWidths; - const firstRowCells = this._getCellsOfFirstRow(); - firstRowCells.forEach((c, i) => (c.style.width = `${widths[i]}%`)); - } - - private _resizeColumns(resizeBodyCells = true) { - const widths = this._columnResizeController.columnWidths; - - const headerCells = this._getHeaderCells(); - headerCells.forEach((h, i) => (h.style.width = `${widths[i]}%`)); - - if (resizeBodyCells) { - this._updateBodyColumnWidths(); - } - } - private _handleSplitterPointerDown(event: PointerEvent) { event.stopPropagation(); @@ -678,14 +696,14 @@ export class VscodeTable extends VscElement { }; private _handlePreferredColumnWidthChange = ( - event: VscTableChangePreferredColumnWidthEvent + _event: VscTableChangePreferredColumnWidthEvent ) => { - console.log(event); this._updateColumnWidths(); }; + //#endregion + override render(): TemplateResult { - console.log('render'); const splitterPositions = this._columnResizeController.splitterPositions; const sashes = splitterPositions.map((val, index) => { From d4b89d8faf45117638a060bfbbd874233d23c2d6 Mon Sep 17 00:00:00 2001 From: bendera Date: Wed, 7 Jan 2026 00:08:26 +0100 Subject: [PATCH 6/7] Add demo for #584 --- dev/vscode-table/shift-table-columns.html | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/dev/vscode-table/shift-table-columns.html b/dev/vscode-table/shift-table-columns.html index a459b8a9..8ffcbe02 100644 --- a/dev/vscode-table/shift-table-columns.html +++ b/dev/vscode-table/shift-table-columns.html @@ -95,6 +95,28 @@

Basic example

+ + +
From 27c60fe791db572923dc4317a838d2ff8d583d08 Mon Sep 17 00:00:00 2001 From: bendera Date: Wed, 7 Jan 2026 23:11:55 +0100 Subject: [PATCH 7/7] Update column widths in table body Update column widths in the table body when the default slot content changes. --- src/vscode-table-body/vscode-table-body.ts | 13 ++++++++++++- src/vscode-table/vscode-table.ts | 12 ++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/vscode-table-body/vscode-table-body.ts b/src/vscode-table-body/vscode-table-body.ts index 0d97f757..f2a74499 100644 --- a/src/vscode-table-body/vscode-table-body.ts +++ b/src/vscode-table-body/vscode-table-body.ts @@ -14,8 +14,15 @@ export class VscodeTableBody extends VscElement { @property({reflect: true}) override role = 'rowgroup'; + private _handleSlotChange() { + /** @internal */ + this.dispatchEvent( + new Event('vsc-table-body-slot-changed', {bubbles: true}) + ); + } + override render(): TemplateResult { - return html` `; + return html` `; } } @@ -23,4 +30,8 @@ declare global { interface HTMLElementTagNameMap { 'vscode-table-body': VscodeTableBody; } + + interface GlobalEventHandlersEventMap { + 'vsc-table-body-slot-changed': Event; + } } diff --git a/src/vscode-table/vscode-table.ts b/src/vscode-table/vscode-table.ts index e342ab2c..78bd0ffb 100644 --- a/src/vscode-table/vscode-table.ts +++ b/src/vscode-table/vscode-table.ts @@ -601,7 +601,6 @@ export class VscodeTable extends VscElement { private _onBodySlotChange() { // this._initDefaultColumnSizes(); - this._updateBodyColumnWidths(); this._initResizeObserver(); this._updateResizeHandlersSize(); @@ -701,6 +700,11 @@ export class VscodeTable extends VscElement { this._updateColumnWidths(); }; + private _handleTableBodySlotChange() { + this._cellsOfFirstRow = []; + this._updateBodyColumnWidths(); + } + //#endregion override render(): TemplateResult { @@ -755,7 +759,11 @@ export class VscodeTable extends VscElement {
- +
${sashes}