Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui5-panel): panel sticky header implementation #7313

Merged
merged 12 commits into from
Jul 25, 2023
Merged
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}}"
Okiana marked this conversation as resolved.
Show resolved Hide resolved
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.
Okiana marked this conversation as resolved.
Show resolved Hide resolved
* 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);
Okiana marked this conversation as resolved.
Show resolved Hide resolved
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 () => {
Okiana marked this conversation as resolved.
Show resolved Hide resolved
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 />
Okiana marked this conversation as resolved.
Show resolved Hide resolved
<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