Skip to content

Commit

Permalink
feat(ui5-panel): panel sticky header implementation (#7313)
Browse files Browse the repository at this point in the history
* feat(ui5-panel): panel sticky header implementation

* feat(ui5-panel): update comments

* feat(ui5-panel): panel sticky header implementation

* feat(ui5-panel): add forgotten comma

* feat(ui5-panel): update comments - restore empty lines

* feat(ui5-panel): update comments - restore empty lines

* feat(ui5-panel): update test and fix wrong theme
variables

* feat(ui5-panel): update property description

* feat(ui5-panel): update parameters - use the one which
repeats in the base and add for horizon

* feat(ui5-panel):  use max-height + add story

* feat(ui5-panel): comment update
  • Loading branch information
Okiana authored Jul 25, 2023
1 parent 0b2ef4f commit 18c0e4f
Show file tree
Hide file tree
Showing 12 changed files with 198 additions and 3 deletions.
2 changes: 1 addition & 1 deletion packages/main/src/Panel.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
{{#if hasHeaderOrHeaderText}}
{{! header: either header or h1 with header text}}
<div
class="ui5-panel-heading-wrapper"
class="ui5-panel-heading-wrapper{{classes.stickyHeaderClass}}"
role="{{headingWrapperRole}}"
aria-level="{{headingWrapperAriaLevel}}"
>
Expand Down
17 changes: 17 additions & 0 deletions packages/main/src/Panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 <code>true</code>, the <code>accessibleName</code> property will be
* applied not only on the panel root itself, but on its toggle button too.
Expand Down Expand Up @@ -348,6 +362,9 @@ class Panel extends UI5Element {
headerBtn: {
"ui5-panel-header-button-animated": !this.shouldNotAnimate(),
},
stickyHeaderClass: {
"ui5-panel-heading-wrapper-sticky": this.stickyHeader,
},
};
}

Expand Down
15 changes: 15 additions & 0 deletions packages/main/src/themes/Panel.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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;
}
5 changes: 3 additions & 2 deletions packages/main/src/themes/base/Panel-parameters.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
1 change: 1 addition & 0 deletions packages/main/src/themes/sap_horizon/Panel-parameters.css
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
22 changes: 22 additions & 0 deletions packages/main/test/pages/Panel.html
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,28 @@

<br>

<ui5-panel id="panel-stickyHeader" sticky-header header-text="Panel with sticky header">
<!-- Content -->
<ui5-title>Lorem ipsum!</ui5-title>

<ui5-label id="contentSticky" wrapping-type="Normal">
<span>
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.
</span>
</ui5-label>
</ui5-panel>

<br>
<ui5-panel id="panel1" collapsed header-text="Click to expand!" header-level="H3" accessible-role="Form">

<!-- Content -->
Expand Down
4 changes: 4 additions & 0 deletions packages/main/test/pages/styles/Panel.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@
.panel1auto {
background-color: var(--sapBackgroundColor);
}

#panel-stickyHeader::part(content) {
max-height: 70px;
}
38 changes: 38 additions & 0 deletions packages/main/test/specs/Panel.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down
94 changes: 94 additions & 0 deletions packages/playground/_stories/main/Panel/Panel.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -29,13 +30,15 @@ export default {

const Template : UI5StoryArgs<Panel, StoryArgsSlots> = (args) => html`
<ui5-panel
id="panel-${++index}"
accessible-role="${ifDefined(args.accessibleRole)}"
header-text="${ifDefined(args.headerText)}"
?fixed="${ifDefined(args.fixed)}"
?collapsed="${ifDefined(args.collapsed)}"
?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)}
Expand Down Expand Up @@ -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`
<style>
#panel-${index+1}::part(content) {
max-height: 50px;
}
#second-panel-stickyHeader::part(content) {
max-height: 100px;
}
</style>
<div style="height: 250px; overflow: scroll;">
${story()}
<br />
<ui5-panel id="second-panel-stickyHeader" sticky-header header-text="Second Panel with sticky header">
<ui5-title>Another Lorem ipsum!</ui5-title>
<ui5-label wrapping-type="Normal">
<span>
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.
</span>
</ui5-label>
</ui5-panel>
</div>`
}
]
StickyHeader.args = {
default: `
<ui5-title>Lorem ipsum!</ui5-title>
<ui5-label id="contentSticky" wrapping-type="Normal">
<span>
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.
</span>
</ui5-label>`,
headerText: "Sticky header",
stickyHeader: true
};

export const PanelCustomHeader = Template.bind({});
PanelCustomHeader.decorators = [
Expand Down

0 comments on commit 18c0e4f

Please sign in to comment.