From 62ef6a38510db0b2d2b35759ab445c53bb9bb539 Mon Sep 17 00:00:00 2001 From: Diego Cardoso Date: Mon, 10 Feb 2025 14:32:06 +0200 Subject: [PATCH 01/27] feat: add auto-responsive to form-layout --- .../src/vaadin-form-layout-mixin.js | 31 +++++++++++++++++-- .../src/vaadin-form-layout-styles.js | 19 ++++++++++-- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/packages/form-layout/src/vaadin-form-layout-mixin.js b/packages/form-layout/src/vaadin-form-layout-mixin.js index 49858e831df..26177fa6539 100644 --- a/packages/form-layout/src/vaadin-form-layout-mixin.js +++ b/packages/form-layout/src/vaadin-form-layout-mixin.js @@ -98,11 +98,29 @@ export const FormLayoutMixin = (superClass) => type: Boolean, sync: true, }, + + autoResponsive: { + type: Boolean, + value: false, + reflectToAttribute: true, + }, + + columnWidth: { + type: String, + value: '13em', + observer: '_columnWidthChanged', + }, + + maxColumns: { + type: Number, + value: 10, + observer: '_maxColumnsChanged', + }, }; } static get observers() { - return ['_invokeUpdateLayout(_columnCount, _labelsOnTop)']; + return ['_invokeUpdateLayout(_columnCount, _labelsOnTop, autoResponsive)']; } /** @protected */ @@ -225,7 +243,7 @@ export const FormLayoutMixin = (superClass) => */ _updateLayout() { // Do not update layout when invisible - if (isElementHidden(this)) { + if (isElementHidden(this) || this.autoResponsive) { return; } @@ -312,6 +330,15 @@ export const FormLayoutMixin = (superClass) => }); } + /**@private */ + _columnWidthChanged(columnWidth) { + this.style.setProperty('--vaadin-form-layout-column-width', columnWidth); + } + + _maxColumnsChanged(maxColumns) { + this.style.setProperty('--vaadin-form-layout-max-columns', maxColumns); + } + /** * @protected * @override diff --git a/packages/form-layout/src/vaadin-form-layout-styles.js b/packages/form-layout/src/vaadin-form-layout-styles.js index 1bbf41dee2d..68421e857d4 100644 --- a/packages/form-layout/src/vaadin-form-layout-styles.js +++ b/packages/form-layout/src/vaadin-form-layout-styles.js @@ -21,7 +21,7 @@ export const formLayoutStyles = css` display: none !important; } - #layout { + :host(:not([auto-responsive])) #layout { display: flex; align-items: baseline; /* default \`stretch\` is not appropriate */ @@ -29,7 +29,7 @@ export const formLayoutStyles = css` flex-wrap: wrap; /* the items should wrap */ } - #layout ::slotted(*) { + :host(:not([auto-responsive])) #layout ::slotted(*) { /* Items should neither grow nor shrink. */ flex-grow: 0; flex-shrink: 0; @@ -42,6 +42,21 @@ export const formLayoutStyles = css` #layout ::slotted(br) { display: none; } + + :host([auto-responsive]) #layout { + /** + * Calculated values. + */ + --gap-count: calc(var(--vaadin-form-layout-max-columns) - 1); + --total-gap-width: calc(var(--gap-count) * var(--vaadin-form-layout-column-spacing)); + --grid-item--max-width: calc((100% - var(--total-gap-width)) / var(--vaadin-form-layout-max-columns)); + display: grid; + grid-template-columns: repeat( + auto-fill, + minmax(max(var(--vaadin-form-layout-column-width), var(--grid-item--max-width)), 1fr) + ); + gap: var(--vaadin-form-layout-row-spacing) var(--vaadin-form-layout-column-spacing); + } `; export const formItemStyles = css` From 95f05146be189f018e29b848d5c4f3f40de05a19 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Mon, 10 Feb 2025 18:01:12 +0400 Subject: [PATCH 02/27] implement expandColumns --- .../src/vaadin-form-layout-mixin.js | 6 ++++ .../src/vaadin-form-layout-styles.js | 32 +++++++++++++------ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/packages/form-layout/src/vaadin-form-layout-mixin.js b/packages/form-layout/src/vaadin-form-layout-mixin.js index 26177fa6539..af3817fb231 100644 --- a/packages/form-layout/src/vaadin-form-layout-mixin.js +++ b/packages/form-layout/src/vaadin-form-layout-mixin.js @@ -116,6 +116,12 @@ export const FormLayoutMixin = (superClass) => value: 10, observer: '_maxColumnsChanged', }, + + expandColumns: { + type: String, + value: false, + reflectToAttribute: true, + }, }; } diff --git a/packages/form-layout/src/vaadin-form-layout-styles.js b/packages/form-layout/src/vaadin-form-layout-styles.js index 68421e857d4..22e886b32f5 100644 --- a/packages/form-layout/src/vaadin-form-layout-styles.js +++ b/packages/form-layout/src/vaadin-form-layout-styles.js @@ -43,20 +43,32 @@ export const formLayoutStyles = css` display: none; } + :host([auto-responsive]) { + --vaadin-form-layout-column-max-width: var(--vaadin-form-layout-column-width); + } + :host([auto-responsive]) #layout { - /** - * Calculated values. - */ - --gap-count: calc(var(--vaadin-form-layout-max-columns) - 1); - --total-gap-width: calc(var(--gap-count) * var(--vaadin-form-layout-column-spacing)); - --grid-item--max-width: calc((100% - var(--total-gap-width)) / var(--vaadin-form-layout-max-columns)); + --_max-columns: var(--vaadin-form-layout-max-columns); + --_column-width: var(--vaadin-form-layout-column-width); + + --_total-gap-width: calc((var(--_max-columns) - 1) * var(--vaadin-form-layout-column-spacing)); + --_total-col-width: calc(var(--_max-columns) * var(--_column-width)); + + --_column-max-width: var(--vaadin-form-layout-column-max-width); + --_column-min-width: max(var(--_column-width), calc((100% - var(--_total-gap-width)) / var(--_max-columns))); + display: grid; - grid-template-columns: repeat( - auto-fill, - minmax(max(var(--vaadin-form-layout-column-width), var(--grid-item--max-width)), 1fr) - ); + grid-template-columns: repeat(auto-fill, minmax(var(--_column-min-width), var(--_column-max-width))); gap: var(--vaadin-form-layout-row-spacing) var(--vaadin-form-layout-column-spacing); } + + :host([auto-responsive]:not([expand-columns])) #layout { + max-width: calc(var(--_total-col-width) + var(--_total-gap-width)); + } + + :host([auto-responsive][expand-columns='always']) { + --vaadin-form-layout-column-max-width: 1fr; + } `; export const formItemStyles = css` From eb78da03a4f403302dc1a7bd4f51136c52f91180 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Tue, 11 Feb 2025 10:33:52 +0400 Subject: [PATCH 03/27] ensure colspan is capped at column count --- .../src/vaadin-form-layout-mixin.js | 37 ++++++++++++++++++- .../src/vaadin-form-layout-styles.js | 28 +++++++------- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/packages/form-layout/src/vaadin-form-layout-mixin.js b/packages/form-layout/src/vaadin-form-layout-mixin.js index af3817fb231..92acddf93ad 100644 --- a/packages/form-layout/src/vaadin-form-layout-mixin.js +++ b/packages/form-layout/src/vaadin-form-layout-mixin.js @@ -249,7 +249,12 @@ export const FormLayoutMixin = (superClass) => */ _updateLayout() { // Do not update layout when invisible - if (isElementHidden(this) || this.autoResponsive) { + if (isElementHidden(this)) { + return; + } + + if (this.autoResponsive) { + this._updateCSSGridLayout(); return; } @@ -336,6 +341,36 @@ export const FormLayoutMixin = (superClass) => }); } + /** @private */ + _updateCSSGridLayout() { + const computedColumnWidths = getComputedStyle(this.$.layout).gridTemplateColumns.split(' '); + + const columnCount = computedColumnWidths.filter((width) => width !== '0px').length; + this.$.layout.style.setProperty('--_column-count', columnCount); + + // let resetColumn = false; + [...this.children] + .filter((child) => getComputedStyle(child).display !== 'none' || child.localName === 'br') + .forEach((child) => { + if (child.localName === 'br') { + // resetColumn = true; + return; + } + + const colspan = child.getAttribute('colspan') || child.getAttribute('data-colspan'); + if (colspan) { + child.style.setProperty('--_colspan', colspan); + } + + // if (resetColumn) { + // child.style.setProperty('--_grid-colstart', 1); + // resetColumn = false; + // } else { + // child.style.removeProperty('--_grid-colstart'); + // } + }); + } + /**@private */ _columnWidthChanged(columnWidth) { this.style.setProperty('--vaadin-form-layout-column-width', columnWidth); diff --git a/packages/form-layout/src/vaadin-form-layout-styles.js b/packages/form-layout/src/vaadin-form-layout-styles.js index 22e886b32f5..8f8563eeb37 100644 --- a/packages/form-layout/src/vaadin-form-layout-styles.js +++ b/packages/form-layout/src/vaadin-form-layout-styles.js @@ -43,31 +43,31 @@ export const formLayoutStyles = css` display: none; } - :host([auto-responsive]) { - --vaadin-form-layout-column-max-width: var(--vaadin-form-layout-column-width); - } - :host([auto-responsive]) #layout { - --_max-columns: var(--vaadin-form-layout-max-columns); --_column-width: var(--vaadin-form-layout-column-width); + --_column-max-count: var(--vaadin-form-layout-max-columns); - --_total-gap-width: calc((var(--_max-columns) - 1) * var(--vaadin-form-layout-column-spacing)); - --_total-col-width: calc(var(--_max-columns) * var(--_column-width)); + --_max-total-gap-width: calc((var(--_column-max-count) - 1) * var(--vaadin-form-layout-column-spacing)); + --_max-total-col-width: calc(var(--_column-max-count) * var(--_column-width)); - --_column-max-width: var(--vaadin-form-layout-column-max-width); - --_column-min-width: max(var(--_column-width), calc((100% - var(--_total-gap-width)) / var(--_max-columns))); + --_column-min-width: max( + var(--_column-width), + calc((100% - var(--_max-total-gap-width)) / var(--_column-max-count)) + ); + --_column-max-width: 1fr; display: grid; - grid-template-columns: repeat(auto-fill, minmax(var(--_column-min-width), var(--_column-max-width))); + grid-template-columns: repeat(auto-fit, minmax(var(--_column-min-width), var(--_column-max-width))); + grid-auto-columns: 0; gap: var(--vaadin-form-layout-row-spacing) var(--vaadin-form-layout-column-spacing); } - :host([auto-responsive]:not([expand-columns])) #layout { - max-width: calc(var(--_total-col-width) + var(--_total-gap-width)); + :host([auto-responsive]) #layout ::slotted(*) { + grid-column-end: span min(var(--_colspan), var(--_column-count)); } - :host([auto-responsive][expand-columns='always']) { - --vaadin-form-layout-column-max-width: 1fr; + :host([auto-responsive]:not([expand-columns])) #layout { + max-width: calc(var(--_max-total-col-width) + var(--_max-total-gap-width)); } `; From 24f5216a04fcb35531603798d82baa2954e1bcdb Mon Sep 17 00:00:00 2001 From: Diego Cardoso Date: Tue, 11 Feb 2025 11:17:48 +0200 Subject: [PATCH 04/27] fix: do not expand columns by default --- packages/form-layout/src/vaadin-form-layout-styles.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/form-layout/src/vaadin-form-layout-styles.js b/packages/form-layout/src/vaadin-form-layout-styles.js index 8f8563eeb37..b4e7249736e 100644 --- a/packages/form-layout/src/vaadin-form-layout-styles.js +++ b/packages/form-layout/src/vaadin-form-layout-styles.js @@ -54,7 +54,8 @@ export const formLayoutStyles = css` var(--_column-width), calc((100% - var(--_max-total-gap-width)) / var(--_column-max-count)) ); - --_column-max-width: 1fr; + /* Using the same value as min-width for now. Should be conditionally changed based on the expandColumn value */ + --_column-max-width: var(--_column-min-width); display: grid; grid-template-columns: repeat(auto-fit, minmax(var(--_column-min-width), var(--_column-max-width))); From 298931f7ad17ef456ed2a776db3f113076cc048e Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Tue, 11 Feb 2025 19:50:32 +0400 Subject: [PATCH 05/27] use different approach to cap column count --- .../src/vaadin-form-layout-mixin.js | 6 ++-- .../src/vaadin-form-layout-styles.js | 28 +++++++++++++------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/packages/form-layout/src/vaadin-form-layout-mixin.js b/packages/form-layout/src/vaadin-form-layout-mixin.js index 92acddf93ad..3d9afa11250 100644 --- a/packages/form-layout/src/vaadin-form-layout-mixin.js +++ b/packages/form-layout/src/vaadin-form-layout-mixin.js @@ -344,9 +344,9 @@ export const FormLayoutMixin = (superClass) => /** @private */ _updateCSSGridLayout() { const computedColumnWidths = getComputedStyle(this.$.layout).gridTemplateColumns.split(' '); - - const columnCount = computedColumnWidths.filter((width) => width !== '0px').length; - this.$.layout.style.setProperty('--_column-count', columnCount); + const computedAutoColumnWidths = computedColumnWidths.filter((width) => width === '0px'); + const computedColumnCount = computedColumnWidths.length - computedAutoColumnWidths.length; + this.$.layout.style.setProperty('--_js-computed-column-count', computedColumnCount); // let resetColumn = false; [...this.children] diff --git a/packages/form-layout/src/vaadin-form-layout-styles.js b/packages/form-layout/src/vaadin-form-layout-styles.js index b4e7249736e..0f288a28208 100644 --- a/packages/form-layout/src/vaadin-form-layout-styles.js +++ b/packages/form-layout/src/vaadin-form-layout-styles.js @@ -50,25 +50,35 @@ export const formLayoutStyles = css` --_max-total-gap-width: calc((var(--_column-max-count) - 1) * var(--vaadin-form-layout-column-spacing)); --_max-total-col-width: calc(var(--_column-max-count) * var(--_column-width)); - --_column-min-width: max( - var(--_column-width), - calc((100% - var(--_max-total-gap-width)) / var(--_column-max-count)) - ); - /* Using the same value as min-width for now. Should be conditionally changed based on the expandColumn value */ - --_column-max-width: var(--_column-min-width); + --_column-min-width: var(--_column-width); + --_column-max-width: var(--_column-width); display: grid; grid-template-columns: repeat(auto-fit, minmax(var(--_column-min-width), var(--_column-max-width))); + /* + Auto-columns can be created when an item's colspan exceeds the available column count. + By setting auto-columns to 0, we exclude these columns from --_js-computed-column-count, + which is then used to cap the colspan. + */ grid-auto-columns: 0; gap: var(--vaadin-form-layout-row-spacing) var(--vaadin-form-layout-column-spacing); + min-width: var(--_column-width); + max-width: calc(var(--_max-total-col-width) + var(--_max-total-gap-width)); } :host([auto-responsive]) #layout ::slotted(*) { - grid-column-end: span min(var(--_colspan), var(--_column-count)); + /* The column count is calculated in JS using getComputedStyle(this.$.layout).gridTemplateColumns */ + grid-column-end: span min(var(--_colspan), var(--_js-computed-column-count)); } - :host([auto-responsive]:not([expand-columns])) #layout { - max-width: calc(var(--_max-total-col-width) + var(--_max-total-gap-width)); + :host([auto-responsive][expand-columns]) #layout { + --_column-min-width: max( + var(--_column-width), + calc((100% - var(--_max-total-gap-width)) / var(--_column-max-count)) + ); + --_column-max-width: 1fr; + + max-width: initial; } `; From 12b7d81ff44e34980e9320180ba70b90ebda5031 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Wed, 12 Feb 2025 11:47:33 +0400 Subject: [PATCH 06/27] add example pages --- ...-layout-auto-responsive-inside-dialog.html | 63 ++++++ dev/form-layout-auto-responsive.html | 204 ++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100644 dev/form-layout-auto-responsive-inside-dialog.html create mode 100644 dev/form-layout-auto-responsive.html diff --git a/dev/form-layout-auto-responsive-inside-dialog.html b/dev/form-layout-auto-responsive-inside-dialog.html new file mode 100644 index 00000000000..9982dac8940 --- /dev/null +++ b/dev/form-layout-auto-responsive-inside-dialog.html @@ -0,0 +1,63 @@ + + + + + maxColumns=2 + + + + maxColumns=2 + expandColumns + + + + Set dialog width 80% + + + + diff --git a/dev/form-layout-auto-responsive.html b/dev/form-layout-auto-responsive.html new file mode 100644 index 00000000000..b025ea2a87f --- /dev/null +++ b/dev/form-layout-auto-responsive.html @@ -0,0 +1,204 @@ + + + + + + + Form Layout + + + + + + + + +

autoResponsive + maxColumns=2

+ + + + + + + + + +

autoResponsive + maxColumns=2 + expandColumns

+ + + + + + + + + + + + + + + + + + + From cc111ed226e840921db532e4ce34d72d8675b650 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Wed, 12 Feb 2025 13:39:05 +0400 Subject: [PATCH 07/27] add more examples --- ...form-layout-auto-responsive-inside-dialog.html | 3 --- dev/form-layout-auto-responsive.html | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/dev/form-layout-auto-responsive-inside-dialog.html b/dev/form-layout-auto-responsive-inside-dialog.html index 9982dac8940..1ad93a5c548 100644 --- a/dev/form-layout-auto-responsive-inside-dialog.html +++ b/dev/form-layout-auto-responsive-inside-dialog.html @@ -38,9 +38,6 @@ - - - `, }; diff --git a/dev/form-layout-auto-responsive.html b/dev/form-layout-auto-responsive.html index b025ea2a87f..26e02fb7510 100644 --- a/dev/form-layout-auto-responsive.html +++ b/dev/form-layout-auto-responsive.html @@ -12,6 +12,7 @@ import '@vaadin/form-layout/vaadin-form-item.js'; import '@vaadin/text-field'; import '@vaadin/password-field'; + import '@vaadin/horizontal-layout'; - - - - - - - + } + customElements.define('examples-view', ExamplesView); + + + From 72448709be0bbe39d95c9e14a44345e5e7700590 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Thu, 13 Feb 2025 17:04:17 +0400 Subject: [PATCH 19/27] format form-layout-auto-responsive.html --- dev/form-layout-auto-responsive.html | 122 +++++++++++++-------------- 1 file changed, 60 insertions(+), 62 deletions(-) diff --git a/dev/form-layout-auto-responsive.html b/dev/form-layout-auto-responsive.html index be14a9cc64f..f3269de5544 100644 --- a/dev/form-layout-auto-responsive.html +++ b/dev/form-layout-auto-responsive.html @@ -1,43 +1,42 @@ - - - - - - Form Layout - - - - - - - - - - - + customElements.define('examples-view', ExamplesView); + + From 803c13ff006302c963c6f1293e10fcb50d1c6781 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Fri, 14 Feb 2025 10:54:10 +0400 Subject: [PATCH 20/27] improve code documentation --- .../form-layout/src/vaadin-form-layout-styles.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/form-layout/src/vaadin-form-layout-styles.js b/packages/form-layout/src/vaadin-form-layout-styles.js index cac2ebf23a1..d3c68e33794 100644 --- a/packages/form-layout/src/vaadin-form-layout-styles.js +++ b/packages/form-layout/src/vaadin-form-layout-styles.js @@ -78,8 +78,8 @@ export const formLayoutStyles = css` grid-auto-columns: 0; /* - A max width needs to be defined to prevent the layout from expanding to more columns - than allowed by the --_column-max-count property: + The layout's width needs to be capped to prevent it from expanding to more columns + than defined by --_column-max-count: 1. "width" + "flex-grow" are used instead of "max-width" for the layout to be able to shrink to its minimum width in , which doesn't work otherwise. @@ -105,12 +105,10 @@ export const formLayoutStyles = css` :host([auto-responsive][expand-columns]) #layout { /* - This construction makes the CSS grid columns switch from a fixed width - to the same width expressed as a percentage of the total width of the - maximum number of columns and gaps when the layout reaches that width. - This prevents the CSS grid from creating new columns and instead causes - it to keep the existing columns expanding evenly to fill available space - when --_column-max-count is reached. + When the layout reaches the maximum number of columns, this expression + switches from fixed width to percentage-based width. As a result, the + grid stops adding new columns and instead evenly expands the existing + columns to fill the available space */ --_column-min-width: max( var(--_column-width), From c648dbebfbcd76eaa9f87deb1ce6b6542714fefb Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Fri, 14 Feb 2025 15:34:06 +0400 Subject: [PATCH 21/27] add labelsAside mode --- dev/form-layout-auto-responsive.html | 2 +- .../src/vaadin-form-layout-mixin.js | 13 +++++- .../src/vaadin-form-layout-styles.js | 40 ++++++++++++------- 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/dev/form-layout-auto-responsive.html b/dev/form-layout-auto-responsive.html index f3269de5544..4f8f69acb34 100644 --- a/dev/form-layout-auto-responsive.html +++ b/dev/form-layout-auto-responsive.html @@ -72,7 +72,7 @@

autoResponsive + br

autoResponsive + label aside

- + diff --git a/packages/form-layout/src/vaadin-form-layout-mixin.js b/packages/form-layout/src/vaadin-form-layout-mixin.js index 07a92386b5d..1f76430da4c 100644 --- a/packages/form-layout/src/vaadin-form-layout-mixin.js +++ b/packages/form-layout/src/vaadin-form-layout-mixin.js @@ -122,6 +122,12 @@ export const FormLayoutMixin = (superClass) => value: false, reflectToAttribute: true, }, + + labelsAside: { + type: Boolean, + value: false, + reflectToAttribute: true, + }, }; } @@ -347,11 +353,14 @@ export const FormLayoutMixin = (superClass) => /** @private */ _updateCSSGridLayout() { - const { gridTemplateColumns } = getComputedStyle(this.$.layout); + const layoutComputedStyle = getComputedStyle(this.$.layout); // Calculate the number of rendered columns, excluding CSS grid auto columns (0px) + const { gridTemplateColumns } = layoutComputedStyle; const renderedColumnCount = gridTemplateColumns.split(' ').filter((width) => width !== '0px').length; + this.$.layout.style.setProperty('--_rendered-column-count', renderedColumnCount); + // this.$.layout.style.setProperty('--_rendered-layout-width', `${this.offsetWidth}px`); let resetColumn = false; [...this.children] @@ -365,6 +374,8 @@ export const FormLayoutMixin = (superClass) => const colspan = child.getAttribute('colspan') || child.getAttribute('data-colspan'); if (colspan) { child.style.setProperty('--_colspan', colspan); + } else { + child.style.removeProperty('--_colspan'); } if (resetColumn) { diff --git a/packages/form-layout/src/vaadin-form-layout-styles.js b/packages/form-layout/src/vaadin-form-layout-styles.js index d3c68e33794..3aaffe0c4fd 100644 --- a/packages/form-layout/src/vaadin-form-layout-styles.js +++ b/packages/form-layout/src/vaadin-form-layout-styles.js @@ -44,31 +44,32 @@ export const formLayoutStyles = css` } :host([auto-responsive]) { - --_column-width: var(--vaadin-form-layout-column-width); - --_column-max-count: var(--vaadin-form-layout-max-columns); - display: flex; - min-width: var(--_column-width); + min-width: var(--vaadin-form-layout-column-width); } :host([auto-responsive]) #layout { - --_max-total-gap-width: calc((var(--_column-max-count) - 1) * var(--vaadin-form-layout-column-spacing)); - --_max-total-col-width: calc(var(--_column-max-count) * var(--_column-width)); + --_column-width-with-label-top: var(--vaadin-form-layout-column-width); + /* prettier-ignore */ + --_column-width-with-label-aside: calc( + var(--vaadin-form-item-label-width) + + var(--vaadin-form-item-label-spacing) + + var(--vaadin-form-layout-column-width) + ); + + --_column-gap: var(--vaadin-form-layout-column-spacing); + --_column-width: var(--_column-width-with-label-top); --_column-min-width: var(--_column-width); --_column-max-width: var(--_column-width); - --_colstart: auto; - --_colspan: 1; + --_column-max-count: var(--vaadin-form-layout-max-columns); - /* - The column count is calculated in JS using getComputedStyle(this.$.layout).gridTemplateColumns - after the layout is rendered. - */ - --_rendered-column-count: 1; + --_max-total-gap-width: calc((var(--_column-max-count) - 1) * var(--_column-gap)); + --_max-total-col-width: calc(var(--_column-max-count) * var(--_column-width)); display: grid; grid-template-columns: repeat(auto-fit, minmax(var(--_column-min-width), var(--_column-max-width))); - gap: var(--vaadin-form-layout-row-spacing) var(--vaadin-form-layout-column-spacing); + gap: var(--vaadin-form-layout-row-spacing) var(--_column-gap); /* Auto-columns can be created when an item's colspan exceeds the rendered column count. @@ -100,7 +101,16 @@ export const formLayoutStyles = css` } :host([auto-responsive]) #layout ::slotted(*) { - grid-column: var(--_colstart) / span min(var(--_colspan), var(--_rendered-column-count)); + /* + The column count (--_rendered-column-count) is calculated in JS + using getComputedStyle(this.$.layout).gridTemplateColumns after + the layout is rendered. + */ + grid-column: var(--_colstart, auto) / span min(var(--_colspan, 1), var(--_rendered-column-count)); + } + + :host([auto-responsive][labels-aside]) #layout { + --_column-width: var(--_column-width-with-label-aside); } :host([auto-responsive][expand-columns]) #layout { From 99ac4899aca80f289ac5d7881687298938dcfeba Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Fri, 14 Feb 2025 16:16:23 +0400 Subject: [PATCH 22/27] add --is-label-aside --- .../src/vaadin-form-layout-styles.js | 18 +++++++++++++----- packages/form-layout/src/vaadin-form-layout.js | 1 + 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/form-layout/src/vaadin-form-layout-styles.js b/packages/form-layout/src/vaadin-form-layout-styles.js index 3aaffe0c4fd..187ee0d5aac 100644 --- a/packages/form-layout/src/vaadin-form-layout-styles.js +++ b/packages/form-layout/src/vaadin-form-layout-styles.js @@ -44,11 +44,6 @@ export const formLayoutStyles = css` } :host([auto-responsive]) { - display: flex; - min-width: var(--vaadin-form-layout-column-width); - } - - :host([auto-responsive]) #layout { --_column-width-with-label-top: var(--vaadin-form-layout-column-width); /* prettier-ignore */ @@ -58,6 +53,19 @@ export const formLayoutStyles = css` var(--vaadin-form-layout-column-width) ); + --_is-label-aside: clamp(0px, calc(100% - var(--_column-width-with-label-aside)), 1px); + transform: translateX(calc(var(--_is-label-aside) * 100)); + + display: flex; + min-width: var(--_column-width-with-label-top); + } + + /* :host([auto-responsive]) #style { + background-position-x: var(--_column-width-with-label-top); + background-position-y: var(--_column-width-with-label-aside); + } */ + + :host([auto-responsive]) #layout { --_column-gap: var(--vaadin-form-layout-column-spacing); --_column-width: var(--_column-width-with-label-top); --_column-min-width: var(--_column-width); diff --git a/packages/form-layout/src/vaadin-form-layout.js b/packages/form-layout/src/vaadin-form-layout.js index 5c274f73078..c063d0f04f5 100644 --- a/packages/form-layout/src/vaadin-form-layout.js +++ b/packages/form-layout/src/vaadin-form-layout.js @@ -116,6 +116,7 @@ class FormLayout extends FormLayoutMixin(ThemableMixin(ElementMixin(PolymerEleme static get template() { return html` +
From e7b15305af09a2cbea554b827612724ab6c55ce0 Mon Sep 17 00:00:00 2001 From: Diego Cardoso Date: Fri, 14 Feb 2025 16:09:41 +0200 Subject: [PATCH 23/27] set column width with label to background-position-x --- packages/form-layout/src/vaadin-form-layout-styles.js | 8 +++----- packages/form-layout/src/vaadin-form-layout.js | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/form-layout/src/vaadin-form-layout-styles.js b/packages/form-layout/src/vaadin-form-layout-styles.js index 187ee0d5aac..85d2c21af00 100644 --- a/packages/form-layout/src/vaadin-form-layout-styles.js +++ b/packages/form-layout/src/vaadin-form-layout-styles.js @@ -54,16 +54,14 @@ export const formLayoutStyles = css` ); --_is-label-aside: clamp(0px, calc(100% - var(--_column-width-with-label-aside)), 1px); - transform: translateX(calc(var(--_is-label-aside) * 100)); display: flex; min-width: var(--_column-width-with-label-top); } - /* :host([auto-responsive]) #style { - background-position-x: var(--_column-width-with-label-top); - background-position-y: var(--_column-width-with-label-aside); - } */ + :host([auto-responsive]) #style { + background-position-x: var(--_column-width-with-label-aside); + } :host([auto-responsive]) #layout { --_column-gap: var(--vaadin-form-layout-column-spacing); diff --git a/packages/form-layout/src/vaadin-form-layout.js b/packages/form-layout/src/vaadin-form-layout.js index c063d0f04f5..7c5566b859c 100644 --- a/packages/form-layout/src/vaadin-form-layout.js +++ b/packages/form-layout/src/vaadin-form-layout.js @@ -116,7 +116,7 @@ class FormLayout extends FormLayoutMixin(ThemableMixin(ElementMixin(PolymerEleme static get template() { return html` - +
From 7f8ea8953df1f7cc85770dc26d954304f6b329b8 Mon Sep 17 00:00:00 2001 From: Diego Cardoso Date: Fri, 14 Feb 2025 16:41:08 +0200 Subject: [PATCH 24/27] make labels go above --- .../src/vaadin-form-layout-mixin.js | 6 ++++- .../src/vaadin-form-layout-styles.js | 23 +++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/form-layout/src/vaadin-form-layout-mixin.js b/packages/form-layout/src/vaadin-form-layout-mixin.js index 1f76430da4c..f1c84d20ee9 100644 --- a/packages/form-layout/src/vaadin-form-layout-mixin.js +++ b/packages/form-layout/src/vaadin-form-layout-mixin.js @@ -126,7 +126,6 @@ export const FormLayoutMixin = (superClass) => labelsAside: { type: Boolean, value: false, - reflectToAttribute: true, }, }; } @@ -354,6 +353,11 @@ export const FormLayoutMixin = (superClass) => /** @private */ _updateCSSGridLayout() { const layoutComputedStyle = getComputedStyle(this.$.layout); + const styleComputeStyle = getComputedStyle(this.$.style); + + const columnWidthWithLabelAside = styleComputeStyle.backgroundPositionX; + const isLabelAside = this.offsetWidth >= parseFloat(columnWidthWithLabelAside); + this.toggleAttribute('labels-aside', isLabelAside); // Calculate the number of rendered columns, excluding CSS grid auto columns (0px) const { gridTemplateColumns } = layoutComputedStyle; diff --git a/packages/form-layout/src/vaadin-form-layout-styles.js b/packages/form-layout/src/vaadin-form-layout-styles.js index 85d2c21af00..e4aea2fe658 100644 --- a/packages/form-layout/src/vaadin-form-layout-styles.js +++ b/packages/form-layout/src/vaadin-form-layout-styles.js @@ -53,10 +53,19 @@ export const formLayoutStyles = css` var(--vaadin-form-layout-column-width) ); - --_is-label-aside: clamp(0px, calc(100% - var(--_column-width-with-label-aside)), 1px); + --_vaadin-form-layout-label-position: initial; display: flex; min-width: var(--_column-width-with-label-top); + background-position-x: var(--_is-label-aside); + } + + :host([auto-responsive][labels-aside]) { + --_vaadin-form-layout-label-position: ' '; + } + + :host([auto-responsive][labels-aside]) #layout { + --_column-width: var(--_column-width-with-label-aside); } :host([auto-responsive]) #style { @@ -115,10 +124,6 @@ export const formLayoutStyles = css` grid-column: var(--_colstart, auto) / span min(var(--_colspan, 1), var(--_rendered-column-count)); } - :host([auto-responsive][labels-aside]) #layout { - --_column-width: var(--_column-width-with-label-aside); - } - :host([auto-responsive][expand-columns]) #layout { /* When the layout reaches the maximum number of columns, this expression @@ -148,8 +153,12 @@ export const formLayoutStyles = css` export const formItemStyles = css` :host { display: inline-flex; - flex-direction: row; - align-items: baseline; + /* This is a bit convoluted, but the end result is that + LABELS ABOVE => align-items: stretch; justify-content: normal; + LABELS ASIDE => align-items: stretch; justify-content: baseline; */ + flex-flow: var(--_vaadin-form-layout-label-position, column) nowrap; + place-items: var(--_vaadin-form-layout-label-position, stretch) baseline; + justify-content: normal; margin: calc(0.5 * var(--vaadin-form-item-row-spacing, var(--vaadin-form-layout-row-spacing, 1em))) 0; } From 39de5f56096df64d077720f2142f2af46cd020e0 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Mon, 17 Feb 2025 11:02:13 +0400 Subject: [PATCH 25/27] clean up labels aside implementation --- .../src/vaadin-form-layout-mixin.js | 32 ++++++++------ .../src/vaadin-form-layout-styles.js | 43 +++++++++---------- .../form-layout/src/vaadin-form-layout.js | 1 - 3 files changed, 40 insertions(+), 36 deletions(-) diff --git a/packages/form-layout/src/vaadin-form-layout-mixin.js b/packages/form-layout/src/vaadin-form-layout-mixin.js index f1c84d20ee9..f4b456d03ef 100644 --- a/packages/form-layout/src/vaadin-form-layout-mixin.js +++ b/packages/form-layout/src/vaadin-form-layout-mixin.js @@ -126,6 +126,7 @@ export const FormLayoutMixin = (superClass) => labelsAside: { type: Boolean, value: false, + reflectToAttribute: true, }, }; } @@ -352,19 +353,10 @@ export const FormLayoutMixin = (superClass) => /** @private */ _updateCSSGridLayout() { - const layoutComputedStyle = getComputedStyle(this.$.layout); - const styleComputeStyle = getComputedStyle(this.$.style); - - const columnWidthWithLabelAside = styleComputeStyle.backgroundPositionX; - const isLabelAside = this.offsetWidth >= parseFloat(columnWidthWithLabelAside); - this.toggleAttribute('labels-aside', isLabelAside); - - // Calculate the number of rendered columns, excluding CSS grid auto columns (0px) - const { gridTemplateColumns } = layoutComputedStyle; - const renderedColumnCount = gridTemplateColumns.split(' ').filter((width) => width !== '0px').length; + const fitsLabelsAside = this.offsetWidth >= this._columnWidthWithLabelsAside; + this.$.layout.toggleAttribute('fits-labels-aside', this.labelsAside && fitsLabelsAside); - this.$.layout.style.setProperty('--_rendered-column-count', renderedColumnCount); - // this.$.layout.style.setProperty('--_rendered-layout-width', `${this.offsetWidth}px`); + this.$.layout.style.setProperty('--_rendered-column-count', this._renderedColumnCount); let resetColumn = false; [...this.children] @@ -415,4 +407,20 @@ export const FormLayoutMixin = (superClass) => this.$.layout.style.opacity = ''; } + + get _columnWidthWithLabelsAbove() { + const { backgroundPositionX } = getComputedStyle(this.$.layout, '::before'); + return parseFloat(backgroundPositionX); + } + + get _columnWidthWithLabelsAside() { + const { backgroundPositionY } = getComputedStyle(this.$.layout, '::before'); + return parseFloat(backgroundPositionY); + } + + get _renderedColumnCount() { + // Calculate the number of rendered columns, excluding CSS grid auto columns (0px) + const { gridTemplateColumns } = getComputedStyle(this.$.layout); + return gridTemplateColumns.split(' ').filter((width) => width !== '0px').length; + } }; diff --git a/packages/form-layout/src/vaadin-form-layout-styles.js b/packages/form-layout/src/vaadin-form-layout-styles.js index e4aea2fe658..196f76a5ad4 100644 --- a/packages/form-layout/src/vaadin-form-layout-styles.js +++ b/packages/form-layout/src/vaadin-form-layout-styles.js @@ -44,41 +44,29 @@ export const formLayoutStyles = css` } :host([auto-responsive]) { - --_column-width-with-label-top: var(--vaadin-form-layout-column-width); - + --_column-width-with-labels-above: var(--vaadin-form-layout-column-width); /* prettier-ignore */ - --_column-width-with-label-aside: calc( + --_column-width-with-labels-aside: calc( var(--vaadin-form-item-label-width) + var(--vaadin-form-item-label-spacing) + var(--vaadin-form-layout-column-width) ); - --_vaadin-form-layout-label-position: initial; - display: flex; - min-width: var(--_column-width-with-label-top); - background-position-x: var(--_is-label-aside); - } - - :host([auto-responsive][labels-aside]) { - --_vaadin-form-layout-label-position: ' '; - } - - :host([auto-responsive][labels-aside]) #layout { - --_column-width: var(--_column-width-with-label-aside); + min-width: var(--_column-width-with-labels-above); } - :host([auto-responsive]) #style { - background-position-x: var(--_column-width-with-label-aside); + :host([auto-responsive]) #layout::before { + background-position-x: var(--_column-width-with-labels-above); + background-position-y: var(--_column-width-with-labels-aside); } :host([auto-responsive]) #layout { --_column-gap: var(--vaadin-form-layout-column-spacing); - --_column-width: var(--_column-width-with-label-top); + --_column-width: var(--_column-width-with-labels-above); --_column-min-width: var(--_column-width); --_column-max-width: var(--_column-width); --_column-max-count: var(--vaadin-form-layout-max-columns); - --_max-total-gap-width: calc((var(--_column-max-count) - 1) * var(--_column-gap)); --_max-total-col-width: calc(var(--_column-max-count) * var(--_column-width)); @@ -148,23 +136,32 @@ export const formLayoutStyles = css` */ flex-grow: 1; } + + :host([auto-responsive][labels-aside]) #layout[fits-labels-aside] { + --_column-width: var(--_column-width-with-labels-aside); + } + + :host([auto-responsive][labels-aside]) #layout[fits-labels-aside] ::slotted(*) { + --_label-position: ' '; + } `; export const formItemStyles = css` :host { + --_label-position: initial; + display: inline-flex; /* This is a bit convoluted, but the end result is that LABELS ABOVE => align-items: stretch; justify-content: normal; LABELS ASIDE => align-items: stretch; justify-content: baseline; */ - flex-flow: var(--_vaadin-form-layout-label-position, column) nowrap; - place-items: var(--_vaadin-form-layout-label-position, stretch) baseline; + flex-flow: var(--_label-position, column) nowrap; + place-items: var(--_label-position, stretch) baseline; justify-content: normal; margin: calc(0.5 * var(--vaadin-form-item-row-spacing, var(--vaadin-form-layout-row-spacing, 1em))) 0; } :host([label-position='top']) { - flex-direction: column; - align-items: stretch; + --_label-position: ' '; } :host([hidden]) { diff --git a/packages/form-layout/src/vaadin-form-layout.js b/packages/form-layout/src/vaadin-form-layout.js index 7c5566b859c..5c274f73078 100644 --- a/packages/form-layout/src/vaadin-form-layout.js +++ b/packages/form-layout/src/vaadin-form-layout.js @@ -116,7 +116,6 @@ class FormLayout extends FormLayoutMixin(ThemableMixin(ElementMixin(PolymerEleme static get template() { return html` -
From 3656f4e884e9584b088fb7bb84e82d3182f5cc78 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Mon, 17 Feb 2025 11:27:31 +0400 Subject: [PATCH 26/27] add more examples --- dev/form-layout-auto-responsive.html | 44 +++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/dev/form-layout-auto-responsive.html b/dev/form-layout-auto-responsive.html index 4f8f69acb34..e42e24d97ce 100644 --- a/dev/form-layout-auto-responsive.html +++ b/dev/form-layout-auto-responsive.html @@ -26,6 +26,7 @@