Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] refactor!: initial implementation of form-layout using CSS grid #8590

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev/form-layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
<title>Form Layout</title>
<script type="module" src="./common.js"></script>

Expand Down
98 changes: 25 additions & 73 deletions packages/form-layout/src/vaadin-form-layout-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export const FormLayoutMixin = (superClass) =>
_columnCount: {
type: Number,
sync: true,
observer: '__columnCountChanged',
},

/**
Expand All @@ -90,6 +91,7 @@ export const FormLayoutMixin = (superClass) =>
_labelsOnTop: {
type: Boolean,
sync: true,
observer: '__labelsOnTopChanged',
},

/** @private */
Expand All @@ -99,10 +101,6 @@ export const FormLayoutMixin = (superClass) =>
};
}

static get observers() {
return ['_invokeUpdateLayout(_columnCount, _labelsOnTop)'];
}

/** @protected */
ready() {
// Here we attach a style element that we use for validating
Expand Down Expand Up @@ -328,7 +326,12 @@ export const FormLayoutMixin = (superClass) =>
}

/** @private */
_invokeUpdateLayout() {
__columnCountChanged(columnCount) {
this.$.layout.style.setProperty('--_grid-cols', columnCount);
}

/** @private */
__labelsOnTopChanged() {
this._updateLayout();
}

Expand All @@ -342,78 +345,15 @@ export const FormLayoutMixin = (superClass) =>
return;
}

/*
The item width formula:

itemWidth = colspan / columnCount * 100% - columnSpacing

We have to subtract columnSpacing, because the column spacing space is taken
by item margins of 1/2 * spacing on both sides
*/

const style = getComputedStyle(this);
const columnSpacing = style.getPropertyValue('--vaadin-form-layout-column-spacing');

const direction = style.direction;
const marginStartProp = `margin-${direction === 'ltr' ? 'left' : 'right'}`;
const marginEndProp = `margin-${direction === 'ltr' ? 'right' : 'left'}`;

const containerWidth = this.offsetWidth;

let col = 0;
Array.from(this.children)
.filter((child) => child.localName === 'br' || getComputedStyle(child).display !== 'none')
.forEach((child, index, children) => {
let resetColumn = false;
[...this.children]
.filter((child) => getComputedStyle(child).display !== 'none' || child.localName === 'br')
.forEach((child) => {
if (child.localName === 'br') {
// Reset column count on line break
col = 0;
resetColumn = true;
return;
}

const attrColspan = child.getAttribute('colspan') || child.getAttribute('data-colspan');
let colspan;
colspan = this._naturalNumberOrOne(parseFloat(attrColspan));

// Never span further than the number of columns
colspan = Math.min(colspan, this._columnCount);

const childRatio = colspan / this._columnCount;

// Note: using 99.9% for 100% fixes rounding errors in MS Edge
// (< v16), otherwise the items might wrap, resizing is wobbly.
child.style.width = `calc(${childRatio * 99.9}% - ${1 - childRatio} * ${columnSpacing})`;

if (col + colspan > this._columnCount) {
// Too big to fit on this row, let's wrap it
col = 0;
}

// At the start edge
if (col === 0) {
child.style.setProperty(marginStartProp, '0px');
} else {
child.style.removeProperty(marginStartProp);
}

const nextIndex = index + 1;
const nextLineBreak = nextIndex < children.length && children[nextIndex].localName === 'br';

// At the end edge
if (col + colspan === this._columnCount) {
child.style.setProperty(marginEndProp, '0px');
} else if (nextLineBreak) {
const colspanRatio = (this._columnCount - col - colspan) / this._columnCount;
child.style.setProperty(
marginEndProp,
`calc(${colspanRatio * containerWidth}px + ${colspanRatio} * ${columnSpacing})`,
);
} else {
child.style.removeProperty(marginEndProp);
}

// Move the column counter
col = (col + colspan) % this._columnCount;

if (child.localName === 'vaadin-form-item') {
if (this._labelsOnTop) {
if (child.getAttribute('label-position') !== 'top') {
Expand All @@ -425,6 +365,18 @@ export const FormLayoutMixin = (superClass) =>
child.removeAttribute('label-position');
}
}

const colspan = child.getAttribute('colspan') || child.getAttribute('data-colspan');
if (colspan) {
child.style.setProperty('--_grid-colspan', colspan);
}

if (resetColumn) {
child.style.setProperty('--_grid-colstart', 1);
resetColumn = false;
} else {
child.style.removeProperty('--_grid-colstart');
}
});
}

Expand Down
18 changes: 6 additions & 12 deletions packages/form-layout/src/vaadin-form-layout-styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export const formLayoutStyles = css`
display: block;
max-width: 100%;
animation: 1ms vaadin-form-layout-appear;
/* Number of cols, defined by breakpoints. Default value is probably pointless. */
--_grid-cols: 10;
/* CSS API for host */
--vaadin-form-item-label-width: 8em;
--vaadin-form-item-label-spacing: 1em;
Expand All @@ -29,21 +31,14 @@ export const formLayoutStyles = css`
}

#layout {
display: flex;

display: grid;
grid-template-columns: repeat(var(--_grid-cols), 1fr);
gap: var(--vaadin-form-item-row-spacing) var(--vaadin-form-layout-column-spacing);
align-items: baseline; /* default \`stretch\` is not appropriate */

flex-wrap: wrap; /* the items should wrap */
}

#layout ::slotted(*) {
/* Items should neither grow nor shrink. */
flex-grow: 0;
flex-shrink: 0;

/* Margins make spacing between the columns */
margin-left: calc(0.5 * var(--vaadin-form-layout-column-spacing));
margin-right: calc(0.5 * var(--vaadin-form-layout-column-spacing));
grid-column: var(--_grid-colstart, auto) / span min(var(--_grid-colspan, 1), var(--_grid-cols));
}

#layout ::slotted(br) {
Expand All @@ -56,7 +51,6 @@ export const formItemStyles = css`
display: inline-flex;
flex-direction: row;
align-items: baseline;
margin: calc(0.5 * var(--vaadin-form-item-row-spacing, 1em)) 0;
}

:host([label-position='top']) {
Expand Down
Loading
Loading