UNPKG

preline

Version:

Preline UI is an open-source set of prebuilt UI components based on the utility-first Tailwind CSS framework.

269 lines (219 loc) 6.14 kB
/* * @version: 3.0.1 * @author: Preline Labs Ltd. * @license: Licensed under MIT and Preline UI Fair Use License (https://preline.co/docs/license.html) * Copyright 2024 Preline Labs Ltd. */ const stringToBoolean = (string: string): boolean => { return string === 'true' ? true : false; }; const getClassProperty = (el: HTMLElement, prop: string, val = '') => { return (window.getComputedStyle(el).getPropertyValue(prop) || val).replace( ' ', '', ); }; const getClassPropertyAlt = ( el: HTMLElement, prop?: string, val: string = '', ) => { let targetClass = ''; el.classList.forEach((c) => { if (c.includes(prop)) { targetClass = c; } }); return targetClass.match(/:(.*)]/) ? targetClass.match(/:(.*)]/)[1] : val; }; const getZIndex = (el: HTMLElement) => { const computedStyle = window.getComputedStyle(el); const zIndex = computedStyle.getPropertyValue('z-index'); return zIndex; }; const getHighestZIndex = (arr: HTMLElement[]) => { let highestZIndex = Number.NEGATIVE_INFINITY; arr.forEach((el) => { let zIndex: string | number = getZIndex(el); if (zIndex !== 'auto') { zIndex = parseInt(zIndex, 10); if (zIndex > highestZIndex) highestZIndex = zIndex; } }); return highestZIndex; } const isDirectChild = (parent: Element, child: HTMLElement) => { const children = parent.children; for (let i = 0; i < children.length; i++) { if (children[i] === child) return true; } return false; }; const isEnoughSpace = ( el: HTMLElement, toggle: HTMLElement, preferredPosition: 'top' | 'bottom' | 'auto' = 'auto', space = 10, wrapper: HTMLElement | null = null, ) => { const referenceRect = toggle.getBoundingClientRect(); const wrapperRect = wrapper ? wrapper.getBoundingClientRect() : null; const viewportHeight = window.innerHeight; const spaceAbove = wrapperRect ? referenceRect.top - wrapperRect.top : referenceRect.top; const spaceBelow = (wrapper ? wrapperRect.bottom : viewportHeight) - referenceRect.bottom; const minimumSpaceRequired = el.clientHeight + space; if (preferredPosition === 'bottom') { return spaceBelow >= minimumSpaceRequired; } else if (preferredPosition === 'top') { return spaceAbove >= minimumSpaceRequired; } else { return ( spaceAbove >= minimumSpaceRequired || spaceBelow >= minimumSpaceRequired ); } }; const isFocused = (target: HTMLElement) => { return document.activeElement === target; }; const isFormElement = (target: HTMLElement) => { return ( target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement ); }; const isIOS = () => { if (/iPad|iPhone|iPod/.test(navigator.platform)) { return true; } else { return ( navigator.maxTouchPoints && navigator.maxTouchPoints > 2 && /MacIntel/.test(navigator.platform) ); } }; const isIpadOS = () => { return ( navigator.maxTouchPoints && navigator.maxTouchPoints > 2 && /MacIntel/.test(navigator.platform) ); }; const isJson = (str: string) => { if (typeof str !== 'string') return false; const firstChar = str.trim()[0]; const lastChar = str.trim().slice(-1); if ((firstChar === '{' && lastChar === '}') || (firstChar === '[' && lastChar === ']')) { try { JSON.parse(str); return true; } catch { return false; } } return false; }; const isParentOrElementHidden = (element: any): any => { if (!element) return false; const computedStyle = window.getComputedStyle(element); if (computedStyle.display === 'none') return true; return isParentOrElementHidden(element.parentElement); }; const isScrollable = (el: HTMLElement) => { const style = window.getComputedStyle(el); const overflowY = style.overflowY; const overflowX = style.overflowX; const canScrollVertically = (overflowY === 'scroll' || overflowY === 'auto') && el.scrollHeight > el.clientHeight; const canScrollHorizontally = (overflowX === 'scroll' || overflowX === 'auto') && el.scrollWidth > el.clientWidth; return canScrollVertically || canScrollHorizontally; } const debounce = (func: Function, timeout = 200) => { let timer: any; return (...args: any[]) => { clearTimeout(timer); timer = setTimeout(() => { func.apply(this, args); }, timeout); }; }; const dispatch = (evt: string, element: any, payload: any = null) => { const event = new CustomEvent(evt, { detail: { payload }, bubbles: true, cancelable: true, composed: false, }); element.dispatchEvent(event); }; const afterTransition = (el: HTMLElement, callback: Function) => { const handleEvent = () => { callback(); el.removeEventListener('transitionend', handleEvent, true); }; const computedStyle = window.getComputedStyle(el); const transitionDuration = computedStyle.getPropertyValue( 'transition-duration', ); const transitionProperty = computedStyle.getPropertyValue( 'transition-property', ); const hasTransition = transitionProperty !== 'none' && parseFloat(transitionDuration) > 0; if (hasTransition) el.addEventListener('transitionend', handleEvent, true); else callback(); }; const htmlToElement = (html: string): HTMLElement => { const template = document.createElement('template'); html = html.trim(); template.innerHTML = html; return template.content.firstChild as HTMLElement; }; const classToClassList = ( classes: string, target: HTMLElement, splitter = ' ', action: 'add' | 'remove' = 'add', ) => { const classesToArray = classes.split(splitter); classesToArray.forEach((cl) => action === 'add' ? target.classList.add(cl) : target.classList.remove(cl), ); }; const menuSearchHistory = { historyIndex: -1, addHistory(index: number) { this.historyIndex = index; }, existsInHistory(index: number) { return index > this.historyIndex; }, clearHistory() { this.historyIndex = -1; }, }; export { stringToBoolean, getClassProperty, getClassPropertyAlt, getZIndex, getHighestZIndex, isEnoughSpace, isFocused, isFormElement, isDirectChild, isIOS, isIpadOS, isJson, isParentOrElementHidden, isScrollable, debounce, dispatch, afterTransition, htmlToElement, classToClassList, menuSearchHistory, };