UNPKG

@public-ui/components

Version:

Contains all web components that belong to KoliBri - The accessible HTML-Standard.

335 lines (334 loc) 13.7 kB
/*! * KoliBri - The accessible HTML-Standard */ import { h, Host } from "@stencil/core"; import { KolTreeItemTag, KolTreeTag } from "../../core/component-names"; import { validateLabel } from "../../schema"; export class KolTreeWc { constructor() { this.state = { _label: '', }; this.cacheValid = false; } validateLabel(value) { validateLabel(this, value); } async focus() { var _a; const openItems = await this.getOpenTreeItemElements(); await ((_a = openItems === null || openItems === void 0 ? void 0 : openItems[0]) === null || _a === void 0 ? void 0 : _a.focus()); } async invalidateOpenItemsCache() { await Promise.resolve((this.cacheValid = false)); } render() { return (h(Host, { key: 'a788072549f6998bb11036a8d4b6fdb86ecc589b', onSlotchange: this.handleSlotchange.bind(this) }, h("nav", { key: '655f5ab41e487c1351df3526e8cfe9880787247a', class: "kol-tree", "aria-label": this.state._label }, h("ul", { key: 'a11bb5d15793e011bb53df02a6ee9627d6060b4e', class: "kol-tree__treeview-navigation", role: "tree", "aria-label": this.state._label }, h("slot", { key: 'c861df068ff6bfff14c5a5262d3f718db3b7da85' }))))); } static isTreeItem(element) { return (element === null || element === void 0 ? void 0 : element.tagName) === KolTreeItemTag.toUpperCase(); } componentWillLoad() { this.validateLabel(this._label); this.handleTreeChange(); this.observeChildListMutations(); } disconnectedCallback() { var _a; (_a = this.observer) === null || _a === void 0 ? void 0 : _a.disconnect(); if (this.rafHandle !== undefined) { cancelAnimationFrame(this.rafHandle); this.rafHandle = undefined; } } observeChildListMutations() { this.observer = new MutationObserver(() => this.scheduleTreeChange()); this.observeTopLevelItems(); } handleSlotchange() { this.observeTopLevelItems(); this.scheduleTreeChange(); } observeTopLevelItems() { var _a; (_a = this.getTopLevelTreeItems()) === null || _a === void 0 ? void 0 : _a.forEach((treeItem) => { var _a; (_a = this.observer) === null || _a === void 0 ? void 0 : _a.observe(treeItem, { childList: true, subtree: true }); }); } scheduleTreeChange() { if (this.rafHandle) cancelAnimationFrame(this.rafHandle); this.rafHandle = requestAnimationFrame(() => { this.handleTreeChange(); }); } getTopLevelTreeItems() { var _a, _b, _c, _d; return (_d = (_c = (_b = (_a = this.host) === null || _a === void 0 ? void 0 : _a.querySelector('slot')) === null || _b === void 0 ? void 0 : _b.assignedNodes) === null || _c === void 0 ? void 0 : _c.call(_b)) === null || _d === void 0 ? void 0 : _d.filter(KolTreeWc.isTreeItem); } handleTreeChange() { this.treeItemElements = this.getTreeItemElements(); this.cacheValid = false; void this.ensureActiveItemVisibility(); } getTreeItemElements() { var _a; return (_a = this.getTopLevelTreeItems()) === null || _a === void 0 ? void 0 : _a.reduce((accumulator, currentValue) => { const children = currentValue.querySelectorAll(KolTreeItemTag); return [...accumulator, currentValue, ...children]; }, []); } async getOpenTreeItemElements() { if (!this.treeItemElements) { return; } if (this.cacheValid && this.cachedOpenItems) { return this.cachedOpenItems; } const areAllParentsOpen = async (element) => { let parent = element.parentElement; while (parent && KolTreeWc.isTreeItem(parent)) { if (!(await parent.isOpen())) { return false; } parent = parent.parentElement; } return true; }; this.cachedOpenItems = await Promise.all(this.treeItemElements.map(async (item) => ({ item, isOpen: await areAllParentsOpen(item), }))).then((results) => results.filter(({ isOpen }) => isOpen).map(({ item }) => item)); this.cacheValid = true; return this.cachedOpenItems; } async handleKeyDown(event) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; const openItems = await this.getOpenTreeItemElements(); const currentTreeItem = (_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.closest(KolTreeItemTag); const hasModifierKeyPressed = event.metaKey || event.altKey || event.ctrlKey || event.shiftKey; if (!openItems || !currentTreeItem) { return; } const currentIndex = openItems === null || openItems === void 0 ? void 0 : openItems.findIndex((elem) => elem === currentTreeItem); switch (event.key) { case 'ArrowDown': { await ((_b = openItems[currentIndex + 1]) === null || _b === void 0 ? void 0 : _b.focus()); event.preventDefault(); break; } case 'ArrowUp': { await ((_c = openItems[currentIndex - 1]) === null || _c === void 0 ? void 0 : _c.focus()); event.preventDefault(); break; } case 'Right': case 'ArrowRight': { event.preventDefault(); if (await currentTreeItem.isOpen()) { await ((_d = openItems[currentIndex + 1]) === null || _d === void 0 ? void 0 : _d.focus()); } else { await currentTreeItem.expand(); } break; } case 'Left': case 'ArrowLeft': { event.preventDefault(); if (await currentTreeItem.isOpen()) { await currentTreeItem.collapse(); } else { const parentItem = currentTreeItem.parentElement; const parentIndex = parentItem ? openItems.indexOf(parentItem) : -1; if (parentIndex !== -1) { await ((_e = openItems[parentIndex]) === null || _e === void 0 ? void 0 : _e.focus()); } } break; } case 'Home': { await ((_f = openItems[0]) === null || _f === void 0 ? void 0 : _f.focus()); event.preventDefault(); break; } case 'End': { await ((_g = openItems[openItems.length - 1]) === null || _g === void 0 ? void 0 : _g.focus()); event.preventDefault(); break; } case (_h = event.key.match(/^[a-zA-Z0-9]$/)) === null || _h === void 0 ? void 0 : _h.input: { if (!hasModifierKeyPressed) { const char = event.key.toLowerCase(); const startIndex = openItems.indexOf(currentTreeItem) + 1; let matchIndex = openItems.slice(startIndex).findIndex((item) => { var _a; return (_a = item.getAttribute('_label')) === null || _a === void 0 ? void 0 : _a.trim().toLowerCase().startsWith(char); }); if (matchIndex === -1) { matchIndex = openItems.slice(0, startIndex).findIndex((item) => { var _a; return (_a = item.getAttribute('_label')) === null || _a === void 0 ? void 0 : _a.trim().toLowerCase().startsWith(char); }); if (matchIndex !== -1) { } } else { matchIndex += startIndex; } if (matchIndex !== -1) { await ((_j = openItems[matchIndex]) === null || _j === void 0 ? void 0 : _j.focus()); event.preventDefault(); } } break; } case '*': { const siblings = (_k = currentTreeItem.parentElement) === null || _k === void 0 ? void 0 : _k.querySelectorAll(KolTreeItemTag); siblings === null || siblings === void 0 ? void 0 : siblings.forEach((element) => { void element.expand(); }); break; } } } handleFocusIn(event) { var _a; if (event.target === this.host && !((_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.closest(KolTreeItemTag))) { requestAnimationFrame(() => { void this.focus(); }); } } handleFocusOut(event) { if (event.relatedTarget && !event.relatedTarget.closest(KolTreeTag)) { this.ensureActiveItemVisibility(); } } ensureActiveItemVisibility() { const findActiveItem = () => { var _a, _b, _c, _d, _e; const rootNodes = (_e = (_d = (_c = (_b = (_a = this.host) === null || _a === void 0 ? void 0 : _a.querySelector('slot')) === null || _b === void 0 ? void 0 : _b.assignedNodes) === null || _c === void 0 ? void 0 : _c.call(_b)) === null || _d === void 0 ? void 0 : _d.filter(KolTreeWc.isTreeItem)) !== null && _e !== void 0 ? _e : []; for (const rootNode of rootNodes) { if (rootNode._active) { return rootNode; } const childMatch = rootNode.querySelector(`${KolTreeItemTag}[_active="true"]`); if (childMatch && childMatch._active) { return childMatch; } } }; const expandParentElements = (element) => { if (KolTreeWc.isTreeItem(element.parentElement)) { void element.parentElement.expand(); expandParentElements(element.parentElement); } }; const target = findActiveItem(); if (target) { expandParentElements(target); } } static get is() { return "kol-tree-wc"; } static get properties() { return { "_label": { "type": "string", "mutable": false, "complexType": { "original": "LabelPropType", "resolved": "string", "references": { "LabelPropType": { "location": "import", "path": "../../schema", "id": "src/schema/index.ts::LabelPropType" } } }, "required": true, "optional": false, "docs": { "tags": [], "text": "Defines the visible or semantic label of the component (e.g. aria-label, label, headline, caption, summary, etc.)." }, "getter": false, "setter": false, "reflect": false, "attribute": "_label" } }; } static get states() { return { "state": {} }; } static get methods() { return { "focus": { "complexType": { "signature": "() => Promise<void>", "parameters": [], "references": { "Promise": { "location": "global", "id": "global::Promise" } }, "return": "Promise<void>" }, "docs": { "text": "Sets focus on the first focusable tree item.", "tags": [] } }, "invalidateOpenItemsCache": { "complexType": { "signature": "() => Promise<void>", "parameters": [], "references": { "Promise": { "location": "global", "id": "global::Promise" } }, "return": "Promise<void>" }, "docs": { "text": "Invalidates the cache for open tree items.\nCalled by tree-item when expand/collapse occurs.", "tags": [{ "name": "internal", "text": undefined }] } } }; } static get elementRef() { return "host"; } static get watchers() { return [{ "propName": "_label", "methodName": "validateLabel" }]; } static get listeners() { return [{ "name": "keydown", "method": "handleKeyDown", "target": undefined, "capture": false, "passive": false }, { "name": "focusin", "method": "handleFocusIn", "target": undefined, "capture": false, "passive": false }, { "name": "focusout", "method": "handleFocusOut", "target": undefined, "capture": false, "passive": false }]; } } //# sourceMappingURL=component.js.map