Skip to content

Commit f184114

Browse files
Merge branch 'main' into user-menu-item-sample
2 parents 2307aec + 46007ca commit f184114

6 files changed

Lines changed: 7 additions & 466 deletions

File tree

packages/main/cypress/specs/Panel.cy.tsx

Lines changed: 0 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import Button from "../../src/Button.js";
21
import Label from "../../src/Label.js";
32
import Panel from "../../src/Panel.js";
43
import Title from "../../src/Title.js";
@@ -726,139 +725,3 @@ describe("Accessibility", () => {
726725
.should("have.attr", "aria-label", accessibleNamePanel);
727726
});
728727
});
729-
730-
describe("Scrollable Content Focus", () => {
731-
function addPageStyles(styles: string) {
732-
cy.document().then((doc) => {
733-
const style = doc.createElement("style");
734-
style.id = "panel-focus-styles";
735-
style.innerHTML = styles;
736-
doc.head.appendChild(style);
737-
});
738-
}
739-
function clearPageStyles() {
740-
cy.window()
741-
.then($el => {
742-
const styleTag = $el.document.head.querySelector("style[id='panel-focus-styles']");
743-
styleTag?.remove();
744-
});
745-
}
746-
747-
it("Scrollable content with no focusable children is focusable", () => {
748-
addPageStyles(`
749-
#panel-scroll::part(content) {
750-
max-height: 50px;
751-
}
752-
`);
753-
754-
const longText = "Lorem ipsum dolor sit amet. ".repeat(20);
755-
756-
cy.mount(
757-
<Panel headerText="Scrollable Panel" id="panel-scroll">
758-
<div>{longText}</div>
759-
</Panel>
760-
);
761-
762-
cy.get("[ui5-panel]")
763-
.shadow()
764-
.find(".ui5-panel-content")
765-
.as("content");
766-
767-
cy.get("[ui5-panel]")
768-
.shadow()
769-
.find(".ui5-panel-content-wrapper")
770-
.as("wrapper");
771-
772-
cy.wait(100);
773-
774-
cy.get("@content")
775-
.should($el => {
776-
expect($el[0].scrollHeight).to.be.greaterThan($el[0].clientHeight);
777-
});
778-
779-
cy.get("@content")
780-
.should("have.attr", "tabindex", "0");
781-
782-
cy.get("@wrapper")
783-
.should("have.class", "ui5-panel-content-focusable");
784-
785-
cy.get("[ui5-panel]")
786-
.shadow()
787-
.find(".ui5-panel-header")
788-
.focus()
789-
.realPress("Tab");
790-
791-
cy.get("@content")
792-
.should("be.focused");
793-
794-
clearPageStyles();
795-
});
796-
797-
it("Scrollable content with focusable children is NOT focusable", () => {
798-
addPageStyles(`
799-
#panel-button::part(content) {
800-
max-height: 50px;
801-
}
802-
`);
803-
804-
const longText = "Lorem ipsum dolor sit amet. ".repeat(10);
805-
806-
cy.mount(
807-
<Panel headerText="Panel with Button" id="panel-button">
808-
<div>{longText}</div>
809-
<Button>Click me</Button>
810-
<div>{longText}</div>
811-
</Panel>
812-
);
813-
814-
cy.get("[ui5-panel]")
815-
.shadow()
816-
.find(".ui5-panel-content")
817-
.as("content");
818-
819-
cy.get("[ui5-panel]")
820-
.shadow()
821-
.find(".ui5-panel-content-wrapper")
822-
.as("wrapper");
823-
824-
cy.wait(100);
825-
826-
cy.get("@content")
827-
.should("not.have.attr", "tabindex");
828-
829-
cy.get("@wrapper")
830-
.should("not.have.class", "ui5-panel-content-focusable");
831-
832-
cy.get("[ui5-panel]")
833-
.shadow()
834-
.find(".ui5-panel-header")
835-
.focus()
836-
.realPress("Tab");
837-
838-
cy.get("[ui5-button]")
839-
.should("be.focused");
840-
841-
clearPageStyles();
842-
});
843-
844-
it("Non-scrollable content is NOT focusable", () => {
845-
cy.mount(
846-
<Panel headerText="Short Content Panel">
847-
<Label>Short text</Label>
848-
</Panel>
849-
);
850-
851-
cy.get("[ui5-panel]")
852-
.shadow()
853-
.find(".ui5-panel-content")
854-
.as("content");
855-
856-
cy.get("@content")
857-
.should($el => {
858-
expect($el[0].scrollHeight).to.be.lte($el[0].clientHeight);
859-
});
860-
861-
cy.get("@content")
862-
.should("not.have.attr", "tabindex");
863-
});
864-
});

packages/main/src/Panel.ts

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import { supportsTouch } from "@ui5/webcomponents-base/dist/Device.js";
1414
import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
1515
import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
1616
import type { UI5CustomEvent } from "@ui5/webcomponents-base";
17-
import { getTabbableElements } from "@ui5/webcomponents-base/dist/util/TabbableElements.js";
1817
import type TitleLevel from "./types/TitleLevel.js";
1918
import type Button from "./Button.js";
2019
import type PanelAccessibleRole from "./types/PanelAccessibleRole.js";
@@ -204,14 +203,6 @@ class Panel extends UI5Element {
204203
@property({ type: Boolean })
205204
_touched = false;
206205

207-
/**
208-
* Indicates whether the content area should be focusable.
209-
* This is true when content is scrollable and has no focusable children.
210-
* @private
211-
*/
212-
@property({ type: Boolean, noAttribute: true })
213-
_contentFocusable = false;
214-
215206
/**
216207
* Defines the component header area.
217208
*
@@ -233,10 +224,6 @@ class Panel extends UI5Element {
233224
this._hasHeader = !!this.header.length;
234225
}
235226

236-
onAfterRendering() {
237-
this._updateContentFocusable();
238-
}
239-
240227
shouldToggle(element: HTMLElement): boolean {
241228
const customContent = this.header.length;
242229
if (customContent) {
@@ -348,50 +335,6 @@ class Panel extends UI5Element {
348335
return target.classList.contains("sapMPanelWrappingDiv");
349336
}
350337

351-
/**
352-
* Updates the focusability of the content area.
353-
* Content becomes focusable when:
354-
* - Panel is expanded (not collapsed)
355-
* - Content is scrollable (scrollHeight > clientHeight or scrollWidth > clientWidth)
356-
* - No focusable children exist inside
357-
* @private
358-
*/
359-
_updateContentFocusable() {
360-
// Not focusable when collapsed
361-
if (this.collapsed) {
362-
this._contentFocusable = false;
363-
return;
364-
}
365-
366-
const contentDom = this.shadowRoot?.querySelector(".ui5-panel-content") as HTMLElement | null;
367-
if (!contentDom) {
368-
this._contentFocusable = false;
369-
return;
370-
}
371-
372-
// Check if scrollable (vertical OR horizontal)
373-
const isScrollable = contentDom.scrollHeight > contentDom.clientHeight
374-
|| contentDom.scrollWidth > contentDom.clientWidth;
375-
376-
if (!isScrollable) {
377-
this._contentFocusable = false;
378-
return;
379-
}
380-
381-
// Check for focusable children (synchronous)
382-
const tabbables = getTabbableElements(contentDom);
383-
this._contentFocusable = tabbables.length === 0;
384-
}
385-
386-
/**
387-
* Returns the tabindex for the content area.
388-
* Returns 0 when content should be focusable, undefined otherwise (removes attribute).
389-
* @private
390-
*/
391-
get _contentTabIndex(): number | undefined {
392-
return this._contentFocusable ? 0 : undefined;
393-
}
394-
395338
get toggleButtonTitle() {
396339
return Panel.i18nBundle.getText(PANEL_ICON);
397340
}

packages/main/src/PanelTemplate.tsx

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -89,22 +89,15 @@ export default function PanelTemplate(this: Panel) {
8989

9090
{/* content area */}
9191
<div
92-
class={{
93-
"ui5-panel-content-wrapper": true,
94-
"ui5-panel-content-focusable": this._contentFocusable,
95-
}}
92+
class="ui5-panel-content"
93+
id={ `${this._id}-content` }
94+
tabindex={ -1 }
9695
style={{
9796
display: this._contentExpanded ? "block" : "none",
9897
}}
98+
part="content"
9999
>
100-
<div
101-
class="ui5-panel-content"
102-
id={ `${this._id}-content` }
103-
tabindex={ this._contentTabIndex }
104-
part="content"
105-
>
106-
<slot></slot>
107-
</div>
100+
<slot></slot>
108101
</div>
109102
</div>
110103
</>);

packages/main/src/themes/Panel.css

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -91,30 +91,13 @@
9191
white-space: nowrap;
9292
}
9393

94-
.ui5-panel-content-wrapper {
95-
overflow: hidden;
94+
.ui5-panel-content {
9695
padding: var(--_ui5_panel_content_padding);
9796
background-color: var(--sapGroup_ContentBackground);
97+
outline: none;
9898
border-bottom-left-radius: var(--_ui5_panel_border_radius);
9999
border-bottom-right-radius: var(--_ui5_panel_border_radius);
100-
flex: 1;
101-
min-height: 0;
102-
box-sizing: border-box;
103-
}
104-
105-
.ui5-panel-content-wrapper.ui5-panel-content-focusable:focus-within {
106-
outline: var(--_ui5_panel_focus_border);
107-
outline-offset: var(--_ui5_panel_content_focus_offset);
108-
}
109-
110-
.ui5-panel-content {
111-
height: 100%;
112100
overflow: auto;
113-
outline: none;
114-
}
115-
116-
.ui5-panel-content:focus {
117-
outline: none;
118101
}
119102

120103
.ui5-panel-header-button-root {

packages/main/src/themes/base/Panel-parameters.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
--_ui5_panel_focus_offset: 1px;
1414
--_ui5_panel_focus_bottom_offset: var(--_ui5_panel_focus_offset);
1515
--_ui5_panel_content_padding: 0.625rem 1rem 1.375rem 1rem;
16-
--_ui5_panel_content_focus_offset: -0.1875rem;
1716
--_ui5_panel_header_background_color: var(--sapBackgroundColor);
1817
}
1918

0 commit comments

Comments
 (0)