diff --git a/packages/main/src/Panel.hbs b/packages/main/src/Panel.hbs index d167315fc3c6..d7c3a05aa826 100644 --- a/packages/main/src/Panel.hbs +++ b/packages/main/src/Panel.hbs @@ -8,7 +8,7 @@ {{#if hasHeaderOrHeaderText}} {{! header: either header or h1 with header text}}
diff --git a/packages/main/src/Panel.ts b/packages/main/src/Panel.ts index 1ec38591982c..8d9d584bf050 100644 --- a/packages/main/src/Panel.ts +++ b/packages/main/src/Panel.ts @@ -196,6 +196,20 @@ class Panel extends UI5Element { @property() accessibleName!: string; + /** + * Indicates whether the Panel header is sticky or not. + * If stickyHeader is set to true, then whenever you scroll the content or + * the application, the header of the panel will be always visible and + * a solid color will be used for its design. + * @type {boolean} + * @name sap.ui.webc.main.Panel.prototype.stickyHeader + * @defaultvalue false + * @public + * @since 1.16.0-rc.1 + */ + @property({ type: Boolean }) + stickyHeader!: boolean; + /** * When set to true, the accessibleName property will be * applied not only on the panel root itself, but on its toggle button too. @@ -348,6 +362,9 @@ class Panel extends UI5Element { headerBtn: { "ui5-panel-header-button-animated": !this.shouldNotAnimate(), }, + stickyHeaderClass: { + "ui5-panel-heading-wrapper-sticky": this.stickyHeader, + }, }; } diff --git a/packages/main/src/themes/Panel.css b/packages/main/src/themes/Panel.css index bdb409713e0a..b5b2f7f62968 100644 --- a/packages/main/src/themes/Panel.css +++ b/packages/main/src/themes/Panel.css @@ -68,6 +68,14 @@ width: 100%; } +.ui5-panel-heading-wrapper.ui5-panel-heading-wrapper-sticky { + position: sticky; + top: 0; + background-color: var(--_ui5_panel_header_background_color); + z-index: 100; /* The z-index of the table header is 99 therefore to have table in the panel and panel header to be on top we need 100 */ + border-radius: var(--_ui5_panel_border_radius); +} + .ui5-panel-header-title { width: calc(100% - var(--_ui5_panel_button_root_width)); overflow: hidden; @@ -86,6 +94,7 @@ outline: none; border-bottom-left-radius: var(--_ui5_panel_border_radius); border-bottom-right-radius: var(--_ui5_panel_border_radius); + overflow: auto; } .ui5-panel-header-button-root { @@ -136,4 +145,10 @@ .ui5-panel-header-icon-wrapper, [ui5-button].ui5-panel-header-button-with-icon [ui5-icon] { pointer-events: none; +} + +.ui5-panel-root { + height: 100%; + display: flex; + flex-direction: column; } \ No newline at end of file diff --git a/packages/main/src/themes/base/Panel-parameters.css b/packages/main/src/themes/base/Panel-parameters.css index 9898e72c372a..16f01e0e08f9 100644 --- a/packages/main/src/themes/base/Panel-parameters.css +++ b/packages/main/src/themes/base/Panel-parameters.css @@ -10,11 +10,12 @@ --_ui5_panel_header_padding_right: 0.5rem; --_ui5_panel_header_button_wrapper_padding: .25rem; --_ui5_panel_focus_offset: 1px; - --_ui5_panel_content_padding: 0.625rem 1rem 1.375rem 1rem + --_ui5_panel_content_padding: 0.625rem 1rem 1.375rem 1rem; + --_ui5_panel_header_background_color: var(--sapBackgroundColor); } [data-ui5-compact-size], .ui5-content-density-compact, .sapUiSizeCompact { --_ui5_panel_header_button_wrapper_padding: .5625rem .375rem; -} \ No newline at end of file +} diff --git a/packages/main/src/themes/sap_horizon/Panel-parameters.css b/packages/main/src/themes/sap_horizon/Panel-parameters.css index 91ee8a14b2f6..dbc312c15d2a 100644 --- a/packages/main/src/themes/sap_horizon/Panel-parameters.css +++ b/packages/main/src/themes/sap_horizon/Panel-parameters.css @@ -10,4 +10,5 @@ --_ui5_panel_icon_color: var(--sapButton_Lite_TextColor); --_ui5_panel_focus_offset: -1px; --_ui5_panel_content_padding: 0.625rem 1rem; + --_ui5_panel_header_background_color: var(--sapGroup_TitleBackground); } \ No newline at end of file diff --git a/packages/main/src/themes/sap_horizon_dark/Panel-parameters.css b/packages/main/src/themes/sap_horizon_dark/Panel-parameters.css index 91ee8a14b2f6..dbc312c15d2a 100644 --- a/packages/main/src/themes/sap_horizon_dark/Panel-parameters.css +++ b/packages/main/src/themes/sap_horizon_dark/Panel-parameters.css @@ -10,4 +10,5 @@ --_ui5_panel_icon_color: var(--sapButton_Lite_TextColor); --_ui5_panel_focus_offset: -1px; --_ui5_panel_content_padding: 0.625rem 1rem; + --_ui5_panel_header_background_color: var(--sapGroup_TitleBackground); } \ No newline at end of file diff --git a/packages/main/src/themes/sap_horizon_hcb/Panel-parameters.css b/packages/main/src/themes/sap_horizon_hcb/Panel-parameters.css index 6bb582c00a34..4025c896d49b 100644 --- a/packages/main/src/themes/sap_horizon_hcb/Panel-parameters.css +++ b/packages/main/src/themes/sap_horizon_hcb/Panel-parameters.css @@ -6,4 +6,5 @@ --_ui5_panel_outline_offset: -0.125rem; --_ui5_panel_icon_color: var(--sapButton_Lite_TextColor); --_ui5_panel_content_padding: 0.625rem 1rem; + --_ui5_panel_header_background_color: var(--sapGroup_TitleBackground); } \ No newline at end of file diff --git a/packages/main/src/themes/sap_horizon_hcw/Panel-parameters.css b/packages/main/src/themes/sap_horizon_hcw/Panel-parameters.css index b5b0c48ed8b5..fa3ae99cd4b0 100644 --- a/packages/main/src/themes/sap_horizon_hcw/Panel-parameters.css +++ b/packages/main/src/themes/sap_horizon_hcw/Panel-parameters.css @@ -7,4 +7,5 @@ --_ui5_panel_outline_offset: -0.125rem; --_ui5_panel_icon_color: var(--sapButton_Lite_TextColor); --_ui5_panel_content_padding: 0.625rem 1rem; + --_ui5_panel_header_background_color: var(--sapGroup_TitleBackground); } \ No newline at end of file diff --git a/packages/main/test/pages/Panel.html b/packages/main/test/pages/Panel.html index 2a50f42861d2..14f97453f0fe 100644 --- a/packages/main/test/pages/Panel.html +++ b/packages/main/test/pages/Panel.html @@ -154,6 +154,28 @@
+ + + Lorem ipsum! + + + + Lorem ipsum dolor sit amet, tamquam invidunt cu sed, unum regione mel ea, quo ea alia novum. Ne qui illud zril + nostrum, vel ea sint dicant postea. Vel ne facete tritani, neglegentur concludaturque sed te. His animal dolorum ut. + Aeterno appareat ei mei, cu sed elit scripserit, an quodsi oportere accusamus quo. Pri ea probo corpora rationibus, + soluta incorrupte ex his. + Mei ei brute cetero, id duo magna aeque torquatos. Quodsi erroribus mediocritatem his ut, ad pri legere iracundia + democritum. Menandri intellegam in mea, ex vero movet qualisque sed. Maiorum verterem perfecto nec ea, est velit + elaboraret consequuntur eu, eam ad reque postea admodum. Ne inimicus convenire pri, doctus vidisse te ius. + Percipitur contentiones in vis, cu vim propriae phaedrum. Has ad magna errem honestatis, duo vero graeco epicurei + no, populo semper sit ne. Vulputate dissentiunt interpretaris ea vis, nec civibus moderatius at. Cu vim stet + dissentias, no vidit saperet indoctum nec, et pro magna prima nobis. Vis consul feugiat qualisque in, regione + persecuti cotidieque id eos, id ius omnesque vituperata. + + + + +
diff --git a/packages/main/test/pages/styles/Panel.css b/packages/main/test/pages/styles/Panel.css index 71d2b28691a3..826ca9890d09 100644 --- a/packages/main/test/pages/styles/Panel.css +++ b/packages/main/test/pages/styles/Panel.css @@ -7,3 +7,7 @@ .panel1auto { background-color: var(--sapBackgroundColor); } + +#panel-stickyHeader::part(content) { + max-height: 70px; +} diff --git a/packages/main/test/specs/Panel.spec.js b/packages/main/test/specs/Panel.spec.js index 9c1ec8ebaa33..5258bca39f66 100644 --- a/packages/main/test/specs/Panel.spec.js +++ b/packages/main/test/specs/Panel.spec.js @@ -124,6 +124,44 @@ describe("Panel general interaction", () => { assert.notOk(await panelWithoutAnimationIcon.hasClass("ui5-panel-header-button-animated"), "Animation is turn off"); }); + it("Test that the header is sticky when inner content scrollable", async () => { + const panel = await browser.$("#panel-stickyHeader"); + const content = await panel.shadow$(".ui5-panel-content"); + const title = await panel.shadow$(".ui5-panel-header-title"); + const sExpected = "Panel with sticky header"; + const panelHeader = panel.shadow$(".ui5-panel-heading-wrapper"); + + assert.strictEqual(await title.getText(), sExpected, "Initially the text is the expected one"); + assert.strictEqual((await content.getCSSProperty('overflow')).value, "auto", "Check if the overflow property is set to 'auto'"); + + const initialScrollPosition = await browser.execute("return document.querySelector('#panel-stickyHeader').shadowRoot.querySelector('.ui5-panel-content').scrollTop"); + await browser.execute("document.querySelector('#panel-stickyHeader').shadowRoot.querySelector('.ui5-panel-content').scrollBy(0, 200)"); + const finalScrollPosition = await browser.execute("return document.querySelector('#panel-stickyHeader').shadowRoot.querySelector('.ui5-panel-content').scrollTop"); + assert.ok(initialScrollPosition < finalScrollPosition, "Initial scroll position of the inner div should be less than the final"); + assert.strictEqual(await panelHeader.isDisplayedInViewport(), true, "Assert that the header is still visible after scroll - it's sticky"); + }); + + it("Test that the header is sticky", async () => { + const panel = await browser.$("#panel-stickyHeader"); + const title = await panel.shadow$(".ui5-panel-header-title"); + const sExpected = "Panel with sticky header"; + + const panelHeader = panel.shadow$(".ui5-panel-heading-wrapper"); + const isStickyCssPosition = await browser.execute("return window.getComputedStyle(document.querySelector('#panel-stickyHeader').shadowRoot.querySelector('.ui5-panel-heading-wrapper')).position"); + + await browser.setWindowSize(1000, 1200); + + assert.strictEqual(await title.getText(), sExpected, "Initially the text is the expected one"); + assert.ok(await panelHeader.hasClass("ui5-panel-heading-wrapper-sticky"), "Assert that sticky css class is available"); + assert.strictEqual(isStickyCssPosition, "sticky", "Assert that the header has a sticky position"); + + let isPanelHeaderDisplayed = await panelHeader.isDisplayedInViewport(); + assert.strictEqual(isPanelHeaderDisplayed, true, "Initially the panel header should be visible"); + await browser.execute("window.scrollBy(0, 500)"); + isPanelHeaderDisplayed = await panelHeader.isDisplayedInViewport(); + assert.strictEqual(isPanelHeaderDisplayed, true, "Assert that the header is still visible after scroll - it's sticky"); + }); + describe("Accessibility", async () => { it("tests whether aria attributes are set correctly with native header", async () => { diff --git a/packages/playground/_stories/main/Panel/Panel.stories.ts b/packages/playground/_stories/main/Panel/Panel.stories.ts index 09569a809173..ee18915ba5d1 100644 --- a/packages/playground/_stories/main/Panel/Panel.stories.ts +++ b/packages/playground/_stories/main/Panel/Panel.stories.ts @@ -15,6 +15,7 @@ import TitleLevel from "@ui5/webcomponents/dist/types/TitleLevel.js"; const component = "ui5-panel"; +let index = 0; export default { title: "Main/Panel", @@ -29,6 +30,7 @@ export default { const Template : UI5StoryArgs = (args) => html` = (args) => html` ?no-animation="${ifDefined(args.noAnimation)}" header-level="${ifDefined(args.headerLevel)}" accessible-name="${ifDefined(args.accessibleName)}" + ?sticky-header="${ifDefined(args.stickyHeader)}" > ${unsafeHTML(args.header)} ${unsafeHTML(args.default)} @@ -88,6 +91,97 @@ FixedPanel.args = { }; FixedPanel.storyName = "Fixed Panel (Can't be Collapsed/Expanded)"; +export const StickyHeader = Template.bind({}); +StickyHeader.decorators = [ + (story) => { + return html` + +
+ ${story()} +
+ + Another Lorem ipsum! + + + + Lorem ipsum dolor sit amet, tamquam invidunt cu sed, unum regione mel ea, quo ea alia novum. Ne qui illud zril + nostrum, vel ea sint dicant postea. Vel ne facete tritani, neglegentur concludaturque sed te. His animal dolorum ut. + Aeterno appareat ei mei, cu sed elit scripserit, an quodsi oportere accusamus quo. Pri ea probo corpora rationibus, + soluta incorrupte ex his. + Mei ei brute cetero, id duo magna aeque torquatos. Quodsi erroribus mediocritatem his ut, ad pri legere iracundia + democritum. Menandri intellegam in mea, ex vero movet qualisque sed. Maiorum verterem perfecto nec ea, est velit + elaboraret consequuntur eu, eam ad reque postea admodum. Ne inimicus convenire pri, doctus vidisse te ius. + Percipitur contentiones in vis, cu vim propriae phaedrum. Has ad magna errem honestatis, duo vero graeco epicurei + no, populo semper sit ne. Vulputate dissentiunt interpretaris ea vis, nec civibus moderatius at. Cu vim stet + dissentias, no vidit saperet indoctum nec, et pro magna prima nobis. Vis consul feugiat qualisque in, regione + persecuti cotidieque id eos, id ius omnesque vituperata. + Lorem ipsum dolor sit amet, tamquam invidunt cu sed, unum regione mel ea, quo ea alia novum. Ne qui illud zril + nostrum, vel ea sint dicant postea. Vel ne facete tritani, neglegentur concludaturque sed te. His animal dolorum ut. + Aeterno appareat ei mei, cu sed elit scripserit, an quodsi oportere accusamus quo. Pri ea probo corpora rationibus, + soluta incorrupte ex his. + Mei ei brute cetero, id duo magna aeque torquatos. Quodsi erroribus mediocritatem his ut, ad pri legere iracundia + democritum. Menandri intellegam in mea, ex vero movet qualisque sed. Maiorum verterem perfecto nec ea, est velit + elaboraret consequuntur eu, eam ad reque postea admodum. Ne inimicus convenire pri, doctus vidisse te ius. + Percipitur contentiones in vis, cu vim propriae phaedrum. Has ad magna errem honestatis, duo vero graeco epicurei + no, populo semper sit ne. Vulputate dissentiunt interpretaris ea vis, nec civibus moderatius at. Cu vim stet + dissentias, no vidit saperet indoctum nec, et pro magna prima nobis. Vis consul feugiat qualisque in, regione + persecuti cotidieque id eos, id ius omnesque vituperata. + Lorem ipsum dolor sit amet, tamquam invidunt cu sed, unum regione mel ea, quo ea alia novum. Ne qui illud zril + nostrum, vel ea sint dicant postea. Vel ne facete tritani, neglegentur concludaturque sed te. His animal dolorum ut. + Aeterno appareat ei mei, cu sed elit scripserit, an quodsi oportere accusamus quo. Pri ea probo corpora rationibus, + soluta incorrupte ex his. + Mei ei brute cetero, id duo magna aeque torquatos. Quodsi erroribus mediocritatem his ut, ad pri legere iracundia + democritum. Menandri intellegam in mea, ex vero movet qualisque sed. Maiorum verterem perfecto nec ea, est velit + elaboraret consequuntur eu, eam ad reque postea admodum. Ne inimicus convenire pri, doctus vidisse te ius. + Percipitur contentiones in vis, cu vim propriae phaedrum. Has ad magna errem honestatis, duo vero graeco epicurei + no, populo semper sit ne. Vulputate dissentiunt interpretaris ea vis, nec civibus moderatius at. Cu vim stet + dissentias, no vidit saperet indoctum nec, et pro magna prima nobis. Vis consul feugiat qualisque in, regione + persecuti cotidieque id eos, id ius omnesque vituperata. + + + +
` + } +] +StickyHeader.args = { + default: ` + Lorem ipsum! + + + Lorem ipsum dolor sit amet, tamquam invidunt cu sed, unum regione mel ea, quo ea alia novum. Ne qui illud zril + nostrum, vel ea sint dicant postea. Vel ne facete tritani, neglegentur concludaturque sed te. His animal dolorum ut. + Aeterno appareat ei mei, cu sed elit scripserit, an quodsi oportere accusamus quo. Pri ea probo corpora rationibus, + soluta incorrupte ex his. + Mei ei brute cetero, id duo magna aeque torquatos. Quodsi erroribus mediocritatem his ut, ad pri legere iracundia + democritum. Menandri intellegam in mea, ex vero movet qualisque sed. Maiorum verterem perfecto nec ea, est velit + elaboraret consequuntur eu, eam ad reque postea admodum. Ne inimicus convenire pri, doctus vidisse te ius. + Percipitur contentiones in vis, cu vim propriae phaedrum. Has ad magna errem honestatis, duo vero graeco epicurei + no, populo semper sit ne. Vulputate dissentiunt interpretaris ea vis, nec civibus moderatius at. Cu vim stet + dissentias, no vidit saperet indoctum nec, et pro magna prima nobis. Vis consul feugiat qualisque in, regione + persecuti cotidieque id eos, id ius omnesque vituperata. + Lorem ipsum dolor sit amet, tamquam invidunt cu sed, unum regione mel ea, quo ea alia novum. Ne qui illud zril + nostrum, vel ea sint dicant postea. Vel ne facete tritani, neglegentur concludaturque sed te. His animal dolorum ut. + Aeterno appareat ei mei, cu sed elit scripserit, an quodsi oportere accusamus quo. Pri ea probo corpora rationibus, + soluta incorrupte ex his. + Mei ei brute cetero, id duo magna aeque torquatos. Quodsi erroribus mediocritatem his ut, ad pri legere iracundia + democritum. Menandri intellegam in mea, ex vero movet qualisque sed. Maiorum verterem perfecto nec ea, est velit + elaboraret consequuntur eu, eam ad reque postea admodum. Ne inimicus convenire pri, doctus vidisse te ius. + Percipitur contentiones in vis, cu vim propriae phaedrum. Has ad magna errem honestatis, duo vero graeco epicurei + no, populo semper sit ne. Vulputate dissentiunt interpretaris ea vis, nec civibus moderatius at. Cu vim stet + dissentias, no vidit saperet indoctum nec, et pro magna prima nobis. Vis consul feugiat qualisque in, regione + persecuti cotidieque id eos, id ius omnesque vituperata. + + `, + headerText: "Sticky header", + stickyHeader: true +}; export const PanelCustomHeader = Template.bind({}); PanelCustomHeader.decorators = [