Skip to content

Commit

Permalink
refactor(ui5-menu): display custom list items (#8476)
Browse files Browse the repository at this point in the history
- This change is meant to ease the further implementation
for custom content supplied by the application developers.

- The menu width is adjusted based on the menu item's contents,
in order to fulfill the accessibility standard. The menu item text will
truncate in case there is insufficient space in the viewport to display it.

Fixes: #7082
Related to: #6350
  • Loading branch information
unazko authored Mar 29, 2024
1 parent 0f753da commit 8d1fcd9
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 116 deletions.
26 changes: 0 additions & 26 deletions packages/main/src/Menu.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -77,32 +77,6 @@
@keydown={{../_itemKeyDown}}
@_focused={{../_onfocusin}}
>
<div class="ui5-menu-item-text">
{{#if this.item.hasDummyIcon}}
<div
class="ui5-menu-item-dummy-icon"
>
</div>
{{/if}}
{{this.item.text}}
{{#if this.item.hasSubmenu}}
<div
class="ui5-menu-item-submenu-icon"
>
<ui5-icon
part="subicon"
name="slim-arrow-right"
class="ui5-menu-item-icon-end"
>
</ui5-icon>
</div>
{{else if this.item._siblingsWithChildren}}
<div
class="ui5-menu-item-no-icon-end"
>
</div>
{{/if}}
</div>
</ui5-menu-li>
{{/each}}
</ui5-list>
Expand Down
2 changes: 1 addition & 1 deletion packages/main/src/Menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ class Menu extends UI5Element {
const menuListItem = target.hasAttribute("ui5-menu-li")
? target as MenuListItem
: (target.getRootNode() as ShadowRoot).host as MenuListItem;
const item = menuListItem.associatedItem as MenuItem;
const item = menuListItem.associatedItem;
const mainMenu = this._findMainMenu(item);
mainMenu?.fireEvent<MenuItemFocusEventDetail>("item-focus", { ref: menuListItem, item });
}
Expand Down
35 changes: 35 additions & 0 deletions packages/main/src/MenuListItem.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{{>include "./ListItem.hbs"}}

{{#*inline "listItemContent"}}
{{#if text}}
<div class="ui5-menu-item-text">{{text}}</div>
{{/if}}
{{#if _additionalText}}
<span part="additional-text" class="ui5-li-additional-text">{{_additionalText}}</span>
{{/if}}
{{/inline}}

{{#*inline "iconBegin"}}
{{#if _siblingsWithIcon}}
{{#if hasIcon}}
<ui5-icon class="ui5-li-icon" name="{{icon}}"></ui5-icon>
{{else}}
<div class="ui5-menu-item-dummy-icon"></div>
{{/if}}
{{/if}}
{{/inline}}

{{#*inline "iconEnd"}}
{{#if hasSubmenu}}
<div
class="ui5-menu-item-submenu-icon"
>
<ui5-icon
part="subicon"
name="slim-arrow-right"
class="ui5-menu-item-icon-end"
>
</ui5-icon>
</div>
{{/if}}
{{/inline}}
64 changes: 56 additions & 8 deletions packages/main/src/MenuListItem.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import customElement from "@ui5/webcomponents-base/dist/decorators/customElement.js";
import property from "@ui5/webcomponents-base/dist/decorators/property.js";
import StandardListItem from "./StandardListItem.js";
import StandardListItemTemplate from "./generated/templates/StandardListItemTemplate.lit.js";
import CustomListItem from "./CustomListItem.js";
import MenuListItemTemplate from "./generated/templates/MenuListItemTemplate.lit.js";
import MenuItem from "./MenuItem.js";
import HasPopup from "./types/HasPopup.js";

Expand All @@ -11,30 +11,78 @@ import menuListItemCss from "./generated/themes/MenuListItem.css.js";
/**
* @class
* @constructor
* @extends StandardListItem
* @extends CustomListItem
* @since 1.23.0
* @private
*/
@customElement({
tag: "ui5-menu-li",
template: StandardListItemTemplate,
styles: [StandardListItem.styles, menuListItemCss],
template: MenuListItemTemplate,
styles: [CustomListItem.styles, menuListItemCss],
})
class MenuListItem extends StandardListItem {
class MenuListItem extends CustomListItem {
/**
* Defines the associated MenuItem instance
* @private
*/
@property({ type: Object })
associatedItem?: MenuItem;
associatedItem!: MenuItem;

/**
* Defines the icon to be displayed as graphical element within the component.
* The SAP-icons font provides numerous options.
*
* **Example:**
*
* See all the available icons in the [Icon Explorer](https://sdk.openui5.org/test-resources/sap/m/demokit/iconExplorer/webapp/index.html).
* @default ""
* @public
* @since 1.24.0
*/
@property()
icon!: string;

/**
* Defines the `additionalText`, displayed in the end of the menu item.
*
* **Note:** The additional text would not be displayed if the item has a submenu.
* @default ""
* @public
* @since 1.24.0
*/
@property()
additionalText!: string;

get text() {
return this.associatedItem?.text;
}

get _additionalText() {
return this.associatedItem?._additionalText;
}

get hasIcon() {
return !!this.associatedItem?.icon;
}

get hasSubmenu() {
return !!(this.associatedItem?.items.length || this.associatedItem?.busy);
}

get subMenuOpened() {
return !!this.associatedItem?._subMenu;
}

get _siblingsWithIcon() {
return this.associatedItem?._siblingsWithIcon;
}

get _focusable() {
return true;
}

get _accInfo() {
const accInfoSettings = {
role: "menuitem",
ariaHaspopup: this.associatedItem?.hasSubmenu ? HasPopup.Menu.toLowerCase() as Lowercase<HasPopup> : undefined,
};

Expand Down
80 changes: 0 additions & 80 deletions packages/main/src/themes/Menu.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,6 @@
.ui5-menu-rp[ui5-responsive-popover] {
box-shadow: var(--sapContent_Shadow1);
border-radius: var(--_ui5_menu_popover_border_radius);
max-width: 20rem;
}

.ui5-menu-item-icon-end {
display: inline-block;
vertical-align: middle;
padding-inline-start: 0.5rem;
pointer-events: none;
position: absolute;
inset-inline-end: var(--_ui5_menu_item_submenu_icon_right);
}

.ui5-menu-item-no-icon-end {
min-width: var(--_ui5_list_item_icon_size);
min-height: var(--_ui5_list_item_icon_size);
display: inline-block;
vertical-align: middle;
padding-inline-start: 0.5rem;
pointer-events: none;
inset-inline-end: var(--_ui5_menu_item_submenu_icon_right);
}

.ui5-menu-item[additional-text] .ui5-menu-item-no-icon-end {
display: none;
}

.ui5-menu-item-dummy-icon {
min-width: var(--_ui5_list_item_icon_size);
min-height: var(--_ui5_list_item_icon_size);
display: inline-block;
vertical-align: middle;
padding-inline-end: 0.5rem;
pointer-events: none;
}

.ui5-menu-item-submenu-icon {
min-width: var(--_ui5_list_item_icon_size);
min-height: var(--_ui5_list_item_icon_size);
display: inline-block;
vertical-align: middle;
pointer-events: none;
}

.ui5-menu-busy-indicator {
Expand Down Expand Up @@ -86,28 +45,6 @@
margin-right: 1rem;
}

.ui5-menu-item::part(title) {
font-size: var(--sapFontSize);
padding-top: 0.125rem;
}

.ui5-menu-item[icon]:not([is-phone])::part(title),
.ui5-menu-item[is-phone]:not([icon=""])::part(title) {
padding-top: 0;
}

.ui5-menu-item:not([is-phone])::part(native-li) {
padding: var(--_ui5_menu_item_padding);
}

.ui5-menu-item[starts-section] {
border-top: 1px solid var(--sapGroup_ContentBorderColor);
}

.ui5-menu-item[active] .ui5-menu-item-icon-end {
color: var(--sapList_Active_TextColor);
}

.ui5-menu-rp[sub-menu] {
margin-top: 0.25rem;
margin-inline: var(--_ui5_menu_submenu_margin_offset);
Expand All @@ -116,21 +53,4 @@
.ui5-menu-rp[sub-menu][actual-placement-type="Left"] {
margin-top: 0.25rem;
margin-inline: var(--_ui5_menu_submenu_placement_type_left_margin_offset);
}

.ui5-menu-item::part(additional-text) {
margin-inline-start: var(--_ui5_menu_item_additional_text_start_margin);
color: var(--sapContent_LabelColor);
min-width: max-content;
}

.ui5-menu-item-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
pointer-events: none;
}

.ui5-menu-item-text:has(.ui5-menu-item-submenu-icon) {
padding-inline-end: 1rem;
}
74 changes: 73 additions & 1 deletion packages/main/src/themes/MenuListItem.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
}

:host([disabled])::part(content) {
opacity: var(--_ui5-listitembase_disabled_opacity);
opacity: var(--_ui5-listitembase_disabled_opacity);
}

/* hovered and active */
Expand All @@ -20,4 +20,76 @@

:host([focused]:not([active]):not([disabled])) {
background-color: var(--sapList_Hover_Background);
}

:host(:not([is-phone]))::part(native-li) {
padding: var(--_ui5_menu_item_padding);
}

:host::part(additional-text) {
margin: unset;
margin-inline-start: 1rem;
color: var(--sapContent_LabelColor);
min-width: max-content;
}

.ui5-menu-item-text {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
pointer-events: none;
display: inline-block;
}

.ui5-menu-item-dummy-icon {
visibility: hidden;
}

:host::part(title) {
font-size: var(--sapFontSize);
padding-top: 0.125rem;
}

:host([icon]:not([is-phone]))::part(title),
:host([is-phone]:not([icon=""]))::part(title) {
padding-top: 0;
}

:host(:not([is-phone]))::part(native-li) {
padding: var(--_ui5_menu_item_padding);
}

:host([starts-section]) {
border-top: 1px solid var(--sapGroup_ContentBorderColor);
}

:host::part(content) {
padding-inline-end: 0.5rem;
}

.ui5-menu-item-submenu-icon {
min-width: var(--_ui5_list_item_icon_size);
min-height: var(--_ui5_list_item_icon_size);
display: inline-block;
vertical-align: middle;
pointer-events: none;
}

.ui5-menu-item-icon-end {
display: inline-block;
vertical-align: middle;
padding-inline-start: 0.5rem;
pointer-events: none;
position: absolute;
inset-inline-end: var(--_ui5_menu_item_submenu_icon_right);
}

.ui5-menu-item-dummy-icon {
min-width: var(--_ui5_list_item_icon_size);
min-height: var(--_ui5_list_item_icon_size);
display: inline-block;
vertical-align: middle;
padding-inline-end: 0.5rem;
pointer-events: none;
}

0 comments on commit 8d1fcd9

Please sign in to comment.