UNPKG

flyonui

Version:

The easiest, free and open-source Tailwind CSS component library with semantic classes.

239 lines (189 loc) 6.17 kB
/* * @version: 3.2.2 * @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 => { if (cl.trim()) { 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 { afterTransition, classToClassList, debounce, dispatch, getClassProperty, getClassPropertyAlt, getHighestZIndex, getZIndex, htmlToElement, isDirectChild, isEnoughSpace, isFocused, isFormElement, isIOS, isIpadOS, isJson, isParentOrElementHidden, isScrollable, menuSearchHistory, stringToBoolean }