import React, { createContext, useContext, useEffect, useRef } from 'react' import { isStr, isFn, isObj, isPlainObj } from '@designable/shared' import { observer } from '@formily/reactive-react' import { Tooltip, TooltipProps } from 'antd' import { usePrefix, useRegistry, useTheme } from '../../hooks' import cls from 'classnames' import './styles.less' const IconContext = createContext(null) const isNumSize = (val: any) => /^[\d.]+$/.test(val) export interface IconProviderProps { tooltip?: boolean } export interface IShadowSVGProps { content?: string width?: number | string height?: number | string } export interface IIconWidgetProps extends React.HTMLAttributes { tooltip?: React.ReactNode | TooltipProps infer: React.ReactNode | { shadow: string } size?: number | string } export const IconWidget: React.FC & { Provider?: React.FC ShadowSVG?: React.FC } = observer((props: React.PropsWithChildren) => { const theme = useTheme() const context = useContext(IconContext) const registry = useRegistry() const prefix = usePrefix('icon') const size = props.size || '1em' const height = props.style?.height || size const width = props.style?.width || size const takeIcon = (infer: React.ReactNode) => { if (isStr(infer)) { const finded = registry.getDesignerIcon(infer) if (finded) { return takeIcon(finded) } return } else if (isFn(infer)) { return React.createElement(infer, { height, width, fill: 'currentColor', }) } else if (React.isValidElement(infer)) { if (infer.type === 'svg') { return React.cloneElement(infer, { height, width, fill: 'currentColor', viewBox: infer.props.viewBox || '0 0 1024 1024', focusable: 'false', 'aria-hidden': 'true', }) } else if (infer.type === 'path' || infer.type === 'g') { return ( ) } return infer } else if (isPlainObj(infer)) { if (infer[theme]) { return takeIcon(infer[theme]) } else if (infer['shadow']) { return ( ) } return null } } const renderTooltips = (children: React.ReactElement): React.ReactElement => { if (!isStr(props.infer) && context?.tooltip) return children as any const tooltip = props.tooltip || registry.getDesignerMessage(`icons.${props.infer}`) if (tooltip) { const title = React.isValidElement(tooltip) || isStr(tooltip) ? tooltip : tooltip.title const props = React.isValidElement(tooltip) || isStr(tooltip) ? {} : isObj(tooltip) ? tooltip : {} return ( {children} ) } return children } if (!props.infer) return null return renderTooltips( {takeIcon(props.infer)} ) }) IconWidget.ShadowSVG = (props) => { const ref = useRef() const width = isNumSize(props.width) ? `${props.width}px` : props.width const height = isNumSize(props.height) ? `${props.height}px` : props.height useEffect(() => { if (ref.current) { const root = ref.current.attachShadow({ mode: 'open', }) root.innerHTML = `${props.content}` } }, []) return
} IconWidget.Provider = (props) => { return ( {props.children} ) }