react-tooltip
Version:
react tooltip component
1 lines • 64 kB
Source Map (JSON)
{"version":3,"file":"react-tooltip.min.mjs","sources":["../src/utils/handle-style.ts","../src/utils/debounce.ts","../src/components/TooltipProvider/TooltipProvider.tsx","../src/components/TooltipProvider/TooltipWrapper.tsx","../src/utils/use-isomorphic-layout-effect.ts","../src/utils/get-scroll-parent.ts","../src/utils/compute-positions.ts","../src/components/Tooltip/Tooltip.tsx","../src/components/TooltipContent/TooltipContent.tsx","../src/components/TooltipController/TooltipController.tsx","../src/index.tsx"],"sourcesContent":["// This is the ID for the core styles of ReactTooltip\nconst REACT_TOOLTIP_CORE_STYLES_ID = 'react-tooltip-core-styles'\n// This is the ID for the visual styles of ReactTooltip\nconst REACT_TOOLTIP_BASE_STYLES_ID = 'react-tooltip-base-styles'\n\nfunction injectStyle({\n css,\n id = REACT_TOOLTIP_BASE_STYLES_ID,\n type = 'base',\n ref,\n}: {\n css: string\n id?: string\n type?: string\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ref?: any\n}) {\n if (\n type === 'core' &&\n typeof process !== 'undefined' && // this validation prevents docs from breaking even with `process?`\n process?.env?.REACT_TOOLTIP_DISABLE_CORE_STYLES\n ) {\n return\n }\n\n if (\n type !== 'core' &&\n typeof process !== 'undefined' && // this validation prevents docs from breaking even with `process?`\n process?.env?.REACT_TOOLTIP_DISABLE_BASE_STYLES\n ) {\n return\n }\n\n if (type === 'core') {\n // eslint-disable-next-line no-param-reassign\n id = REACT_TOOLTIP_CORE_STYLES_ID\n }\n\n if (!ref) {\n // eslint-disable-next-line no-param-reassign\n ref = {}\n }\n const { insertAt } = ref\n\n if (!css || typeof document === 'undefined' || document.getElementById(id)) {\n return\n }\n\n const head = document.head || document.getElementsByTagName('head')[0]\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const style: any = document.createElement('style')\n style.id = id\n style.type = 'text/css'\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild)\n } else {\n head.appendChild(style)\n }\n } else {\n head.appendChild(style)\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css\n } else {\n style.appendChild(document.createTextNode(css))\n }\n}\n\nfunction removeStyle({\n type = 'base',\n id = REACT_TOOLTIP_BASE_STYLES_ID,\n}: {\n type?: string\n id?: string\n} = {}) {\n if (type === 'core') {\n // eslint-disable-next-line no-param-reassign\n id = REACT_TOOLTIP_CORE_STYLES_ID\n }\n\n const style = document.getElementById(id)\n style?.remove()\n}\n\nexport { injectStyle, removeStyle }\n","/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * This function debounce the received function\n * @param { function } \tfunc\t\t\t\tFunction to be debounced\n * @param { number } \t\twait\t\t\t\tTime to wait before execut the function\n * @param { boolean } \timmediate\t\tParam to define if the function will be executed immediately\n */\nconst debounce = (func: (...args: any[]) => void, wait?: number, immediate?: true) => {\n let timeout: NodeJS.Timeout | null = null\n\n return function debounced(this: typeof func, ...args: any[]) {\n const later = () => {\n timeout = null\n if (!immediate) {\n func.apply(this, args)\n }\n }\n\n if (immediate && !timeout) {\n /**\n * there's not need to clear the timeout\n * since we expect it to resolve and set `timeout = null`\n */\n func.apply(this, args)\n timeout = setTimeout(later, wait)\n }\n\n if (!immediate) {\n if (timeout) {\n clearTimeout(timeout)\n }\n timeout = setTimeout(later, wait)\n }\n }\n}\n\nexport default debounce\n","import React, {\n createContext,\n PropsWithChildren,\n useCallback,\n useContext,\n useMemo,\n useState,\n} from 'react'\n\nimport type {\n AnchorRef,\n TooltipContextData,\n TooltipContextDataWrapper,\n} from './TooltipProviderTypes'\n\nconst DEFAULT_TOOLTIP_ID = 'DEFAULT_TOOLTIP_ID'\nconst DEFAULT_CONTEXT_DATA: TooltipContextData = {\n anchorRefs: new Set(),\n activeAnchor: { current: null },\n attach: () => {\n /* attach anchor element */\n },\n detach: () => {\n /* detach anchor element */\n },\n setActiveAnchor: () => {\n /* set active anchor */\n },\n}\n\nconst DEFAULT_CONTEXT_DATA_WRAPPER: TooltipContextDataWrapper = {\n getTooltipData: () => DEFAULT_CONTEXT_DATA,\n}\n\nconst TooltipContext = createContext<TooltipContextDataWrapper>(DEFAULT_CONTEXT_DATA_WRAPPER)\n\n/**\n * @deprecated Use the `data-tooltip-id` attribute, or the `anchorSelect` prop instead.\n * See https://react-tooltip.com/docs/getting-started\n */\nconst TooltipProvider: React.FC<PropsWithChildren<void>> = ({ children }) => {\n const [anchorRefMap, setAnchorRefMap] = useState<Record<string, Set<AnchorRef>>>({\n [DEFAULT_TOOLTIP_ID]: new Set(),\n })\n const [activeAnchorMap, setActiveAnchorMap] = useState<Record<string, AnchorRef>>({\n [DEFAULT_TOOLTIP_ID]: { current: null },\n })\n\n const attach = (tooltipId: string, ...refs: AnchorRef[]) => {\n setAnchorRefMap((oldMap) => {\n const tooltipRefs = oldMap[tooltipId] ?? new Set()\n refs.forEach((ref) => tooltipRefs.add(ref))\n // create new object to trigger re-render\n return { ...oldMap, [tooltipId]: new Set(tooltipRefs) }\n })\n }\n\n const detach = (tooltipId: string, ...refs: AnchorRef[]) => {\n setAnchorRefMap((oldMap) => {\n const tooltipRefs = oldMap[tooltipId]\n if (!tooltipRefs) {\n // tooltip not found\n // maybe thow error?\n return oldMap\n }\n refs.forEach((ref) => tooltipRefs.delete(ref))\n // create new object to trigger re-render\n return { ...oldMap }\n })\n }\n\n const setActiveAnchor = (tooltipId: string, ref: React.RefObject<HTMLElement>) => {\n setActiveAnchorMap((oldMap) => {\n if (oldMap[tooltipId]?.current === ref.current) {\n return oldMap\n }\n // create new object to trigger re-render\n return { ...oldMap, [tooltipId]: ref }\n })\n }\n\n const getTooltipData = useCallback(\n (tooltipId = DEFAULT_TOOLTIP_ID) => ({\n anchorRefs: anchorRefMap[tooltipId] ?? new Set(),\n activeAnchor: activeAnchorMap[tooltipId] ?? { current: null },\n attach: (...refs: AnchorRef[]) => attach(tooltipId, ...refs),\n detach: (...refs: AnchorRef[]) => detach(tooltipId, ...refs),\n setActiveAnchor: (ref: AnchorRef) => setActiveAnchor(tooltipId, ref),\n }),\n [anchorRefMap, activeAnchorMap, attach, detach],\n )\n\n const context = useMemo(() => {\n return {\n getTooltipData,\n }\n }, [getTooltipData])\n\n return <TooltipContext.Provider value={context}>{children}</TooltipContext.Provider>\n}\n\nexport function useTooltip(tooltipId = DEFAULT_TOOLTIP_ID) {\n return useContext(TooltipContext).getTooltipData(tooltipId)\n}\n\nexport default TooltipProvider\n","import React, { useEffect, useRef } from 'react'\nimport classNames from 'classnames'\nimport { useTooltip } from './TooltipProvider'\nimport type { ITooltipWrapper } from './TooltipProviderTypes'\n\n/**\n * @deprecated Use the `data-tooltip-id` attribute, or the `anchorSelect` prop instead.\n * See https://react-tooltip.com/docs/getting-started\n */\nconst TooltipWrapper = ({\n tooltipId,\n children,\n className,\n place,\n content,\n html,\n variant,\n offset,\n wrapper,\n events,\n positionStrategy,\n delayShow,\n delayHide,\n}: ITooltipWrapper) => {\n const { attach, detach } = useTooltip(tooltipId)\n const anchorRef = useRef<HTMLElement | null>(null)\n\n useEffect(() => {\n attach(anchorRef)\n return () => {\n detach(anchorRef)\n }\n }, [])\n\n return (\n <span\n ref={anchorRef}\n className={classNames('react-tooltip-wrapper', className)}\n data-tooltip-place={place}\n data-tooltip-content={content}\n data-tooltip-html={html}\n data-tooltip-variant={variant}\n data-tooltip-offset={offset}\n data-tooltip-wrapper={wrapper}\n data-tooltip-events={events}\n data-tooltip-position-strategy={positionStrategy}\n data-tooltip-delay-show={delayShow}\n data-tooltip-delay-hide={delayHide}\n >\n {children}\n </span>\n )\n}\n\nexport default TooltipWrapper\n","import { useLayoutEffect, useEffect } from 'react'\n\nconst useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect\n\nexport default useIsomorphicLayoutEffect\n","const isScrollable = (node: Element) => {\n if (!(node instanceof HTMLElement || node instanceof SVGElement)) {\n return false\n }\n const style = getComputedStyle(node)\n return ['overflow', 'overflow-x', 'overflow-y'].some((propertyName) => {\n const value = style.getPropertyValue(propertyName)\n return value === 'auto' || value === 'scroll'\n })\n}\n\nexport const getScrollParent = (node: Element | null) => {\n if (!node) {\n return null\n }\n let currentParent = node.parentElement\n while (currentParent) {\n if (isScrollable(currentParent)) {\n return currentParent\n }\n currentParent = currentParent.parentElement\n }\n return document.scrollingElement || document.documentElement\n}\n","import { computePosition, offset, shift, arrow, flip } from '@floating-ui/dom'\nimport type { IComputePositions } from './compute-positions-types'\n\nexport const computeTooltipPosition = async ({\n elementReference = null,\n tooltipReference = null,\n tooltipArrowReference = null,\n place = 'top',\n offset: offsetValue = 10,\n strategy = 'absolute',\n middlewares = [offset(Number(offsetValue)), flip(), shift({ padding: 5 })],\n border,\n}: IComputePositions) => {\n if (!elementReference) {\n // elementReference can be null or undefined and we will not compute the position\n // eslint-disable-next-line no-console\n // console.error('The reference element for tooltip was not defined: ', elementReference)\n return { tooltipStyles: {}, tooltipArrowStyles: {}, place }\n }\n\n if (tooltipReference === null) {\n return { tooltipStyles: {}, tooltipArrowStyles: {}, place }\n }\n\n const middleware = middlewares\n\n if (tooltipArrowReference) {\n middleware.push(arrow({ element: tooltipArrowReference as HTMLElement, padding: 5 }))\n\n return computePosition(elementReference as HTMLElement, tooltipReference as HTMLElement, {\n placement: place,\n strategy,\n middleware,\n }).then(({ x, y, placement, middlewareData }) => {\n const styles = { left: `${x}px`, top: `${y}px`, border }\n\n const { x: arrowX, y: arrowY } = middlewareData.arrow ?? { x: 0, y: 0 }\n\n const staticSide =\n {\n top: 'bottom',\n right: 'left',\n bottom: 'top',\n left: 'right',\n }[placement.split('-')[0]] ?? 'bottom'\n\n const borderSide =\n border &&\n {\n top: { borderBottom: border, borderRight: border },\n right: { borderBottom: border, borderLeft: border },\n bottom: { borderTop: border, borderLeft: border },\n left: { borderTop: border, borderRight: border },\n }[placement.split('-')[0]]\n\n let borderWidth = 0\n if (border) {\n const match = `${border}`.match(/(\\d+)px/)\n if (match?.[1]) {\n borderWidth = Number(match[1])\n } else {\n /**\n * this means `border` was set without `width`, or non-px value\n */\n borderWidth = 1\n }\n }\n\n const arrowStyle = {\n left: arrowX != null ? `${arrowX}px` : '',\n top: arrowY != null ? `${arrowY}px` : '',\n right: '',\n bottom: '',\n ...borderSide,\n [staticSide]: `-${4 + borderWidth}px`,\n }\n\n return { tooltipStyles: styles, tooltipArrowStyles: arrowStyle, place: placement }\n })\n }\n\n return computePosition(elementReference as HTMLElement, tooltipReference as HTMLElement, {\n placement: 'bottom',\n strategy,\n middleware,\n }).then(({ x, y, placement }) => {\n const styles = { left: `${x}px`, top: `${y}px` }\n\n return { tooltipStyles: styles, tooltipArrowStyles: {}, place: placement }\n })\n}\n","import React, { useEffect, useState, useRef } from 'react'\nimport classNames from 'classnames'\nimport debounce from 'utils/debounce'\nimport { useTooltip } from 'components/TooltipProvider'\nimport useIsomorphicLayoutEffect from 'utils/use-isomorphic-layout-effect'\nimport { getScrollParent } from 'utils/get-scroll-parent'\nimport { computeTooltipPosition } from 'utils/compute-positions'\nimport coreStyles from './core-styles.module.css'\nimport styles from './styles.module.css'\nimport type { IPosition, ITooltip, PlacesType } from './TooltipTypes'\n\nconst Tooltip = ({\n // props\n id,\n className,\n classNameArrow,\n variant = 'dark',\n anchorId,\n anchorSelect,\n place = 'top',\n offset = 10,\n events = ['hover'],\n openOnClick = false,\n positionStrategy = 'absolute',\n middlewares,\n wrapper: WrapperElement,\n delayShow = 0,\n delayHide = 0,\n float = false,\n hidden = false,\n noArrow = false,\n clickable = false,\n closeOnEsc = false,\n closeOnScroll = false,\n closeOnResize = false,\n style: externalStyles,\n position,\n afterShow,\n afterHide,\n // props handled by controller\n content,\n contentWrapperRef,\n isOpen,\n setIsOpen,\n activeAnchor,\n setActiveAnchor,\n border,\n opacity,\n}: ITooltip) => {\n const tooltipRef = useRef<HTMLElement>(null)\n const tooltipArrowRef = useRef<HTMLElement>(null)\n const tooltipShowDelayTimerRef = useRef<NodeJS.Timeout | null>(null)\n const tooltipHideDelayTimerRef = useRef<NodeJS.Timeout | null>(null)\n const [actualPlacement, setActualPlacement] = useState(place)\n const [inlineStyles, setInlineStyles] = useState({})\n const [inlineArrowStyles, setInlineArrowStyles] = useState({})\n const [show, setShow] = useState(false)\n const [rendered, setRendered] = useState(false)\n const wasShowing = useRef(false)\n const lastFloatPosition = useRef<IPosition | null>(null)\n /**\n * @todo Remove this in a future version (provider/wrapper method is deprecated)\n */\n const { anchorRefs, setActiveAnchor: setProviderActiveAnchor } = useTooltip(id)\n const hoveringTooltip = useRef(false)\n const [anchorsBySelect, setAnchorsBySelect] = useState<HTMLElement[]>([])\n const mounted = useRef(false)\n\n const shouldOpenOnClick = openOnClick || events.includes('click')\n\n /**\n * useLayoutEffect runs before useEffect,\n * but should be used carefully because of caveats\n * https://beta.reactjs.org/reference/react/useLayoutEffect#caveats\n */\n useIsomorphicLayoutEffect(() => {\n mounted.current = true\n return () => {\n mounted.current = false\n }\n }, [])\n\n useEffect(() => {\n if (!show) {\n /**\n * this fixes weird behavior when switching between two anchor elements very quickly\n * remove the timeout and switch quickly between two adjancent anchor elements to see it\n *\n * in practice, this means the tooltip is not immediately removed from the DOM on hide\n */\n const timeout = setTimeout(() => {\n setRendered(false)\n }, 150)\n return () => {\n clearTimeout(timeout)\n }\n }\n return () => null\n }, [show])\n\n const handleShow = (value: boolean) => {\n if (!mounted.current) {\n return\n }\n if (value) {\n setRendered(true)\n }\n /**\n * wait for the component to render and calculate position\n * before actually showing\n */\n setTimeout(() => {\n if (!mounted.current) {\n return\n }\n setIsOpen?.(value)\n if (isOpen === undefined) {\n setShow(value)\n }\n }, 10)\n }\n\n /**\n * this replicates the effect from `handleShow()`\n * when `isOpen` is changed from outside\n */\n useEffect(() => {\n if (isOpen === undefined) {\n return () => null\n }\n if (isOpen) {\n setRendered(true)\n }\n const timeout = setTimeout(() => {\n setShow(isOpen)\n }, 10)\n return () => {\n clearTimeout(timeout)\n }\n }, [isOpen])\n\n useEffect(() => {\n if (show === wasShowing.current) {\n return\n }\n wasShowing.current = show\n if (show) {\n afterShow?.()\n } else {\n afterHide?.()\n }\n }, [show])\n\n const handleShowTooltipDelayed = () => {\n if (tooltipShowDelayTimerRef.current) {\n clearTimeout(tooltipShowDelayTimerRef.current)\n }\n\n tooltipShowDelayTimerRef.current = setTimeout(() => {\n handleShow(true)\n }, delayShow)\n }\n\n const handleHideTooltipDelayed = (delay = delayHide) => {\n if (tooltipHideDelayTimerRef.current) {\n clearTimeout(tooltipHideDelayTimerRef.current)\n }\n\n tooltipHideDelayTimerRef.current = setTimeout(() => {\n if (hoveringTooltip.current) {\n return\n }\n handleShow(false)\n }, delay)\n }\n\n const handleShowTooltip = (event?: Event) => {\n if (!event) {\n return\n }\n const target = (event.currentTarget ?? event.target) as HTMLElement | null\n if (!target?.isConnected) {\n /**\n * this happens when the target is removed from the DOM\n * at the same time the tooltip gets triggered\n */\n setActiveAnchor(null)\n setProviderActiveAnchor({ current: null })\n return\n }\n if (delayShow) {\n handleShowTooltipDelayed()\n } else {\n handleShow(true)\n }\n setActiveAnchor(target)\n setProviderActiveAnchor({ current: target })\n\n if (tooltipHideDelayTimerRef.current) {\n clearTimeout(tooltipHideDelayTimerRef.current)\n }\n }\n\n const handleHideTooltip = () => {\n if (clickable) {\n // allow time for the mouse to reach the tooltip, in case there's a gap\n handleHideTooltipDelayed(delayHide || 100)\n } else if (delayHide) {\n handleHideTooltipDelayed()\n } else {\n handleShow(false)\n }\n\n if (tooltipShowDelayTimerRef.current) {\n clearTimeout(tooltipShowDelayTimerRef.current)\n }\n }\n\n const handleTooltipPosition = ({ x, y }: IPosition) => {\n const virtualElement = {\n getBoundingClientRect() {\n return {\n x,\n y,\n width: 0,\n height: 0,\n top: y,\n left: x,\n right: x,\n bottom: y,\n }\n },\n } as Element\n computeTooltipPosition({\n place,\n offset,\n elementReference: virtualElement,\n tooltipReference: tooltipRef.current,\n tooltipArrowReference: tooltipArrowRef.current,\n strategy: positionStrategy,\n middlewares,\n border,\n }).then((computedStylesData) => {\n if (Object.keys(computedStylesData.tooltipStyles).length) {\n setInlineStyles(computedStylesData.tooltipStyles)\n }\n if (Object.keys(computedStylesData.tooltipArrowStyles).length) {\n setInlineArrowStyles(computedStylesData.tooltipArrowStyles)\n }\n setActualPlacement(computedStylesData.place as PlacesType)\n })\n }\n\n const handleMouseMove = (event?: Event) => {\n if (!event) {\n return\n }\n const mouseEvent = event as MouseEvent\n const mousePosition = {\n x: mouseEvent.clientX,\n y: mouseEvent.clientY,\n }\n handleTooltipPosition(mousePosition)\n lastFloatPosition.current = mousePosition\n }\n\n const handleClickTooltipAnchor = (event?: Event) => {\n handleShowTooltip(event)\n if (delayHide) {\n handleHideTooltipDelayed()\n }\n }\n\n const handleClickOutsideAnchors = (event: MouseEvent) => {\n const anchorById = document.querySelector<HTMLElement>(`[id='${anchorId}']`)\n const anchors = [anchorById, ...anchorsBySelect]\n if (anchors.some((anchor) => anchor?.contains(event.target as HTMLElement))) {\n return\n }\n if (tooltipRef.current?.contains(event.target as HTMLElement)) {\n return\n }\n handleShow(false)\n if (tooltipShowDelayTimerRef.current) {\n clearTimeout(tooltipShowDelayTimerRef.current)\n }\n }\n\n // debounce handler to prevent call twice when\n // mouse enter and focus events being triggered toggether\n const debouncedHandleShowTooltip = debounce(handleShowTooltip, 50, true)\n const debouncedHandleHideTooltip = debounce(handleHideTooltip, 50, true)\n\n useEffect(() => {\n const elementRefs = new Set(anchorRefs)\n\n anchorsBySelect.forEach((anchor) => {\n elementRefs.add({ current: anchor })\n })\n\n const anchorById = document.querySelector<HTMLElement>(`[id='${anchorId}']`)\n if (anchorById) {\n elementRefs.add({ current: anchorById })\n }\n\n const handleScrollResize = () => {\n handleShow(false)\n }\n\n const anchorScrollParent = getScrollParent(activeAnchor)\n const tooltipScrollParent = getScrollParent(tooltipRef.current)\n\n if (closeOnScroll) {\n window.addEventListener('scroll', handleScrollResize)\n anchorScrollParent?.addEventListener('scroll', handleScrollResize)\n tooltipScrollParent?.addEventListener('scroll', handleScrollResize)\n }\n if (closeOnResize) {\n window.addEventListener('resize', handleScrollResize)\n }\n\n const handleEsc = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') {\n return\n }\n handleShow(false)\n }\n\n if (closeOnEsc) {\n window.addEventListener('keydown', handleEsc)\n }\n\n const enabledEvents: { event: string; listener: (event?: Event) => void }[] = []\n\n if (shouldOpenOnClick) {\n window.addEventListener('click', handleClickOutsideAnchors)\n enabledEvents.push({ event: 'click', listener: handleClickTooltipAnchor })\n } else {\n enabledEvents.push(\n { event: 'mouseenter', listener: debouncedHandleShowTooltip },\n { event: 'mouseleave', listener: debouncedHandleHideTooltip },\n { event: 'focus', listener: debouncedHandleShowTooltip },\n { event: 'blur', listener: debouncedHandleHideTooltip },\n )\n if (float) {\n enabledEvents.push({\n event: 'mousemove',\n listener: handleMouseMove,\n })\n }\n }\n\n const handleMouseEnterTooltip = () => {\n hoveringTooltip.current = true\n }\n const handleMouseLeaveTooltip = () => {\n hoveringTooltip.current = false\n handleHideTooltip()\n }\n\n if (clickable && !shouldOpenOnClick) {\n tooltipRef.current?.addEventListener('mouseenter', handleMouseEnterTooltip)\n tooltipRef.current?.addEventListener('mouseleave', handleMouseLeaveTooltip)\n }\n\n enabledEvents.forEach(({ event, listener }) => {\n elementRefs.forEach((ref) => {\n ref.current?.addEventListener(event, listener)\n })\n })\n\n return () => {\n if (closeOnScroll) {\n window.removeEventListener('scroll', handleScrollResize)\n anchorScrollParent?.removeEventListener('scroll', handleScrollResize)\n tooltipScrollParent?.removeEventListener('scroll', handleScrollResize)\n }\n if (closeOnResize) {\n window.removeEventListener('resize', handleScrollResize)\n }\n if (shouldOpenOnClick) {\n window.removeEventListener('click', handleClickOutsideAnchors)\n }\n if (closeOnEsc) {\n window.removeEventListener('keydown', handleEsc)\n }\n if (clickable && !shouldOpenOnClick) {\n tooltipRef.current?.removeEventListener('mouseenter', handleMouseEnterTooltip)\n tooltipRef.current?.removeEventListener('mouseleave', handleMouseLeaveTooltip)\n }\n enabledEvents.forEach(({ event, listener }) => {\n elementRefs.forEach((ref) => {\n ref.current?.removeEventListener(event, listener)\n })\n })\n }\n /**\n * rendered is also a dependency to ensure anchor observers are re-registered\n * since `tooltipRef` becomes stale after removing/adding the tooltip to the DOM\n */\n }, [rendered, anchorRefs, anchorsBySelect, closeOnEsc, events])\n\n useEffect(() => {\n let selector = anchorSelect ?? ''\n if (!selector && id) {\n selector = `[data-tooltip-id='${id}']`\n }\n const documentObserverCallback: MutationCallback = (mutationList) => {\n const newAnchors: HTMLElement[] = []\n mutationList.forEach((mutation) => {\n if (mutation.type === 'attributes' && mutation.attributeName === 'data-tooltip-id') {\n const newId = (mutation.target as HTMLElement).getAttribute('data-tooltip-id')\n if (newId === id) {\n newAnchors.push(mutation.target as HTMLElement)\n }\n }\n if (mutation.type !== 'childList') {\n return\n }\n if (activeAnchor) {\n ;[...mutation.removedNodes].some((node) => {\n if (node?.contains?.(activeAnchor)) {\n setRendered(false)\n handleShow(false)\n setActiveAnchor(null)\n if (tooltipShowDelayTimerRef.current) {\n clearTimeout(tooltipShowDelayTimerRef.current)\n }\n if (tooltipHideDelayTimerRef.current) {\n clearTimeout(tooltipHideDelayTimerRef.current)\n }\n return true\n }\n return false\n })\n }\n if (!selector) {\n return\n }\n try {\n const elements = [...mutation.addedNodes].filter((node) => node.nodeType === 1)\n newAnchors.push(\n // the element itself is an anchor\n ...(elements.filter((element) =>\n (element as HTMLElement).matches(selector),\n ) as HTMLElement[]),\n )\n newAnchors.push(\n // the element has children which are anchors\n ...elements.flatMap(\n (element) =>\n [...(element as HTMLElement).querySelectorAll(selector)] as HTMLElement[],\n ),\n )\n } catch {\n /**\n * invalid CSS selector.\n * already warned on tooltip controller\n */\n }\n })\n if (newAnchors.length) {\n setAnchorsBySelect((anchors) => [...anchors, ...newAnchors])\n }\n }\n const documentObserver = new MutationObserver(documentObserverCallback)\n // watch for anchor being removed from the DOM\n documentObserver.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['data-tooltip-id'],\n })\n return () => {\n documentObserver.disconnect()\n }\n }, [id, anchorSelect, activeAnchor])\n\n const updateTooltipPosition = () => {\n if (position) {\n // if `position` is set, override regular and `float` positioning\n handleTooltipPosition(position)\n return\n }\n\n if (float) {\n if (lastFloatPosition.current) {\n /*\n Without this, changes to `content`, `place`, `offset`, ..., will only\n trigger a position calculation after a `mousemove` event.\n\n To see why this matters, comment this line, run `yarn dev` and click the\n \"Hover me!\" anchor.\n */\n handleTooltipPosition(lastFloatPosition.current)\n }\n // if `float` is set, override regular positioning\n return\n }\n\n computeTooltipPosition({\n place,\n offset,\n elementReference: activeAnchor,\n tooltipReference: tooltipRef.current,\n tooltipArrowReference: tooltipArrowRef.current,\n strategy: positionStrategy,\n middlewares,\n border,\n }).then((computedStylesData) => {\n if (!mounted.current) {\n // invalidate computed positions after remount\n return\n }\n if (Object.keys(computedStylesData.tooltipStyles).length) {\n setInlineStyles(computedStylesData.tooltipStyles)\n }\n if (Object.keys(computedStylesData.tooltipArrowStyles).length) {\n setInlineArrowStyles(computedStylesData.tooltipArrowStyles)\n }\n setActualPlacement(computedStylesData.place as PlacesType)\n })\n }\n\n useEffect(() => {\n updateTooltipPosition()\n }, [show, activeAnchor, content, externalStyles, place, offset, positionStrategy, position])\n\n useEffect(() => {\n if (!contentWrapperRef?.current) {\n return () => null\n }\n const contentObserver = new ResizeObserver(() => {\n updateTooltipPosition()\n })\n contentObserver.observe(contentWrapperRef.current)\n return () => {\n contentObserver.disconnect()\n }\n }, [content, contentWrapperRef?.current])\n\n useEffect(() => {\n const anchorById = document.querySelector<HTMLElement>(`[id='${anchorId}']`)\n const anchors = [...anchorsBySelect, anchorById]\n if (!activeAnchor || !anchors.includes(activeAnchor)) {\n /**\n * if there is no active anchor,\n * or if the current active anchor is not amongst the allowed ones,\n * reset it\n */\n setActiveAnchor(anchorsBySelect[0] ?? anchorById)\n }\n }, [anchorId, anchorsBySelect, activeAnchor])\n\n useEffect(() => {\n return () => {\n if (tooltipShowDelayTimerRef.current) {\n clearTimeout(tooltipShowDelayTimerRef.current)\n }\n if (tooltipHideDelayTimerRef.current) {\n clearTimeout(tooltipHideDelayTimerRef.current)\n }\n }\n }, [])\n\n useEffect(() => {\n let selector = anchorSelect\n if (!selector && id) {\n selector = `[data-tooltip-id='${id}']`\n }\n if (!selector) {\n return\n }\n try {\n const anchors = Array.from(document.querySelectorAll<HTMLElement>(selector))\n setAnchorsBySelect(anchors)\n } catch {\n // warning was already issued in the controller\n setAnchorsBySelect([])\n }\n }, [id, anchorSelect])\n\n const canShow = !hidden && content && show && Object.keys(inlineStyles).length > 0\n\n return rendered ? (\n <WrapperElement\n id={id}\n role=\"tooltip\"\n className={classNames(\n 'react-tooltip',\n coreStyles['tooltip'],\n styles['tooltip'],\n styles[variant],\n className,\n `react-tooltip__place-${actualPlacement}`,\n {\n [coreStyles['show']]: canShow,\n [coreStyles['fixed']]: positionStrategy === 'fixed',\n [coreStyles['clickable']]: clickable,\n },\n )}\n style={{\n ...externalStyles,\n ...inlineStyles,\n opacity: opacity !== undefined && canShow ? opacity : undefined,\n }}\n ref={tooltipRef}\n >\n {content}\n <WrapperElement\n className={classNames(\n 'react-tooltip-arrow',\n coreStyles['arrow'],\n styles['arrow'],\n classNameArrow,\n {\n /**\n * changed from dash `no-arrow` to camelcase because of:\n * https://github.com/indooorsman/esbuild-css-modules-plugin/issues/42\n */\n [coreStyles['noArrow']]: noArrow,\n },\n )}\n style={inlineArrowStyles}\n ref={tooltipArrowRef}\n />\n </WrapperElement>\n ) : null\n}\n\nexport default Tooltip\n","/* eslint-disable react/no-danger */\nimport React from 'react'\nimport type { ITooltipContent } from './TooltipContentTypes'\n\nconst TooltipContent = ({ content }: ITooltipContent) => {\n return <span dangerouslySetInnerHTML={{ __html: content }} />\n}\n\nexport default TooltipContent\n","import React, { useEffect, useRef, useState } from 'react'\nimport { Tooltip } from 'components/Tooltip'\nimport type {\n EventsType,\n PositionStrategy,\n PlacesType,\n VariantType,\n WrapperType,\n DataAttribute,\n ITooltip,\n ChildrenType,\n} from 'components/Tooltip/TooltipTypes'\nimport { useTooltip } from 'components/TooltipProvider'\nimport { TooltipContent } from 'components/TooltipContent'\nimport type { ITooltipController } from './TooltipControllerTypes'\n\nconst TooltipController = ({\n id,\n anchorId,\n anchorSelect,\n content,\n html,\n render,\n className,\n classNameArrow,\n variant = 'dark',\n place = 'top',\n offset = 10,\n wrapper = 'div',\n children = null,\n events = ['hover'],\n openOnClick = false,\n positionStrategy = 'absolute',\n middlewares,\n delayShow = 0,\n delayHide = 0,\n float = false,\n hidden = false,\n noArrow = false,\n clickable = false,\n closeOnEsc = false,\n closeOnScroll = false,\n closeOnResize = false,\n style,\n position,\n isOpen,\n border,\n opacity,\n setIsOpen,\n afterShow,\n afterHide,\n}: ITooltipController) => {\n const [tooltipContent, setTooltipContent] = useState(content)\n const [tooltipHtml, setTooltipHtml] = useState(html)\n const [tooltipPlace, setTooltipPlace] = useState(place)\n const [tooltipVariant, setTooltipVariant] = useState(variant)\n const [tooltipOffset, setTooltipOffset] = useState(offset)\n const [tooltipDelayShow, setTooltipDelayShow] = useState(delayShow)\n const [tooltipDelayHide, setTooltipDelayHide] = useState(delayHide)\n const [tooltipFloat, setTooltipFloat] = useState(float)\n const [tooltipHidden, setTooltipHidden] = useState(hidden)\n const [tooltipWrapper, setTooltipWrapper] = useState<WrapperType>(wrapper)\n const [tooltipEvents, setTooltipEvents] = useState(events)\n const [tooltipPositionStrategy, setTooltipPositionStrategy] = useState(positionStrategy)\n const [activeAnchor, setActiveAnchor] = useState<HTMLElement | null>(null)\n /**\n * @todo Remove this in a future version (provider/wrapper method is deprecated)\n */\n const { anchorRefs, activeAnchor: providerActiveAnchor } = useTooltip(id)\n\n const getDataAttributesFromAnchorElement = (elementReference: HTMLElement) => {\n const dataAttributes = elementReference?.getAttributeNames().reduce((acc, name) => {\n if (name.startsWith('data-tooltip-')) {\n const parsedAttribute = name.replace(/^data-tooltip-/, '') as DataAttribute\n acc[parsedAttribute] = elementReference?.getAttribute(name) ?? null\n }\n return acc\n }, {} as Record<DataAttribute, string | null>)\n\n return dataAttributes\n }\n\n const applyAllDataAttributesFromAnchorElement = (\n dataAttributes: Record<string, string | null>,\n ) => {\n const handleDataAttributes: Record<DataAttribute, (value: string | null) => void> = {\n place: (value) => {\n setTooltipPlace((value as PlacesType) ?? place)\n },\n content: (value) => {\n setTooltipContent(value ?? content)\n },\n html: (value) => {\n setTooltipHtml(value ?? html)\n },\n variant: (value) => {\n setTooltipVariant((value as VariantType) ?? variant)\n },\n offset: (value) => {\n setTooltipOffset(value === null ? offset : Number(value))\n },\n wrapper: (value) => {\n setTooltipWrapper((value as WrapperType) ?? wrapper)\n },\n events: (value) => {\n const parsed = value?.split(' ') as EventsType[]\n setTooltipEvents(parsed ?? events)\n },\n 'position-strategy': (value) => {\n setTooltipPositionStrategy((value as PositionStrategy) ?? positionStrategy)\n },\n 'delay-show': (value) => {\n setTooltipDelayShow(value === null ? delayShow : Number(value))\n },\n 'delay-hide': (value) => {\n setTooltipDelayHide(value === null ? delayHide : Number(value))\n },\n float: (value) => {\n setTooltipFloat(value === null ? float : value === 'true')\n },\n hidden: (value) => {\n setTooltipHidden(value === null ? hidden : value === 'true')\n },\n }\n // reset unset data attributes to default values\n // without this, data attributes from the last active anchor will still be used\n Object.values(handleDataAttributes).forEach((handler) => handler(null))\n Object.entries(dataAttributes).forEach(([key, value]) => {\n handleDataAttributes[key as DataAttribute]?.(value)\n })\n }\n\n useEffect(() => {\n setTooltipContent(content)\n }, [content])\n\n useEffect(() => {\n setTooltipHtml(html)\n }, [html])\n\n useEffect(() => {\n setTooltipPlace(place)\n }, [place])\n\n useEffect(() => {\n setTooltipVariant(variant)\n }, [variant])\n\n useEffect(() => {\n setTooltipOffset(offset)\n }, [offset])\n\n useEffect(() => {\n setTooltipDelayShow(delayShow)\n }, [delayShow])\n\n useEffect(() => {\n setTooltipDelayHide(delayHide)\n }, [delayHide])\n\n useEffect(() => {\n setTooltipFloat(float)\n }, [float])\n\n useEffect(() => {\n setTooltipHidden(hidden)\n }, [hidden])\n\n useEffect(() => {\n setTooltipPositionStrategy(positionStrategy)\n }, [positionStrategy])\n\n useEffect(() => {\n const elementRefs = new Set(anchorRefs)\n\n let selector = anchorSelect\n if (!selector && id) {\n selector = `[data-tooltip-id='${id}']`\n }\n if (selector) {\n try {\n const anchorsBySelect = document.querySelectorAll<HTMLElement>(selector)\n anchorsBySelect.forEach((anchor) => {\n elementRefs.add({ current: anchor })\n })\n } catch {\n if (!process.env.NODE_ENV || process.env.NODE_ENV !== 'production') {\n // eslint-disable-next-line no-console\n console.warn(`[react-tooltip] \"${selector}\" is not a valid CSS selector`)\n }\n }\n }\n\n const anchorById = document.querySelector<HTMLElement>(`[id='${anchorId}']`)\n if (anchorById) {\n elementRefs.add({ current: anchorById })\n }\n\n if (!elementRefs.size) {\n return () => null\n }\n\n const anchorElement = activeAnchor ?? anchorById ?? providerActiveAnchor.current\n\n const observerCallback: MutationCallback = (mutationList) => {\n mutationList.forEach((mutation) => {\n if (\n !anchorElement ||\n mutation.type !== 'attributes' ||\n !mutation.attributeName?.startsWith('data-tooltip-')\n ) {\n return\n }\n // make sure to get all set attributes, since all unset attributes are reset\n const dataAttributes = getDataAttributesFromAnchorElement(anchorElement)\n applyAllDataAttributesFromAnchorElement(dataAttributes)\n })\n }\n\n // Create an observer instance linked to the callback function\n const observer = new MutationObserver(observerCallback)\n\n // do not check for subtree and childrens, we only want to know attribute changes\n // to stay watching `data-attributes-*` from anchor element\n const observerConfig = { attributes: true, childList: false, subtree: false }\n\n if (anchorElement) {\n const dataAttributes = getDataAttributesFromAnchorElement(anchorElement)\n applyAllDataAttributesFromAnchorElement(dataAttributes)\n // Start observing the target node for configured mutations\n observer.observe(anchorElement, observerConfig)\n }\n\n return () => {\n // Remove the observer when the tooltip is destroyed\n observer.disconnect()\n }\n }, [anchorRefs, providerActiveAnchor, activeAnchor, anchorId, anchorSelect])\n\n useEffect(() => {\n if (process.env.NODE_ENV === 'production') {\n return\n }\n if (style?.border) {\n // eslint-disable-next-line no-console\n console.warn('[react-tooltip] Do not set `style.border`. Use `border` prop instead.')\n }\n if (border && !CSS.supports('border', `${border}`)) {\n // eslint-disable-next-line no-console\n console.warn(`[react-tooltip] \"${border}\" is not a valid \\`border\\`.`)\n }\n if (style?.opacity) {\n // eslint-disable-next-line no-console\n console.warn('[react-tooltip] Do not set `style.opacity`. Use `opacity` prop instead.')\n }\n if (opacity && !CSS.supports('opacity', `${opacity}`)) {\n // eslint-disable-next-line no-console\n console.warn(`[react-tooltip] \"${opacity}\" is not a valid \\`opacity\\`.`)\n }\n }, [])\n\n /**\n * content priority: children < render or content < html\n * children should be lower priority so that it can be used as the \"default\" content\n */\n let renderedContent: ChildrenType = children\n const contentWrapperRef = useRef<HTMLDivElement>(null)\n if (render) {\n const rendered = render({ content: tooltipContent ?? null, activeAnchor }) as React.ReactNode\n renderedContent = rendered ? (\n <div ref={contentWrapperRef} className=\"react-tooltip-content-wrapper\">\n {rendered}\n </div>\n ) : null\n } else if (tooltipContent) {\n renderedContent = tooltipContent\n }\n if (tooltipHtml) {\n renderedContent = <TooltipContent content={tooltipHtml} />\n }\n\n const props: ITooltip = {\n id,\n anchorId,\n anchorSelect,\n className,\n classNameArrow,\n content: renderedContent,\n contentWrapperRef,\n place: tooltipPlace,\n variant: tooltipVariant,\n offset: tooltipOffset,\n wrapper: tooltipWrapper,\n events: tooltipEvents,\n openOnClick,\n positionStrategy: tooltipPositionStrategy,\n middlewares,\n delayShow: tooltipDelayShow,\n delayHide: tooltipDelayHide,\n float: tooltipFloat,\n hidden: tooltipHidden,\n noArrow,\n clickable,\n closeOnEsc,\n closeOnScroll,\n closeOnResize,\n style,\n position,\n isOpen,\n border,\n opacity,\n setIsOpen,\n afterShow,\n afterHide,\n activeAnchor,\n setActiveAnchor: (anchor: HTMLElement | null) => setActiveAnchor(anchor),\n }\n\n return <Tooltip {...props} />\n}\n\nexport default TooltipController\n","import './tokens.css'\n\nimport { injectStyle } from 'utils/handle-style'\n\nimport type {\n ChildrenType,\n DataAttribute,\n EventsType,\n PlacesType,\n PositionStrategy,\n VariantType,\n WrapperType,\n IPosition,\n Middleware,\n} from './components/Tooltip/TooltipTypes'\nimport type { ITooltipController } from './components/TooltipController/TooltipControllerTypes'\nimport type { ITooltipWrapper } from './components/TooltipProvider/TooltipProviderTypes'\n\n// those content will be replaced in build time with the `react-tooltip.css` builded content\nconst TooltipCoreStyles = 'react-tooltip-core-css-placeholder'\nconst TooltipStyles = 'react-tooltip-css-placeholder'\n\ninjectStyle({ css: TooltipCoreStyles, type: 'core' })\ninjectStyle({ css: TooltipStyles })\n\nexport { TooltipController as Tooltip } from './components/TooltipController'\nexport { TooltipProvider, TooltipWrapper } from './components/TooltipProvider'\nexport type {\n ChildrenType,\n DataAttribute,\n EventsType,\n PlacesType,\n PositionStrategy,\n VariantType,\n WrapperType,\n ITooltipController as ITooltip,\n ITooltipWrapper,\n IPosition,\n Middleware,\n}\n\nexport { removeStyle } from './utils/handle-style'\n"],"names":["REACT_TOOLTIP_CORE_STYLES_ID","REACT_TOOLTIP_BASE_STYLES_ID","injectStyle","css","id","type","ref","process","_a","env","REACT_TOOLTIP_DISABLE_CORE_STYLES","_b","REACT_TOOLTIP_DISABLE_BASE_STYLES","insertAt","document","getElementById","head","getElementsByTagName","style","createElement","firstChild","insertBefore","appendChild","styleSheet","cssText","createTextNode","removeStyle","remove","debounce","func","wait","immediate","timeout","args","later","apply","this","setTimeout","clearTimeout","DEFAULT_TOOLTIP_ID","DEFAULT_CONTEXT_DATA","anchorRefs","Set","activeAnchor","current","attach","detach","setActiveAnchor","TooltipContext","createContext","getTooltipData","TooltipProvider","children","anchorRefMap","setAnchorRefMap","useState","activeAnchorMap","setActiveAnchorMap","tooltipId","refs","oldMap","tooltipRefs","forEach","add","delete","useCallback","context","useMemo","React","Provider","value","useTooltip","useContext","TooltipWrapper","className","place","content","html","variant","offset","wrapper","events","positionStrategy","delayShow","delayHide","anchorRef","useRef","useEffect","classNames","useIsomorphicLayoutEffect","window","useLayoutEffect","isScrollable","node","HTMLElement","SVGElement","getComputedStyle","some","propertyName","getPropertyValue","getScrollParent","currentParent","parentElement","scrollingElement","documentElement","computeTooltipPosition","async","elementReference","tooltipReference","tooltipArrowReference","offsetValue","strategy","middlewares","Number","flip","shift","padding","border","tooltipStyles","tooltipArrowStyles","middleware","push","arrow","element","computePosition","placement","then","x","y","middlewareData","styles","left","top","arrowX","arrowY","staticSide","right","bottom","split","borderSide","borderBottom","borderRight","borderLeft","borderTop","borderWidth","match","Tooltip","classNameArrow","anchorId","anchorSelect","openOnClick","WrapperElement","float","hidden","noArrow","clickable","closeOnEsc","closeOnScroll","closeOnResize","externalStyles","position","afterShow","afterHide","contentWrapperRef","isOpen","setIsOpen","opacity","tooltipRef","tooltipArrowRef","tooltipShowDelayTimerRef","tooltipHideDelayTimerRef","actualPlacement","setActualPlacement","inlineStyles","setInlineStyles","inlineArrowStyles","setInlineArrowStyles","show","setShow","rendered","setRendered","wasShowing","lastFloatPosition","setProviderActiveAnchor","hoveringTooltip","anchorsBySelect","setAnchorsBySelect","mounted","shouldOpenOnClick","includes","handleShow","undefined","handleHideTooltipDelayed","delay","handleShowTooltip","event","target","currentTarget","isConnected","handleHideTooltip","handleTooltipPosition","getBoundingClientRect","width","height","computedStylesData","Object","keys","length","handleMouseMove","mouseEvent","mousePosition","clientX","clientY","handleClickTooltipAnchor","handleClickOutsideAnchors","querySelector","anchor","contains","debouncedHandleShowTooltip","debouncedHandleHideTooltip","elementRefs","anchorById","handleScrollResize","anchorScrollParent","tooltipScrollParent","addEventListener","handleEsc","key","enabledEvents","listener","handleMouseEnterTooltip","handleMouseLeaveTooltip","removeEventListener","selector","documentObserver","MutationObserver","mutationList","newAnchors","mutation","attributeName","getAttribute","removedNodes","call","elements","addedNodes","filter","nodeType","matches","flatMap","querySelectorAll","anchors","observe","body","childList","subtree","attributes","attributeFilter","disconnect","updateTooltipPosition","contentObserver","ResizeObserver","Array","from","canShow","role","coreStyles","coreStyles_show","coreStyles_fixed","coreStyles_clickable","coreStyles_noArrow","TooltipContent","dangerouslySetInnerHTML","__html","TooltipController","render","tooltipContent","setTooltipContent","tooltipHtml","setTooltipHtml","tooltipPlace","setTooltipPlace","tooltipVariant","setTooltipVariant","tooltipOffset","setTooltipOffset","tooltipDelayShow","setTooltipDelayShow","tooltipDelayHide","setTooltipDelayHide","tooltipFloat","setTooltipFloat","tooltipHidden","setTooltipHidden","tooltipWrapper","setTooltipWrapper","tooltipEvents","setTooltipEvents","tooltipPositionStrategy","setTooltipPositionStrategy","providerActiveAnchor","getDataAttributesFromAnchorElement","getAttributeNames","reduce","acc","name","startsWith","replace","applyAllDataAttributesFromAnchorElement","dataAttributes","handleDataAttributes","parsed","values","handler","entries","console","warn","size","anchorElement","observer","observerConfig","CSS","supports","renderedContent","props"],"mappings":";;;;;;8QACA,MAAMA,EAA+B,4BAE/BC,EAA+B,4BAErC,SAASC,GAAYC,IACnBA,EAAGC,GACHA,EAAKH,EAA4BI,KACjCA,EAAO,OAAMC,IACbA,YAQA,GACW,SAATD,GACmB,oBAAZE,UACK,QAAZC,EAAA,OAAAD,cAAA,IAAAA,aAAA,EAAAA,QAASE,WAAG,IAAAD,OAAA,EAAAA,EAAEE,mCAEd,OAGF,GACW,SAATL,GACmB,oBAAZE,UACK,QAAZI,EAAA,OAAAJ,cAAA,IAAAA,aAAA,EAAAA,QAASE,WAAG,IAAAE,OAAA,EAAAA,EAAEC,mCAEd,OAGW,SAATP,IAEFD,EAAKJ,GAGFM,IAEHA,EAAM,CAAA,GAER,MAAMO,SAAEA,GAAaP,EAErB,IAAKH,GAA2B,oBAAbW,UAA4BA,SAASC,eAAeX,GACrE,OAGF,MAAMY,EAAOF,SAASE,MAAQF,SAASG,qBAAqB,QAAQ,GAE9DC,EAAaJ,SAASK,cAAc,SAC1CD,EAAMd,GAAKA,EACXc,EAAMb,KAAO,WAEI,QAAbQ,GACEG,EAAKI,WACPJ,EAAKK,aAAaH,EAAOF,EAAKI,YAKhCJ,EAAKM,YAAYJ,GAGfA,EAAMK,WACRL,EAAMK,WAAWC,QAAUrB,EAE3Be,EAAMI,YAAYR,SAASW,eAAetB,GAE9C,CAEA,SAASuB,GAAYrB,KACnBA,EAAO,OAAMD,GACbA,EAAKH,GAIH,IACW,SAATI,IAEFD,EAAKJ,GAGP,MAAMkB,EAAQJ,SAASC,eAAeX,GACtCc,SAAAA,EAAOS,QACT,CC9EA,MAAMC,EAAW,CAACC,EAAgCC,EAAeC,KAC/D,IAAIC,EAAiC,KAErC,OAAO,YAAyCC,GAC9C,MAAMC,EAAQ,KACZF,EAAU,KACLD,GACHF,EAAKM,MAAMC,KAAMH,EAClB,EAGCF,IAAcC,IAKhBH,EAAKM,MAAMC,KAAMH,GACjBD,EAAUK,WAAWH,EAAOJ,IAGzBC,IACCC,GACFM,aAAaN,GAEfA,EAAUK,WAAWH,EAAOJ,GAEhC,CAAC,EClBGS,EAAqB,qBACrBC,EAA2C,CAC/CC,WAAY,IAAIC,IAChBC,aAAc,CAAEC,QAAS,MACzBC,OAAQ,OAGRC,OAAQ,OAGRC,gBAAiB,QASbC,EAAiBC,EAJyC,CAC9DC,eAAgB,IAAMV,IASlBW,EAAqD,EAAGC,eAC5D,MAAOC,EAAcC,GAAmBC,EAAyC,CAC/EhB,CAACA,GAAqB,IAAIG,OAErBc,EAAiBC,GAAsBF,EAAoC,CAChFhB,CAACA,GAAqB,CAAEK,QAAS,QAG7BC,EAAS,CAACa,KAAsBC,KACpCL,GAAiBM,UACf,MAAMC,EAAmC,QAArBrD,EAAAoD,EAAOF,UAAc,IAAAlD,EAAAA,EAAA,IAAIkC,IAG7C,OAFAiB,EAAKG,SAASxD,GAAQuD,EAAYE,IAAIzD,KAE/B,IAAKsD,EAAQF,CAACA,GAAY,IAAIhB,IAAImB,GAAc,GACvD,EAGEf,EAAS,CAACY,KAAsBC,KACpCL,GAAiBM,IACf,MAAMC,EAAcD,EAAOF,GAC3B,OAAKG,GAKLF,EAAKG,SAASxD,GAAQuD,EAAYG,OAAO1D,KAElC,IAAKsD,IAJHA,CAIW,GACpB,EAaEV,EAAiBe,GACrB,CAACP,EAAYnB,aAAuB,MAAC,CACnCE,WAAmC,UAAvBY,EAAaK,UAAU,IAAAlD,EAAAA,EAAI,IAAIkC,IAC3CC,aAAwC,QAA1BhC,EAAA6C,EAAgBE,UAAU,IAAA/C,EAAAA,EAAI,CAAEiC,QAAS,MACvDC,OAAQ,IAAIc,IAAsBd,EAAOa,KAAcC,GACvDb,OAAQ,IAAIa,IAAsBb,EAAOY,KAAcC,GACvDZ,gBAAkBzC,GAhBE,EAACoD,EAAmBpD,KAC1CmD,GAAoBG,UAClB,OAAuB,QAAnBpD,EAAAoD,EAAOF,UAAY,IAAAlD,OAAA,EAAAA,EAAAoC,WAAYtC,EAAIsC,QAC9BgB,EAGF,IAAKA,EAAQF,CAACA,GAAYpD,EAAK,GACtC,EASqCyC,CAAgBW,EAAWpD,GAChE,GA