UNPKG

@progress/kendo-angular-menu

Version:

Kendo UI Angular Menu component

105 lines (104 loc) 3.11 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { NODE_INDEX } from './constants'; const DEFAULT_ID = 'kendo-matches-container'; const focusableRegex = /^(?:a|input|select|option|textarea|button|object)$/i; const matches = (element, selector) => (element.matches || element.msMatchesSelector).call(element, selector); /** * @hidden */ export const closest = (node, predicate) => { while (node && !predicate(node)) { node = node.parentNode; } return node; }; /** * @hidden */ export const closestInScope = (node, predicate, scope) => { while (node && node !== scope && !predicate(node)) { node = node.parentNode; } if (node !== scope) { return node; } }; /** * @hidden */ export const isFocusable = (element) => { if (element.tagName) { const tagName = element.tagName.toLowerCase(); const tabIndex = element.getAttribute('tabIndex'); const skipTab = tabIndex === '-1'; let focusable = tabIndex !== null && !skipTab; if (focusableRegex.test(tagName)) { focusable = !element.disabled && !skipTab; } return focusable; } return false; }; const toClassList = (classNames) => String(classNames).trim().split(' '); /** * @hidden */ export const hasClass = (element, name) => { return toClassList(element.className).indexOf(name) >= 0; }; /** * @hidden */ export const matchesClasses = (classes) => { const list = toClassList(classes); return (element) => { const classList = toClassList(element.className); return Boolean(list.find(name => classList.indexOf(name) >= 0)); }; }; /** * @hidden */ export const nodeIndex = (node) => node.getAttribute(NODE_INDEX); /** * @hidden */ export const closestItem = (node, scope) => closestInScope(node, nodeIndex, scope); /** * @hidden */ export const closestList = (node) => { let list = closest(node, matchesClasses('k-menu-popup k-menu k-menu-group')); if (list && hasClass(list, 'k-menu-popup')) { list = list.querySelector('.k-menu-group'); } return list; }; /** * @hidden */ export const inMenu = (node, itemsService) => { if (node === itemsService.lists[0].element.nativeElement) { return false; } const list = closestList(node); return list && itemsService.containsList(list); }; /** * @hidden */ export const findInContainer = (element, selector, container) => { const id = container.getAttribute('id'); if (!id) { container.setAttribute('id', DEFAULT_ID); } const contextSelector = `#${id || DEFAULT_ID} ${selector}`; const match = closestInScope(element, node => matches(node, contextSelector), container); if (!id) { container.removeAttribute('id'); } return match; };