UNPKG

ivt

Version:

Ivt Components Library

598 lines (594 loc) 22.9 kB
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