@limetech/lime-elements
Version:
101 lines (100 loc) • 4.73 kB
JavaScript
import { h } from "@stencil/core";
import { isFunction } from "lodash-es";
export class MenuListRenderer {
constructor() {
this.defaultConfig = {
isOpen: true,
badgeIcons: false,
};
/**
* Determine which MenuItem should have the `tab-index` attribute set,
* and return the index at which that MenuItem is located in `items`.
* Returns `undefined` if no item should have the attribute set.
* See https://github.com/material-components/material-components-web/tree/e66a43a75fef4f9179e24856649518e15e279a04/packages/mdc-list#accessibility
*
* @param items - the items of the list, including any `ListSeparator`:s
* @returns the index as per the description
*/
this.getIndexForWhichToApplyTabIndex = (items) => {
let result;
for (let i = 0, max = items.length; i < max; i += 1) {
if ('separator' in items[i]) {
// Ignore ListSeparator
}
else {
const item = items[i];
if (item.disabled) {
// Skip disabled items - they should never get tabindex
continue;
}
if (item.selected) {
result = i;
break;
}
if (result === undefined) {
result = i;
// Do NOT break, as any later item with
// `selected=true` should get the tab-index instead!
}
}
}
return result;
};
/**
* Render a single list item
*
* @param item - the item to render
* @param index - the index the item had in the `items` array
* @returns the list item
*/
this.renderMenuItem = (item, index) => {
var _a;
if ('separator' in item) {
return (h("li", { class: "mdc-deprecated-list-divider", role: "separator", key: `sep-${index}` }, this.renderTextForSeparator(item), h("div", { class: "limel-list-divider-line" })));
}
const attributes = {};
if (index === this.applyTabIndexToItemAtIndex) {
attributes.tabindex = '0';
}
const hasSubMenu = this.hasSubItems(item);
const hasMeta = hasSubMenu ||
item.badge !== undefined ||
!!item.hotkey ||
!!item.commandText;
const primaryComponent = hasMeta
? {
name: 'limel-menu-item-meta',
props: {
commandText: item.commandText,
hotkey: item.hotkey,
disabled: !!item.disabled,
badge: item.badge,
showChevron: hasSubMenu,
},
}
: undefined;
const key = (_a = item.id) !== null && _a !== void 0 ? _a : `item-${index}`;
const classNames = {
'mdc-deprecated-list-item': true, // required for keyboard navigation with arrow keys
'mdc-deprecated-list-item--disabled': !!item.disabled, // MDC’s foundation checks for the disabled class before toggling selected state
};
return (h("limel-list-item", Object.assign({ key: key, class: classNames, "data-index": index }, attributes, { "aria-haspopup": hasSubMenu ? 'menu' : undefined, "aria-expanded": hasSubMenu ? 'false' : undefined, type: "menuitem", text: item.text, secondaryText: item.secondaryText, icon: item.icon, primaryComponent: primaryComponent, badgeIcon: this.config.badgeIcons, selected: item.selected, disabled: item.disabled })));
};
this.renderTextForSeparator = (item) => {
if ('text' in item) {
return h("h2", { class: "limel-list-divider-title" }, item.text);
}
};
this.hasSubItems = (item) => {
return ((Array.isArray(item.items) && item.items.length > 0) ||
isFunction(item.items));
};
}
render(items, config = {}) {
items = items || [];
this.config = Object.assign(Object.assign({}, this.defaultConfig), config);
this.applyTabIndexToItemAtIndex =
this.getIndexForWhichToApplyTabIndex(items);
return (h("ul", { class: "mdc-deprecated-list", role: "menu", "aria-orientation": "vertical", style: { '--maxLinesSecondaryText': '2' } }, items.map(this.renderMenuItem)));
}
}