Et2Details + Et2Groupbox: Stop using <details> tag so we can control layout

This commit is contained in:
nathan 2024-11-19 14:24:45 -07:00
parent f6874330fc
commit fe56fc2a8b
2 changed files with 141 additions and 86 deletions

View File

@ -8,11 +8,12 @@
*/ */
import {Et2Widget} from "../../Et2Widget/Et2Widget"; import {Et2Widget} from "../../Et2Widget/Et2Widget";
import {css} from "lit"; import {css, html} from "lit";
import {SlDetails} from "@shoelace-style/shoelace"; import {SlDetails} from "@shoelace-style/shoelace";
import shoelace from "../../Styles/shoelace"; import shoelace from "../../Styles/shoelace";
import {property} from "lit/decorators/property.js"; import {property} from "lit/decorators/property.js";
import {customElement} from "lit/decorators/custom-element.js"; import {customElement} from "lit/decorators/custom-element.js";
import {classMap} from "lit/directives/class-map.js";
@customElement("et2-details") @customElement("et2-details")
export class Et2Details extends Et2Widget(SlDetails) export class Et2Details extends Et2Widget(SlDetails)
@ -30,21 +31,27 @@ export class Et2Details extends Et2Widget(SlDetails)
:host([align="right"]) > div { :host([align="right"]) > div {
justify-content: flex-end; justify-content: flex-end;
} }
:host([align="left"]) > div { :host([align="left"]) > div {
justify-content: flex-start; justify-content: flex-start;
} }
/* CSS for child elements */ /* CSS for child elements */
::slotted(*) { ::slotted(*) {
flex: 1 1 auto; flex: 1 1 auto;
} }
::slotted(img),::slotted(et2-image) {
::slotted(img), ::slotted(et2-image) {
/* Stop images from growing. In general we want them to stay */ /* Stop images from growing. In general we want them to stay */
flex-grow: 0; flex-grow: 0;
} }
::slotted([align="left"]) { ::slotted([align="left"]) {
margin-right: auto; margin-right: auto;
order: -1; order: -1;
} }
::slotted([align="right"]) { ::slotted([align="right"]) {
margin-left: auto; margin-left: auto;
order: 1; order: 1;
@ -53,11 +60,21 @@ export class Et2Details extends Et2Widget(SlDetails)
.details { .details {
border: var(--sl-panel-border-width) solid var(--sl-panel-border-color); border: var(--sl-panel-border-width) solid var(--sl-panel-border-color);
margin: 0px; margin: 0px;
overflow: hidden;
} }
.details.hoist { .details.hoist {
position: relative; position: relative;
} }
.details__body {
display: none;
}
.details--open .details__body {
display: block;
}
.details.hoist .details__body { .details.hoist .details__body {
position: absolute; position: absolute;
z-index: var(--sl-z-index-drawer); z-index: var(--sl-z-index-drawer);
@ -70,14 +87,20 @@ export class Et2Details extends Et2Widget(SlDetails)
max-height: 15em; max-height: 15em;
overflow-y: auto; overflow-y: auto;
} }
.details.hoist .details__body.overlaySummaryLeftAligned { .details.hoist .details__body.overlaySummaryLeftAligned {
top: 0; top: 0;
left: 2em; left: 2em;
width: calc(100% - 2em); width: calc(100% - 2em);
} }
.details.hoist .details__body.overlaySummaryRightAligned { .details.hoist .details__body.overlaySummaryRightAligned {
top: 0; top: 0;
} }
.details__summary-icon--left-aligned {
order: -1;
}
`, `,
]; ];
} }
@ -128,19 +151,6 @@ export class Et2Details extends Et2Widget(SlDetails)
this.addEventListener("mouseover", this.show); this.addEventListener("mouseover", this.show);
window.document.addEventListener('mouseout', this._mouseOutEvent.bind(this)); window.document.addEventListener('mouseout', this._mouseOutEvent.bind(this));
} }
if (this.hoist)
{
this.shadowRoot.querySelector('.details').classList.add('hoist');
}
if (this.toggleAlign === 'left')
{
this.shadowRoot.querySelector('.details__summary-icon').style.order = -1;
}
if (this.overlaySummaryOnOpen)
{
this.shadowRoot.querySelector('.details__body').classList.add(this.toggleAlign === 'left' ?
'overlaySummaryLeftAligend' : 'overlaySummaryRightAligned');
}
}); });
} }
@ -158,4 +168,57 @@ export class Et2Details extends Et2Widget(SlDetails)
{ {
if (!this.getDOMNode().contains(event.relatedTarget)) this.hide(); if (!this.getDOMNode().contains(event.relatedTarget)) this.hide();
} }
render()
{
const isRtl = this.matches(':dir(rtl)');
return html`
<div
part="base"
class=${classMap({
details: true,
'details--open': this.open,
'details--disabled': this.disabled,
'details--rtl': isRtl,
'hoist': this.hoist
})}
>
<summary
part="header"
id="header"
class="details__header"
role="button"
aria-expanded=${this.open ? 'true' : 'false'}
aria-controls="content"
aria-disabled=${this.disabled ? 'true' : 'false'}
tabindex=${this.disabled ? '-1' : '0'}
@click=${this.handleSummaryClick}
@keydown=${this.handleSummaryKeyDown}
>
<slot name="summary" part="summary" class="details__summary">${this.summary}</slot>
<span part="summary-icon" class=${classMap({
"details__summary-icon": true,
"details__summary-icon--left-aligned": this.toggleAlign == "left"
})}>
<slot name="expand-icon">
<sl-icon library="system" name=${isRtl ? 'chevron-left' : 'chevron-right'}></sl-icon>
</slot>
<slot name="collapse-icon">
<sl-icon library="system" name=${isRtl ? 'chevron-left' : 'chevron-right'}></sl-icon>
</slot>
</span>
</summary>
<div class=${classMap({
details__body: true,
overlaySummaryLeftAligned: this.overlaySummaryOnOpen && this.toggleAlign === 'left',
overlaySummaryRightAligned: this.overlaySummaryOnOpen && this.toggleAlign !== 'left',
})} role="region" aria-labelledby="header">
<slot part="content" id="content" class="details__content"></slot>
</div>
</div>
`;
}
} }

View File

@ -39,18 +39,15 @@ export class Et2Groupbox extends Et2Details
display: none; display: none;
} }
details { .details {
height: 100%; height: 100%;
position: relative; position: relative;
margin: 2px; display: flex;
flex-direction: column;
} }
/* work around details not respecting flex
height is 100% - header - border radius
*/
.details__body { .details__body {
height: calc(100% - 2em - var(--sl-border-radius-medium)) !important; flex: 1 1 auto;
position: relative; position: relative;
} }
@ -62,21 +59,15 @@ export class Et2Groupbox extends Et2Details
.details__content { .details__content {
overflow: hidden; overflow: hidden;
overflow-y: auto; overflow-y: auto;
height: calc(100% - 2 * var(--sl-spacing-medium)); height: 100%;
} }
/* end workaround */
summary { summary {
flex: 0 0 auto;
pointer-events: none; pointer-events: none;
} }
/*.details { .details.summaryOnTop > summary {
border-color: var(--sl-color-neutral-500);
border-width: 2px;
}*/
details.summaryOnTop > summary {
position: absolute; position: absolute;
pointer-events: none; pointer-events: none;
width: fit-content; width: fit-content;
@ -86,10 +77,11 @@ export class Et2Groupbox extends Et2Details
background: var(--sl-color-neutral-0); background: var(--sl-color-neutral-0);
} }
details.summaryOnTop { .details.summaryOnTop {
padding-top: .5rem; padding-top: .5rem;
margin-top: .5rem; margin-top: .5rem;
height: auto; height: auto;
overflow: visible;
} }
`, `,
]; ];
@ -106,7 +98,7 @@ export class Et2Groupbox extends Et2Details
{ {
super.firstUpdated(changedProperties); super.firstUpdated(changedProperties);
this.shadowRoot.querySelector('details').classList.toggle('summaryOnTop', !this.summaryInside); this.shadowRoot.querySelector('.details').classList.toggle('summaryOnTop', !this.summaryInside);
} }
/** /**
@ -121,7 +113,7 @@ export class Et2Groupbox extends Et2Details
if (changedProperties.has('summaryInside')) if (changedProperties.has('summaryInside'))
{ {
this.shadowRoot.querySelector('details').classList.toggle('summaryOnTop', !this.summaryInside); this.shadowRoot.querySelector('.details').classList.toggle('summaryOnTop', !this.summaryInside);
} }
} }
} }