@wordpress/components
Version:
UI components for WordPress.
123 lines (117 loc) • 4.13 kB
JavaScript
/**
* External dependencies
*/
import * as Ariakit from '@ariakit/react';
import clsx from 'clsx';
/**
* WordPress dependencies
*/
import { useInstanceId } from '@wordpress/compose';
import { Children, useContext, createContext, forwardRef, cloneElement } from '@wordpress/element';
import deprecated from '@wordpress/deprecated';
/**
* Internal dependencies
*/
import Shortcut from '../shortcut';
import { positionToPlacement } from '../popover/utils';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const TooltipInternalContext = createContext({
isNestedInTooltip: false
});
/**
* Time over anchor to wait before showing tooltip
*/
export const TOOLTIP_DELAY = 700;
const CONTEXT_VALUE = {
isNestedInTooltip: true
};
function UnforwardedTooltip(props, ref) {
const {
children,
className,
delay = TOOLTIP_DELAY,
hideOnClick = true,
placement,
position,
shortcut,
text,
...restProps
} = props;
const {
isNestedInTooltip
} = useContext(TooltipInternalContext);
const baseId = useInstanceId(Tooltip, 'tooltip');
const describedById = text || shortcut ? baseId : undefined;
const isOnlyChild = Children.count(children) === 1;
// console error if more than one child element is added
if (!isOnlyChild) {
if ('development' === process.env.NODE_ENV) {
// eslint-disable-next-line no-console
console.error('wp-components.Tooltip should be called with only a single child element.');
}
}
// Compute tooltip's placement:
// - give priority to `placement` prop, if defined
// - otherwise, compute it from the legacy `position` prop (if defined)
// - finally, fallback to the default placement: 'bottom'
let computedPlacement;
if (placement !== undefined) {
computedPlacement = placement;
} else if (position !== undefined) {
computedPlacement = positionToPlacement(position);
deprecated('`position` prop in wp.components.tooltip', {
since: '6.4',
alternative: '`placement` prop'
});
}
computedPlacement = computedPlacement || 'bottom';
const tooltipStore = Ariakit.useTooltipStore({
placement: computedPlacement,
showTimeout: delay
});
const mounted = Ariakit.useStoreState(tooltipStore, 'mounted');
if (isNestedInTooltip) {
return isOnlyChild ? /*#__PURE__*/_jsx(Ariakit.Role, {
...restProps,
render: children
}) : children;
}
// TODO: this is a temporary workaround to minimize the effects of the
// Ariakit upgrade. Ariakit doesn't pass the `aria-describedby` prop to
// the tooltip anchor anymore since 0.4.0, so we need to add it manually.
// The `aria-describedby` attribute is added only if the anchor doesn't have
// one already, and if the tooltip text is not the same as the anchor's
// `aria-label`
// See: https://github.com/WordPress/gutenberg/pull/64066
// See: https://github.com/WordPress/gutenberg/pull/65989
function addDescribedById(element) {
return describedById && mounted && element.props['aria-describedby'] === undefined && element.props['aria-label'] !== text ? cloneElement(element, {
'aria-describedby': describedById
}) : element;
}
return /*#__PURE__*/_jsxs(TooltipInternalContext.Provider, {
value: CONTEXT_VALUE,
children: [/*#__PURE__*/_jsx(Ariakit.TooltipAnchor, {
onClick: hideOnClick ? tooltipStore.hide : undefined,
store: tooltipStore,
render: isOnlyChild ? addDescribedById(children) : undefined,
ref: ref,
children: isOnlyChild ? undefined : children
}), isOnlyChild && (text || shortcut) && /*#__PURE__*/_jsxs(Ariakit.Tooltip, {
...restProps,
className: clsx('components-tooltip', className),
unmountOnHide: true,
gutter: 4,
id: describedById,
overflowPadding: 0.5,
store: tooltipStore,
children: [text, shortcut && /*#__PURE__*/_jsx(Shortcut, {
className: text ? 'components-tooltip__shortcut' : '',
shortcut: shortcut
})]
})]
});
}
export const Tooltip = forwardRef(UnforwardedTooltip);
export default Tooltip;
//# sourceMappingURL=index.js.map