Skip to content

Commit 6a11248

Browse files
committed
wip
1 parent 266fc58 commit 6a11248

File tree

3 files changed

+66
-80
lines changed

3 files changed

+66
-80
lines changed

dev/master-detail-layout.html

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,11 @@
7272

7373
<template id="static-detail">
7474
<div class="static-detail">
75-
<vaadin-form-layout auto-responsive max-columns="3" auto-rows>
76-
<vaadin-text-field label="First Name"></vaadin-text-field>
77-
<vaadin-text-field label="Last Name"></vaadin-text-field>
78-
<vaadin-text-field label="Email"></vaadin-text-field>
79-
<vaadin-select label="Country"></vaadin-select>
80-
</vaadin-form-layout>
81-
<vaadin-button>Close</vaadin-button>
75+
<vaadin-button>Close</vaadin-button><br />
76+
<vaadin-text-field label="First Name"></vaadin-text-field>
77+
<vaadin-text-field label="Last Name"></vaadin-text-field>
78+
<vaadin-text-field label="Email"></vaadin-text-field>
79+
<vaadin-select label="Country"></vaadin-select>
8280
</div>
8381
</template>
8482

@@ -96,7 +94,6 @@
9694
import '@vaadin/icon';
9795
import '@vaadin/master-detail-layout';
9896
import '@vaadin/tooltip';
99-
import '@vaadin/form-layout';
10097
import '@vaadin/vaadin-lumo-styles/icons';
10198
import { html, LitElement, render } from 'lit';
10299

@@ -160,10 +157,6 @@
160157
this._parentMdl._setDetail(null);
161158
}
162159

163-
recalculateDetailSize() {
164-
this._mdl.recalculateDetailSize();
165-
}
166-
167160
replaceDetail() {
168161
window.mdlCount++;
169162
const detail = this.createDetail();
@@ -178,7 +171,7 @@
178171

179172
render() {
180173
return html`
181-
<vaadin-master-detail-layout @backdrop-click=${this.closeDetail} overlay-size="100%">
174+
<vaadin-master-detail-layout @backdrop-click=${this.closeDetail}>
182175
<div class="master">
183176
<header>
184177
<vaadin-button
@@ -235,13 +228,7 @@ <h3>View ${window.mdlCount}</h3>
235228
<vaadin-radio-button value="layout" label="Layout"></vaadin-radio-button>
236229
<vaadin-radio-button value="viewport" label="Viewport"></vaadin-radio-button>
237230
</vaadin-radio-group>
238-
<vaadin-radio-group
239-
@change=${this._configChange}
240-
class="expand"
241-
label="Expand"
242-
theme="vertical"
243-
value="both"
244-
>
231+
<vaadin-radio-group @change=${this._configChange} class="expand" label="Expand" theme="vertical" value="both">
245232
<vaadin-radio-button value="both" label="Both"></vaadin-radio-button>
246233
<vaadin-radio-button value="master" label="Master"></vaadin-radio-button>
247234
<vaadin-radio-button value="detail" label="Detail"></vaadin-radio-button>
@@ -273,7 +260,6 @@ <h3>View ${window.mdlCount}</h3>
273260
<vaadin-checkbox @change=${this._togglePlaceholder} label="Detail Placeholder"></vaadin-checkbox>
274261
<vaadin-button @click=${this.openStaticDetail}>Open Static Detail</vaadin-button>
275262
<vaadin-button @click=${this.openDetail}>Open Nested Test View</vaadin-button>
276-
<vaadin-button @click=${this.recalculateDetailSize}>Recalculate Detail Size</vaadin-button>
277263
<p>${lorem}</p>
278264
</div>
279265
</vaadin-master-detail-layout>

packages/master-detail-layout/src/styles/vaadin-master-detail-layout-base-styles.js

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,10 @@ export const masterDetailLayoutStyles = css`
1111
--_master-size: 30rem;
1212
--_master-extra: 0px;
1313
14-
--_detail-size: min-content;
14+
--_detail-size: 15rem;
1515
--_detail-extra: 0px;
16-
--_detail-cached-size: initial;
1716
18-
--_master-column: var(--_master-size) var(--_master-extra);
19-
--_detail-column: minmax(var(--_detail-cached-size, var(--_detail-size)), var(--_detail-extra));
17+
--_nested-layout-size: var(--_detail-size);
2018
2119
--_transition-duration: 0s;
2220
--_transition-easing: cubic-bezier(0.78, 0, 0.22, 1);
@@ -29,7 +27,10 @@ export const masterDetailLayoutStyles = css`
2927
position: relative;
3028
z-index: 0;
3129
overflow: clip;
32-
grid-template-columns: [master-start] var(--_master-column) [detail-start] var(--_detail-column) [detail-end];
30+
grid-template-columns:
31+
[master-start] var(--_master-size) var(--_master-extra)
32+
[detail-start] var(--_nested-layout-size, var(--_detail-size)) var(--_detail-extra)
33+
[detail-end];
3334
grid-template-rows: 100%;
3435
}
3536
@@ -45,7 +46,10 @@ export const masterDetailLayoutStyles = css`
4546
--_detail-offscreen: 0 30px;
4647
4748
grid-template-columns: 100%;
48-
grid-template-rows: [master-start] var(--_master-column) [detail-start] var(--_detail-column) [detail-end];
49+
grid-template-rows:
50+
[master-start] var(--_master-size) var(--_master-extra)
51+
[detail-start] var(--_nested-layout-size, var(--_detail-size)) var(--_detail-extra)
52+
[detail-end];
4953
}
5054
5155
:is(#master, #detail, #detail-placeholder, #outgoing) {
@@ -81,6 +85,7 @@ export const masterDetailLayoutStyles = css`
8185
}
8286
8387
#backdrop {
88+
display: none;
8489
position: absolute;
8590
inset: 0;
8691
z-index: 1;
@@ -95,25 +100,26 @@ export const masterDetailLayoutStyles = css`
95100
--_master-extra: 1fr;
96101
}
97102
98-
:host(:not([has-detail])),
103+
:host([keep-detail-column-offscreen]),
99104
:host([has-detail-placeholder][overlay]),
100-
:host([keep-detail-column-offscreen]) {
105+
:host(:not([has-detail-placeholder], [has-detail])) {
101106
--_master-extra: calc(100% - var(--_master-size));
102107
}
103108
104109
:host([expand='both'][has-detail]),
105-
:host([expand='detail'][has-detail]) {
106-
--_detail-max-size: 1fr;
110+
:host([expand='detail'][has-detail]),
111+
:host([expand='detail'][has-detail-placeholder]) {
112+
--_detail-extra: 1fr;
107113
}
108114
109115
:host([orientation='horizontal']) #detail-placeholder,
110-
:host([orientation='horizontal']:not([overlay])) #detail {
116+
:host([orientation='horizontal'][has-detail]:not([overlay])) #detail {
111117
border-inline-start: var(--vaadin-master-detail-layout-border-width, 1px) solid
112118
var(--vaadin-master-detail-layout-border-color, var(--vaadin-border-color-secondary));
113119
}
114120
115121
:host([orientation='vertical']) #detail-placeholder,
116-
:host([orientation='vertical']:not([overlay])) #detail {
122+
:host([orientation='vertical'][has-detail]:not([overlay])) #detail {
117123
border-top: var(--vaadin-master-detail-layout-border-width, 1px) solid
118124
var(--vaadin-master-detail-layout-border-color, var(--vaadin-border-color-secondary));
119125
}
@@ -149,6 +155,7 @@ export const masterDetailLayoutStyles = css`
149155
}
150156
151157
:host([has-detail][overlay]) #backdrop {
158+
display: block;
152159
opacity: 1;
153160
pointer-events: auto;
154161
}

packages/master-detail-layout/src/vaadin-master-detail-layout.js

Lines changed: 40 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,25 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
1212
import { masterDetailLayoutStyles } from './styles/vaadin-master-detail-layout-base-styles.js';
1313

1414
function parseTrackSizes(gridTemplate) {
15-
return gridTemplate
15+
const sizes = gridTemplate
1616
.replace(/\[[^\]]+\]/gu, '')
1717
.replace(/\s+/gu, ' ')
1818
.trim()
1919
.split(' ')
2020
.map(parseFloat);
21+
return {
22+
masterSize: sizes[0],
23+
masterExtra: sizes[1],
24+
detailSize: sizes[2],
25+
detailExtra: sizes[3],
26+
};
2127
}
2228

23-
function detectOverflow(hostSize, trackSizes) {
24-
const [masterSize, masterExtra, detailSize] = trackSizes;
25-
26-
if (Math.floor(masterSize + masterExtra + detailSize) <= Math.floor(hostSize)) {
29+
function detectOverflow({ hostSize, masterSize, masterExtra, detailSize, detailExtra }) {
30+
if (Math.floor(masterSize + masterExtra + detailSize + detailExtra) <= Math.floor(hostSize)) {
2731
return false;
2832
}
29-
if (Math.floor(masterExtra) >= Math.floor(detailSize)) {
33+
if (Math.floor(masterExtra) >= Math.floor(detailSize + detailExtra)) {
3034
return false;
3135
}
3236
return true;
@@ -314,7 +318,7 @@ class MasterDetailLayout extends ElementMixin(ThemableMixin(PolylitMixin(LitElem
314318
this.__resizeObserver = this.__resizeObserver || new ResizeObserver(() => this.__onResize());
315319
this.__resizeObserver.disconnect();
316320

317-
const children = this.querySelectorAll(':scope > [slot="detail"], :scope >:not([slot])');
321+
const children = this.querySelectorAll(':scope > [slot="detail"], :scope > :not([slot])');
318322
[this, this.$.master, this.$.detail, ...children].forEach((node) => {
319323
this.__resizeObserver.observe(node);
320324
});
@@ -340,7 +344,7 @@ class MasterDetailLayout extends ElementMixin(ThemableMixin(PolylitMixin(LitElem
340344
__readLayoutState() {
341345
const isVertical = this.orientation === 'vertical';
342346

343-
const detailContent = this.querySelector('[slot="detail"]');
347+
const detailContent = this.querySelector(':scope > [slot="detail"]');
344348
const detailPlaceholder = this.querySelector(':scope > [slot="detail-placeholder"]');
345349

346350
const hadDetail = this.hasAttribute('has-detail');
@@ -354,53 +358,53 @@ class MasterDetailLayout extends ElementMixin(ThemableMixin(PolylitMixin(LitElem
354358
const trackSizesProp = isVertical ? 'gridTemplateRows' : 'gridTemplateColumns';
355359
const trackSizes = parseTrackSizes(computedStyle[trackSizesProp]);
356360

357-
const hadOverflow = this.hasAttribute('overlay');
358-
const hasOverflow = (hasDetail || hasDetailPlaceholder) && detectOverflow(hostSize, trackSizes);
361+
let nestedLayoutSize = 0;
362+
if (hasDetail && detailContent.matches(this.constructor.is)) {
363+
const nestedLayout = detailContent.__readLayoutState();
364+
365+
nestedLayoutSize += nestedLayout.trackSizes.masterSize;
366+
367+
if (nestedLayout.nestedLayoutSize > 0) {
368+
nestedLayoutSize += nestedLayout.nestedLayoutSize;
369+
} else if (nestedLayout.hasDetail) {
370+
nestedLayoutSize += nestedLayout.trackSizes.detailSize;
371+
}
372+
}
373+
374+
const hasOverflow =
375+
(hasDetail || hasDetailPlaceholder) &&
376+
detectOverflow({
377+
hostSize,
378+
masterSize: trackSizes.masterSize,
379+
masterExtra: trackSizes.masterExtra,
380+
detailSize: nestedLayoutSize > 0 ? nestedLayoutSize : trackSizes.detailSize,
381+
detailExtra: trackSizes.detailExtra,
382+
});
359383
const focusTarget = !hadDetail && hasDetail && hasOverflow ? getFocusableElements(detailContent)[0] : null;
360384

361385
return {
362386
hadDetail,
363387
hasDetail,
364388
hasDetailPlaceholder,
365-
hadOverflow,
366389
hasOverflow,
367390
focusTarget,
368391
hostSize,
369392
trackSizes,
393+
nestedLayoutSize,
370394
};
371395
}
372396

373397
/**
374398
* Applies layout state to DOM attributes. Pure writes, no reads.
375399
* @private
376400
*/
377-
__writeLayoutState({
378-
hadDetail,
379-
hasDetail,
380-
hasDetailPlaceholder,
381-
hasOverflow,
382-
hadOverflow,
383-
focusTarget,
384-
trackSizes,
385-
}) {
386-
const [_masterSize, _masterExtra, detailSize] = trackSizes;
387-
388-
// If no detailSize is explicitily set, cache the intrinsic size (min-content) of
389-
// the slotted detail content to use as a fallback for the detail column size
390-
// while the detail content is rendered in an overlay.
391-
if (!hadOverflow && hasOverflow && !this.detailSize && !this.__detailCachedSize) {
392-
this.__detailCachedSize = `${Math.ceil(detailSize)}px`;
401+
__writeLayoutState({ hadDetail, hasDetail, hasDetailPlaceholder, hasOverflow, focusTarget, nestedLayoutSize }) {
402+
if (nestedLayoutSize > 0) {
403+
this.style.setProperty('--_nested-layout-size', `${nestedLayoutSize}px`);
404+
} else {
405+
this.style.removeProperty('--_nested-layout-size');
393406
}
394407

395-
if ((hadOverflow && !hasOverflow) || (!hasDetail && !hasDetailPlaceholder)) {
396-
this.__detailCachedSize = null;
397-
}
398-
// if (!this.detailSize && !this.__detailCachedSize && hasDetail && detailSize > 0) {
399-
// this.__detailCachedSize = `${Math.ceil(detailSize)}px`;
400-
// } else if (hadDetail && !hasDetail) {
401-
// this.__detailCachedSize = null;
402-
// }
403-
404408
// Force the detail column offscreen when it first appears and overflow
405409
// is already detected. This prevents unnecessary master column shrinking,
406410
// as the detail content is rendered in an overlay anyway.
@@ -423,17 +427,6 @@ class MasterDetailLayout extends ElementMixin(ThemableMixin(PolylitMixin(LitElem
423427
}
424428
}
425429

426-
recalculateDetailSize() {
427-
this.__detailCachedSize = null;
428-
this.removeAttribute('overlay');
429-
this.toggleAttribute('recalculating-detail-size', true);
430-
431-
const { focusTarget, ...state } = this.__readLayoutState();
432-
this.__writeLayoutState(state);
433-
434-
this.toggleAttribute('recalculating-detail-size', false);
435-
}
436-
437430
/** @private */
438431
__onBackdropClick() {
439432
this.dispatchEvent(new CustomEvent('backdrop-click'));

0 commit comments

Comments
 (0)