import React, { ReactNode } from 'react' export const getId = (): string => { return Math.random().toString(32).slice(2, 10) } export const hasChild = (children: ReactNode | undefined, child: React.ElementType): boolean => { const types = React.Children.map(children, (item) => { if (!React.isValidElement(item)) return null return item.type }) return (types || []).includes(child) } export const pickChild = ( children: ReactNode | undefined, targetChild: React.ElementType ): [ReactNode | undefined, ReactNode | undefined] => { const target: ReactNode[] = [] const withoutTargetChildren = React.Children.map(children, (item) => { if (!React.isValidElement(item)) return item if (item.type === targetChild) { target.push(item) return null } return item }) return [withoutTargetChildren, target] } export const pickChildByProps = ( children: ReactNode | undefined, key: string, value: any | Array ): [ReactNode | undefined, ReactNode | undefined] => { const target: ReactNode[] = [] const isArray = Array.isArray(value) const withoutPropChildren = React.Children.map(children, (item) => { if (!React.isValidElement(item)) return null if (!item.props) return item if (isArray) { if (value.includes(item.props[key])) { target.push(item) return null } return item } if (item.props[key] === value) { target.push(item) return null } return item }) return [withoutPropChildren, target] } export const pickChildrenFirst = (children: ReactNode | undefined): ReactNode | undefined => { return React.Children.toArray(children)[0] } export const setChildrenProps = ( children: ReactNode | undefined, props: Record = {}, targetComponents: Array = [] ): ReactNode | undefined => { if (React.Children.count(children) === 0) return [] const allowAll = targetComponents.length === 0 const clone = (child: React.ReactElement, props = {}) => React.cloneElement(child, props) return React.Children.map(children, (item) => { if (!React.isValidElement(item)) return item if (allowAll) return clone(item, props) const isAllowed = targetComponents.find((child) => child === item.type) if (isAllowed) return clone(item, props) return item }) } export const setChildrenIndex = ( children: ReactNode | undefined, targetComponents: Array = [] ): ReactNode | undefined => { if (React.Children.count(children) === 0) return [] const allowAll = targetComponents.length === 0 const clone = (child: React.ReactElement, props = {}) => React.cloneElement(child, props) let index = 0 return React.Children.map(children, (item) => { if (!React.isValidElement(item)) return item index = index + 1 if (allowAll) return clone(item, { index }) const isAllowed = targetComponents.find((child) => child === item.type) if (isAllowed) return clone(item, { index }) index = index - 1 return item }) } export const getReactNode = (node?: React.ReactNode | (() => React.ReactNode)): React.ReactNode => { if (!node) return null if (typeof node !== 'function') return node return (node as () => React.ReactNode)() } export const isChildElement = ( parent: Element | null | undefined, child: Element | null | undefined ): boolean => { if (!parent || !child) return false let node: (Node & ParentNode) | null = child while (node) { if (node === parent) return true node = node.parentNode } return false } export const isHuiElement = (el?: HTMLElement): boolean => { if (!el) return false if (el?.dataset && el?.dataset['hui']) return true el.attributes.getNamedItem('data-hui') return !!el.attributes.getNamedItem('data-hui') } export const isCSSNumberValue = (value?: string | number) => value !== undefined && !Number.isNaN(+value)