ivt
Version:
Ivt Components Library
598 lines (594 loc) • 22.9 kB
JavaScript
import * as React from 'react';
import React__default from 'react';
import { c as composeEventHandlers } from './index-Bl-WJHvp.mjs';
import { u as useComposedRefs } from './index-1tQVI0Jh.mjs';
import { c as createContextScope } from './index-DT8WgpCS.mjs';
import { D as DismissableLayer } from './index-DUpRrJTH.mjs';
import { u as useId } from './index-tkRL9Tft.mjs';
import { c as createPopperScope, R as Root2, A as Anchor, C as Content, a as Arrow } from './index-aLIsJMgt.mjs';
import { P as Portal$1 } from './index-BTe1rv5Z.mjs';
import { P as Presence } from './index-C6s8KI_8.mjs';
import { P as Primitive } from './index-DgKlJYZP.mjs';
import { createSlottable } from '@radix-ui/react-slot';
import { u as useControllableState } from './index-D4FMFHi9.mjs';
import { R as Root } from './index-An4yBrAZ.mjs';
import { jsx, jsxs } from 'react/jsx-runtime';
import { c as cn } from './utils-05LlW3Cl.mjs';
var [createTooltipContext] = createContextScope("Tooltip", [
createPopperScope
]);
var usePopperScope = createPopperScope();
var PROVIDER_NAME = "TooltipProvider";
var DEFAULT_DELAY_DURATION = 700;
var TOOLTIP_OPEN = "tooltip.open";
var [TooltipProviderContextProvider, useTooltipProviderContext] = createTooltipContext(PROVIDER_NAME);
var TooltipProvider$1 = (props)=>{
const { __scopeTooltip, delayDuration = DEFAULT_DELAY_DURATION, skipDelayDuration = 300, disableHoverableContent = false, children } = props;
const isOpenDelayedRef = React.useRef(true);
const isPointerInTransitRef = React.useRef(false);
const skipDelayTimerRef = React.useRef(0);
React.useEffect(()=>{
const skipDelayTimer = skipDelayTimerRef.current;
return ()=>window.clearTimeout(skipDelayTimer);
}, []);
return /* @__PURE__ */ jsx(TooltipProviderContextProvider, {
scope: __scopeTooltip,
isOpenDelayedRef,
delayDuration,
onOpen: React.useCallback(()=>{
window.clearTimeout(skipDelayTimerRef.current);
isOpenDelayedRef.current = false;
}, []),
onClose: React.useCallback(()=>{
window.clearTimeout(skipDelayTimerRef.current);
skipDelayTimerRef.current = window.setTimeout(()=>isOpenDelayedRef.current = true, skipDelayDuration);
}, [
skipDelayDuration
]),
isPointerInTransitRef,
onPointerInTransitChange: React.useCallback((inTransit)=>{
isPointerInTransitRef.current = inTransit;
}, []),
disableHoverableContent,
children
});
};
TooltipProvider$1.displayName = PROVIDER_NAME;
var TOOLTIP_NAME = "Tooltip";
var [TooltipContextProvider, useTooltipContext] = createTooltipContext(TOOLTIP_NAME);
var Tooltip$1 = (props)=>{
const { __scopeTooltip, children, open: openProp, defaultOpen, onOpenChange, disableHoverableContent: disableHoverableContentProp, delayDuration: delayDurationProp } = props;
const providerContext = useTooltipProviderContext(TOOLTIP_NAME, props.__scopeTooltip);
const popperScope = usePopperScope(__scopeTooltip);
const [trigger, setTrigger] = React.useState(null);
const contentId = useId();
const openTimerRef = React.useRef(0);
const disableHoverableContent = disableHoverableContentProp ?? providerContext.disableHoverableContent;
const delayDuration = delayDurationProp ?? providerContext.delayDuration;
const wasOpenDelayedRef = React.useRef(false);
const [open, setOpen] = useControllableState({
prop: openProp,
defaultProp: defaultOpen ?? false,
onChange: (open2)=>{
if (open2) {
providerContext.onOpen();
document.dispatchEvent(new CustomEvent(TOOLTIP_OPEN));
} else {
providerContext.onClose();
}
onOpenChange?.(open2);
},
caller: TOOLTIP_NAME
});
const stateAttribute = React.useMemo(()=>{
return open ? wasOpenDelayedRef.current ? "delayed-open" : "instant-open" : "closed";
}, [
open
]);
const handleOpen = React.useCallback(()=>{
window.clearTimeout(openTimerRef.current);
openTimerRef.current = 0;
wasOpenDelayedRef.current = false;
setOpen(true);
}, [
setOpen
]);
const handleClose = React.useCallback(()=>{
window.clearTimeout(openTimerRef.current);
openTimerRef.current = 0;
setOpen(false);
}, [
setOpen
]);
const handleDelayedOpen = React.useCallback(()=>{
window.clearTimeout(openTimerRef.current);
openTimerRef.current = window.setTimeout(()=>{
wasOpenDelayedRef.current = true;
setOpen(true);
openTimerRef.current = 0;
}, delayDuration);
}, [
delayDuration,
setOpen
]);
React.useEffect(()=>{
return ()=>{
if (openTimerRef.current) {
window.clearTimeout(openTimerRef.current);
openTimerRef.current = 0;
}
};
}, []);
return /* @__PURE__ */ jsx(Root2, {
...popperScope,
children: /* @__PURE__ */ jsx(TooltipContextProvider, {
scope: __scopeTooltip,
contentId,
open,
stateAttribute,
trigger,
onTriggerChange: setTrigger,
onTriggerEnter: React.useCallback(()=>{
if (providerContext.isOpenDelayedRef.current) handleDelayedOpen();
else handleOpen();
}, [
providerContext.isOpenDelayedRef,
handleDelayedOpen,
handleOpen
]),
onTriggerLeave: React.useCallback(()=>{
if (disableHoverableContent) {
handleClose();
} else {
window.clearTimeout(openTimerRef.current);
openTimerRef.current = 0;
}
}, [
handleClose,
disableHoverableContent
]),
onOpen: handleOpen,
onClose: handleClose,
disableHoverableContent,
children
})
});
};
Tooltip$1.displayName = TOOLTIP_NAME;
var TRIGGER_NAME = "TooltipTrigger";
var TooltipTrigger$1 = React.forwardRef((props, forwardedRef)=>{
const { __scopeTooltip, ...triggerProps } = props;
const context = useTooltipContext(TRIGGER_NAME, __scopeTooltip);
const providerContext = useTooltipProviderContext(TRIGGER_NAME, __scopeTooltip);
const popperScope = usePopperScope(__scopeTooltip);
const ref = React.useRef(null);
const composedRefs = useComposedRefs(forwardedRef, ref, context.onTriggerChange);
const isPointerDownRef = React.useRef(false);
const hasPointerMoveOpenedRef = React.useRef(false);
const handlePointerUp = React.useCallback(()=>isPointerDownRef.current = false, []);
React.useEffect(()=>{
return ()=>document.removeEventListener("pointerup", handlePointerUp);
}, [
handlePointerUp
]);
return /* @__PURE__ */ jsx(Anchor, {
asChild: true,
...popperScope,
children: /* @__PURE__ */ jsx(Primitive.button, {
"aria-describedby": context.open ? context.contentId : void 0,
"data-state": context.stateAttribute,
...triggerProps,
ref: composedRefs,
onPointerMove: composeEventHandlers(props.onPointerMove, (event)=>{
if (event.pointerType === "touch") return;
if (!hasPointerMoveOpenedRef.current && !providerContext.isPointerInTransitRef.current) {
context.onTriggerEnter();
hasPointerMoveOpenedRef.current = true;
}
}),
onPointerLeave: composeEventHandlers(props.onPointerLeave, ()=>{
context.onTriggerLeave();
hasPointerMoveOpenedRef.current = false;
}),
onPointerDown: composeEventHandlers(props.onPointerDown, ()=>{
if (context.open) {
context.onClose();
}
isPointerDownRef.current = true;
document.addEventListener("pointerup", handlePointerUp, {
once: true
});
}),
onFocus: composeEventHandlers(props.onFocus, ()=>{
if (!isPointerDownRef.current) context.onOpen();
}),
onBlur: composeEventHandlers(props.onBlur, context.onClose),
onClick: composeEventHandlers(props.onClick, context.onClose)
})
});
});
TooltipTrigger$1.displayName = TRIGGER_NAME;
var PORTAL_NAME = "TooltipPortal";
var [PortalProvider, usePortalContext] = createTooltipContext(PORTAL_NAME, {
forceMount: void 0
});
var TooltipPortal = (props)=>{
const { __scopeTooltip, forceMount, children, container } = props;
const context = useTooltipContext(PORTAL_NAME, __scopeTooltip);
return /* @__PURE__ */ jsx(PortalProvider, {
scope: __scopeTooltip,
forceMount,
children: /* @__PURE__ */ jsx(Presence, {
present: forceMount || context.open,
children: /* @__PURE__ */ jsx(Portal$1, {
asChild: true,
container,
children
})
})
});
};
TooltipPortal.displayName = PORTAL_NAME;
var CONTENT_NAME = "TooltipContent";
var TooltipContent$1 = React.forwardRef((props, forwardedRef)=>{
const portalContext = usePortalContext(CONTENT_NAME, props.__scopeTooltip);
const { forceMount = portalContext.forceMount, side = "top", ...contentProps } = props;
const context = useTooltipContext(CONTENT_NAME, props.__scopeTooltip);
return /* @__PURE__ */ jsx(Presence, {
present: forceMount || context.open,
children: context.disableHoverableContent ? /* @__PURE__ */ jsx(TooltipContentImpl, {
side,
...contentProps,
ref: forwardedRef
}) : /* @__PURE__ */ jsx(TooltipContentHoverable, {
side,
...contentProps,
ref: forwardedRef
})
});
});
var TooltipContentHoverable = React.forwardRef((props, forwardedRef)=>{
const context = useTooltipContext(CONTENT_NAME, props.__scopeTooltip);
const providerContext = useTooltipProviderContext(CONTENT_NAME, props.__scopeTooltip);
const ref = React.useRef(null);
const composedRefs = useComposedRefs(forwardedRef, ref);
const [pointerGraceArea, setPointerGraceArea] = React.useState(null);
const { trigger, onClose } = context;
const content = ref.current;
const { onPointerInTransitChange } = providerContext;
const handleRemoveGraceArea = React.useCallback(()=>{
setPointerGraceArea(null);
onPointerInTransitChange(false);
}, [
onPointerInTransitChange
]);
const handleCreateGraceArea = React.useCallback((event, hoverTarget)=>{
const currentTarget = event.currentTarget;
const exitPoint = {
x: event.clientX,
y: event.clientY
};
const exitSide = getExitSideFromRect(exitPoint, currentTarget.getBoundingClientRect());
const paddedExitPoints = getPaddedExitPoints(exitPoint, exitSide);
const hoverTargetPoints = getPointsFromRect(hoverTarget.getBoundingClientRect());
const graceArea = getHull([
...paddedExitPoints,
...hoverTargetPoints
]);
setPointerGraceArea(graceArea);
onPointerInTransitChange(true);
}, [
onPointerInTransitChange
]);
React.useEffect(()=>{
return ()=>handleRemoveGraceArea();
}, [
handleRemoveGraceArea
]);
React.useEffect(()=>{
if (trigger && content) {
const handleTriggerLeave = (event)=>handleCreateGraceArea(event, content);
const handleContentLeave = (event)=>handleCreateGraceArea(event, trigger);
trigger.addEventListener("pointerleave", handleTriggerLeave);
content.addEventListener("pointerleave", handleContentLeave);
return ()=>{
trigger.removeEventListener("pointerleave", handleTriggerLeave);
content.removeEventListener("pointerleave", handleContentLeave);
};
}
}, [
trigger,
content,
handleCreateGraceArea,
handleRemoveGraceArea
]);
React.useEffect(()=>{
if (pointerGraceArea) {
const handleTrackPointerGrace = (event)=>{
const target = event.target;
const pointerPosition = {
x: event.clientX,
y: event.clientY
};
const hasEnteredTarget = trigger?.contains(target) || content?.contains(target);
const isPointerOutsideGraceArea = !isPointInPolygon(pointerPosition, pointerGraceArea);
if (hasEnteredTarget) {
handleRemoveGraceArea();
} else if (isPointerOutsideGraceArea) {
handleRemoveGraceArea();
onClose();
}
};
document.addEventListener("pointermove", handleTrackPointerGrace);
return ()=>document.removeEventListener("pointermove", handleTrackPointerGrace);
}
}, [
trigger,
content,
pointerGraceArea,
onClose,
handleRemoveGraceArea
]);
return /* @__PURE__ */ jsx(TooltipContentImpl, {
...props,
ref: composedRefs
});
});
var [VisuallyHiddenContentContextProvider, useVisuallyHiddenContentContext] = createTooltipContext(TOOLTIP_NAME, {
isInside: false
});
var Slottable = createSlottable("TooltipContent");
var TooltipContentImpl = React.forwardRef((props, forwardedRef)=>{
const { __scopeTooltip, children, "aria-label": ariaLabel, onEscapeKeyDown, onPointerDownOutside, ...contentProps } = props;
const context = useTooltipContext(CONTENT_NAME, __scopeTooltip);
const popperScope = usePopperScope(__scopeTooltip);
const { onClose } = context;
React.useEffect(()=>{
document.addEventListener(TOOLTIP_OPEN, onClose);
return ()=>document.removeEventListener(TOOLTIP_OPEN, onClose);
}, [
onClose
]);
React.useEffect(()=>{
if (context.trigger) {
const handleScroll = (event)=>{
const target = event.target;
if (target?.contains(context.trigger)) onClose();
};
window.addEventListener("scroll", handleScroll, {
capture: true
});
return ()=>window.removeEventListener("scroll", handleScroll, {
capture: true
});
}
}, [
context.trigger,
onClose
]);
return /* @__PURE__ */ jsx(DismissableLayer, {
asChild: true,
disableOutsidePointerEvents: false,
onEscapeKeyDown,
onPointerDownOutside,
onFocusOutside: (event)=>event.preventDefault(),
onDismiss: onClose,
children: /* @__PURE__ */ jsxs(Content, {
"data-state": context.stateAttribute,
...popperScope,
...contentProps,
ref: forwardedRef,
style: {
...contentProps.style,
// re-namespace exposed content custom properties
...{
"--radix-tooltip-content-transform-origin": "var(--radix-popper-transform-origin)",
"--radix-tooltip-content-available-width": "var(--radix-popper-available-width)",
"--radix-tooltip-content-available-height": "var(--radix-popper-available-height)",
"--radix-tooltip-trigger-width": "var(--radix-popper-anchor-width)",
"--radix-tooltip-trigger-height": "var(--radix-popper-anchor-height)"
}
},
children: [
/* @__PURE__ */ jsx(Slottable, {
children
}),
/* @__PURE__ */ jsx(VisuallyHiddenContentContextProvider, {
scope: __scopeTooltip,
isInside: true,
children: /* @__PURE__ */ jsx(Root, {
id: context.contentId,
role: "tooltip",
children: ariaLabel || children
})
})
]
})
});
});
TooltipContent$1.displayName = CONTENT_NAME;
var ARROW_NAME = "TooltipArrow";
var TooltipArrow = React.forwardRef((props, forwardedRef)=>{
const { __scopeTooltip, ...arrowProps } = props;
const popperScope = usePopperScope(__scopeTooltip);
const visuallyHiddenContentContext = useVisuallyHiddenContentContext(ARROW_NAME, __scopeTooltip);
return visuallyHiddenContentContext.isInside ? null : /* @__PURE__ */ jsx(Arrow, {
...popperScope,
...arrowProps,
ref: forwardedRef
});
});
TooltipArrow.displayName = ARROW_NAME;
function getExitSideFromRect(point, rect) {
const top = Math.abs(rect.top - point.y);
const bottom = Math.abs(rect.bottom - point.y);
const right = Math.abs(rect.right - point.x);
const left = Math.abs(rect.left - point.x);
switch(Math.min(top, bottom, right, left)){
case left:
return "left";
case right:
return "right";
case top:
return "top";
case bottom:
return "bottom";
default:
throw new Error("unreachable");
}
}
function getPaddedExitPoints(exitPoint, exitSide, padding = 5) {
const paddedExitPoints = [];
switch(exitSide){
case "top":
paddedExitPoints.push({
x: exitPoint.x - padding,
y: exitPoint.y + padding
}, {
x: exitPoint.x + padding,
y: exitPoint.y + padding
});
break;
case "bottom":
paddedExitPoints.push({
x: exitPoint.x - padding,
y: exitPoint.y - padding
}, {
x: exitPoint.x + padding,
y: exitPoint.y - padding
});
break;
case "left":
paddedExitPoints.push({
x: exitPoint.x + padding,
y: exitPoint.y - padding
}, {
x: exitPoint.x + padding,
y: exitPoint.y + padding
});
break;
case "right":
paddedExitPoints.push({
x: exitPoint.x - padding,
y: exitPoint.y - padding
}, {
x: exitPoint.x - padding,
y: exitPoint.y + padding
});
break;
}
return paddedExitPoints;
}
function getPointsFromRect(rect) {
const { top, right, bottom, left } = rect;
return [
{
x: left,
y: top
},
{
x: right,
y: top
},
{
x: right,
y: bottom
},
{
x: left,
y: bottom
}
];
}
function isPointInPolygon(point, polygon) {
const { x, y } = point;
let inside = false;
for(let i = 0, j = polygon.length - 1; i < polygon.length; j = i++){
const ii = polygon[i];
const jj = polygon[j];
const xi = ii.x;
const yi = ii.y;
const xj = jj.x;
const yj = jj.y;
const intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
if (intersect) inside = !inside;
}
return inside;
}
function getHull(points) {
const newPoints = points.slice();
newPoints.sort((a, b)=>{
if (a.x < b.x) return -1;
else if (a.x > b.x) return 1;
else if (a.y < b.y) return -1;
else if (a.y > b.y) return 1;
else return 0;
});
return getHullPresorted(newPoints);
}
function getHullPresorted(points) {
if (points.length <= 1) return points.slice();
const upperHull = [];
for(let i = 0; i < points.length; i++){
const p = points[i];
while(upperHull.length >= 2){
const q = upperHull[upperHull.length - 1];
const r = upperHull[upperHull.length - 2];
if ((q.x - r.x) * (p.y - r.y) >= (q.y - r.y) * (p.x - r.x)) upperHull.pop();
else break;
}
upperHull.push(p);
}
upperHull.pop();
const lowerHull = [];
for(let i = points.length - 1; i >= 0; i--){
const p = points[i];
while(lowerHull.length >= 2){
const q = lowerHull[lowerHull.length - 1];
const r = lowerHull[lowerHull.length - 2];
if ((q.x - r.x) * (p.y - r.y) >= (q.y - r.y) * (p.x - r.x)) lowerHull.pop();
else break;
}
lowerHull.push(p);
}
lowerHull.pop();
if (upperHull.length === 1 && lowerHull.length === 1 && upperHull[0].x === lowerHull[0].x && upperHull[0].y === lowerHull[0].y) {
return upperHull;
} else {
return upperHull.concat(lowerHull);
}
}
var Provider = TooltipProvider$1;
var Root3 = Tooltip$1;
var Trigger = TooltipTrigger$1;
var Portal = TooltipPortal;
var Content2 = TooltipContent$1;
function TooltipProvider({ delayDuration = 700, ...props }) {
return /*#__PURE__*/ React__default.createElement(Provider, {
"data-slot": "tooltip-provider",
delayDuration: delayDuration,
...props
});
}
function Tooltip({ ...props }) {
return /*#__PURE__*/ React__default.createElement(TooltipProvider, null, /*#__PURE__*/ React__default.createElement(Root3, {
"data-slot": "tooltip",
...props
}));
}
function TooltipTrigger({ ...props }) {
return /*#__PURE__*/ React__default.createElement(Trigger, {
"data-slot": "tooltip-trigger",
...props
});
}
function TooltipContent({ className, sideOffset = 0, children, ...props }) {
return /*#__PURE__*/ React__default.createElement(Portal, null, /*#__PURE__*/ React__default.createElement(Content2, {
"data-slot": "tooltip-content",
sideOffset: sideOffset,
className: cn("bg-popover text-popover-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 overflow-hidden rounded-md px-3 py-1.5 text-sm shadow-md drop-shadow", className),
...props
}, children));
}
export { Tooltip as T, TooltipTrigger as a, TooltipContent as b, TooltipProvider as c };
//# sourceMappingURL=tooltip-BTEGteNb.mjs.map