@vaadin/form-layout 24.7.0-beta1 → 24.8.0-alpha1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +11 -11
- package/src/layouts/abstract-layout.js +85 -0
- package/src/layouts/auto-responsive-layout.js +177 -0
- package/src/layouts/responsive-steps-layout.js +233 -0
- package/src/vaadin-form-layout-mixin.d.ts +83 -2
- package/src/vaadin-form-layout-mixin.js +151 -201
- package/src/vaadin-form-layout-styles.js +158 -11
- package/src/vaadin-form-layout.d.ts +82 -0
- package/src/vaadin-form-layout.js +82 -0
- package/src/vaadin-form-row.d.ts +24 -0
- package/src/vaadin-form-row.js +37 -0
- package/src/vaadin-lit-form-row.d.ts +6 -0
- package/src/vaadin-lit-form-row.js +38 -0
- package/theme/lumo/vaadin-form-row.d.ts +1 -0
- package/theme/lumo/vaadin-form-row.js +1 -0
- package/theme/lumo/vaadin-lit-form-row.d.ts +1 -0
- package/theme/lumo/vaadin-lit-form-row.js +1 -0
- package/theme/material/vaadin-form-row.d.ts +1 -0
- package/theme/material/vaadin-form-row.js +1 -0
- package/theme/material/vaadin-lit-form-row.d.ts +1 -0
- package/theme/material/vaadin-lit-form-row.js +1 -0
- package/vaadin-form-row.d.ts +1 -0
- package/vaadin-form-row.js +2 -0
- package/vaadin-lit-form-row.d.ts +1 -0
- package/vaadin-lit-form-row.js +2 -0
- package/web-types.json +177 -2
- package/web-types.lit.json +57 -2
|
@@ -3,22 +3,17 @@
|
|
|
3
3
|
* Copyright (c) 2017 - 2025 Vaadin Ltd.
|
|
4
4
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// Check if the value is a valid CSS length and not `inherit` or `normal`,
|
|
11
|
-
// which are also valid values for `word-spacing`, see:
|
|
12
|
-
// https://drafts.csswg.org/css-text-3/#word-spacing-property
|
|
13
|
-
return CSS.supports('word-spacing', value) && !['inherit', 'normal'].includes(value);
|
|
14
|
-
}
|
|
6
|
+
import { SlotStylesMixin } from '@vaadin/component-base/src/slot-styles-mixin.js';
|
|
7
|
+
import { AutoResponsiveLayout } from './layouts/auto-responsive-layout.js';
|
|
8
|
+
import { ResponsiveStepsLayout } from './layouts/responsive-steps-layout.js';
|
|
9
|
+
import { formLayoutSlotStyles } from './vaadin-form-layout-styles.js';
|
|
15
10
|
|
|
16
11
|
/**
|
|
17
12
|
* @polymerMixin
|
|
18
|
-
* @mixes
|
|
13
|
+
* @mixes SlotStylesMixin
|
|
19
14
|
*/
|
|
20
15
|
export const FormLayoutMixin = (superClass) =>
|
|
21
|
-
class extends
|
|
16
|
+
class extends SlotStylesMixin(superClass) {
|
|
22
17
|
static get properties() {
|
|
23
18
|
return {
|
|
24
19
|
/**
|
|
@@ -77,100 +72,169 @@ export const FormLayoutMixin = (superClass) =>
|
|
|
77
72
|
{ minWidth: '40em', columns: 2 },
|
|
78
73
|
];
|
|
79
74
|
},
|
|
80
|
-
observer: '
|
|
75
|
+
observer: '__responsiveStepsChanged',
|
|
76
|
+
sync: true,
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Enables the auto responsive mode in which the component automatically creates and adjusts
|
|
81
|
+
* columns based on the container's width. Columns have a fixed width defined by `columnWidth`
|
|
82
|
+
* and their number increases up to the limit set by `maxColumns`. The component dynamically
|
|
83
|
+
* adjusts the number of columns as the container size changes. When this mode is enabled,
|
|
84
|
+
* the `responsiveSteps` are ignored.
|
|
85
|
+
*
|
|
86
|
+
* By default, each field is placed on a new row. To organize fields into rows, there are
|
|
87
|
+
* two options:
|
|
88
|
+
*
|
|
89
|
+
* 1. Use `<vaadin-form-row>` to explicitly group fields into rows.
|
|
90
|
+
*
|
|
91
|
+
* 2. Enable the `autoRows` property to automatically arrange fields in available columns,
|
|
92
|
+
* wrapping to a new row when necessary. `<br>` elements can be used to force a new row.
|
|
93
|
+
*
|
|
94
|
+
* @attr {boolean} auto-responsive
|
|
95
|
+
*/
|
|
96
|
+
autoResponsive: {
|
|
97
|
+
type: Boolean,
|
|
81
98
|
sync: true,
|
|
99
|
+
value: false,
|
|
100
|
+
reflectToAttribute: true,
|
|
82
101
|
},
|
|
83
102
|
|
|
84
103
|
/**
|
|
85
|
-
*
|
|
86
|
-
*
|
|
104
|
+
* When `autoResponsive` is enabled, defines the width of each column.
|
|
105
|
+
* The value must be defined in CSS length units, e.g., `100px` or `13em`.
|
|
106
|
+
* The default value is `13em`.
|
|
107
|
+
*
|
|
108
|
+
* @attr {string} column-width
|
|
87
109
|
*/
|
|
88
|
-
|
|
110
|
+
columnWidth: {
|
|
111
|
+
type: String,
|
|
112
|
+
sync: true,
|
|
113
|
+
value: '13em',
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* When `autoResponsive` is enabled, defines the maximum number of columns
|
|
118
|
+
* that the layout can create. The layout will create columns up to this
|
|
119
|
+
* limit based on the available container width. The default value is `10`.
|
|
120
|
+
*
|
|
121
|
+
* @attr {number} max-columns
|
|
122
|
+
*/
|
|
123
|
+
maxColumns: {
|
|
89
124
|
type: Number,
|
|
90
125
|
sync: true,
|
|
126
|
+
value: 10,
|
|
91
127
|
},
|
|
92
128
|
|
|
93
129
|
/**
|
|
94
|
-
*
|
|
95
|
-
*
|
|
130
|
+
* When enabled with `autoResponsive`, distributes fields across columns
|
|
131
|
+
* by placing each field in the next available column and wrapping to
|
|
132
|
+
* the next row when the current row is full. `<br>` elements can be
|
|
133
|
+
* used to force a new row.
|
|
134
|
+
*
|
|
135
|
+
* @attr {boolean} auto-rows
|
|
96
136
|
*/
|
|
97
|
-
|
|
137
|
+
autoRows: {
|
|
98
138
|
type: Boolean,
|
|
99
139
|
sync: true,
|
|
140
|
+
value: false,
|
|
141
|
+
reflectToAttribute: true,
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* When enabled with `autoResponsive`, `<vaadin-form-item>` prefers positioning
|
|
146
|
+
* labels beside the fields. If the layout is too narrow to fit a single column
|
|
147
|
+
* with side labels, they revert to their default position above the fields.
|
|
148
|
+
*
|
|
149
|
+
* To customize the label width and the gap between the label and the field,
|
|
150
|
+
* use the following CSS properties:
|
|
151
|
+
*
|
|
152
|
+
* - `--vaadin-form-layout-label-width`
|
|
153
|
+
* - `--vaadin-form-layout-label-spacing`
|
|
154
|
+
*
|
|
155
|
+
* @attr {boolean} labels-aside
|
|
156
|
+
*/
|
|
157
|
+
labelsAside: {
|
|
158
|
+
type: Boolean,
|
|
159
|
+
sync: true,
|
|
160
|
+
value: false,
|
|
161
|
+
reflectToAttribute: true,
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* When `autoResponsive` is enabled, specifies whether the columns should expand
|
|
166
|
+
* in width to evenly fill any remaining space after the layout has created as
|
|
167
|
+
* many fixed-width (`columnWidth`) columns as possible within the `maxColumns`
|
|
168
|
+
* limit. The default value is `false`.
|
|
169
|
+
*
|
|
170
|
+
* @attr {boolean} expand-columns
|
|
171
|
+
*/
|
|
172
|
+
expandColumns: {
|
|
173
|
+
type: Boolean,
|
|
174
|
+
sync: true,
|
|
175
|
+
value: false,
|
|
176
|
+
reflectToAttribute: true,
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* When `autoResponsive` is enabled, specifies whether fields should stretch
|
|
181
|
+
* to take up all available space within columns. This setting also applies
|
|
182
|
+
* to fields inside `<vaadin-form-item>` elements. The default value is `false`.
|
|
183
|
+
*
|
|
184
|
+
* @attr {boolean} expand-fields
|
|
185
|
+
*/
|
|
186
|
+
expandFields: {
|
|
187
|
+
type: Boolean,
|
|
188
|
+
sync: true,
|
|
189
|
+
value: false,
|
|
190
|
+
reflectToAttribute: true,
|
|
100
191
|
},
|
|
101
192
|
};
|
|
102
193
|
}
|
|
103
194
|
|
|
104
195
|
static get observers() {
|
|
105
|
-
return [
|
|
196
|
+
return [
|
|
197
|
+
'__autoResponsiveLayoutPropsChanged(columnWidth, maxColumns, autoRows, labelsAside, expandColumns, expandFields)',
|
|
198
|
+
'__autoResponsiveChanged(autoResponsive)',
|
|
199
|
+
];
|
|
106
200
|
}
|
|
107
201
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
super.connectedCallback();
|
|
202
|
+
constructor() {
|
|
203
|
+
super();
|
|
111
204
|
|
|
112
|
-
|
|
113
|
-
this.
|
|
114
|
-
this.__childrenObserver.observe(this, { childList: true });
|
|
205
|
+
/** @type {import('./layouts/abstract-layout.js').AbstractLayout} */
|
|
206
|
+
this.__currentLayout;
|
|
115
207
|
|
|
116
|
-
|
|
117
|
-
this.
|
|
118
|
-
|
|
119
|
-
this._updateLayout();
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
this.__childrenAttributesObserver.observe(this, {
|
|
123
|
-
subtree: true,
|
|
124
|
-
attributes: true,
|
|
125
|
-
attributeFilter: ['colspan', 'data-colspan', 'hidden'],
|
|
126
|
-
});
|
|
208
|
+
this.__autoResponsiveLayout = new AutoResponsiveLayout(this);
|
|
209
|
+
this.__responsiveStepsLayout = new ResponsiveStepsLayout(this);
|
|
210
|
+
}
|
|
127
211
|
|
|
128
|
-
|
|
129
|
-
|
|
212
|
+
/** @protected */
|
|
213
|
+
connectedCallback() {
|
|
214
|
+
super.connectedCallback();
|
|
215
|
+
this.__currentLayout.connect();
|
|
130
216
|
}
|
|
131
217
|
|
|
132
218
|
/** @protected */
|
|
133
219
|
disconnectedCallback() {
|
|
134
220
|
super.disconnectedCallback();
|
|
221
|
+
this.__currentLayout.disconnect();
|
|
222
|
+
}
|
|
135
223
|
|
|
136
|
-
|
|
137
|
-
|
|
224
|
+
/** @override */
|
|
225
|
+
get slotStyles() {
|
|
226
|
+
return [`${formLayoutSlotStyles}`.replace('vaadin-form-layout', this.localName)];
|
|
138
227
|
}
|
|
139
228
|
|
|
140
|
-
/** @
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return Math.floor(n);
|
|
144
|
-
}
|
|
145
|
-
return 1;
|
|
229
|
+
/** @protected */
|
|
230
|
+
_updateLayout() {
|
|
231
|
+
this.__currentLayout.updateLayout();
|
|
146
232
|
}
|
|
147
233
|
|
|
148
234
|
/** @private */
|
|
149
|
-
|
|
235
|
+
__responsiveStepsChanged(responsiveSteps, oldResponsiveSteps) {
|
|
150
236
|
try {
|
|
151
|
-
|
|
152
|
-
throw new Error('Invalid "responsiveSteps" type, an Array is required.');
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (responsiveSteps.length < 1) {
|
|
156
|
-
throw new Error('Invalid empty "responsiveSteps" array, at least one item is required.');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
responsiveSteps.forEach((step) => {
|
|
160
|
-
if (this._naturalNumberOrOne(step.columns) !== step.columns) {
|
|
161
|
-
throw new Error(`Invalid 'columns' value of ${step.columns}, a natural number is required.`);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (step.minWidth !== undefined && !isValidCSSLength(step.minWidth)) {
|
|
165
|
-
throw new Error(`Invalid 'minWidth' value of ${step.minWidth}, a valid CSS length required.`);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (step.labelsPosition !== undefined && ['aside', 'top'].indexOf(step.labelsPosition) === -1) {
|
|
169
|
-
throw new Error(
|
|
170
|
-
`Invalid 'labelsPosition' value of ${step.labelsPosition}, 'aside' or 'top' string is required.`,
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
});
|
|
237
|
+
this.__responsiveStepsLayout.setProps({ responsiveSteps });
|
|
174
238
|
} catch (e) {
|
|
175
239
|
if (oldResponsiveSteps && oldResponsiveSteps !== responsiveSteps) {
|
|
176
240
|
console.warn(`${e.message} Using previously set 'responsiveSteps' instead.`);
|
|
@@ -184,147 +248,33 @@ export const FormLayoutMixin = (superClass) =>
|
|
|
184
248
|
];
|
|
185
249
|
}
|
|
186
250
|
}
|
|
187
|
-
|
|
188
|
-
this._selectResponsiveStep();
|
|
189
251
|
}
|
|
190
252
|
|
|
191
253
|
/** @private */
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
// Compare step min-width with the host width, select the passed step
|
|
202
|
-
if (stepMinWidthPx <= this.offsetWidth) {
|
|
203
|
-
selectedStep = step;
|
|
204
|
-
}
|
|
254
|
+
// eslint-disable-next-line @typescript-eslint/max-params
|
|
255
|
+
__autoResponsiveLayoutPropsChanged(columnWidth, maxColumns, autoRows, labelsAside, expandColumns, expandFields) {
|
|
256
|
+
this.__autoResponsiveLayout.setProps({
|
|
257
|
+
columnWidth,
|
|
258
|
+
maxColumns,
|
|
259
|
+
autoRows,
|
|
260
|
+
labelsAside,
|
|
261
|
+
expandColumns,
|
|
262
|
+
expandFields,
|
|
205
263
|
});
|
|
206
|
-
this.$.layout.style.removeProperty(tmpStyleProp);
|
|
207
|
-
|
|
208
|
-
// Sometimes converting units is not possible, e.g, when element is
|
|
209
|
-
// not connected. Then the `selectedStep` stays `undefined`.
|
|
210
|
-
if (selectedStep) {
|
|
211
|
-
// Apply the chosen responsive step's properties
|
|
212
|
-
this._columnCount = selectedStep.columns;
|
|
213
|
-
this._labelsOnTop = selectedStep.labelsPosition === 'top';
|
|
214
|
-
}
|
|
215
264
|
}
|
|
216
265
|
|
|
217
266
|
/** @private */
|
|
218
|
-
|
|
219
|
-
this.
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Update the layout.
|
|
224
|
-
* @protected
|
|
225
|
-
*/
|
|
226
|
-
_updateLayout() {
|
|
227
|
-
// Do not update layout when invisible
|
|
228
|
-
if (isElementHidden(this)) {
|
|
229
|
-
return;
|
|
267
|
+
__autoResponsiveChanged(autoResponsive) {
|
|
268
|
+
if (this.__currentLayout) {
|
|
269
|
+
this.__currentLayout.disconnect();
|
|
230
270
|
}
|
|
231
271
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
We have to subtract columnSpacing, because the column spacing space is taken
|
|
238
|
-
by item margins of 1/2 * spacing on both sides
|
|
239
|
-
*/
|
|
240
|
-
|
|
241
|
-
const style = getComputedStyle(this);
|
|
242
|
-
const columnSpacing = style.getPropertyValue('--vaadin-form-layout-column-spacing');
|
|
243
|
-
|
|
244
|
-
const direction = style.direction;
|
|
245
|
-
const marginStartProp = `margin-${direction === 'ltr' ? 'left' : 'right'}`;
|
|
246
|
-
const marginEndProp = `margin-${direction === 'ltr' ? 'right' : 'left'}`;
|
|
247
|
-
|
|
248
|
-
const containerWidth = this.offsetWidth;
|
|
249
|
-
|
|
250
|
-
let col = 0;
|
|
251
|
-
Array.from(this.children)
|
|
252
|
-
.filter((child) => child.localName === 'br' || getComputedStyle(child).display !== 'none')
|
|
253
|
-
.forEach((child, index, children) => {
|
|
254
|
-
if (child.localName === 'br') {
|
|
255
|
-
// Reset column count on line break
|
|
256
|
-
col = 0;
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const attrColspan = child.getAttribute('colspan') || child.getAttribute('data-colspan');
|
|
261
|
-
let colspan;
|
|
262
|
-
colspan = this._naturalNumberOrOne(parseFloat(attrColspan));
|
|
263
|
-
|
|
264
|
-
// Never span further than the number of columns
|
|
265
|
-
colspan = Math.min(colspan, this._columnCount);
|
|
266
|
-
|
|
267
|
-
const childRatio = colspan / this._columnCount;
|
|
268
|
-
child.style.width = `calc(${childRatio * 100}% - ${1 - childRatio} * ${columnSpacing})`;
|
|
269
|
-
|
|
270
|
-
if (col + colspan > this._columnCount) {
|
|
271
|
-
// Too big to fit on this row, let's wrap it
|
|
272
|
-
col = 0;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// At the start edge
|
|
276
|
-
if (col === 0) {
|
|
277
|
-
child.style.setProperty(marginStartProp, '0px');
|
|
278
|
-
} else {
|
|
279
|
-
child.style.removeProperty(marginStartProp);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
const nextIndex = index + 1;
|
|
283
|
-
const nextLineBreak = nextIndex < children.length && children[nextIndex].localName === 'br';
|
|
284
|
-
|
|
285
|
-
// At the end edge
|
|
286
|
-
if (col + colspan === this._columnCount) {
|
|
287
|
-
child.style.setProperty(marginEndProp, '0px');
|
|
288
|
-
} else if (nextLineBreak) {
|
|
289
|
-
const colspanRatio = (this._columnCount - col - colspan) / this._columnCount;
|
|
290
|
-
child.style.setProperty(
|
|
291
|
-
marginEndProp,
|
|
292
|
-
`calc(${colspanRatio * containerWidth}px + ${colspanRatio} * ${columnSpacing})`,
|
|
293
|
-
);
|
|
294
|
-
} else {
|
|
295
|
-
child.style.removeProperty(marginEndProp);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Move the column counter
|
|
299
|
-
col = (col + colspan) % this._columnCount;
|
|
300
|
-
|
|
301
|
-
if (child.localName === 'vaadin-form-item') {
|
|
302
|
-
if (this._labelsOnTop) {
|
|
303
|
-
if (child.getAttribute('label-position') !== 'top') {
|
|
304
|
-
child.__useLayoutLabelPosition = true;
|
|
305
|
-
child.setAttribute('label-position', 'top');
|
|
306
|
-
}
|
|
307
|
-
} else if (child.__useLayoutLabelPosition) {
|
|
308
|
-
delete child.__useLayoutLabelPosition;
|
|
309
|
-
child.removeAttribute('label-position');
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* @protected
|
|
317
|
-
* @override
|
|
318
|
-
*/
|
|
319
|
-
_onResize(contentRect) {
|
|
320
|
-
if (contentRect.width === 0 && contentRect.height === 0) {
|
|
321
|
-
this.$.layout.style.opacity = '0';
|
|
322
|
-
return;
|
|
272
|
+
if (autoResponsive) {
|
|
273
|
+
this.__currentLayout = this.__autoResponsiveLayout;
|
|
274
|
+
} else {
|
|
275
|
+
this.__currentLayout = this.__responsiveStepsLayout;
|
|
323
276
|
}
|
|
324
277
|
|
|
325
|
-
this.
|
|
326
|
-
this._updateLayout();
|
|
327
|
-
|
|
328
|
-
this.$.layout.style.opacity = '';
|
|
278
|
+
this.__currentLayout.connect();
|
|
329
279
|
}
|
|
330
280
|
};
|
|
@@ -22,7 +22,7 @@ export const formLayoutStyles = css`
|
|
|
22
22
|
display: none !important;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
#layout {
|
|
25
|
+
:host(:not([auto-responsive])) #layout {
|
|
26
26
|
display: flex;
|
|
27
27
|
|
|
28
28
|
align-items: baseline; /* default \`stretch\` is not appropriate */
|
|
@@ -30,7 +30,7 @@ export const formLayoutStyles = css`
|
|
|
30
30
|
flex-wrap: wrap; /* the items should wrap */
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
#layout ::slotted(*) {
|
|
33
|
+
:host(:not([auto-responsive])) #layout ::slotted(*) {
|
|
34
34
|
/* Items should neither grow nor shrink. */
|
|
35
35
|
flex-grow: 0;
|
|
36
36
|
flex-shrink: 0;
|
|
@@ -43,19 +43,167 @@ export const formLayoutStyles = css`
|
|
|
43
43
|
#layout ::slotted(br) {
|
|
44
44
|
display: none;
|
|
45
45
|
}
|
|
46
|
+
|
|
47
|
+
:host([auto-responsive]) {
|
|
48
|
+
--_column-width-labels-above: var(--_column-width);
|
|
49
|
+
--_column-width-labels-aside: calc(
|
|
50
|
+
var(--_column-width) + var(--vaadin-form-layout-label-width) + var(--vaadin-form-layout-label-spacing)
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
display: flex;
|
|
54
|
+
min-width: var(--_column-width-labels-above);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
:host([auto-responsive]) #layout {
|
|
58
|
+
/* By default, labels should be displayed above the fields */
|
|
59
|
+
--_form-item-labels-above: initial; /* true */
|
|
60
|
+
--_form-item-labels-aside: ' '; /* false */
|
|
61
|
+
|
|
62
|
+
/* CSS grid related properties */
|
|
63
|
+
--_grid-column-gap: var(--vaadin-form-layout-column-spacing);
|
|
64
|
+
--_grid-column-width: var(--_column-width-labels-above);
|
|
65
|
+
--_grid-column-max-total-gap: calc((var(--_max-columns) - 1) * var(--_grid-column-gap));
|
|
66
|
+
--_grid-column-max-total-width: calc(var(--_max-columns) * var(--_column-width-labels-above));
|
|
67
|
+
--_grid-repeat: var(--_grid-column-width);
|
|
68
|
+
|
|
69
|
+
display: grid;
|
|
70
|
+
grid-template-columns: repeat(auto-fill, var(--_grid-repeat));
|
|
71
|
+
|
|
72
|
+
/*
|
|
73
|
+
Auto-columns can be created when an item's colspan exceeds the rendered column count.
|
|
74
|
+
By setting auto-columns to 0, we exclude these columns from --_grid-rendered-column-count,
|
|
75
|
+
which is then used to cap the colspan.
|
|
76
|
+
*/
|
|
77
|
+
grid-auto-columns: 0;
|
|
78
|
+
|
|
79
|
+
justify-items: start;
|
|
80
|
+
gap: var(--vaadin-form-layout-row-spacing) var(--_grid-column-gap);
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
To prevent the layout from exceeding the column limit defined by --_max-columns,
|
|
84
|
+
its width needs to be constrained:
|
|
85
|
+
|
|
86
|
+
1. "width" is used instead of "max-width" because, together with the default "flex: 0 1 auto",
|
|
87
|
+
it allows the layout to shrink to its minimum width inside <vaadin-horizontal-layout>, which
|
|
88
|
+
wouldn't work otherwise.
|
|
89
|
+
|
|
90
|
+
2. "width" is used instead of "flex-basis" to make the layout expand to the maximum
|
|
91
|
+
number of columns inside <vaadin-overlay>, which creates a new stacking context
|
|
92
|
+
without a predefined width.
|
|
93
|
+
*/
|
|
94
|
+
width: calc(var(--_grid-column-max-total-width) + var(--_grid-column-max-total-gap));
|
|
95
|
+
|
|
96
|
+
/*
|
|
97
|
+
Firefox requires min-width on both :host and #layout to allow the layout
|
|
98
|
+
to shrink below the value specified in the CSS width property above.
|
|
99
|
+
*/
|
|
100
|
+
min-width: inherit;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
:host([auto-responsive]) #layout::before {
|
|
104
|
+
background-position-y: var(--_column-width-labels-aside);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
:host([auto-responsive]) #layout ::slotted(*) {
|
|
108
|
+
/* Make form items inherit label position from the layout */
|
|
109
|
+
--_form-item-labels-above: inherit;
|
|
110
|
+
--_form-item-labels-aside: inherit;
|
|
111
|
+
|
|
112
|
+
/* By default, place each child on a new row */
|
|
113
|
+
grid-column: 1 / span min(var(--_grid-colspan, 1), var(--_grid-rendered-column-count));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
:host([auto-responsive][auto-rows]) #layout ::slotted(*) {
|
|
117
|
+
grid-column-start: var(--_grid-colstart, auto);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
:host([auto-responsive][labels-aside]) #layout {
|
|
121
|
+
--_grid-column-max-total-width: calc(var(--_max-columns) * var(--_column-width-labels-aside));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
:host([auto-responsive][labels-aside]) #layout[fits-labels-aside] {
|
|
125
|
+
--_form-item-labels-above: ' '; /* false */
|
|
126
|
+
--_form-item-labels-aside: initial; /* true */
|
|
127
|
+
--_grid-column-width: var(--_column-width-labels-aside);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
:host([auto-responsive][expand-columns]) #layout {
|
|
131
|
+
/*
|
|
132
|
+
The "min" value in minmax ensures that once "maxColumns" is reached, the grid stops adding
|
|
133
|
+
new columns and instead expands the existing ones evenly to fill the available space.
|
|
134
|
+
|
|
135
|
+
The "max" value in minmax allows CSS grid columns to grow and evenly distribute any space
|
|
136
|
+
that remains when there isn't room for an additional column and "maxColumns" hasn't been
|
|
137
|
+
reached yet.
|
|
138
|
+
*/
|
|
139
|
+
--_grid-repeat: minmax(
|
|
140
|
+
max(var(--_grid-column-width), calc((100% - var(--_grid-column-max-total-gap)) / var(--_max-columns))),
|
|
141
|
+
1fr
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
/* Allow the layout to take up full available width of the parent element. */
|
|
145
|
+
flex-grow: 1;
|
|
146
|
+
}
|
|
147
|
+
`;
|
|
148
|
+
|
|
149
|
+
export const formLayoutSlotStyles = css`
|
|
150
|
+
/* Using :where to ensure user styles always take precedence */
|
|
151
|
+
:where(
|
|
152
|
+
vaadin-form-layout[auto-responsive] > *,
|
|
153
|
+
vaadin-form-layout[auto-responsive] vaadin-form-row > *,
|
|
154
|
+
vaadin-form-layout[auto-responsive] vaadin-form-item > *
|
|
155
|
+
) {
|
|
156
|
+
box-sizing: border-box;
|
|
157
|
+
max-width: 100%;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
:where(
|
|
161
|
+
vaadin-form-layout[auto-responsive][expand-fields] > *,
|
|
162
|
+
vaadin-form-layout[auto-responsive][expand-fields] vaadin-form-row > *,
|
|
163
|
+
vaadin-form-layout[auto-responsive][expand-fields] vaadin-form-item > *
|
|
164
|
+
) {
|
|
165
|
+
min-width: 100%;
|
|
166
|
+
}
|
|
167
|
+
`;
|
|
168
|
+
|
|
169
|
+
export const formRowStyles = css`
|
|
170
|
+
:host {
|
|
171
|
+
display: contents;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
:host([hidden]) {
|
|
175
|
+
display: none !important;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
::slotted(*) {
|
|
179
|
+
/* Make form items inherit label position from the layout */
|
|
180
|
+
--_form-item-labels-above: inherit;
|
|
181
|
+
--_form-item-labels-aside: inherit;
|
|
182
|
+
|
|
183
|
+
grid-column: auto / span min(var(--_grid-colspan, 1), var(--_grid-rendered-column-count));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
::slotted(:first-child) {
|
|
187
|
+
grid-column-start: 1;
|
|
188
|
+
}
|
|
46
189
|
`;
|
|
47
190
|
|
|
48
191
|
export const formItemStyles = css`
|
|
49
192
|
:host {
|
|
193
|
+
/* By default, when auto-responsive mode is disabled, labels should be displayed beside the fields. */
|
|
194
|
+
--_form-item-labels-above: ' '; /* false */
|
|
195
|
+
--_form-item-labels-aside: initial; /* true */
|
|
196
|
+
|
|
50
197
|
display: inline-flex;
|
|
51
|
-
|
|
52
|
-
|
|
198
|
+
align-items: var(--_form-item-labels-aside, baseline);
|
|
199
|
+
flex-flow: var(--_form-item-labels-above, column) nowrap;
|
|
200
|
+
justify-self: stretch;
|
|
53
201
|
margin: calc(0.5 * var(--vaadin-form-item-row-spacing, var(--vaadin-form-layout-row-spacing, 1em))) 0;
|
|
54
202
|
}
|
|
55
203
|
|
|
56
204
|
:host([label-position='top']) {
|
|
57
|
-
|
|
58
|
-
|
|
205
|
+
--_form-item-labels-above: initial; /* true */
|
|
206
|
+
--_form-item-labels-aside: ' '; /* false */
|
|
59
207
|
}
|
|
60
208
|
|
|
61
209
|
:host([hidden]) {
|
|
@@ -63,14 +211,13 @@ export const formItemStyles = css`
|
|
|
63
211
|
}
|
|
64
212
|
|
|
65
213
|
#label {
|
|
66
|
-
width: var(
|
|
214
|
+
width: var(
|
|
215
|
+
--_form-item-labels-aside,
|
|
216
|
+
var(--vaadin-form-item-label-width, var(--vaadin-form-layout-label-width, 8em))
|
|
217
|
+
);
|
|
67
218
|
flex: 0 0 auto;
|
|
68
219
|
}
|
|
69
220
|
|
|
70
|
-
:host([label-position='top']) #label {
|
|
71
|
-
width: auto;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
221
|
#spacing {
|
|
75
222
|
width: var(--vaadin-form-item-label-spacing, var(--vaadin-form-layout-label-spacing, 1em));
|
|
76
223
|
flex: 0 0 auto;
|