Skip to content

Commit f74c5a0

Browse files
ugur-vaadinvursen
andauthored
feat: add min columns feature for form layout (#8935)
* feat: add min columns feature for form layout * refactor: set min-width on the host to avoid overflow * chore: cleanup debugging leftovers * fix: move the css grid variables to host * fix: move grid column max total width property calculation to host * fix: update fits label aside breakpoint calculation * fix: refletct fits label aside on the host and update the style to use host * test: update snapshots * test: add visual tests * refactor: revert reflecting attribute to host and update css calculation * test: update visual tests and add baseline images * chore: cleanup and revert unnecessary changes * chore: remove extra line * test: update snapshots * test: update material visual test baseline * reorganize CSS properties for better clarity * Update packages/form-layout/src/layouts/auto-responsive-layout.js Co-authored-by: Sergey Vinogradov <[email protected]> * Update packages/form-layout/test/visual/lumo/form-layout-auto-responsive.test.js Co-authored-by: Sergey Vinogradov <[email protected]> * Update packages/form-layout/test/visual/lumo/form-layout-auto-responsive.test.js Co-authored-by: Sergey Vinogradov <[email protected]> * Update packages/form-layout/test/visual/lumo/form-layout-auto-responsive.test.js Co-authored-by: Sergey Vinogradov <[email protected]> * chore: revert mincolumn and maxcolumn updates to examples * chore: add separate min columns examples * test: update material test naming to match lumo and update snapshots --------- Co-authored-by: Sergey Vinogradov <[email protected]>
1 parent c806835 commit f74c5a0

20 files changed

+448
-32
lines changed

dev/form-layout-auto-responsive.html

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ <h1>autoResponsive</h1>
5858
<vaadin-button>Register</vaadin-button>
5959
</vaadin-form-layout>
6060
61+
<h1>autoResponsive + minColumns</h1>
62+
<vaadin-form-layout auto-responsive auto-rows min-columns="2">
63+
<vaadin-text-field label="First name"></vaadin-text-field>
64+
<vaadin-text-field label="Last name"></vaadin-text-field>
65+
<vaadin-text-area label="Address" colspan="2"></vaadin-text-area>
66+
<vaadin-password-field label="Password"></vaadin-password-field>
67+
<vaadin-password-field label="Confirm"></vaadin-password-field>
68+
<vaadin-button>Register</vaadin-button>
69+
</vaadin-form-layout>
70+
6171
<h1>autoResponsive + expandColumns</h1>
6272
<vaadin-form-layout auto-responsive auto-rows max-columns="2" expand-columns>
6373
<vaadin-text-field label="First name"></vaadin-text-field>
@@ -145,6 +155,24 @@ <h1>autoResponsive inside HorizontalLayout + flex:1</h1>
145155
</vaadin-form-layout>
146156
</vaadin-horizontal-layout>
147157
158+
<h1>autoResponsive inside HorizontalLayout + flex:1 + minColumns</h1>
159+
<vaadin-horizontal-layout theme="spacing">
160+
<vaadin-form-layout style="flex: 1;" auto-responsive auto-rows min-columns="2">
161+
<vaadin-text-field label="First name"></vaadin-text-field>
162+
<vaadin-text-field label="Last name"></vaadin-text-field>
163+
<vaadin-text-area label="Address" colspan="2"></vaadin-text-area>
164+
<vaadin-password-field label="Password"></vaadin-password-field>
165+
<vaadin-password-field label="Confirm"></vaadin-password-field>
166+
</vaadin-form-layout>
167+
<vaadin-form-layout style="flex: 1;" auto-responsive auto-rows min-columns="2" expand-columns>
168+
<vaadin-text-field label="First name"></vaadin-text-field>
169+
<vaadin-text-field label="Last name"></vaadin-text-field>
170+
<vaadin-text-area label="Address" colspan="2"></vaadin-text-area>
171+
<vaadin-password-field label="Password"></vaadin-password-field>
172+
<vaadin-password-field label="Confirm"></vaadin-password-field>
173+
</vaadin-form-layout>
174+
</vaadin-horizontal-layout>
175+
148176
<h1>autoResponsive inside HorizontalLayout + labels aside</h1>
149177
<vaadin-horizontal-layout theme="spacing">
150178
<vaadin-form-layout style="flex: 1;" auto-responsive auto-rows max-columns="2" labels-aside>
@@ -209,6 +237,22 @@ <h1>autoResponsive inside Dialog</h1>
209237
></vaadin-dialog>
210238
<vaadin-button @click="${this.openPrevSiblingDialog}">Open</vaadin-button>
211239
240+
<h1>autoResponsive inside Dialog + minColumns</h1>
241+
<vaadin-dialog
242+
${dialogRenderer(
243+
(dialog) => html`
244+
<vaadin-form-layout auto-responsive auto-rows min-columns="2">
245+
<vaadin-text-field label="First name"></vaadin-text-field>
246+
<vaadin-text-field label="Last name"></vaadin-text-field>
247+
<vaadin-text-area label="Address" colspan="2"></vaadin-text-area>
248+
<vaadin-password-field label="Password"></vaadin-password-field>
249+
<vaadin-password-field label="Confirm"></vaadin-password-field>
250+
</vaadin-form-layout>
251+
`,
252+
)}
253+
></vaadin-dialog>
254+
<vaadin-button @click="${this.openPrevSiblingDialog}">Open</vaadin-button>
255+
212256
<h1>autoResponsive inside Dialog + expandColumns + expandFields</h1>
213257
<vaadin-dialog
214258
${dialogRenderer(
@@ -256,6 +300,37 @@ <h1>autoResponsive inside Dialog + labelsAside</h1>
256300
></vaadin-dialog>
257301
<vaadin-button @click="${this.openPrevSiblingDialog}">Open</vaadin-button>
258302
303+
<h1>autoResponsive inside Dialog + labelsAside + minColumns</h1>
304+
<vaadin-dialog
305+
${dialogRenderer(
306+
(dialog) => html`
307+
<vaadin-form-layout auto-responsive auto-rows min-columns="2" labels-aside>
308+
<vaadin-form-item>
309+
<label slot="label"> First name </label>
310+
<vaadin-text-field></vaadin-text-field>
311+
</vaadin-form-item>
312+
<vaadin-form-item>
313+
<label slot="label"> Last name </label>
314+
<vaadin-text-field></vaadin-text-field>
315+
</vaadin-form-item>
316+
<vaadin-form-item colspan="2">
317+
<label slot="label"> Username </label>
318+
<vaadin-text-field colspan="2"></vaadin-text-field>
319+
</vaadin-form-item>
320+
<vaadin-form-item>
321+
<label slot="label"> Password </label>
322+
<vaadin-password-field></vaadin-password-field>
323+
</vaadin-form-item>
324+
<vaadin-form-item>
325+
<label slot="label"> Confirm </label>
326+
<vaadin-password-field></vaadin-password-field>
327+
</vaadin-form-item>
328+
</vaadin-form-layout>
329+
`,
330+
)}
331+
></vaadin-dialog>
332+
<vaadin-button @click="${this.openPrevSiblingDialog}">Open</vaadin-button>
333+
259334
<h1>autoResponsive inside Dialog 80%</h1>
260335
<vaadin-dialog
261336
width="80%"

packages/form-layout/src/layouts/auto-responsive-layout.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ export class AutoResponsiveLayout extends AbstractLayout {
130130
host.style.removeProperty('--_column-width');
131131
}
132132

133-
host.style.setProperty('--_max-columns', Math.min(props.maxColumns, maxColumns));
133+
host.style.setProperty('--_min-columns', props.minColumns);
134+
host.style.setProperty('--_max-columns', Math.min(Math.max(props.minColumns, props.maxColumns), maxColumns));
134135

135136
host.$.layout.toggleAttribute('fits-labels-aside', this.props.labelsAside && this.__fitsLabelsAside);
136137
host.$.layout.style.setProperty('--_grid-rendered-column-count', this.__renderedColumnCount);
@@ -170,13 +171,13 @@ export class AutoResponsiveLayout extends AbstractLayout {
170171
}
171172

172173
/** @private */
173-
get __columnWidthWithLabelsAside() {
174+
get __minWidthLabelsAside() {
174175
const { backgroundPositionY } = getComputedStyle(this.host.$.layout, '::before');
175176
return parseFloat(backgroundPositionY);
176177
}
177178

178179
/** @private */
179180
get __fitsLabelsAside() {
180-
return this.host.offsetWidth >= this.__columnWidthWithLabelsAside;
181+
return this.host.offsetWidth >= this.__minWidthLabelsAside;
181182
}
182183
}

packages/form-layout/src/vaadin-form-layout-mixin.d.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,17 @@ export declare class FormLayoutMixinClass {
119119
*/
120120
maxColumns: number;
121121

122+
/**
123+
* When `autoResponsive` is enabled, defines the minimum number of columns
124+
* that the layout can create. The layout will create columns at least up
125+
* to this limit provided the container width allows it.
126+
*
127+
* The default value is `1`.
128+
*
129+
* @attr {number} min-columns
130+
*/
131+
minColumns: number;
132+
122133
/**
123134
* When enabled with `autoResponsive`, distributes fields across columns
124135
* by placing each field in the next available column and wrapping to

packages/form-layout/src/vaadin-form-layout-mixin.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,21 @@ export const FormLayoutMixin = (superClass) =>
156156
value: 10,
157157
},
158158

159+
/**
160+
* When `autoResponsive` is enabled, defines the minimum number of columns
161+
* that the layout can create. The layout will create columns at least up
162+
* to this limit.
163+
*
164+
* The default value is `1`.
165+
*
166+
* @attr {number} min-columns
167+
*/
168+
minColumns: {
169+
type: Number,
170+
sync: true,
171+
value: 1,
172+
},
173+
159174
/**
160175
* When enabled with `autoResponsive`, distributes fields across columns
161176
* by placing each field in the next available column and wrapping to
@@ -231,7 +246,7 @@ export const FormLayoutMixin = (superClass) =>
231246

232247
static get observers() {
233248
return [
234-
'__autoResponsiveLayoutPropsChanged(columnWidth, maxColumns, autoRows, labelsAside, expandColumns, expandFields)',
249+
'__autoResponsiveLayoutPropsChanged(columnWidth, maxColumns, minColumns, autoRows, labelsAside, expandColumns, expandFields)',
235250
'__autoResponsiveChanged(autoResponsive)',
236251
];
237252
}
@@ -289,10 +304,19 @@ export const FormLayoutMixin = (superClass) =>
289304

290305
/** @private */
291306
// eslint-disable-next-line @typescript-eslint/max-params
292-
__autoResponsiveLayoutPropsChanged(columnWidth, maxColumns, autoRows, labelsAside, expandColumns, expandFields) {
307+
__autoResponsiveLayoutPropsChanged(
308+
columnWidth,
309+
maxColumns,
310+
minColumns,
311+
autoRows,
312+
labelsAside,
313+
expandColumns,
314+
expandFields,
315+
) {
293316
this.__autoResponsiveLayout.setProps({
294317
columnWidth,
295318
maxColumns,
319+
minColumns,
296320
autoRows,
297321
labelsAside,
298322
expandColumns,

packages/form-layout/src/vaadin-form-layout-styles.js

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,29 @@ export const formLayoutStyles = css`
4545
}
4646
4747
:host([auto-responsive]) {
48+
/* Column width */
4849
--_column-width: var(--vaadin-field-default-width, 12em);
4950
--_column-width-labels-above: var(--_column-width);
5051
--_column-width-labels-aside: calc(
5152
var(--_column-width) + var(--vaadin-form-layout-label-width) + var(--vaadin-form-layout-label-spacing)
5253
);
5354
55+
/* Column gap */
56+
--_min-total-gap: calc((var(--_min-columns) - 1) * var(--vaadin-form-layout-column-spacing));
57+
--_max-total-gap: calc((var(--_max-columns) - 1) * var(--vaadin-form-layout-column-spacing));
58+
59+
/* Minimum form layout width */
60+
--_min-width-labels-above: calc(var(--_min-columns) * var(--_column-width-labels-above) + var(--_min-total-gap));
61+
--_min-width-labels-aside: calc(var(--_min-columns) * var(--_column-width-labels-aside) + var(--_min-total-gap));
62+
--_min-width: var(--_min-width-labels-above);
63+
64+
/* Maximum form layout width */
65+
--_max-width-labels-above: calc(var(--_max-columns) * var(--_column-width-labels-above) + var(--_max-total-gap));
66+
--_max-width-labels-aside: calc(var(--_max-columns) * var(--_column-width-labels-aside) + var(--_max-total-gap));
67+
--_max-width: var(--_max-width-labels-above);
68+
5469
display: flex;
55-
min-width: var(--_column-width-labels-above);
70+
min-width: var(--_min-width);
5671
}
5772
5873
:host([auto-responsive]) #layout {
@@ -61,10 +76,7 @@ export const formLayoutStyles = css`
6176
--_form-item-labels-aside: ' '; /* false */
6277
6378
/* CSS grid related properties */
64-
--_grid-column-gap: var(--vaadin-form-layout-column-spacing);
6579
--_grid-column-width: var(--_column-width-labels-above);
66-
--_grid-column-max-total-gap: calc((var(--_max-columns) - 1) * var(--_grid-column-gap));
67-
--_grid-column-max-total-width: calc(var(--_max-columns) * var(--_column-width-labels-above));
6880
--_grid-repeat: var(--_grid-column-width);
6981
7082
display: grid;
@@ -78,7 +90,7 @@ export const formLayoutStyles = css`
7890
grid-auto-columns: 0;
7991
8092
justify-items: start;
81-
gap: var(--vaadin-form-layout-row-spacing) var(--_grid-column-gap);
93+
gap: var(--vaadin-form-layout-row-spacing) var(--vaadin-form-layout-column-spacing);
8294
8395
/*
8496
To prevent the layout from exceeding the column limit defined by --_max-columns,
@@ -92,17 +104,17 @@ export const formLayoutStyles = css`
92104
number of columns inside <vaadin-overlay>, which creates a new stacking context
93105
without a predefined width.
94106
*/
95-
width: calc(var(--_grid-column-max-total-width) + var(--_grid-column-max-total-gap));
107+
width: var(--_max-width);
96108
97109
/*
98110
Firefox requires min-width on both :host and #layout to allow the layout
99111
to shrink below the value specified in the CSS width property above.
100112
*/
101-
min-width: inherit;
113+
min-width: var(--_min-width);
102114
}
103115
104116
:host([auto-responsive]) #layout::before {
105-
background-position-y: var(--_column-width-labels-aside);
117+
background-position-y: var(--_min-width-labels-aside);
106118
}
107119
108120
:host([auto-responsive]) #layout ::slotted(*) {
@@ -118,8 +130,8 @@ export const formLayoutStyles = css`
118130
grid-column-start: var(--_grid-colstart, auto);
119131
}
120132
121-
:host([auto-responsive][labels-aside]) #layout {
122-
--_grid-column-max-total-width: calc(var(--_max-columns) * var(--_column-width-labels-aside));
133+
:host([auto-responsive][labels-aside]) {
134+
--_max-width: var(--_max-width-labels-aside);
123135
}
124136
125137
:host([auto-responsive][labels-aside]) #layout[fits-labels-aside] {
@@ -138,7 +150,7 @@ export const formLayoutStyles = css`
138150
reached yet.
139151
*/
140152
--_grid-repeat: minmax(
141-
max(var(--_grid-column-width), calc((100% - var(--_grid-column-max-total-gap)) / var(--_max-columns))),
153+
max(var(--_grid-column-width), calc((100% - var(--_max-total-gap)) / var(--_max-columns))),
142154
1fr
143155
);
144156

0 commit comments

Comments
 (0)