diff --git a/packages/fiori/src/DynamicSideContent.ts b/packages/fiori/src/DynamicSideContent.ts index a0121a178d5e..843655c5a59c 100644 --- a/packages/fiori/src/DynamicSideContent.ts +++ b/packages/fiori/src/DynamicSideContent.ts @@ -7,10 +7,9 @@ import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; import getEffectiveScrollbarStyle from "@ui5/webcomponents-base/dist/util/getEffectiveScrollbarStyle.js"; import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js"; import jsxRenderer from "@ui5/webcomponents-base/dist/renderer/JsxRenderer.js"; -import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js"; import SideContentPosition from "./types/SideContentPosition.js"; import SideContentVisibility from "./types/SideContentVisibility.js"; -import SideContentFallDown from "./types/SideContentFallDown.js"; +import type SideContentFallDown from "./types/SideContentFallDown.js"; import DynamicSideContentTemplate from "./DynamicSideContentTemplate.js"; import type { AccessibilityAttributes, @@ -214,26 +213,20 @@ class DynamicSideContent extends UI5Element { /** * @private */ - @property({ noAttribute: true }) - _mcSpan = "0"; + @property({ type: Boolean, noAttribute: true }) + _toggled = false; /** * @private */ @property({ noAttribute: true }) - _scSpan = "0"; + _currentBreakpoint?: string; /** * @private */ @property({ type: Boolean, noAttribute: true }) - _toggled = false; - - /** - * @private - */ - @property({ noAttribute: true }) - _currentBreakpoint?: string; + _isSideBelow = false; /** * Defines the side content. @@ -242,26 +235,44 @@ class DynamicSideContent extends UI5Element { @slot() sideContent!: Array; - constructor() { - super(); - this._handleResizeBound = this.handleResize.bind(this); - } - - _handleResizeBound: () => void; + _resizeObserver?: ResizeObserver; @i18n("@ui5/webcomponents-fiori") static i18nBundle: I18nBundle; - onAfterRendering() { - this._resizeContents(); - } - onEnterDOM() { - ResizeHandler.register(this, this._handleResizeBound); + this._resizeObserver = new ResizeObserver(entries => { + entries.forEach(entry => { + const width = entry.contentRect.width; + let breakpoint: string; + if (width <= S_M_BREAKPOINT) { + breakpoint = "S"; + } else if (width <= M_L_BREAKPOINT) { + breakpoint = "M"; + } else if (width <= L_XL_BREAKPOINT) { + breakpoint = "L"; + } else { + breakpoint = "XL"; + } + + this._isSideBelow = this.isSideBelow; + + if (breakpoint !== this._currentBreakpoint) { + this.fireDecoratorEvent("layout-change", { + currentBreakpoint: breakpoint, + previousBreakpoint: this._currentBreakpoint, + mainContentVisible: true, // or calculate if needed + sideContentVisible: true, // or calculate if needed + }); + this._currentBreakpoint = breakpoint; + } + }); + }); + this._resizeObserver.observe(this); } onExitDOM() { - ResizeHandler.deregister(this, this._handleResizeBound); + this._resizeObserver?.disconnect(); } /** @@ -275,37 +286,46 @@ class DynamicSideContent extends UI5Element { } get classes() { - const gridPrefix = "ui5-dsc-span", - mcSpan = this._toggled ? this._scSpan : this._mcSpan, - scSpan = this._toggled ? this._mcSpan : this._scSpan; - return { main: { "ui5-dsc-main": true, - [`${gridPrefix}-${mcSpan}`]: true, }, side: { "ui5-dsc-side": true, - [`${gridPrefix}-${scSpan}`]: true, + }, + root: { + "ui5-dsc-root": true, + "ui5-dsc-toggled": this._toggled, }, }; } + get isSideBelow() { + if (this.sideContentVisibility === "NeverShow") { + return false; + } + return ( + (this.sideContentFallDown === "OnMinimumWidth" && this._currentBreakpoint === this.sizeM && this.containerWidth <= MINIMUM_WIDTH_BREAKPOINT) + || (this.sideContentFallDown === "BelowM" && this._currentBreakpoint === this.sizeS) + || (this.sideContentFallDown === "BelowL" && (this._currentBreakpoint === this.sizeM || this._currentBreakpoint === this.sizeS)) + || (this.sideContentFallDown === "BelowXL" && (this._currentBreakpoint === this.sizeL || this._currentBreakpoint === this.sizeM || this._currentBreakpoint === this.sizeS) && this._currentBreakpoint !== this.sizeXL) + || (this.sideContentVisibility === "AlwaysShow" && this._currentBreakpoint === this.sizeS && !this._toggled) + || (this.sideContentVisibility === "AlwaysShow" && this._currentBreakpoint === this.sizeM && this.containerWidth <= MINIMUM_WIDTH_BREAKPOINT) + ); + } + get styles() { - const isToggled = this.breakpoint === this.sizeS && this._toggled, - mcSpan = isToggled ? this._scSpan : this._mcSpan, - scSpan = isToggled ? this._mcSpan : this._scSpan, - contentHeight = this.breakpoint === this.sizeS && this.sideContentVisibility !== SideContentVisibility.AlwaysShow ? "100%" : "auto"; + this._isSideBelow = this.isSideBelow; return { root: { - "flex-wrap": this._mcSpan === "12" ? "wrap" : "nowrap", + "flex-wrap": "nowrap", }, main: { - "height": mcSpan === this.span12 ? contentHeight : "100%", + "height": this._isSideBelow ? "auto" : "100%", }, side: { - "height": scSpan === this.span12 ? contentHeight : "100%", + "height": this._isSideBelow ? "auto" : "100%", }, }; } @@ -337,40 +357,8 @@ class DynamicSideContent extends UI5Element { return "XL"; } - get span0() { - return "0"; - } - - get span3() { - return "3"; - } - - get span4() { - return "4"; - } - - get span6() { - return "6"; - } - - get span8() { - return "8"; - } - - get span9() { - return "9"; - } - - get span12() { - return "12"; - } - - get spanFixed() { - return "fixed"; - } - get containerWidth() { - return (this.parentElement as HTMLElement).getBoundingClientRect().width; + return this.clientWidth; } get breakpoint() { @@ -392,99 +380,6 @@ class DynamicSideContent extends UI5Element { get _isSideContentFirst() { return this.sideContentPosition === SideContentPosition.Start; } - - handleResize() { - this._resizeContents(); - } - - _resizeContents() { - let mainSize!: string, - sideSize!: string, - sideVisible = false; - - // initial set contents sizes - switch (this.breakpoint) { - case this.sizeS: - mainSize = this.span12; - sideSize = this.span12; - break; - case this.sizeM: - if (this.sideContentFallDown === SideContentFallDown.BelowXL - || this.sideContentFallDown === SideContentFallDown.BelowL - || (this.containerWidth <= MINIMUM_WIDTH_BREAKPOINT && this.sideContentFallDown === SideContentFallDown.OnMinimumWidth)) { - mainSize = this.span12; - sideSize = this.span12; - } else { - mainSize = this.equalSplit ? this.span6 : this.spanFixed; - sideSize = this.equalSplit ? this.span6 : this.spanFixed; - } - sideVisible = this.sideContentVisibility === SideContentVisibility.ShowAboveS - || this.sideContentVisibility === SideContentVisibility.AlwaysShow; - break; - case this.sizeL: - if (this.sideContentFallDown === SideContentFallDown.BelowXL) { - mainSize = this.span12; - sideSize = this.span12; - } else { - mainSize = this.equalSplit ? this.span6 : this.span8; - sideSize = this.equalSplit ? this.span6 : this.span4; - } - sideVisible = this.sideContentVisibility === SideContentVisibility.ShowAboveS - || this.sideContentVisibility === SideContentVisibility.ShowAboveM - || this.sideContentVisibility === SideContentVisibility.AlwaysShow; - break; - case this.sizeXL: - mainSize = this.equalSplit ? this.span6 : this.span9; - sideSize = this.equalSplit ? this.span6 : this.span3; - sideVisible = this.sideContentVisibility !== SideContentVisibility.NeverShow; - } - - if (this.sideContentVisibility === SideContentVisibility.AlwaysShow) { - sideVisible = true; - } - - // modify sizes of the contents depending on hideMainContent and hideSideContent properties - if (this.hideSideContent) { - mainSize = this.hideMainContent ? this.span0 : this.span12; - sideSize = this.span0; - sideVisible = false; - } - - if (this.hideMainContent) { - mainSize = this.span0; - sideSize = this.hideSideContent ? this.span0 : this.span12; - sideVisible = true; - } - - // set final sizes of the contents - if (!sideVisible) { - mainSize = this.span12; - sideSize = this.span0; - } - - // fire "layout-change" event - if (this._currentBreakpoint !== this.breakpoint) { - const eventParams = { - currentBreakpoint: this.breakpoint, - previousBreakpoint: this._currentBreakpoint, - mainContentVisible: mainSize !== this.span0, - sideContentVisible: sideSize !== this.span0, - }; - this.fireDecoratorEvent("layout-change", eventParams); - this._currentBreakpoint = this.breakpoint; - } - - // update contents sizes - this._setSpanSizes(mainSize, sideSize); - } - - _setSpanSizes(mainSize: string, sideSize: string) { - this._mcSpan = mainSize; - this._scSpan = sideSize; - if (this.breakpoint !== this.sizeS) { - this._toggled = false; - } - } } DynamicSideContent.define(); diff --git a/packages/fiori/src/DynamicSideContentTemplate.tsx b/packages/fiori/src/DynamicSideContentTemplate.tsx index 538f593c9bbd..15dafe429cea 100644 --- a/packages/fiori/src/DynamicSideContentTemplate.tsx +++ b/packages/fiori/src/DynamicSideContentTemplate.tsx @@ -3,7 +3,7 @@ import type DynamicSideContent from "./DynamicSideContent.js"; export default function DynamicSideContentTemplate(this: DynamicSideContent) { return (
{this._isSideContentFirst ? diff --git a/packages/fiori/src/themes/DynamicSideContent.css b/packages/fiori/src/themes/DynamicSideContent.css index 8c33213092e1..ce352b817989 100644 --- a/packages/fiori/src/themes/DynamicSideContent.css +++ b/packages/fiori/src/themes/DynamicSideContent.css @@ -3,6 +3,7 @@ width: 100%; height: 100%; position: relative; + container-type: inline-size; /* container queries */ } .ui5-dsc-root { @@ -24,43 +25,182 @@ flex: none; } -.ui5-dsc-root > div[class^="ui5-dcs-span"], -.ui5-dsc-root > aside[class^="ui5-dsc-span"] { - overflow: auto; +/* container queries */ + +/* XL: >1440px */ +@container (min-width: 1441px) { + .ui5-dsc-main { width: 75%; min-width: 320px; } + .ui5-dsc-side { width: 25%; min-width: 320px; } } -.ui5-dsc-main.ui5-dsc-span-fixed { - width: calc(100% - 21.25rem); +/* L: 1025px–1440px */ +@container (min-width: 1025px) and (max-width: 1440px) { + .ui5-dsc-main { width: 66.666%; min-width: 320px; } + .ui5-dsc-side { width: 33.333%; min-width: 320px; } } -.ui5-dsc-side.ui5-dsc-span-fixed { - width: 21.25rem; +/* M: 721px–1024px */ +@container (min-width: 721px) and (max-width: 1024px) { + .ui5-dsc-main { width: calc(100% - 340px); } + .ui5-dsc-side { width: 340px; } } -.ui5-dsc-root > .ui5-dsc-span-0 { - display: none; +/* S: <=720px */ +@container (max-width: 720px) { + .ui5-dsc-main, .ui5-dsc-side { width: 100%; } } -.ui5-dsc-root > .ui5-dsc-span-3 { - width: 25%; +/* Equal Split: 50%/50% for main and side, except S breakpoint */ +:host([equal-split]) .ui5-dsc-main, +:host([equal-split]) .ui5-dsc-side { + width: 50%; + min-width: 0; } -.ui5-dsc-root > .ui5-dsc-span-4 { - width: 33.333%; +/* On S breakpoint, still 100% width for both */ +@container (max-width: 720px) { + :host([equal-split]) .ui5-dsc-main, + :host([equal-split]) .ui5-dsc-side { + width: 100%; + } } -.ui5-dsc-root > .ui5-dsc-span-6 { - width: 50%; +/* OnMinimumWidth: fall down between 721px and 960px */ +@container (min-width: 721px) and (max-width: 960px) { + :host([side-content-fall-down="OnMinimumWidth"]) .ui5-dsc-root { + flex-direction: column; + } + :host([side-content-fall-down="OnMinimumWidth"]) .ui5-dsc-main, + :host([side-content-fall-down="OnMinimumWidth"]) .ui5-dsc-side { + width: 100%; + } +} + +/* BelowL: fall down for widths 1024px and below */ +@container (max-width: 1024px) { + :host([side-content-fall-down="BelowL"]) .ui5-dsc-root { + flex-direction: column; + } + :host([side-content-fall-down="BelowL"]) .ui5-dsc-main, + :host([side-content-fall-down="BelowL"]) .ui5-dsc-side { + width: 100%; + } +} + +/* BelowXL: fall down for any width below 1441px */ +@container (max-width: 1440px) { + :host([side-content-fall-down="BelowXL"]) .ui5-dsc-root { + flex-direction: column; + } + :host([side-content-fall-down="BelowXL"]) .ui5-dsc-main, + :host([side-content-fall-down="BelowXL"]) .ui5-dsc-side { + width: 100%; + } } -.ui5-dsc-root > .ui5-dsc-span-8 { - width: 66.666%; +/* hiding main or side content */ +:host([hide-main-content]) .ui5-dsc-main { + display: none; } -.ui5-dsc-root > .ui5-dsc-span-9 { - width: 75%; +:host([hide-main-content]) .ui5-dsc-side { + width: 100%; + min-width: 0; } -.ui5-dsc-root > .ui5-dsc-span-12 { +:host([hide-side-content]) .ui5-dsc-side { + display: none; +} + +:host([hide-side-content]) .ui5-dsc-main { width: 100%; + min-width: 0; +} + + +/* Never show side content (hide on all breakpoints) */ +:host([side-content-visibility="NeverShow"]:not([hide-main-content])) .ui5-dsc-side { + display: none; +} + +/* S: <=720px */ +@container (max-width: 720px) { + :host([side-content-visibility="AlwaysShow"]:not([hide-side-content])) .ui5-dsc-side { + display: block; + width: 100%; + } + :host(:not([side-content-visibility="AlwaysShow"]):not([side-content-fall-down="BelowM"]):not([hide-main-content])) .ui5-dsc-root:not(.ui5-dsc-toggled) .ui5-dsc-side { + display: none; + } + :host([side-content-fall-down="BelowM"]) .ui5-dsc-root { + flex-direction: column; + } + .ui5-dsc-root.ui5-dsc-toggled .ui5-dsc-main { + display: none; + } + .ui5-dsc-root.ui5-dsc-toggled .ui5-dsc-side { + display: block; + width: 100%; + } + /* Toggling logic for all other visibilities */ + :host(:not([side-content-visibility="NeverShow"])) .ui5-dsc-root.ui5-dsc-toggled .ui5-dsc-main { + display: none; + } + :host(:not([side-content-visibility="NeverShow"]):not([hide-main-content])) .ui5-dsc-root:not(.ui5-dsc-toggled) .ui5-dsc-main { + display: block; + width: 100%; + } + :host(:not([side-content-visibility="NeverShow"]):not([side-content-visibility="AlwaysShow"])) .ui5-dsc-root:not(.ui5-dsc-toggled) .ui5-dsc-side { + display: none; + } +} + +/* Never show side content (hide on all breakpoints > S)*/ +@container (min-width: 721px) { + :host([side-content-visibility="NeverShow"]:not([hide-main-content])) .ui5-dsc-main { + display: block; + width: 100%; + min-width: 0; + } + :host(:not([side-content-visibility="NeverShow"]):not([hide-main-content])) .ui5-dsc-root.ui5-dsc-toggled .ui5-dsc-side { + display: block; + width: 100%; + } +} + +@container (max-width: 960px) { + :host([side-content-visibility="AlwaysShow"]) .ui5-dsc-root { + flex-direction: column; + } + :host([side-content-visibility="AlwaysShow"]:not([side-content-fall-down="onMinimumWidth"])) .ui5-dsc-main, + :host([side-content-visibility="AlwaysShow"]:not([side-content-fall-down="onMinimumWidth"])) .ui5-dsc-side { + width: 100%; + } +} + +/* Show side content only above M (L and XL: >1024px) */ +@container (max-width: 1024px) { + :host([side-content-visibility="ShowAboveM"]) .ui5-dsc-side { + display: none; + } + :host([side-content-visibility="ShowAboveM"]) .ui5-dsc-main { + width: 100%; + min-width: 0; + } +} + +/* Show side content only above L (XL: >1440px) */ +@container (max-width: 1440px) { + :host([side-content-visibility="ShowAboveL"]) .ui5-dsc-side { + display: none; + } + :host([side-content-visibility="ShowAboveL"]) .ui5-dsc-main { + width: 100%; + min-width: 0; + } +} +@container (min-width: 1441px) { + :host([side-content-visibility="ShowAboveL"]) .ui5-dsc-side { + display: block; + } } \ No newline at end of file