@public-ui/components
Version:
Contains all web components that belong to KoliBri - The accessible HTML-Standard.
335 lines (334 loc) • 13.7 kB
JavaScript
/*!
* 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