UNPKG

@limetech/lime-elements

Version:
228 lines (227 loc) • 9.06 kB
import { h } from '@stencil/core'; import { CheckboxTemplate } from '../checkbox/checkbox.template'; import { RadioButtonTemplate } from '../radio-button-group/radio-button.template'; import { getIconColor, getIconName, getIconTitle, } from '../icon/get-icon-props'; import { isEmpty } from 'lodash-es'; export class ListRenderer { constructor() { this.defaultConfig = { isOpen: true, badgeIcons: false, }; /** * Determine which ListItem should have the `tab-index` attribute set, * and return the index at which that ListItem 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.renderListItem = (item, index) => { if ('separator' in item) { return (h("li", { class: "mdc-deprecated-list-divider", role: "separator" }, this.renderTextForSeparator(item), h("div", { class: "limel-list-divider-line" }))); } if (['radio', 'checkbox'].includes(this.config.type)) { return this.renderVariantListItem(this.config, item, index); } const classNames = { 'mdc-deprecated-list-item': true, 'mdc-deprecated-list-item--disabled': item.disabled, 'mdc-deprecated-list-item--selected': item.selected, 'has-primary-component': this.hasPrimaryComponent(item), }; const attributes = {}; if (index === this.applyTabIndexToItemAtIndex) { attributes.tabindex = '0'; } return (h("li", Object.assign({ class: classNames, "aria-disabled": item.disabled ? 'true' : 'false', "aria-selected": item.selected ? 'true' : 'false', "data-index": index }, attributes), this.renderIcon(this.config, item), this.renderPicture(item), this.getPrimaryComponent(item), this.renderText(item), this.twoLines && this.avatarList ? this.renderDivider() : null, this.renderActionMenu(item.actions))); }; this.renderTextForSeparator = (item) => { if ('text' in item) { return h("h2", { class: "limel-list-divider-title" }, item.text); } }; this.hasPrimaryComponent = (item) => { var _a; return !!((_a = item === null || item === void 0 ? void 0 : item.primaryComponent) === null || _a === void 0 ? void 0 : _a.name); }; /** * Render the text of the list item * * @param item - the list item * @returns the text for the list item */ this.renderText = (item) => { if (this.isSimpleItem(item)) { return (h("span", { class: "mdc-deprecated-list-item__text" }, item.text)); } return (h("div", { class: "mdc-deprecated-list-item__text" }, h("div", { class: "mdc-deprecated-list-item__primary-command-text" }, h("div", { class: "mdc-deprecated-list-item__primary-text" }, item.text)), h("div", { class: "mdc-deprecated-list-item__secondary-text" }, item.secondaryText))); }; this.isSimpleItem = (item) => { return !('secondaryText' in item); }; /** * Render an icon for a list item * * @param config - the config object, passed on from the `renderListItem` function * @param item - the list item * @returns the icon element */ this.renderIcon = (config, item) => { const style = {}; const name = getIconName(item.icon); if (!name) { return; } const color = getIconColor(item.icon, item.iconColor); const title = getIconTitle(item.icon); if (color) { if (config.badgeIcons) { style['--icon-background-color'] = color; } else { style.color = color; } } return (h("limel-icon", { badge: config.badgeIcons, class: "mdc-deprecated-list-item__graphic", name: name, style: style, size: config.iconSize, "aria-label": title, "aria-hidden": title ? null : 'true' })); }; this.renderDivider = () => { const classes = { 'mdc-deprecated-list-divider': true, 'mdc-deprecated-list-divider--inset': true, }; if (this.config.iconSize) { classes[this.config.iconSize] = true; } return h("hr", { class: classes }); }; this.renderActionMenu = (actions) => { if (!actions || actions.length === 0) { return; } return (h("limel-menu", { class: "mdc-deprecated-list-item__meta", items: actions, openDirection: "left-start" }, h("limel-icon-button", { class: "action-menu-trigger", slot: "trigger", icon: "menu_2" }))); }; this.renderVariantListItem = (config, item, index) => { let itemTemplate; if (config.type === 'radio') { itemTemplate = (h(RadioButtonTemplate, { id: `c_${index}`, checked: item.selected, disabled: item.disabled })); } else if (config.type === 'checkbox') { itemTemplate = (h(CheckboxTemplate, { id: `c_${index}`, checked: item.selected, disabled: item.disabled })); } const classNames = { 'mdc-deprecated-list-item': true, 'mdc-deprecated-list-item--disabled': item.disabled, 'mdc-deprecated-list-item__text': !item.secondaryText, 'has-primary-component': this.hasPrimaryComponent(item), }; const attributes = {}; if (index === this.applyTabIndexToItemAtIndex) { attributes.tabindex = '0'; } return (h("li", Object.assign({ class: classNames, role: config.type, "aria-checked": item.selected ? 'true' : 'false', "aria-disabled": item.disabled ? 'true' : 'false', "data-index": index }, attributes), this.renderVariantListItemContent(config, item, itemTemplate))); }; this.renderVariantListItemContent = (config, item, itemTemplate) => { if (this.hasIcons) { return [ item.icon ? this.renderIcon(config, item) : null, this.getPrimaryComponent(item), this.renderText(item), h("div", { class: "mdc-deprecated-list-item__meta" }, itemTemplate), ]; } return [ h("div", { class: "mdc-deprecated-list-item__graphic" }, itemTemplate), this.getPrimaryComponent(item), this.renderText(item), ]; }; } render(items, config = {}) { items = items || []; this.config = Object.assign(Object.assign({}, this.defaultConfig), config); this.twoLines = items.some((item) => { return 'secondaryText' in item && !!item.secondaryText; }); this.hasIcons = items.some((item) => { return 'icon' in item && !!item.icon; }); this.avatarList = this.config.badgeIcons && this.hasIcons; const selectableListTypes = ['selectable', 'radio', 'checkbox']; let role; switch (this.config.type) { case 'checkbox': { role = 'group'; break; } case 'radio': { role = 'radiogroup'; break; } default: { role = 'listbox'; } } this.applyTabIndexToItemAtIndex = this.getIndexForWhichToApplyTabIndex(items); const classNames = { 'mdc-deprecated-list': true, 'mdc-deprecated-list--two-line': this.twoLines, selectable: selectableListTypes.includes(this.config.type), 'mdc-deprecated-list--avatar-list': this.avatarList, 'list--compact': this.twoLines && this.commandKey && ['small', 'x-small'].includes(this.config.iconSize), }; return (h("ul", { class: classNames, role: role, "aria-orientation": "vertical" }, items.map(this.renderListItem))); } getPrimaryComponent(item) { if (!this.hasPrimaryComponent(item)) { return; } const PrimaryComponent = item.primaryComponent.name; const props = item.primaryComponent.props; return h(PrimaryComponent, Object.assign({}, props)); } renderPicture(item) { const image = item.image; if (isEmpty(image)) { return; } return h("img", { src: image.src, alt: image.alt, loading: "lazy" }); } } //# sourceMappingURL=list-renderer.js.map