UNPKG

@limetech/lime-elements

Version:
405 lines (404 loc) • 16.1 kB
import { MDCList } from "@material/list"; import { strings as listStrings } from "@material/list/constants"; import { h, Host, } from "@stencil/core"; import { ListRenderer } from "./list-renderer"; const { ACTION_EVENT } = listStrings; /** * @exampleComponent limel-example-list-basic * @exampleComponent limel-example-list-secondary * @exampleComponent limel-example-list-separator * @exampleComponent limel-example-list-icons * @exampleComponent limel-example-list-badge-icons * @exampleComponent limel-example-list-pictures * @exampleComponent limel-example-list-selectable * @exampleComponent limel-example-list-checkbox-icons * @exampleComponent limel-example-list-radio-button-icons * @exampleComponent limel-example-list-action * @exampleComponent limel-example-list-striped * @exampleComponent limel-example-list-badge-icons-with-multiple-lines * @exampleComponent limel-example-list-grid * @exampleComponent limel-example-list-primary-component */ export class List { constructor() { /** * Size of the icons in the list */ this.iconSize = 'small'; /** * By default, lists will display 3 lines of text, and then truncate the rest. * Consumers can increase or decrease this number by specifying * `maxLinesSecondaryText`. If consumer enters zero or negative * numbers we default to 1; and if they type decimals we round up. */ this.maxLinesSecondaryText = 3; this.listRenderer = new ListRenderer(); this.setup = () => { this.setupList(); this.setupListeners(); }; this.setupList = () => { if (this.mdcList) { this.teardown(); this.mdcList = null; } const element = this.element.shadowRoot.querySelector('.mdc-deprecated-list'); if (!element) { return; } this.mdcList = new MDCList(element); this.mdcList.hasTypeahead = true; }; this.setupListeners = () => { if (!this.mdcList) { return; } this.mdcList.unlisten(ACTION_EVENT, this.handleAction); this.selectable = ['selectable', 'radio', 'checkbox'].includes(this.type); this.multiple = this.type === 'checkbox'; if (!this.selectable) { return; } this.mdcList.listen(ACTION_EVENT, this.handleAction); this.mdcList.singleSelection = !this.multiple; }; this.teardown = () => { var _a, _b; (_a = this.mdcList) === null || _a === void 0 ? void 0 : _a.unlisten(ACTION_EVENT, this.handleAction); (_b = this.mdcList) === null || _b === void 0 ? void 0 : _b.destroy(); }; this.handleAction = (event) => { if (!this.multiple) { this.handleSingleSelect(event.detail.index); return; } this.handleMultiSelect(event.detail.index); }; this.handleSingleSelect = (index) => { const listItems = this.items.filter(this.isListItem); if (listItems[index].disabled) { return; } const selectedItem = listItems.find((item) => { return !!item.selected; }); let interactedItem; if (selectedItem) { if (this.type !== 'radio') { this.mdcList.selectedIndex = -1; } interactedItem = Object.assign(Object.assign({}, selectedItem), { selected: false }); this.change.emit(interactedItem); } if (listItems[index] !== selectedItem) { interactedItem = Object.assign(Object.assign({}, listItems[index]), { selected: true }); this.change.emit(interactedItem); } this.interact.emit(interactedItem); }; this.handleMultiSelect = (index) => { const listItems = this.items.filter(this.isListItem); if (listItems[index].disabled) { return; } const selectedItems = listItems .filter((item, listIndex) => { if (listIndex === index) { // This is the item that was selected or deselected, // so we negate its previous selection status. return !item.selected; } // This is an item that didn't change, so we keep its selection status. return item.selected; }) .map((item) => { return Object.assign(Object.assign({}, item), { selected: true }); }); this.change.emit(selectedItems); this.interact.emit(Object.assign({}, selectedItems[index])); }; this.isListItem = (item) => { return !('separator' in item); }; } connectedCallback() { this.setup(); } disconnectedCallback() { this.teardown(); } componentDidLoad() { this.setup(); this.triggerIconColorWarning(); } render() { var _a; this.config = { badgeIcons: this.badgeIcons, type: this.type, iconSize: this.iconSize, }; let maxLinesSecondaryText = +((_a = this.maxLinesSecondaryText) === null || _a === void 0 ? void 0 : _a.toFixed()); if (this.maxLinesSecondaryText < 1) { maxLinesSecondaryText = 1; } const html = this.listRenderer.render(this.items, this.config); return (h(Host, { key: 'cbe0fda77189118ad3515dc3c4ab02c6cd9bc58a', style: { '--maxLinesSecondaryText': `${maxLinesSecondaryText}`, } }, html)); } handleType() { this.setupListeners(); } itemsChanged() { if (!this.mdcList) { return; } setTimeout(() => { this.setup(); const listItems = this.items.filter(this.isListItem); if (this.multiple) { this.mdcList.selectedIndex = listItems .filter((item) => item.selected) .map((item) => listItems.indexOf(item)); } else { const selectedIndex = listItems.findIndex((item) => item.selected); if (selectedIndex === -1) { this.mdcList.initializeListType(); } else { this.mdcList.selectedIndex = selectedIndex; } } }, 0); } triggerIconColorWarning() { var _a; if ((_a = this.items) === null || _a === void 0 ? void 0 : _a.some((item) => 'iconColor' in item)) { console.warn("The `iconColor` prop is deprecated, has no visual effect anymore, and will soon be removed! Use the new `Icon` interface, and instead of `iconColor: 'color-name'` write `icon: { name: 'icon-name', color: 'color-name' }`."); } } static get is() { return "limel-list"; } static get encapsulation() { return "shadow"; } static get delegatesFocus() { return true; } static get originalStyleUrls() { return { "$": ["list.scss"] }; } static get styleUrls() { return { "$": ["list.css"] }; } static get properties() { return { "items": { "type": "unknown", "mutable": false, "complexType": { "original": "Array<ListItem | ListSeparator>", "resolved": "(ListSeparator | ListItem<any>)[]", "references": { "Array": { "location": "global", "id": "global::Array" }, "ListItem": { "location": "import", "path": "../list-item/list-item.types", "id": "src/components/list-item/list-item.types.ts::ListItem", "referenceLocation": "ListItem" }, "ListSeparator": { "location": "import", "path": "../list-item/list-item.types", "id": "src/components/list-item/list-item.types.ts::ListSeparator", "referenceLocation": "ListSeparator" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "List of items to display" }, "getter": false, "setter": false }, "badgeIcons": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Set to `true` if the list should display larger icons with a background" }, "getter": false, "setter": false, "reflect": false, "attribute": "badge-icons" }, "iconSize": { "type": "string", "mutable": false, "complexType": { "original": "IconSize", "resolved": "\"large\" | \"medium\" | \"small\" | \"x-small\"", "references": { "IconSize": { "location": "import", "path": "../icon/icon.types", "id": "src/components/icon/icon.types.ts::IconSize", "referenceLocation": "IconSize" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "Size of the icons in the list" }, "getter": false, "setter": false, "reflect": false, "attribute": "icon-size", "defaultValue": "'small'" }, "type": { "type": "string", "mutable": false, "complexType": { "original": "ListType", "resolved": "\"checkbox\" | \"radio\" | \"selectable\"", "references": { "ListType": { "location": "import", "path": "./list.types", "id": "src/components/list/list.types.ts::ListType", "referenceLocation": "ListType" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "The type of the list, omit to get a regular list. Available types are:\n`selectable`: regular list with single selection.\n`radio`: radio button list with single selection.\n`checkbox`: checkbox list with multiple selection." }, "getter": false, "setter": false, "reflect": false, "attribute": "type" }, "maxLinesSecondaryText": { "type": "number", "mutable": false, "complexType": { "original": "number", "resolved": "number", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "By default, lists will display 3 lines of text, and then truncate the rest.\nConsumers can increase or decrease this number by specifying\n`maxLinesSecondaryText`. If consumer enters zero or negative\nnumbers we default to 1; and if they type decimals we round up." }, "getter": false, "setter": false, "reflect": false, "attribute": "max-lines-secondary-text", "defaultValue": "3" } }; } static get events() { return [{ "method": "change", "name": "change", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Fired when a new value has been selected from the list.\nOnly fired if `type` is set to `selectable`, `radio` or `checkbox`." }, "complexType": { "original": "ListItem | ListItem[]", "resolved": "ListItem<any> | ListItem<any>[]", "references": { "ListItem": { "location": "import", "path": "../list-item/list-item.types", "id": "src/components/list-item/list-item.types.ts::ListItem", "referenceLocation": "ListItem" } } } }, { "method": "select", "name": "select", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Fired when an action has been selected from the action menu of a list item" }, "complexType": { "original": "ListItem | ListItem[]", "resolved": "ListItem<any> | ListItem<any>[]", "references": { "ListItem": { "location": "import", "path": "../list-item/list-item.types", "id": "src/components/list-item/list-item.types.ts::ListItem", "referenceLocation": "ListItem" } } } }, { "method": "interact", "name": "interact", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Fires when a user interacts with an item in the list (e.g., click,\nkeyboard select)." }, "complexType": { "original": "ListItem", "resolved": "ListItem<any>", "references": { "ListItem": { "location": "import", "path": "../list-item/list-item.types", "id": "src/components/list-item/list-item.types.ts::ListItem", "referenceLocation": "ListItem" } } } }]; } static get elementRef() { return "element"; } static get watchers() { return [{ "propName": "type", "methodName": "handleType" }, { "propName": "items", "methodName": "itemsChanged" }]; } }