diff --git a/src/App.tsx b/src/App.tsx index fd85b9ad..29910fef 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,8 +1,8 @@ /* eslint-disable jsx-a11y/no-static-element-interactions */ /* eslint-disable jsx-a11y/click-events-have-key-events */ import { TooltipController as Tooltip } from 'components/TooltipController' -import { IPosition } from 'components/Tooltip/TooltipTypes.d' -import React, { useState } from 'react' +import { IPosition, TooltipImperativeProps } from 'components/Tooltip/TooltipTypes.d' +import React, { useEffect, useRef, useState } from 'react' import { inline, offset } from '@floating-ui/dom' import styles from './styles.module.css' @@ -11,6 +11,7 @@ function App() { const [isDarkOpen, setIsDarkOpen] = useState(false) const [position, setPosition] = useState({ x: 0, y: 0 }) const [toggle, setToggle] = useState(false) + const tooltipRef = useRef(null) const handlePositionClick: React.MouseEventHandler = (event) => { const x = event.clientX @@ -23,6 +24,19 @@ function App() { setAnchorId(target.id) } + useEffect(() => { + const handleQ = (event: KeyboardEvent) => { + if (event.key === 'q') { + // q + tooltipRef.current?.close() + } + } + window.addEventListener('keydown', handleQ) + return () => { + window.removeEventListener('keydown', handleQ) + } + }) + return (
diff --git a/src/components/Tooltip/Tooltip.tsx b/src/components/Tooltip/Tooltip.tsx index 5413a652..2a436341 100644 --- a/src/components/Tooltip/Tooltip.tsx +++ b/src/components/Tooltip/Tooltip.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState, useRef, useCallback } from 'react' +import React, { useEffect, useState, useRef, useCallback, useImperativeHandle } from 'react' import { autoUpdate } from '@floating-ui/dom' import classNames from 'classnames' import debounce from 'utils/debounce' @@ -8,10 +8,11 @@ import { getScrollParent } from 'utils/get-scroll-parent' import { computeTooltipPosition } from 'utils/compute-positions' import coreStyles from './core-styles.module.css' import styles from './styles.module.css' -import type { IPosition, ITooltip, PlacesType } from './TooltipTypes' +import type { IPosition, ITooltip, PlacesType, TooltipImperativeOpenOptions } from './TooltipTypes' const Tooltip = ({ // props + forwardRef, id, className, classNameArrow, @@ -58,6 +59,9 @@ const Tooltip = ({ const [inlineArrowStyles, setInlineArrowStyles] = useState({}) const [show, setShow] = useState(false) const [rendered, setRendered] = useState(false) + const [imperativeOptions, setImperativeOptions] = useState( + null, + ) const wasShowing = useRef(false) const lastFloatPosition = useRef(null) /** @@ -149,6 +153,7 @@ const Tooltip = ({ if (show) { afterShow?.() } else { + setImperativeOptions(null) afterHide?.() } }, [show]) @@ -274,6 +279,9 @@ const Tooltip = ({ } const handleClickOutsideAnchors = (event: MouseEvent) => { + if (!show) { + return + } const anchorById = document.querySelector(`[id='${anchorId}']`) const anchors = [anchorById, ...anchorsBySelect] if (anchors.some((anchor) => anchor?.contains(event.target as HTMLElement))) { @@ -293,9 +301,10 @@ const Tooltip = ({ const debouncedHandleShowTooltip = debounce(handleShowTooltip, 50, true) const debouncedHandleHideTooltip = debounce(handleHideTooltip, 50, true) const updateTooltipPosition = useCallback(() => { - if (position) { + const actualPosition = imperativeOptions?.position ?? position + if (actualPosition) { // if `position` is set, override regular and `float` positioning - handleTooltipPosition(position) + handleTooltipPosition(actualPosition) return } @@ -349,6 +358,7 @@ const Tooltip = ({ offset, positionStrategy, position, + imperativeOptions?.position, float, ]) @@ -484,7 +494,7 @@ const Tooltip = ({ ]) useEffect(() => { - let selector = anchorSelect ?? '' + let selector = imperativeOptions?.anchorSelect ?? anchorSelect ?? '' if (!selector && id) { selector = `[data-tooltip-id='${id}']` } @@ -584,7 +594,7 @@ const Tooltip = ({ return () => { documentObserver.disconnect() } - }, [id, anchorSelect, activeAnchor]) + }, [id, anchorSelect, imperativeOptions?.anchorSelect, activeAnchor]) useEffect(() => { updateTooltipPosition() @@ -628,7 +638,7 @@ const Tooltip = ({ }, []) useEffect(() => { - let selector = anchorSelect + let selector = imperativeOptions?.anchorSelect ?? anchorSelect if (!selector && id) { selector = `[data-tooltip-id='${id}']` } @@ -642,9 +652,34 @@ const Tooltip = ({ // warning was already issued in the controller setAnchorsBySelect([]) } - }, [id, anchorSelect]) + }, [id, anchorSelect, imperativeOptions?.anchorSelect]) + + const actualContent = imperativeOptions?.content ?? content + const canShow = Boolean(!hidden && actualContent && show && Object.keys(inlineStyles).length > 0) - const canShow = !hidden && content && show && Object.keys(inlineStyles).length > 0 + useImperativeHandle(forwardRef, () => ({ + open: (options) => { + if (options?.anchorSelect) { + try { + document.querySelector(options.anchorSelect) + } catch { + if (!process.env.NODE_ENV || process.env.NODE_ENV !== 'production') { + // eslint-disable-next-line no-console + console.warn(`[react-tooltip] "${options.anchorSelect}" is not a valid CSS selector`) + } + return + } + } + setImperativeOptions(options ?? null) + handleShow(true) + }, + close: () => { + handleShow(false) + }, + activeAnchor, + place: actualPlacement, + isOpen: rendered && canShow, + })) return rendered ? ( - {content} + {actualContent} void + close: () => void + /** + * @readonly + */ + activeAnchor: HTMLElement | null + /** + * @readonly + */ + place: PlacesType + /** + * @readonly + */ + isOpen: boolean +} + export interface ITooltip { + forwardRef?: React.ForwardedRef className?: string classNameArrow?: string content?: ChildrenType diff --git a/src/components/TooltipController/TooltipController.tsx b/src/components/TooltipController/TooltipController.tsx index 729e77b8..5dd2de08 100644 --- a/src/components/TooltipController/TooltipController.tsx +++ b/src/components/TooltipController/TooltipController.tsx @@ -9,341 +9,348 @@ import type { DataAttribute, ITooltip, ChildrenType, + TooltipImperativeProps, } from 'components/Tooltip/TooltipTypes' import { useTooltip } from 'components/TooltipProvider' import { TooltipContent } from 'components/TooltipContent' import type { ITooltipController } from './TooltipControllerTypes' -const TooltipController = ({ - id, - anchorId, - anchorSelect, - content, - html, - render, - className, - classNameArrow, - variant = 'dark', - place = 'top', - offset = 10, - wrapper = 'div', - children = null, - events = ['hover'], - openOnClick = false, - positionStrategy = 'absolute', - middlewares, - delayShow = 0, - delayHide = 0, - float = false, - hidden = false, - noArrow = false, - clickable = false, - closeOnEsc = false, - closeOnScroll = false, - closeOnResize = false, - style, - position, - isOpen, - disableStyleInjection = false, - border, - opacity, - arrowColor, - setIsOpen, - afterShow, - afterHide, -}: ITooltipController) => { - const [tooltipContent, setTooltipContent] = useState(content) - const [tooltipHtml, setTooltipHtml] = useState(html) - const [tooltipPlace, setTooltipPlace] = useState(place) - const [tooltipVariant, setTooltipVariant] = useState(variant) - const [tooltipOffset, setTooltipOffset] = useState(offset) - const [tooltipDelayShow, setTooltipDelayShow] = useState(delayShow) - const [tooltipDelayHide, setTooltipDelayHide] = useState(delayHide) - const [tooltipFloat, setTooltipFloat] = useState(float) - const [tooltipHidden, setTooltipHidden] = useState(hidden) - const [tooltipWrapper, setTooltipWrapper] = useState(wrapper) - const [tooltipEvents, setTooltipEvents] = useState(events) - const [tooltipPositionStrategy, setTooltipPositionStrategy] = useState(positionStrategy) - const [activeAnchor, setActiveAnchor] = useState(null) - const styleInjectionRef = useRef(disableStyleInjection) - /** - * @todo Remove this in a future version (provider/wrapper method is deprecated) - */ - const { anchorRefs, activeAnchor: providerActiveAnchor } = useTooltip(id) +const TooltipController = React.forwardRef( + ( + { + id, + anchorId, + anchorSelect, + content, + html, + render, + className, + classNameArrow, + variant = 'dark', + place = 'top', + offset = 10, + wrapper = 'div', + children = null, + events = ['hover'], + openOnClick = false, + positionStrategy = 'absolute', + middlewares, + delayShow = 0, + delayHide = 0, + float = false, + hidden = false, + noArrow = false, + clickable = false, + closeOnEsc = false, + closeOnScroll = false, + closeOnResize = false, + style, + position, + isOpen, + disableStyleInjection = false, + border, + opacity, + arrowColor, + setIsOpen, + afterShow, + afterHide, + }: ITooltipController, + ref, + ) => { + const [tooltipContent, setTooltipContent] = useState(content) + const [tooltipHtml, setTooltipHtml] = useState(html) + const [tooltipPlace, setTooltipPlace] = useState(place) + const [tooltipVariant, setTooltipVariant] = useState(variant) + const [tooltipOffset, setTooltipOffset] = useState(offset) + const [tooltipDelayShow, setTooltipDelayShow] = useState(delayShow) + const [tooltipDelayHide, setTooltipDelayHide] = useState(delayHide) + const [tooltipFloat, setTooltipFloat] = useState(float) + const [tooltipHidden, setTooltipHidden] = useState(hidden) + const [tooltipWrapper, setTooltipWrapper] = useState(wrapper) + const [tooltipEvents, setTooltipEvents] = useState(events) + const [tooltipPositionStrategy, setTooltipPositionStrategy] = useState(positionStrategy) + const [activeAnchor, setActiveAnchor] = useState(null) + const styleInjectionRef = useRef(disableStyleInjection) + /** + * @todo Remove this in a future version (provider/wrapper method is deprecated) + */ + const { anchorRefs, activeAnchor: providerActiveAnchor } = useTooltip(id) - const getDataAttributesFromAnchorElement = (elementReference: HTMLElement) => { - const dataAttributes = elementReference?.getAttributeNames().reduce((acc, name) => { - if (name.startsWith('data-tooltip-')) { - const parsedAttribute = name.replace(/^data-tooltip-/, '') as DataAttribute - acc[parsedAttribute] = elementReference?.getAttribute(name) ?? null - } - return acc - }, {} as Record) + const getDataAttributesFromAnchorElement = (elementReference: HTMLElement) => { + const dataAttributes = elementReference?.getAttributeNames().reduce((acc, name) => { + if (name.startsWith('data-tooltip-')) { + const parsedAttribute = name.replace(/^data-tooltip-/, '') as DataAttribute + acc[parsedAttribute] = elementReference?.getAttribute(name) ?? null + } + return acc + }, {} as Record) - return dataAttributes - } + return dataAttributes + } - const applyAllDataAttributesFromAnchorElement = ( - dataAttributes: Record, - ) => { - const handleDataAttributes: Record void> = { - place: (value) => { - setTooltipPlace((value as PlacesType) ?? place) - }, - content: (value) => { - setTooltipContent(value ?? content) - }, - html: (value) => { - setTooltipHtml(value ?? html) - }, - variant: (value) => { - setTooltipVariant((value as VariantType) ?? variant) - }, - offset: (value) => { - setTooltipOffset(value === null ? offset : Number(value)) - }, - wrapper: (value) => { - setTooltipWrapper((value as WrapperType) ?? wrapper) - }, - events: (value) => { - const parsed = value?.split(' ') as EventsType[] - setTooltipEvents(parsed ?? events) - }, - 'position-strategy': (value) => { - setTooltipPositionStrategy((value as PositionStrategy) ?? positionStrategy) - }, - 'delay-show': (value) => { - setTooltipDelayShow(value === null ? delayShow : Number(value)) - }, - 'delay-hide': (value) => { - setTooltipDelayHide(value === null ? delayHide : Number(value)) - }, - float: (value) => { - setTooltipFloat(value === null ? float : value === 'true') - }, - hidden: (value) => { - setTooltipHidden(value === null ? hidden : value === 'true') - }, + const applyAllDataAttributesFromAnchorElement = ( + dataAttributes: Record, + ) => { + const handleDataAttributes: Record void> = { + place: (value) => { + setTooltipPlace((value as PlacesType) ?? place) + }, + content: (value) => { + setTooltipContent(value ?? content) + }, + html: (value) => { + setTooltipHtml(value ?? html) + }, + variant: (value) => { + setTooltipVariant((value as VariantType) ?? variant) + }, + offset: (value) => { + setTooltipOffset(value === null ? offset : Number(value)) + }, + wrapper: (value) => { + setTooltipWrapper((value as WrapperType) ?? wrapper) + }, + events: (value) => { + const parsed = value?.split(' ') as EventsType[] + setTooltipEvents(parsed ?? events) + }, + 'position-strategy': (value) => { + setTooltipPositionStrategy((value as PositionStrategy) ?? positionStrategy) + }, + 'delay-show': (value) => { + setTooltipDelayShow(value === null ? delayShow : Number(value)) + }, + 'delay-hide': (value) => { + setTooltipDelayHide(value === null ? delayHide : Number(value)) + }, + float: (value) => { + setTooltipFloat(value === null ? float : value === 'true') + }, + hidden: (value) => { + setTooltipHidden(value === null ? hidden : value === 'true') + }, + } + // reset unset data attributes to default values + // without this, data attributes from the last active anchor will still be used + Object.values(handleDataAttributes).forEach((handler) => handler(null)) + Object.entries(dataAttributes).forEach(([key, value]) => { + handleDataAttributes[key as DataAttribute]?.(value) + }) } - // reset unset data attributes to default values - // without this, data attributes from the last active anchor will still be used - Object.values(handleDataAttributes).forEach((handler) => handler(null)) - Object.entries(dataAttributes).forEach(([key, value]) => { - handleDataAttributes[key as DataAttribute]?.(value) - }) - } - useEffect(() => { - setTooltipContent(content) - }, [content]) + useEffect(() => { + setTooltipContent(content) + }, [content]) - useEffect(() => { - setTooltipHtml(html) - }, [html]) + useEffect(() => { + setTooltipHtml(html) + }, [html]) - useEffect(() => { - setTooltipPlace(place) - }, [place]) + useEffect(() => { + setTooltipPlace(place) + }, [place]) - useEffect(() => { - setTooltipVariant(variant) - }, [variant]) + useEffect(() => { + setTooltipVariant(variant) + }, [variant]) - useEffect(() => { - setTooltipOffset(offset) - }, [offset]) + useEffect(() => { + setTooltipOffset(offset) + }, [offset]) - useEffect(() => { - setTooltipDelayShow(delayShow) - }, [delayShow]) + useEffect(() => { + setTooltipDelayShow(delayShow) + }, [delayShow]) - useEffect(() => { - setTooltipDelayHide(delayHide) - }, [delayHide]) + useEffect(() => { + setTooltipDelayHide(delayHide) + }, [delayHide]) - useEffect(() => { - setTooltipFloat(float) - }, [float]) + useEffect(() => { + setTooltipFloat(float) + }, [float]) - useEffect(() => { - setTooltipHidden(hidden) - }, [hidden]) + useEffect(() => { + setTooltipHidden(hidden) + }, [hidden]) - useEffect(() => { - setTooltipPositionStrategy(positionStrategy) - }, [positionStrategy]) + useEffect(() => { + setTooltipPositionStrategy(positionStrategy) + }, [positionStrategy]) - useEffect(() => { - if (styleInjectionRef.current === disableStyleInjection) { - return - } - if (process.env.NODE_ENV !== 'production') { - // eslint-disable-next-line no-console - console.warn('[react-tooltip] Do not change `disableStyleInjection` dynamically.') - } - }, [disableStyleInjection]) + useEffect(() => { + if (styleInjectionRef.current === disableStyleInjection) { + return + } + if (process.env.NODE_ENV !== 'production') { + // eslint-disable-next-line no-console + console.warn('[react-tooltip] Do not change `disableStyleInjection` dynamically.') + } + }, [disableStyleInjection]) - useEffect(() => { - if (typeof window !== 'undefined') { - window.dispatchEvent( - new CustomEvent('react-tooltip-inject-styles', { - detail: { - disableCore: disableStyleInjection === 'core', - disableBase: disableStyleInjection, - }, - }), - ) - } - }, []) + useEffect(() => { + if (typeof window !== 'undefined') { + window.dispatchEvent( + new CustomEvent('react-tooltip-inject-styles', { + detail: { + disableCore: disableStyleInjection === 'core', + disableBase: disableStyleInjection, + }, + }), + ) + } + }, []) - useEffect(() => { - const elementRefs = new Set(anchorRefs) + useEffect(() => { + const elementRefs = new Set(anchorRefs) - let selector = anchorSelect - if (!selector && id) { - selector = `[data-tooltip-id='${id}']` - } - if (selector) { - try { - const anchorsBySelect = document.querySelectorAll(selector) - anchorsBySelect.forEach((anchor) => { - elementRefs.add({ current: anchor }) - }) - } catch { - if (!process.env.NODE_ENV || process.env.NODE_ENV !== 'production') { - // eslint-disable-next-line no-console - console.warn(`[react-tooltip] "${selector}" is not a valid CSS selector`) + let selector = anchorSelect + if (!selector && id) { + selector = `[data-tooltip-id='${id}']` + } + if (selector) { + try { + const anchorsBySelect = document.querySelectorAll(selector) + anchorsBySelect.forEach((anchor) => { + elementRefs.add({ current: anchor }) + }) + } catch { + if (!process.env.NODE_ENV || process.env.NODE_ENV !== 'production') { + // eslint-disable-next-line no-console + console.warn(`[react-tooltip] "${selector}" is not a valid CSS selector`) + } } } - } - const anchorById = document.querySelector(`[id='${anchorId}']`) - if (anchorById) { - elementRefs.add({ current: anchorById }) - } + const anchorById = document.querySelector(`[id='${anchorId}']`) + if (anchorById) { + elementRefs.add({ current: anchorById }) + } - if (!elementRefs.size) { - return () => null - } + if (!elementRefs.size) { + return () => null + } - const anchorElement = activeAnchor ?? anchorById ?? providerActiveAnchor.current + const anchorElement = activeAnchor ?? anchorById ?? providerActiveAnchor.current - const observerCallback: MutationCallback = (mutationList) => { - mutationList.forEach((mutation) => { - if ( - !anchorElement || - mutation.type !== 'attributes' || - !mutation.attributeName?.startsWith('data-tooltip-') - ) { - return - } - // make sure to get all set attributes, since all unset attributes are reset + const observerCallback: MutationCallback = (mutationList) => { + mutationList.forEach((mutation) => { + if ( + !anchorElement || + mutation.type !== 'attributes' || + !mutation.attributeName?.startsWith('data-tooltip-') + ) { + return + } + // make sure to get all set attributes, since all unset attributes are reset + const dataAttributes = getDataAttributesFromAnchorElement(anchorElement) + applyAllDataAttributesFromAnchorElement(dataAttributes) + }) + } + + // Create an observer instance linked to the callback function + const observer = new MutationObserver(observerCallback) + + // do not check for subtree and childrens, we only want to know attribute changes + // to stay watching `data-attributes-*` from anchor element + const observerConfig = { attributes: true, childList: false, subtree: false } + + if (anchorElement) { const dataAttributes = getDataAttributesFromAnchorElement(anchorElement) applyAllDataAttributesFromAnchorElement(dataAttributes) - }) - } + // Start observing the target node for configured mutations + observer.observe(anchorElement, observerConfig) + } - // Create an observer instance linked to the callback function - const observer = new MutationObserver(observerCallback) + return () => { + // Remove the observer when the tooltip is destroyed + observer.disconnect() + } + }, [anchorRefs, providerActiveAnchor, activeAnchor, anchorId, anchorSelect]) - // do not check for subtree and childrens, we only want to know attribute changes - // to stay watching `data-attributes-*` from anchor element - const observerConfig = { attributes: true, childList: false, subtree: false } + useEffect(() => { + if (process.env.NODE_ENV === 'production') { + return + } + if (style?.border) { + // eslint-disable-next-line no-console + console.warn('[react-tooltip] Do not set `style.border`. Use `border` prop instead.') + } + if (border && !CSS.supports('border', `${border}`)) { + // eslint-disable-next-line no-console + console.warn(`[react-tooltip] "${border}" is not a valid \`border\`.`) + } + if (style?.opacity) { + // eslint-disable-next-line no-console + console.warn('[react-tooltip] Do not set `style.opacity`. Use `opacity` prop instead.') + } + if (opacity && !CSS.supports('opacity', `${opacity}`)) { + // eslint-disable-next-line no-console + console.warn(`[react-tooltip] "${opacity}" is not a valid \`opacity\`.`) + } + }, []) - if (anchorElement) { - const dataAttributes = getDataAttributesFromAnchorElement(anchorElement) - applyAllDataAttributesFromAnchorElement(dataAttributes) - // Start observing the target node for configured mutations - observer.observe(anchorElement, observerConfig) + /** + * content priority: children < render or content < html + * children should be lower priority so that it can be used as the "default" content + */ + let renderedContent: ChildrenType = children + const contentWrapperRef = useRef(null) + if (render) { + const rendered = render({ content: tooltipContent ?? null, activeAnchor }) as React.ReactNode + renderedContent = rendered ? ( +
+ {rendered} +
+ ) : null + } else if (tooltipContent) { + renderedContent = tooltipContent } - - return () => { - // Remove the observer when the tooltip is destroyed - observer.disconnect() + if (tooltipHtml) { + renderedContent = } - }, [anchorRefs, providerActiveAnchor, activeAnchor, anchorId, anchorSelect]) - useEffect(() => { - if (process.env.NODE_ENV === 'production') { - return - } - if (style?.border) { - // eslint-disable-next-line no-console - console.warn('[react-tooltip] Do not set `style.border`. Use `border` prop instead.') + const props: ITooltip = { + forwardRef: ref, + id, + anchorId, + anchorSelect, + className, + classNameArrow, + content: renderedContent, + contentWrapperRef, + place: tooltipPlace, + variant: tooltipVariant, + offset: tooltipOffset, + wrapper: tooltipWrapper, + events: tooltipEvents, + openOnClick, + positionStrategy: tooltipPositionStrategy, + middlewares, + delayShow: tooltipDelayShow, + delayHide: tooltipDelayHide, + float: tooltipFloat, + hidden: tooltipHidden, + noArrow, + clickable, + closeOnEsc, + closeOnScroll, + closeOnResize, + style, + position, + isOpen, + border, + opacity, + arrowColor, + setIsOpen, + afterShow, + afterHide, + activeAnchor, + setActiveAnchor: (anchor: HTMLElement | null) => setActiveAnchor(anchor), } - if (border && !CSS.supports('border', `${border}`)) { - // eslint-disable-next-line no-console - console.warn(`[react-tooltip] "${border}" is not a valid \`border\`.`) - } - if (style?.opacity) { - // eslint-disable-next-line no-console - console.warn('[react-tooltip] Do not set `style.opacity`. Use `opacity` prop instead.') - } - if (opacity && !CSS.supports('opacity', `${opacity}`)) { - // eslint-disable-next-line no-console - console.warn(`[react-tooltip] "${opacity}" is not a valid \`opacity\`.`) - } - }, []) - - /** - * content priority: children < render or content < html - * children should be lower priority so that it can be used as the "default" content - */ - let renderedContent: ChildrenType = children - const contentWrapperRef = useRef(null) - if (render) { - const rendered = render({ content: tooltipContent ?? null, activeAnchor }) as React.ReactNode - renderedContent = rendered ? ( -
- {rendered} -
- ) : null - } else if (tooltipContent) { - renderedContent = tooltipContent - } - if (tooltipHtml) { - renderedContent = - } - - const props: ITooltip = { - id, - anchorId, - anchorSelect, - className, - classNameArrow, - content: renderedContent, - contentWrapperRef, - place: tooltipPlace, - variant: tooltipVariant, - offset: tooltipOffset, - wrapper: tooltipWrapper, - events: tooltipEvents, - openOnClick, - positionStrategy: tooltipPositionStrategy, - middlewares, - delayShow: tooltipDelayShow, - delayHide: tooltipDelayHide, - float: tooltipFloat, - hidden: tooltipHidden, - noArrow, - clickable, - closeOnEsc, - closeOnScroll, - closeOnResize, - style, - position, - isOpen, - border, - opacity, - arrowColor, - setIsOpen, - afterShow, - afterHide, - activeAnchor, - setActiveAnchor: (anchor: HTMLElement | null) => setActiveAnchor(anchor), - } - return -} + return + }, +) export default TooltipController diff --git a/src/index.tsx b/src/index.tsx index 6dc35544..1faa1755 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -12,6 +12,7 @@ import type { WrapperType, IPosition, Middleware, + TooltipImperativeProps, } from './components/Tooltip/TooltipTypes' import type { ITooltipController } from './components/TooltipController/TooltipControllerTypes' import type { ITooltipWrapper } from './components/TooltipProvider/TooltipProviderTypes' @@ -47,6 +48,7 @@ export type { ITooltipWrapper, IPosition, Middleware, + TooltipImperativeProps as TooltipRefProps, } export { removeStyle } from './utils/handle-style'