UNPKG

@progress/kendo-angular-toolbar

Version:

Kendo UI Angular Toolbar component - a single UI element that organizes buttons and other navigation elements

243 lines (242 loc) 7.26 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { Keys } from '@progress/kendo-angular-common'; /** * @hidden */ const focusableRegex = /^(?:a|input|select|textarea|button|object)$/i; /** * @hidden */ export function outerWidth(element) { let width = element.offsetWidth; const style = getComputedStyle(element); width += parseFloat(style.marginLeft) || 0 + parseFloat(style.marginRight) || 0; return width; } /** * @hidden */ export function innerWidth(element) { let width = element.offsetWidth; const style = getComputedStyle(element); width -= parseFloat(style.paddingLeft) || 0 + parseFloat(style.borderLeftWidth) || 0; width -= parseFloat(style.paddingRight) || 0 + parseFloat(style.borderRightWidth) || 0; return width; } /** * @hidden */ export function outerHeight(element) { let width = element.offsetHeight; const style = getComputedStyle(element); width += parseFloat(style.marginTop) || 0 + parseFloat(style.marginBottom) || 0; return width; } /** * @hidden */ export const closest = (node, predicate) => { while (node && !predicate(node)) { node = node.parentNode; } return node; }; /** * @hidden */ export const isVisible = (element) => { const rect = element.getBoundingClientRect(); const hasSize = rect.width > 0 && rect.height > 0; const hasPosition = rect.x !== 0 && rect.y !== 0; // Elements can have zero size due to styling, but they should still count as visible. // For example, the selection checkbox has no size, but is made visible through styling. return (hasSize || hasPosition) && window.getComputedStyle(element).visibility !== 'hidden'; }; /** * @hidden */ export const findElement = (node, predicate, matchSelf = true) => { if (!node) { return; } if (matchSelf && predicate(node)) { return node; } node = node.firstChild; while (node) { if (node.nodeType === 1) { const element = findElement(node, predicate); if (element) { return element; } } node = node.nextSibling; } }; /** * @hidden */ export const isFocusable = (element, checkVisibility = true) => { if (element.tagName) { const tagName = element.tagName.toLowerCase(); const tabIndex = element.getAttribute('tabIndex'); let focusable = tabIndex !== null; if (focusableRegex.test(tagName)) { focusable = !element.disabled; } return focusable && (!checkVisibility || isVisible(element)); } return false; }; /** * @hidden */ export const findFocusable = (element, checkVisibility = true) => { return findElement(element, node => isFocusable(node, checkVisibility)); }; /** * @hidden */ export const findFocusableChild = (element, checkVisibility = true) => { return findElement(element, node => isFocusable(node, checkVisibility), false); }; /** * @hidden */ export const findFocusableSibling = (element, checkVisibility = true, reverse) => { let node = reverse ? element.prevSibling : element.nextSibling; while (node) { if (node.nodeType === 1) { const result = findElement(node, el => isFocusable(el, checkVisibility)); if (result) { return result; } } node = reverse ? node.prevSibling : node.nextSibling; } }; /** * @hidden */ export const isPresent = (value) => value !== null && value !== undefined; /** * @hidden */ export const makePeeker = (collection) => (index) => isPresent(collection[index]); /** * @hidden */ export const getIndexOfFocused = (prevKeyCode, nextKeyCode, collection) => (ev) => { switch (ev.type) { case 'keydown': if (ev.keyCode === prevKeyCode) { return collection.length - 1; } if (ev.keyCode === nextKeyCode) { return 0; } break; case 'click': return collection.findIndex(be => be === ev.target || be.contains(ev.target)); case 'focus': return 0; default: return 0; } }; /** * @hidden */ export const seekFocusedIndex = (prevKeyCode, nextKeyCode, seeker) => (startIndex, ev) => { switch (ev.keyCode) { case prevKeyCode: return seeker(startIndex - 1) ? startIndex - 1 : startIndex; case nextKeyCode: return seeker(startIndex + 1) ? startIndex + 1 : startIndex; default: return startIndex; } }; /** * @hidden */ export const areEqual = (first) => (second) => first === second; /** * @hidden */ export const getNextKey = (rtl = false) => (overflows = true) => overflows ? Keys.ArrowDown : rtl ? Keys.ArrowLeft : Keys.ArrowRight; /** * @hidden */ export const getPrevKey = (rtl = false) => (overflows = true) => overflows ? Keys.ArrowUp : rtl ? Keys.ArrowRight : Keys.ArrowLeft; /** * @hidden */ export const getValueForLocation = (property, displayMode, overflows) => { switch (displayMode) { case 'toolbar': return overflows ? undefined : property; case 'menu': return overflows ? property : undefined; case 'never': return; default: return property; } }; /** * @hidden */ export const SIZES = { small: 'sm', medium: 'md', large: 'lg' }; /** * @hidden * * Returns the styling classes to be added and removed */ export const getStylingClasses = (componentType, stylingOption, previousValue, newValue) => { switch (stylingOption) { case 'size': return { toRemove: `k-${componentType}-${SIZES[previousValue]}`, toAdd: newValue !== 'none' ? `k-${componentType}-${SIZES[newValue]}` : '' }; case 'fillMode': return { toRemove: `k-${componentType}-${previousValue}`, toAdd: newValue !== 'none' ? `k-${componentType}-${newValue}` : '' }; default: break; } }; /** * @hidden * * Checks whether a Node is Text or Element node. * nodeType 1 is Element, nodeType 3 is Text */ export const isElementOrTextNode = n => n.nodeType === 1 || n.nodeType === 3; /** * @hidden */ export const normalizeOverflowSettings = (overflow) => { const defaultOverflowSettings = { mode: 'none', scrollButtons: 'auto', scrollButtonsPosition: 'split' }; let normalizedSettings = {}; if (typeof overflow === 'object') { normalizedSettings = Object.assign(defaultOverflowSettings, overflow); } else if (typeof overflow === 'boolean') { normalizedSettings = overflow ? Object.assign(defaultOverflowSettings, { mode: 'menu' }) : defaultOverflowSettings; } else { normalizedSettings = Object.assign(defaultOverflowSettings, { mode: overflow }); } return normalizedSettings; };