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-side-navigation): add actions and unselectable items #10482

Merged
merged 32 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ef74d27
feat(ui5-side-navigation): add actions and option to select leaves only
dimovpetar Jan 7, 2025
a27775e
refactor: use unselectable instead of interaction mode
dimovpetar Jan 13, 2025
22257c0
test: isSelectable
dimovpetar Jan 13, 2025
4adbd21
feat: all parts of unselectable items now can toggle them
dimovpetar Jan 13, 2025
1503d1d
test: reorder tests
dimovpetar Jan 13, 2025
d8fc7b7
test: proper assertion
dimovpetar Jan 13, 2025
a9116a3
feat: add ariaAttributes with hasPopup
dimovpetar Jan 13, 2025
9cdeaa9
test: correct indexes
dimovpetar Jan 13, 2025
1afccc5
docs: annotate new properties
dimovpetar Jan 13, 2025
4f21684
Merge branch 'main' of github.com:SAP/ui5-webcomponents into side_nav…
dimovpetar Jan 13, 2025
fb131e1
fix: export SideNavigationItemAccessibilityAttributes
dimovpetar Jan 13, 2025
c944047
test: add tests for selection-change event
dimovpetar Jan 14, 2025
6d86a32
docs: add sample
dimovpetar Jan 14, 2025
f926cc8
fix: toggle unselectable items with keyboard
dimovpetar Jan 14, 2025
f50bac7
docs: document restriction not to use subitems with actions
dimovpetar Jan 14, 2025
1112cf5
Merge branch 'main' of github.com:SAP/ui5-webcomponents into side_nav…
dimovpetar Jan 14, 2025
31fb11a
docs: improve documentation
dimovpetar Jan 20, 2025
6477752
fix: properly fire selection-change from in collapsed mode
dimovpetar Jan 21, 2025
8adc31a
fix: forward design attribute to items in collapsed mode
dimovpetar Jan 21, 2025
e3e99f1
fix: aria-haspopup is now added in collapsed mode
dimovpetar Jan 21, 2025
4cc9f56
fix: don't toggle expanded property on leaf nodes
dimovpetar Jan 21, 2025
1d15c74
fix: fire click event on Enter
dimovpetar Jan 21, 2025
564a6df
fix: set role to menuitem for unselectable items
dimovpetar Jan 21, 2025
3865169
docs: improve unselectable description
dimovpetar Jan 21, 2025
216db08
docs: make all external links unselectable
dimovpetar Jan 21, 2025
a4993ef
docs: replace alert with ui5-dialog
dimovpetar Jan 21, 2025
df8e6ef
docs: improve documentation
alexandar-mitsev Jan 24, 2025
667f1f8
Merge branch 'main' into side_navigation_actions_leaves
alexandar-mitsev Jan 24, 2025
c6c4004
Merge branch 'main' into side_navigation_actions_leaves
alexandar-mitsev Jan 27, 2025
4abeacb
test: fix focusing for navigation items
alexandar-mitsev Jan 27, 2025
bf899bc
fix: revert fix of focusing items
alexandar-mitsev Jan 27, 2025
7fe12de
fix: fix commands and selection for focus
alexandar-mitsev Jan 27, 2025
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
470 changes: 445 additions & 25 deletions packages/fiori/cypress/specs/SideNavigation.cy.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/fiori/src/SideNavigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ class SideNavigation extends UI5Element {
}

_selectItem(item: SideNavigationSelectableItemBase) {
if (item.disabled) {
if (!item.isSelectable) {
return;
}

Expand Down
38 changes: 34 additions & 4 deletions packages/fiori/src/SideNavigationItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@ import customElement from "@ui5/webcomponents-base/dist/decorators/customElement
import jsxRender from "@ui5/webcomponents-base/dist/renderer/JsxRenderer.js";
import property from "@ui5/webcomponents-base/dist/decorators/property.js";
import slot from "@ui5/webcomponents-base/dist/decorators/slot.js";
import { isLeft, isRight } from "@ui5/webcomponents-base/dist/Keys.js";
import {
isLeft,
isRight,
isSpace,
isEnter,
} from "@ui5/webcomponents-base/dist/Keys.js";
import type SideNavigationItemBase from "./SideNavigationItemBase.js";
import SideNavigationSelectableItemBase from "./SideNavigationSelectableItemBase.js";
import type SideNavigation from "./SideNavigation.js";
import type SideNavigationSubItem from "./SideNavigationSubItem.js";

// Templates
import SideNavigationItemTemplate from "./SideNavigationItemTemplate.js";

// Styles
Expand Down Expand Up @@ -89,6 +96,10 @@ class SideNavigationItem extends SideNavigationSelectableItemBase {
}

get _ariaHasPopup() {
if (this.inPopover && this.accessibilityAttributes?.hasPopup) {
return this.accessibilityAttributes.hasPopup;
}

if (!this.disabled && this.sideNavCollapsed && this.items.length) {
return "tree";
}
Expand All @@ -97,7 +108,7 @@ class SideNavigationItem extends SideNavigationSelectableItemBase {
}

get _ariaChecked() {
if (this.isOverflow) {
if (this.isOverflow || this.unselectable) {
return undefined;
}

Expand Down Expand Up @@ -142,10 +153,10 @@ class SideNavigationItem extends SideNavigationSelectableItemBase {
return this.selected;
}

_onToggleClick(e: PointerEvent) {
_onToggleClick(e: CustomEvent) {
e.stopPropagation();

this.expanded = !this.expanded;
this._toggle();
}

_onkeydown(e: KeyboardEvent) {
Expand All @@ -159,6 +170,15 @@ class SideNavigationItem extends SideNavigationSelectableItemBase {
return;
}

if (this.unselectable && isSpace(e)) {
this._toggle();
return;
}

if (this.unselectable && isEnter(e)) {
this._toggle();
}

super._onkeydown(e);
}

Expand All @@ -171,6 +191,10 @@ class SideNavigationItem extends SideNavigationSelectableItemBase {
}

_onclick(e: MouseEvent) {
if (this.unselectable) {
this._toggle();
}

alexandar-mitsev marked this conversation as resolved.
Show resolved Hide resolved
super._onclick(e);
}

Expand Down Expand Up @@ -201,6 +225,12 @@ class SideNavigationItem extends SideNavigationSelectableItemBase {
get isSideNavigationItem() {
return true;
}

_toggle() {
alexandar-mitsev marked this conversation as resolved.
Show resolved Hide resolved
if (this.items.length) {
this.expanded = !this.expanded;
}
}
}

SideNavigationItem.define();
Expand Down
3 changes: 1 addition & 2 deletions packages/fiori/src/SideNavigationItemTemplate.tsx
dimovpetar marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ function TreeItemTemplate(this: SideNavigationItem) {
{!!this.items.length &&
<Icon class="ui5-sn-item-toggle-icon"
name={this.expanded ? navDownArrow : navRightArrow}
// @ts-expect-error
onClick={this._onToggleClick}
/>
}
Expand All @@ -128,6 +127,7 @@ function TreeItemTemplate(this: SideNavigationItem) {
aria-expanded={this._expanded}
aria-current={this._ariaCurrent}
aria-selected={this.selected}
aria-haspopup={this.accessibilityAttributes?.hasPopup}
title={this._tooltip}
aria-owns={this._groupId}
>
Expand All @@ -143,7 +143,6 @@ function TreeItemTemplate(this: SideNavigationItem) {
{!!this.items.length &&
<Icon class="ui5-sn-item-toggle-icon"
name={this.expanded ? navDownArrow : navRightArrow}
// @ts-expect-error
onClick={this._onToggleClick}
/>
}
Expand Down
6 changes: 6 additions & 0 deletions packages/fiori/src/SideNavigationPopoverTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,25 +56,31 @@ export default function SideNavigationTemplate(this: SideNavigation) {
class="ui5-side-navigation-in-popover"
>
<SideNavigationItem
accessibilityAttributes={this._popoverContents.item.accessibilityAttributes}
text={this._popoverContents.item.text}
tooltip={this._popoverContents.item._tooltip}
href={this._popoverContents.item._href}
target={this._popoverContents.item._target}
design={this._popoverContents.item.design}
disabled={this._popoverContents.item.disabled}
expanded={true}
_fixed={true}
selected={this._popoverContents.item.selected}
unselectable={this._popoverContents.item.unselectable}
onui5-click={this.handlePopupItemClick}
ref={this.captureRef.bind(this._popoverContents.item)}
>
{this._popoverContents.subItems.map(item =>
<SideNavigationSubItem
accessibilityAttributes={item.accessibilityAttributes}
text={item.text}
tooltip={item._tooltip}
href={item._href}
target={item._target}
design={item.design}
disabled={item.disabled}
selected={item.selected}
unselectable={item.unselectable}
onui5-click={this.handlePopupItemClick}
ref={this.captureRef.bind(item)}
/>
Expand Down
57 changes: 56 additions & 1 deletion packages/fiori/src/SideNavigationSelectableItemBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import property from "@ui5/webcomponents-base/dist/decorators/property.js";
import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js";
import { isSpace, isEnter } from "@ui5/webcomponents-base/dist/Keys.js";
import SideNavigationItemBase from "./SideNavigationItemBase.js";
import type SideNavigationItemDesign from "./types/SideNavigationItemDesign.js";
import type { AccessibilityAttributes } from "@ui5/webcomponents-base/dist/types.js";

type SideNavigationItemAccessibilityAttributes = Pick<AccessibilityAttributes, "hasPopup">;

/**
* Fired when the component is activated either with a
alexandar-mitsev marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -83,6 +87,50 @@ class SideNavigationSelectableItemBase extends SideNavigationItemBase {
@property()
target?: string;

/**
* Item design.
*
* **Note:** Items with "Action" design must not have sub-items.
*
* @public
* @default "Default"
* @since 2.7.0
*/
@property()
design: `${SideNavigationItemDesign}` = "Default";
dimovpetar marked this conversation as resolved.
Show resolved Hide resolved

/**
alexandar-mitsev marked this conversation as resolved.
Show resolved Hide resolved
* Indicates whether the navigation item is selectable. By default all items are selectable unless specifically marked as unselectable.
alexandar-mitsev marked this conversation as resolved.
Show resolved Hide resolved
*
dimovpetar marked this conversation as resolved.
Show resolved Hide resolved
* When a parent item is marked as unselectable, clicking it will only expand or collapse its sub-items.
alexandar-mitsev marked this conversation as resolved.
Show resolved Hide resolved
* To achieve better user experience you should not mix unselectable parent items and selectable parent items in the same side navigation.
alexandar-mitsev marked this conversation as resolved.
Show resolved Hide resolved
*
*
* **Guidelines**:
* - External links should not be unselectable
alexandar-mitsev marked this conversation as resolved.
Show resolved Hide resolved
* - Items that trigger actions (with design "Action") should be unselectable
alexandar-mitsev marked this conversation as resolved.
Show resolved Hide resolved
*
* @public
* @default false
* @since 2.7.0
*/
@property({ type: Boolean })
unselectable = false;
dimovpetar marked this conversation as resolved.
Show resolved Hide resolved

/**
* Defines the additional accessibility attributes that will be applied to the component.
* The following fields are supported:
dimovpetar marked this conversation as resolved.
Show resolved Hide resolved
*
* - **hasPopup**: Indicates the availability and type of interactive popup element, such as menu or dialog, that can be triggered by the button.
* Accepts the following string values: `dialog`, `grid`, `listbox`, `menu` or `tree`.
*
* @public
* @default {}
* @since 2.7.0
*/
@property({ type: Object })
accessibilityAttributes: SideNavigationItemAccessibilityAttributes = {};

/**
* @private
* @default false
Expand All @@ -92,12 +140,16 @@ class SideNavigationSelectableItemBase extends SideNavigationItemBase {

get ariaRole() {
if (this.sideNavCollapsed) {
return this.isOverflow ? "menuitem" : "menuitemradio";
return this.isOverflow || this.unselectable ? "menuitem" : "menuitemradio";
}

return "treeitem";
}

get isSelectable() {
return !this.unselectable && !this.disabled;
}

get _href() {
return (!this.disabled && this.href) ? this.href : undefined;
}
Expand Down Expand Up @@ -189,3 +241,6 @@ export default SideNavigationSelectableItemBase;
export {
isInstanceOfSideNavigationSelectableItemBase,
};
export type {
SideNavigationItemAccessibilityAttributes,
};
1 change: 1 addition & 0 deletions packages/fiori/src/SideNavigationSubItemTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export default function SideNavigationSubItemTemplate(this: SideNavigationSubIte
onFocusIn={this._onfocusin}
tabIndex={this.effectiveTabIndex ? parseInt(this.effectiveTabIndex) : undefined}
aria-current={this._ariaCurrent}
aria-haspopup={this.accessibilityAttributes?.hasPopup}
aria-selected={this.selected}
title={this._tooltip}
>
Expand Down
8 changes: 8 additions & 0 deletions packages/fiori/src/themes/SideNavigationItemBase.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
display: none;
}

:host([design="Action"]) {
color: var(--sapButton_TextColor);
}

.ui5-sn-item:focus {
outline: none;
}
Expand Down Expand Up @@ -138,6 +142,10 @@ and there is an additional border that appears on hover. */
padding-inline-end: var(--_ui5_side_navigation_icon_padding_inline_end);
}

:host([design="Action"]) .ui5-sn-item-icon {
color: var(--sapButton_TextColor);
}

.ui5-sn-item-toggle-icon,
.ui5-sn-item-external-link-icon {
color: var(--_ui5_side_navigation_expand_icon_color);
Expand Down
24 changes: 24 additions & 0 deletions packages/fiori/src/types/SideNavigationItemDesign.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* SideNavigationItem designs.
* @public
* @since 2.7.0
*/
enum SideNavigationItemDesign {
/**
* Design for items that perform navigation, contain navigation child items, or both.
*
* @public
*/
Default = "Default",

/**
* Design for items that trigger an action, such as opening a dialog.
*
* **Note:** Items with this design must not have sub-items.
*
* @public
*/
Action = "Action",
}

export default SideNavigationItemDesign;
15 changes: 12 additions & 3 deletions packages/fiori/test/pages/SideNavigation.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,23 @@
<ui5-side-navigation-sub-item text="Others"></ui5-side-navigation-sub-item>
</ui5-side-navigation-item>
<ui5-side-navigation-item disabled id="item1" text="Home" icon="home" tooltip="Home tooltip"></ui5-side-navigation-item>
<ui5-side-navigation-item text="Home (unselectable)" icon="home" unselectable></ui5-side-navigation-item>
<ui5-side-navigation-item text="Home (unselectable)" icon="home" unselectable>
<ui5-side-navigation-sub-item text="Local"></ui5-side-navigation-sub-item>
<ui5-side-navigation-sub-item text="Others"></ui5-side-navigation-sub-item>
</ui5-side-navigation-item>

<!-- Fixed Items -->
<ui5-side-navigation-item id="fixedItem1" slot="fixedItems" text="Useful Links" icon="chain-link" tooltip="Useful links tooltip">
<ui5-side-navigation-sub-item id="fixedItem11" text="Vacation Tool" tooltip="Vacation Tool tooltip"></ui5-side-navigation-sub-item>
<ui5-side-navigation-sub-item id="fixedItem12" text="HR tool"></ui5-side-navigation-sub-item>
<ui5-side-navigation-sub-item text="External Link" href="https://sap.com" target="_blank"></ui5-side-navigation-sub-item>
<ui5-side-navigation-sub-item text="External Link (unselectable)" href="https://sap.com" target="_blank" unselectable></ui5-side-navigation-sub-item>
<ui5-side-navigation-sub-item text="Quick Create" design="Action" unselectable></ui5-side-navigation-sub-item>
</ui5-side-navigation-item>
<ui5-side-navigation-item slot="fixedItems" text="History" icon="history"></ui5-side-navigation-item>
<ui5-side-navigation-item slot="fixedItems" text="External Link" icon="chain-link" href="https://sap.com" target="_blank"></ui5-side-navigation-item>
<ui5-side-navigation-item slot="fixedItems" text="Quick Create" icon="write-new" design="Action" unselectable id="quickCreate"></ui5-side-navigation-item>
</ui5-side-navigation>
<div class="inner-content">
<div>
Expand All @@ -80,9 +88,6 @@
</div>
</div>




<script>
var sideNavigation = document.querySelector("ui5-side-navigation"),
input = document.querySelector("#counter"),
Expand Down Expand Up @@ -115,6 +120,10 @@
input.value = `${++counter}`;
});

document.getElementById("quickCreate").accessibilityAttributes = {
hasPopup: "dialog"
};

</script>
</body>
</html>
6 changes: 3 additions & 3 deletions packages/fiori/test/specs/SideNavigation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,9 @@ describe("Component Behavior", () => {

// fixed items
assert.strictEqual(await sideNavigationFixedTree.getAttribute("aria-roledescription"), roleDescription, "Role description of the SideNavigation fixed tree element is correctly set");
assert.notExists(await items[8].getAttribute("aria-roledescription"), "Role description of the SideNavigation fixed tree item is not set");
assert.strictEqual(await items[8].getAttribute("aria-haspopup"), "tree", "There is 'aria-haspopup' with correct value");
assert.notExists(await items[9].getAttribute("aria-haspopup"), "There is no 'aria-haspopup'");
assert.notExists(await items[10].getAttribute("aria-roledescription"), "Role description of the SideNavigation fixed tree item is not set");
assert.strictEqual(await items[10].getAttribute("aria-haspopup"), "tree", "There is 'aria-haspopup' with correct value");
assert.notExists(await items[11].getAttribute("aria-haspopup"), "There is no 'aria-haspopup'");

// popup
await browser.$("#item2").click();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import Basic from "../../../_samples/fiori/SideNavigation/Basic/Basic.md";
import QuickAction from "../../../_samples/fiori/SideNavigation/QuickAction/QuickAction.md";

<%COMPONENT_OVERVIEW%>

## Basic Sample
<Basic />

<%COMPONENT_METADATA%>
<%COMPONENT_METADATA%>

## More Samples

### Quick Action
Quick action items allow for providing access to frequent functionality.

<QuickAction />
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import "@ui5/webcomponents-fiori/dist/SideNavigation.js";
import "@ui5/webcomponents-fiori/dist/SideNavigationItem.js";
import "@ui5/webcomponents-fiori/dist/SideNavigationGroup.js";
import "@ui5/webcomponents-fiori/dist/SideNavigationSubItem.js";

import "@ui5/webcomponents-icons/dist/home.js";
Expand Down
Loading
Loading