@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
JavaScript
/**-----------------------------------------------------------------------------------------
* 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;
};