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

fix(ui5-menu): provide a way to focus items on fetch #10210

Merged
merged 8 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/main/src/Menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
import "@ui5/webcomponents-icons/dist/slim-arrow-right.js";
import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
import type { Timeout } from "@ui5/webcomponents-base/dist/types.js";
import { renderFinished } from "@ui5/webcomponents-base/dist/Render.js";
import DOMReferenceConverter from "@ui5/webcomponents-base/dist/converters/DOMReference.js";
import ResponsivePopover from "./ResponsivePopover.js";
import type { ResponsivePopoverBeforeCloseEventDetail } from "./ResponsivePopover.js";
Expand Down Expand Up @@ -324,6 +325,17 @@ class Menu extends UI5Element {
}
}

async focus(focusOptions?: FocusOptions): Promise<void> {
await renderFinished();
nnaydenow marked this conversation as resolved.
Show resolved Hide resolved
const firstMenuItem = this._menuItems[0];

if (firstMenuItem) {
return firstMenuItem.focus(focusOptions);
}

return super.focus(focusOptions);
}

_startOpenTimeout(item: MenuItem) {
clearTimeout(this._timeout);

Expand Down
11 changes: 11 additions & 0 deletions packages/main/src/MenuItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js";
import { isPhone } from "@ui5/webcomponents-base/dist/Device.js";
import AriaHasPopup from "@ui5/webcomponents-base/dist/types/AriaHasPopup.js";
import type { AccessibilityAttributes } from "@ui5/webcomponents-base/dist/types.js";
import { renderFinished } from "@ui5/webcomponents-base/dist/Render.js";
nnaydenow marked this conversation as resolved.
Show resolved Hide resolved
import "@ui5/webcomponents-icons/dist/nav-back.js";
import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js";
import type { ListItemAccessibilityAttributes } from "./ListItem.js";
Expand Down Expand Up @@ -261,6 +262,16 @@ class MenuItem extends ListItem implements IMenuItem {
});
}

async focus(focusOptions?: FocusOptions): Promise<void> {
await renderFinished();

if (this.hasSubmenu && this.isSubMenuOpen) {
return this._menuItems[0].focus(focusOptions);
}

return super.focus(focusOptions);
}

get _focusable() {
return true;
}
Expand Down
32 changes: 25 additions & 7 deletions packages/main/test/pages/Menu.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,6 @@
</ui5-menu-item>
<ui5-menu-separator></ui5-menu-separator>
<ui5-menu-item text="Open" icon="open-folder" accessible-name="Choose platform" loading-delay="100" loading>
<ui5-menu-item text="Open Locally" icon="open-folder" additional-text="Ctrl+K">
<ui5-menu-item id="menuItemFromC" text="Open from C"></ui5-menu-item>
<ui5-menu-item id="menuItemFromD" text="Open from D"></ui5-menu-item>
<ui5-menu-separator></ui5-menu-separator>
<ui5-menu-item text="Open from E" disabled></ui5-menu-item>
</ui5-menu-item>
<ui5-menu-item text="Open from SAP Cloud" additional-text="Ctrl+L"></ui5-menu-item>
</ui5-menu-item>
<ui5-menu-item text="Save with very long title for a menu item text inside" icon="save">
<ui5-menu-item text="Save Locally" icon="save">
Expand All @@ -43,6 +36,9 @@
<ui5-menu-item id="menuItemExit" text="Exit" icon="journey-arrive"></ui5-menu-item>
</ui5-menu>

<ui5-menu id="delaymenu" loading-delay="100" loading>
</ui5-menu>

<ui5-title level="H5" class="header-title">Clicked menu item text</ui5-title>
<ui5-input id="selectionInput"></ui5-input>

Expand Down Expand Up @@ -119,6 +115,9 @@
<ui5-link id="detailsLink" href="https://en.wikipedia.org/wiki/Google_logo" target="_blank"></ui5-link>
</ui5-popover>


<ui5-button id="btnAddOpenerDelay">Delayed</ui5-button>

<script>
btnOpen.accessibilityAttributes = {
hasPopup: "menu",
Expand Down Expand Up @@ -146,6 +145,24 @@
menu.open = btnToggleOpen.pressed;
});

btnAddOpenerDelay.addEventListener("click", function() {
delaymenu.opener = "btnAddOpenerDelay";
delaymenu.open = !delaymenu.open;
});

delaymenu.addEventListener("ui5-before-open", function(event) {
setTimeout(function() {
delaymenu.removeAttribute("loading");
delaymenu.removeAttribute("loading-delay");
tsanislavgatev marked this conversation as resolved.
Show resolved Hide resolved
let oneNode = document.createElement("ui5-menu-item");
oneNode.setAttribute("text", "Open from Amazon Cloud");
let twoNode = document.createElement("ui5-menu-item");
twoNode.setAttribute("text", "Open from Google Cloud");
delaymenu.append(oneNode, twoNode);
delaymenu.focus();
}, 1000);
});

let fetched = false;

menu.addEventListener("ui5-before-open", function(event) {
Expand All @@ -160,6 +177,7 @@
twoNode.setAttribute("text", "Open from Google Cloud");
item.append(oneNode, twoNode);
fetched = true;
item.focus();
}, 1000);
}
});
Expand Down
7 changes: 6 additions & 1 deletion packages/website/docs/_components_pages/main/Menu/Menu.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Basic from "../../../_samples/main/Menu/Basic/Basic.md";
import SubMenu from "../../../_samples/main/Menu/SubMenu/SubMenu.md";
import AditionalText from "../../../_samples/main/Menu/AditionalText/AditionalText.md";
import MenuEndContent from "../../../_samples/main/Menu/MenuEndContent/MenuEndContent.md";
import DynamicallyAddedItems from "../../../_samples/main/Menu/DynamicallyAddedItems/DynamicallyAddedItems.md";

<%COMPONENT_OVERVIEW%>

Expand All @@ -27,4 +28,8 @@ You can nest menu items to create sub menus.

### Menu Item with End Content

<MenuEndContent />
<MenuEndContent />

### Handling focus behaviour when adding items dynamically

<DynamicallyAddedItems />
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import html from '!!raw-loader!./sample.html';
import js from '!!raw-loader!./main.js';

<Editor html={html} js={js} />
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import "@ui5/webcomponents/dist/Menu.js";
import "@ui5/webcomponents/dist/MenuItem.js";
tsanislavgatev marked this conversation as resolved.
Show resolved Hide resolved

import "@ui5/webcomponents-icons/dist/add-document.js";
import "@ui5/webcomponents-icons/dist/add-folder.js";
import "@ui5/webcomponents-icons/dist/open-folder.js";
import "@ui5/webcomponents-icons/dist/save.js";
import "@ui5/webcomponents-icons/dist/upload-to-cloud.js";
import "@ui5/webcomponents-icons/dist/action-settings.js";
import "@ui5/webcomponents-icons/dist/journey-arrive.js";
import "@ui5/webcomponents-icons/dist/slim-arrow-down.js";

const btnOpenBasic = document.getElementById("btnOpenBasic");
const menuSubs = document.getElementById("menuSubs");
const btnAddOpenerDelay = document.getElementById("btnAddOpenerDelay");
const delaymenu = document.getElementById("delaymenu");


btnAddOpenerDelay.addEventListener("click", function() {
delaymenu.opener = "btnAddOpenerDelay";
tsanislavgatev marked this conversation as resolved.
Show resolved Hide resolved
delaymenu.open = !delaymenu.open;
});

btnOpenBasic.addEventListener("click", function() {
menuSubs.opener = "btnOpenBasic";
menuSubs.open = !menuSubs.open;
});

let menuItemsLoaded = false;

delaymenu.addEventListener("ui5-before-open", function(event) {
if (!menuItemsLoaded) {
setTimeout(function() {
delaymenu.removeAttribute("loading");
delaymenu.removeAttribute("loading-delay");
tsanislavgatev marked this conversation as resolved.
Show resolved Hide resolved
let oneNode = document.createElement("ui5-menu-item");
oneNode.setAttribute("text", "Open from Amazon Cloud");
let twoNode = document.createElement("ui5-menu-item");
twoNode.setAttribute("text", "Open from Google Cloud");
delaymenu.append(oneNode, twoNode);
menuItemsLoaded = true;
delaymenu.focus();
}, 1000);
}
});

let fetched = false;

menuSubs.addEventListener("ui5-before-open", function(event) {
const item = event.detail.item;
if (item && item.text === "Open" && !fetched) {
setTimeout(function() {
item.removeAttribute("loading");
item.removeAttribute("loading-delay");
let oneNode = document.createElement("ui5-menu-item");
oneNode.setAttribute("text", "Open from Amazon Cloud");
let twoNode = document.createElement("ui5-menu-item");
twoNode.setAttribute("text", "Open from Google Cloud");
item.append(oneNode, twoNode);
fetched = true;
item.focus();
}, 1000);
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!-- playground-fold -->
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sample</title>
</head>

<body style="background-color: var(--sapBackgroundColor); height: 350px;">
<!-- playground-fold-end -->

<ui5-button id="btnOpenBasic" end-icon="slim-arrow-down">Open Menu</ui5-button>
<ui5-button id="btnAddOpenerDelay">Delayed</ui5-button> <br>

<ui5-menu id="menuSubs">
<ui5-menu-item text="New File" icon="add-document"></ui5-menu-item>
<ui5-menu-item text="New Folder" icon="add-folder" disabled></ui5-menu-item>
<ui5-menu-item text="Open" icon="open-folder" sloading-delay="100" loading>
tsanislavgatev marked this conversation as resolved.
Show resolved Hide resolved
</ui5-menu-item>
</ui5-menu>

<ui5-menu id="delaymenu" loading-delay="100" loading>
</ui5-menu>
<!-- playground-fold -->
<script type="module" src="main.js"></script>
</body>

</html>
<!-- playground-fold-end -->