@underverse-ui/underverse 2.0.34 → 2.0.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/api-reference.json +1 -1
  2. package/dist/DatePicker-FDOTQMNL.js +15 -0
  3. package/dist/{EmojiPicker-6H52Q4YE.js → EmojiPicker-Z7QPW4DA.js} +5 -4
  4. package/dist/EmojiPicker-Z7QPW4DA.js.map +1 -0
  5. package/dist/chunk-5GMQ23IU.js +719 -0
  6. package/dist/chunk-5GMQ23IU.js.map +1 -0
  7. package/dist/{chunk-L73HBI6E.js → chunk-5VCM2Z7M.js} +6 -4
  8. package/dist/{chunk-L73HBI6E.js.map → chunk-5VCM2Z7M.js.map} +1 -1
  9. package/dist/{chunk-6FAHXNDQ.js → chunk-6XQTRIP6.js} +10 -349
  10. package/dist/chunk-6XQTRIP6.js.map +1 -0
  11. package/dist/chunk-EN33T3LJ.js +358 -0
  12. package/dist/chunk-EN33T3LJ.js.map +1 -0
  13. package/dist/{chunk-UHUKUI5S.js → chunk-JABD2ONI.js} +3 -3
  14. package/dist/chunk-JG3U26V6.js +1692 -0
  15. package/dist/chunk-JG3U26V6.js.map +1 -0
  16. package/dist/{chunk-JYAEYUGM.js → chunk-SCW2XGCE.js} +466 -354
  17. package/dist/chunk-SCW2XGCE.js.map +1 -0
  18. package/dist/{chunk-W3QTP2DM.js → chunk-TSBKJELM.js} +2 -2
  19. package/dist/{chunk-OTPC2OTQ.js → chunk-V4VZZHV7.js} +324 -1031
  20. package/dist/chunk-V4VZZHV7.js.map +1 -0
  21. package/dist/index.cjs +13476 -13310
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +20 -0
  24. package/dist/index.d.ts +20 -0
  25. package/dist/index.js +1942 -3570
  26. package/dist/index.js.map +1 -1
  27. package/dist/{menu-bar-HZBBRX42.js → menu-bar-MX3LXG6T.js} +6 -4
  28. package/dist/{menu-bar-HZBBRX42.js.map → menu-bar-MX3LXG6T.js.map} +1 -1
  29. package/dist/ueditor.cjs +2783 -1101
  30. package/dist/ueditor.cjs.map +1 -1
  31. package/dist/ueditor.d.cts +2 -0
  32. package/dist/ueditor.d.ts +2 -0
  33. package/dist/ueditor.js +6 -4
  34. package/package.json +1 -1
  35. package/dist/chunk-6FAHXNDQ.js.map +0 -1
  36. package/dist/chunk-JYAEYUGM.js.map +0 -1
  37. package/dist/chunk-OTPC2OTQ.js.map +0 -1
  38. /package/dist/{EmojiPicker-6H52Q4YE.js.map → DatePicker-FDOTQMNL.js.map} +0 -0
  39. /package/dist/{chunk-UHUKUI5S.js.map → chunk-JABD2ONI.js.map} +0 -0
  40. /package/dist/{chunk-W3QTP2DM.js.map → chunk-TSBKJELM.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/radius.ts","../src/contexts/UnderverseConfigContext.tsx","../src/utils/animations.ts","../src/components/Popover.tsx"],"sourcesContent":["export const STANDARD_BORDER_MODES = [\"none\", \"sm\", \"md\", \"lg\", \"xl\", \"2xl\", \"3xl\", \"full\"] as const;\n\n// Bản đồ các mode đặc thù theo khách hàng\nexport const CUSTOM_BORDER_MAP = {\n daewoo: \"rounded\",\n infiniq: \"rounded-full\",\n} as const;\n\nexport const BORDER_MODE_DOCS_TYPE = `\"${STANDARD_BORDER_MODES.join('\" | \"')}\" | \"${Object.keys(CUSTOM_BORDER_MAP).join('\" | \"')}\"`;\n\nexport type StandardBorderMode = typeof STANDARD_BORDER_MODES[number];\nexport type CustomBorderMode = keyof typeof CUSTOM_BORDER_MAP;\nexport type BorderMode = StandardBorderMode | CustomBorderMode | (string & {});\n\nexport function getBorderRadiusClass(borderMode: BorderMode | undefined = \"full\") {\n if (!borderMode) return \"rounded-full\";\n\n if (borderMode in CUSTOM_BORDER_MAP) {\n return CUSTOM_BORDER_MAP[borderMode as CustomBorderMode];\n }\n\n if (STANDARD_BORDER_MODES.includes(borderMode as StandardBorderMode)) {\n return `rounded-${borderMode}`;\n }\n\n return borderMode;\n}\n\nexport function getPanelBorderRadiusClass(borderMode: BorderMode | undefined = \"lg\") {\n const resolved = borderMode ?? \"lg\";\n if (resolved === \"full\" || resolved === \"infiniq\") {\n return \"rounded-2xl\";\n }\n return getBorderRadiusClass(resolved);\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport type { BorderMode } from \"../utils/radius\";\n\nexport interface UnderverseUIConfig {\n /** Global default border mode for all components that support it */\n borderMode?: BorderMode;\n button?: {\n borderMode?: BorderMode;\n };\n input?: {\n borderMode?: BorderMode;\n };\n card?: {\n borderMode?: BorderMode;\n };\n table?: {\n borderMode?: BorderMode;\n };\n popover?: {\n borderMode?: BorderMode;\n };\n dropdownMenu?: {\n borderMode?: BorderMode;\n };\n modal?: {\n borderMode?: BorderMode;\n };\n // Future component configs can be added here\n}\n\nconst UnderverseUIConfigContext = React.createContext<UnderverseUIConfig | null>(null);\n\n/** Read the global UI config for Underverse components. */\nexport function useUnderverseUIConfig(): UnderverseUIConfig {\n return React.useContext(UnderverseUIConfigContext) ?? {};\n}\n\nexport interface UnderverseConfigProviderProps {\n children: React.ReactNode;\n config?: UnderverseUIConfig;\n}\n\n/** Provider to configure global default styles/behaviors for Underverse components. */\nexport function UnderverseConfigProvider({ children, config }: UnderverseConfigProviderProps) {\n if (!config) return <>{children}</>;\n return <UnderverseUIConfigContext.Provider value={config}>{children}</UnderverseUIConfigContext.Provider>;\n}\n","/**\n * ShadCN UI Animation Styles - Enhanced with smooth spring-like animations\n *\n * This module provides animation utilities used by Underverse UI components.\n * It can be used standalone or with the useShadCNAnimations hook.\n *\n * @example\n * ```tsx\n * import { useShadCNAnimations } from \"@underverse-ui/underverse\";\n *\n * function MyComponent() {\n * useShadCNAnimations(); // Injects animation styles\n * return <div data-state=\"open\">Animated content</div>;\n * }\n * ```\n */\n\nexport const shadcnAnimationStyles = `\n /* ============================================\n * DROPDOWN / POPOVER ANIMATIONS\n * Uses spring-like cubic-bezier for natural feel\n * ============================================ */\n \n /* Native-like Combobox Animation - Mimics browser default select */\n [data-state=\"open\"][data-combobox-dropdown] {\n animation: comboboxOpen 150ms cubic-bezier(0.2, 0, 0, 1);\n transform-origin: top center;\n }\n\n [data-state=\"closed\"][data-combobox-dropdown] {\n animation: comboboxClose 120ms cubic-bezier(0.4, 0, 1, 1);\n transform-origin: top center;\n }\n\n @keyframes comboboxOpen {\n 0% {\n opacity: 0;\n transform: translateY(-4px) scaleY(0.9);\n }\n 100% {\n opacity: 1;\n transform: translateY(0) scaleY(1);\n }\n }\n\n @keyframes comboboxClose {\n 0% {\n opacity: 1;\n transform: translateY(0) scaleY(1);\n }\n 100% {\n opacity: 0;\n transform: translateY(-4px) scaleY(0.9);\n }\n }\n\n /* Generic dropdown open/close */\n [data-state=\"open\"] {\n animation: slideDownAndFade 220ms cubic-bezier(0.16, 1, 0.3, 1);\n }\n \n [data-state=\"closed\"] {\n animation: slideUpAndFade 180ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n @keyframes slideDownAndFade {\n from {\n opacity: 0;\n transform: translateY(-4px) scale(0.98);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n \n @keyframes slideUpAndFade {\n from {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n to {\n opacity: 0;\n transform: translateY(-4px) scale(0.98);\n }\n }\n \n /* ============================================\n * DROPDOWN ITEMS - Native-like instant appearance\n * ============================================ */\n\n /* Fast staggered animation for native feel */\n .dropdown-item {\n opacity: 0;\n animation: itemFadeIn 120ms cubic-bezier(0.2, 0, 0, 1) forwards;\n }\n\n @keyframes itemFadeIn {\n from {\n opacity: 0;\n transform: translateX(-4px);\n }\n to {\n opacity: 1;\n transform: translateX(0);\n }\n }\n\n /* Item stagger delays - minimal for speed */\n .dropdown-item:nth-child(1) { animation-delay: 0ms; }\n .dropdown-item:nth-child(2) { animation-delay: 15ms; }\n .dropdown-item:nth-child(3) { animation-delay: 30ms; }\n .dropdown-item:nth-child(4) { animation-delay: 45ms; }\n .dropdown-item:nth-child(5) { animation-delay: 60ms; }\n .dropdown-item:nth-child(6) { animation-delay: 75ms; }\n .dropdown-item:nth-child(7) { animation-delay: 90ms; }\n .dropdown-item:nth-child(8) { animation-delay: 105ms; }\n .dropdown-item:nth-child(n+9) { animation-delay: 120ms; }\n\n /* ============================================\n * DATEPICKER ANIMATIONS\n * ============================================ */\n\n .datepicker-day {\n opacity: 0;\n animation: dayFadeIn 200ms cubic-bezier(0.16, 1, 0.3, 1) forwards;\n }\n\n @keyframes dayFadeIn {\n from {\n opacity: 0;\n transform: scale(0.8);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n }\n\n /* ============================================\n * TOOLTIP ANIMATIONS\n * ============================================ */\n\n [data-tooltip] {\n animation: tooltipIn 150ms cubic-bezier(0.16, 1, 0.3, 1);\n }\n\n @keyframes tooltipIn {\n from {\n opacity: 0;\n transform: scale(0.95);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n }\n\n /* ============================================\n * MODAL / DIALOG ANIMATIONS\n * ============================================ */\n\n .modal-content {\n animation: scaleIn 200ms cubic-bezier(0.34, 1.56, 0.64, 1);\n }\n \n @keyframes scaleIn {\n from {\n opacity: 0;\n transform: scale(0.9);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n }\n \n /* Smooth backdrop blur transition */\n .backdrop-animate {\n transition: backdrop-filter 200ms ease, background-color 200ms ease;\n }\n`;\n\n/**\n * Hook to inject ShadCN animation styles into the document head.\n * Call this hook in components that need animations.\n * The styles are only injected once, even if called multiple times.\n *\n * @example\n * ```tsx\n * function Dropdown() {\n * useShadCNAnimations();\n * return <div data-state=\"open\">...</div>;\n * }\n * ```\n */\nfunction ensureAnimationStylesInjected(targetDocument?: Document): void {\n const resolvedDocument = targetDocument ?? (typeof document !== \"undefined\" ? document : undefined);\n if (resolvedDocument) {\n const styleId = \"shadcn-animations\";\n if (!resolvedDocument.getElementById(styleId)) {\n const styleElement = resolvedDocument.createElement(\"style\");\n styleElement.id = styleId;\n styleElement.textContent = shadcnAnimationStyles;\n resolvedDocument.head.appendChild(styleElement);\n }\n }\n}\n\nexport function useShadCNAnimations(targetDocument?: Document | null): void {\n useEffect(() => {\n if (targetDocument === null) return;\n ensureAnimationStylesInjected(targetDocument);\n }, [targetDocument]);\n}\n\n/**\n * Manually inject animation styles.\n * Useful for non-React environments or SSR.\n */\nexport function injectAnimationStyles(targetDocument?: Document): void {\n ensureAnimationStylesInjected(targetDocument);\n}\n\n/**\n * Get the animation styles as a string.\n * Useful for including in a style tag or CSS file.\n */\nexport function getAnimationStyles(): string {\n return shadcnAnimationStyles;\n}\nimport { useEffect } from \"react\";\n","\"use client\";\n\n/* eslint-disable react-hooks/refs -- Popover composes child refs and updates them only from ref/event callbacks; the compiler cannot prove that cloneElement defers those callbacks. */\n\nimport * as React from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"../utils/cn\";\nimport { useShadCNAnimations } from \"../utils/animations\";\nimport { chainEventHandlers, mergeRefs } from \"../utils/react-compose\";\nimport { getBorderRadiusClass, getPanelBorderRadiusClass, type BorderMode } from \"../utils/radius\";\nimport { useUnderverseUIConfig } from \"../contexts/UnderverseConfigContext\";\nimport { resolveUEditorPortalContainer, useUEditorPortalContainerGetter } from \"./UEditor/portal-context\";\n\nexport type PopoverPlacement = \"top\" | \"bottom\" | \"left\" | \"right\" | \"top-start\" | \"bottom-start\" | \"top-end\" | \"bottom-end\";\n\n/** Public props for the `Popover` component. */\nexport interface PopoverProps {\n trigger: React.ReactElement;\n children: React.ReactNode;\n className?: string;\n contentClassName?: string;\n contentProps?: React.HTMLAttributes<HTMLDivElement>;\n contentScrollable?: boolean;\n placement?: PopoverPlacement;\n modal?: boolean;\n disabled?: boolean;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n matchTriggerWidth?: boolean;\n contentWidth?: number; // optional fixed width\n borderMode?: BorderMode;\n /** Resolve the document element that should receive the portal. */\n getPortalContainer?: () => HTMLElement | null;\n /** Constrain vertical placement and height to the largest available viewport side. */\n constrainToAvailableHeight?: boolean;\n}\n\ntype Side = \"top\" | \"bottom\" | \"left\" | \"right\";\ntype Align = \"start\" | \"end\";\n\nfunction getTransformOrigin(side: Side, align: Align) {\n if (side === \"top\") return `${align === \"end\" ? \"right\" : \"left\"} bottom`;\n if (side === \"bottom\") return `${align === \"end\" ? \"right\" : \"left\"} top`;\n if (side === \"left\") return \"right top\";\n return \"left top\";\n}\n\nfunction normalizePlacement(placement: PopoverPlacement): { side: Side; align: Align } {\n switch (placement) {\n case \"top\":\n return { side: \"top\", align: \"start\" };\n case \"bottom\":\n return { side: \"bottom\", align: \"start\" };\n case \"left\":\n return { side: \"left\", align: \"start\" };\n case \"right\":\n return { side: \"right\", align: \"start\" };\n default: {\n const [side, align] = placement.split(\"-\") as [Side, Align];\n return { side, align };\n }\n }\n}\n\nconst clamp = (value: number, min: number, max: number) => Math.max(min, Math.min(max, value));\n\nfunction overflowAmount(left: number, width: number, viewportWidth: number, padding: number) {\n const min = padding;\n const max = viewportWidth - padding;\n const overflowLeft = Math.max(0, min - left);\n const overflowRight = Math.max(0, left + width - max);\n return overflowLeft + overflowRight;\n}\n\nfunction getScrollAncestors(trigger: HTMLElement, ownerWindow: Window) {\n const ancestors: HTMLElement[] = [];\n let current = trigger.parentElement;\n\n while (current) {\n try {\n const style = ownerWindow.getComputedStyle(current);\n const overflow = `${style.overflow} ${style.overflowX} ${style.overflowY}`;\n // Include hidden because those elements can still be scrolled programmatically.\n if (/(auto|scroll|overlay|hidden)/.test(overflow)) ancestors.push(current);\n } catch {\n // A detached/cross-realm node will be handled by the guarded position update.\n }\n current = current.parentElement;\n }\n\n return ancestors;\n}\n\nfunction isFiniteRect(rect: DOMRect) {\n return [rect.top, rect.right, rect.bottom, rect.left, rect.width, rect.height].every(Number.isFinite);\n}\n\nfunction isFullyOutsideViewport(rect: DOMRect, viewportWidth: number, viewportHeight: number) {\n return rect.bottom < 0 || rect.right < 0 || rect.top > viewportHeight || rect.left > viewportWidth;\n}\n\nfunction computePopoverPosition(args: {\n triggerRect: DOMRect;\n contentSize: { width: number; height: number };\n placement: PopoverPlacement;\n offset: number;\n padding: number;\n viewport: { width: number; height: number };\n constrainToAvailableHeight: boolean;\n}): { top: number; left: number; side: Side; align: Align; availableHeight: number } {\n const { triggerRect, contentSize, placement, offset, padding, viewport, constrainToAvailableHeight } = args;\n let { side, align } = normalizePlacement(placement);\n\n const availableBelow = Math.max(0, viewport.height - padding - triggerRect.bottom - offset);\n const availableAbove = Math.max(0, triggerRect.top - padding - offset);\n\n // Keep the preferred vertical side whenever its full content fits. If neither\n // side fits, choose the side with more usable popup-window viewport space.\n if (side === \"bottom\") {\n if (constrainToAvailableHeight) {\n if (contentSize.height > availableBelow && availableAbove > availableBelow) side = \"top\";\n } else {\n const bottomTop = triggerRect.bottom + offset;\n const overflowsBottom = bottomTop + contentSize.height > viewport.height - padding;\n const topTop = triggerRect.top - offset - contentSize.height;\n const fitsTop = topTop >= padding;\n if (overflowsBottom && fitsTop) side = \"top\";\n }\n } else if (side === \"top\") {\n if (constrainToAvailableHeight) {\n if (contentSize.height > availableAbove && availableBelow > availableAbove) side = \"bottom\";\n } else {\n const topTop = triggerRect.top - offset - contentSize.height;\n const overflowsTop = topTop < padding;\n const bottomTop = triggerRect.bottom + offset;\n const fitsBottom = bottomTop + contentSize.height <= viewport.height - padding;\n if (overflowsTop && fitsBottom) side = \"bottom\";\n }\n } else if (side === \"right\") {\n const rightLeft = triggerRect.right + offset;\n const overflowsRight = rightLeft + contentSize.width > viewport.width - padding;\n const leftLeft = triggerRect.left - offset - contentSize.width;\n const fitsLeft = leftLeft >= padding;\n if (overflowsRight && fitsLeft) side = \"left\";\n } else if (side === \"left\") {\n const leftLeft = triggerRect.left - offset - contentSize.width;\n const overflowsLeft = leftLeft < padding;\n const rightLeft = triggerRect.right + offset;\n const fitsRight = rightLeft + contentSize.width <= viewport.width - padding;\n if (overflowsLeft && fitsRight) side = \"right\";\n }\n\n let top = 0;\n let left = 0;\n\n if (side === \"top\" || side === \"bottom\") {\n const leftStart = triggerRect.left;\n const leftEnd = triggerRect.right - contentSize.width;\n\n // If requested align overflows, choose the alternative align if it fits better.\n const startOverflow = overflowAmount(leftStart, contentSize.width, viewport.width, padding);\n const endOverflow = overflowAmount(leftEnd, contentSize.width, viewport.width, padding);\n if (align === \"start\" && startOverflow > 0 && endOverflow < startOverflow) align = \"end\";\n if (align === \"end\" && endOverflow > 0 && startOverflow < endOverflow) align = \"start\";\n\n left = align === \"end\" ? leftEnd : leftStart;\n const availableHeight = side === \"top\" ? availableAbove : availableBelow;\n const renderedHeight = constrainToAvailableHeight\n ? Math.min(contentSize.height, availableHeight)\n : contentSize.height;\n top = side === \"top\" ? triggerRect.top - offset - renderedHeight : triggerRect.bottom + offset;\n\n left = clamp(left, padding, viewport.width - contentSize.width - padding);\n top = clamp(top, padding, viewport.height - renderedHeight - padding);\n\n return { top, left, side, align, availableHeight };\n }\n\n // Left/right placements: align to trigger top by default and clamp to viewport.\n top = triggerRect.top;\n left = side === \"left\" ? triggerRect.left - offset - contentSize.width : triggerRect.right + offset;\n left = clamp(left, padding, viewport.width - contentSize.width - padding);\n top = clamp(top, padding, viewport.height - contentSize.height - padding);\n\n return { top, left, side, align, availableHeight: Math.max(0, viewport.height - padding * 2) };\n}\n\nexport const Popover: React.FC<PopoverProps> = ({\n trigger,\n children,\n className,\n contentClassName,\n contentProps,\n contentScrollable = false,\n placement = \"bottom\",\n modal = false,\n disabled = false,\n open,\n onOpenChange,\n matchTriggerWidth = false,\n contentWidth,\n borderMode,\n getPortalContainer,\n constrainToAvailableHeight = false,\n}) => {\n const isControlled = open !== undefined;\n const [internalOpen, setInternalOpen] = React.useState(false);\n const triggerRef = React.useRef<HTMLElement>(null);\n const [triggerDocument, setTriggerDocument] = React.useState<Document | null>(null);\n const positionerRef = React.useRef<HTMLDivElement>(null);\n const panelRef = React.useRef<HTMLDivElement>(null);\n const pendingFrameRef = React.useRef<{ ownerWindow: Window; frameId: number } | null>(null);\n const closeRequestedRef = React.useRef(false);\n const lastAppliedRef = React.useRef<{\n positioner: HTMLDivElement;\n top: number;\n left: number;\n side: Side;\n align: Align;\n width?: number;\n availableHeight: number;\n } | null>(null);\n \n const globalConfig = useUnderverseUIConfig();\n const resolvedBorderMode = borderMode ?? globalConfig.popover?.borderMode ?? globalConfig.borderMode;\n\n const isOpen = isControlled ? (open as boolean) : internalOpen;\n const contextGetPortalContainer = useUEditorPortalContainerGetter();\n const requestedPortalContainer = isOpen && triggerDocument\n ? resolveUEditorPortalContainer(getPortalContainer, contextGetPortalContainer, triggerDocument)\n : null;\n // Fixed-position coordinates only share a coordinate system inside the trigger's document.\n // If a stale getter points at the opener document, fall back to the trigger document instead.\n const portalContainer = requestedPortalContainer?.ownerDocument === triggerDocument\n ? requestedPortalContainer\n : triggerDocument?.body ?? null;\n\n // Inject animations into the document that actually renders the overlay.\n useShadCNAnimations(isOpen ? triggerDocument : null);\n const setIsOpen = React.useCallback(\n (next: boolean) => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange],\n );\n\n const offset = 4;\n const padding = 8;\n const initialPlacement = React.useMemo(() => normalizePlacement(placement), [placement]);\n\n const cancelScheduledPositionUpdate = React.useCallback(() => {\n const pending = pendingFrameRef.current;\n if (!pending) return;\n pendingFrameRef.current = null;\n try {\n pending.ownerWindow.cancelAnimationFrame(pending.frameId);\n } catch {\n // The popup window may have closed before React cleanup ran.\n }\n }, []);\n\n const closeWhenPositioningIsUnsafe = React.useCallback(() => {\n const positionerEl = positionerRef.current;\n if (positionerEl) {\n positionerEl.style.visibility = \"hidden\";\n positionerEl.style.pointerEvents = \"none\";\n }\n if (closeRequestedRef.current) return;\n closeRequestedRef.current = true;\n setIsOpen(false);\n }, [setIsOpen]);\n\n const updatePosition = React.useCallback(() => {\n const triggerEl = triggerRef.current;\n const positionerEl = positionerRef.current;\n const panelEl = panelRef.current;\n if (!triggerEl || !positionerEl || !panelEl) return;\n\n const ownerDocument = triggerEl.ownerDocument;\n const ownerWindow = ownerDocument.defaultView;\n if (\n !ownerWindow ||\n ownerWindow.closed ||\n !triggerEl.isConnected ||\n !positionerEl.isConnected ||\n positionerEl.ownerDocument !== ownerDocument ||\n panelEl.ownerDocument !== ownerDocument\n ) {\n closeWhenPositioningIsUnsafe();\n return;\n }\n\n const contentEl = panelEl.firstElementChild as HTMLElement | null;\n if (!contentEl) {\n closeWhenPositioningIsUnsafe();\n return;\n }\n\n try {\n // For position: fixed, getBoundingClientRect() is already in viewport coordinates.\n // Do not add pageXOffset/pageYOffset; doing so breaks nested scrolling and CSS zoom.\n const triggerRect = triggerEl.getBoundingClientRect();\n const viewportWidth = ownerWindow.innerWidth;\n const viewportHeight = ownerWindow.innerHeight;\n if (\n !isFiniteRect(triggerRect) ||\n !Number.isFinite(viewportWidth) ||\n !Number.isFinite(viewportHeight) ||\n viewportWidth <= 0 ||\n viewportHeight <= 0 ||\n isFullyOutsideViewport(triggerRect, viewportWidth, viewportHeight)\n ) {\n closeWhenPositioningIsUnsafe();\n return;\n }\n\n const widthWanted = matchTriggerWidth ? triggerRect.width : contentWidth;\n const widthPx = widthWanted == null ? undefined : Math.max(0, Math.round(widthWanted));\n\n if (widthPx == null) {\n if (positionerEl.style.width) positionerEl.style.width = \"\";\n } else if (positionerEl.style.width !== `${widthPx}px`) {\n positionerEl.style.width = `${widthPx}px`;\n }\n\n // Use offset sizes to avoid transform-based measurement jitter during open animations.\n const prevApplied = lastAppliedRef.current;\n const measuredWidth = positionerEl.offsetWidth;\n const measuredHeight = positionerEl.offsetHeight;\n const contentRect = positionerEl.getBoundingClientRect();\n const contentBoxWidth = measuredWidth || contentRect.width;\n const contentBoxHeight = Math.max(measuredHeight, contentRect.height);\n\n const next = computePopoverPosition({\n triggerRect,\n contentSize: { width: contentBoxWidth, height: contentBoxHeight },\n placement,\n offset,\n padding,\n viewport: {\n width: viewportWidth,\n height: viewportHeight,\n },\n constrainToAvailableHeight,\n });\n\n const top = Math.round(next.top);\n const left = Math.round(next.left);\n\n const applied =\n prevApplied &&\n prevApplied.positioner === positionerEl &&\n Math.abs(prevApplied.top - top) < 0.5 &&\n Math.abs(prevApplied.left - left) < 0.5 &&\n prevApplied.side === next.side &&\n prevApplied.align === next.align &&\n prevApplied.width === widthPx &&\n prevApplied.availableHeight === next.availableHeight;\n if (applied) return;\n\n lastAppliedRef.current = {\n positioner: positionerEl,\n top,\n left,\n side: next.side,\n align: next.align,\n width: widthPx,\n availableHeight: next.availableHeight,\n };\n\n positionerEl.style.transform = `translate3d(${left}px, ${top}px, 0)`;\n positionerEl.style.setProperty(\"--underverse-popover-available-height\", `${next.availableHeight}px`);\n positionerEl.dataset.side = next.side;\n positionerEl.dataset.align = next.align;\n panelEl.style.transformOrigin = getTransformOrigin(next.side, next.align);\n if (positionerEl.style.visibility !== \"visible\") positionerEl.style.visibility = \"visible\";\n if (positionerEl.style.pointerEvents !== \"auto\") positionerEl.style.pointerEvents = \"auto\";\n } catch {\n closeWhenPositioningIsUnsafe();\n }\n }, [placement, matchTriggerWidth, contentWidth, constrainToAvailableHeight, closeWhenPositioningIsUnsafe]);\n\n const schedulePositionUpdate = React.useCallback(() => {\n if (pendingFrameRef.current) return;\n const triggerEl = triggerRef.current;\n const ownerWindow = triggerEl?.ownerDocument.defaultView;\n if (!triggerEl || !ownerWindow || ownerWindow.closed) {\n closeWhenPositioningIsUnsafe();\n return;\n }\n\n try {\n const frameId = ownerWindow.requestAnimationFrame(() => {\n pendingFrameRef.current = null;\n updatePosition();\n });\n pendingFrameRef.current = { ownerWindow, frameId };\n } catch {\n closeWhenPositioningIsUnsafe();\n }\n }, [closeWhenPositioningIsUnsafe, updatePosition]);\n\n // Reset transient positioning state before open effects subscribe.\n React.useLayoutEffect(() => {\n if (isOpen) {\n closeRequestedRef.current = false;\n return;\n }\n lastAppliedRef.current = null;\n cancelScheduledPositionUpdate();\n }, [cancelScheduledPositionUpdate, isOpen]);\n\n // Compute a stable position before the first paint when opening.\n React.useLayoutEffect(() => {\n if (!isOpen || !portalContainer) return;\n updatePosition();\n schedulePositionUpdate();\n return cancelScheduledPositionUpdate;\n }, [cancelScheduledPositionUpdate, isOpen, portalContainer, schedulePositionUpdate, updatePosition]);\n\n // Use one owner-window RAF for every scroll/resize/observer notification.\n React.useEffect(() => {\n const triggerEl = triggerRef.current;\n const positionerEl = positionerRef.current;\n if (!isOpen || !triggerEl || !positionerEl || !portalContainer) return;\n\n const ownerDocument = triggerEl.ownerDocument;\n const ownerWindow = ownerDocument.defaultView;\n if (!ownerWindow || ownerWindow.closed || portalContainer.ownerDocument !== ownerDocument) {\n closeWhenPositioningIsUnsafe();\n return;\n }\n\n const scrollAncestors = getScrollAncestors(triggerEl, ownerWindow);\n const passiveOptions: AddEventListenerOptions = { passive: true };\n for (const ancestor of scrollAncestors) {\n ancestor.addEventListener(\"scroll\", schedulePositionUpdate, passiveOptions);\n }\n ownerWindow.addEventListener(\"scroll\", schedulePositionUpdate, passiveOptions);\n ownerWindow.addEventListener(\"resize\", schedulePositionUpdate);\n // Capture is a safety net for scrollable ancestors whose overflow changes while open.\n ownerDocument.addEventListener(\"scroll\", schedulePositionUpdate, { capture: true, passive: true });\n\n const visualViewport = ownerWindow.visualViewport;\n visualViewport?.addEventListener(\"scroll\", schedulePositionUpdate, passiveOptions);\n visualViewport?.addEventListener(\"resize\", schedulePositionUpdate);\n\n const ResizeObserverCtor = ownerWindow.ResizeObserver;\n const resizeObserver = ResizeObserverCtor\n ? new ResizeObserverCtor(schedulePositionUpdate)\n : null;\n resizeObserver?.observe(triggerEl);\n resizeObserver?.observe(positionerEl);\n const contentEl = panelRef.current?.firstElementChild;\n if (contentEl) resizeObserver?.observe(contentEl);\n\n const MutationObserverCtor = ownerWindow.MutationObserver;\n const mutationObserver = MutationObserverCtor\n ? new MutationObserverCtor(() => {\n const currentTrigger = triggerRef.current;\n if (!currentTrigger || !currentTrigger.isConnected || currentTrigger.ownerDocument !== ownerDocument) {\n closeWhenPositioningIsUnsafe();\n }\n })\n : null;\n if (mutationObserver && ownerDocument.documentElement) {\n mutationObserver.observe(ownerDocument.documentElement, { childList: true, subtree: true });\n }\n\n schedulePositionUpdate();\n\n return () => {\n for (const ancestor of scrollAncestors) {\n ancestor.removeEventListener(\"scroll\", schedulePositionUpdate);\n }\n ownerWindow.removeEventListener(\"scroll\", schedulePositionUpdate);\n ownerWindow.removeEventListener(\"resize\", schedulePositionUpdate);\n ownerDocument.removeEventListener(\"scroll\", schedulePositionUpdate, true);\n visualViewport?.removeEventListener(\"scroll\", schedulePositionUpdate);\n visualViewport?.removeEventListener(\"resize\", schedulePositionUpdate);\n resizeObserver?.disconnect();\n mutationObserver?.disconnect();\n cancelScheduledPositionUpdate();\n };\n }, [\n cancelScheduledPositionUpdate,\n closeWhenPositioningIsUnsafe,\n isOpen,\n portalContainer,\n schedulePositionUpdate,\n ]);\n\n // Handle clicks outside\n React.useEffect(() => {\n const triggerEl = triggerRef.current;\n if (!isOpen || !triggerEl || !portalContainer) return;\n const ownerDocument = triggerEl.ownerDocument;\n const ownerWindow = ownerDocument.defaultView;\n if (!ownerWindow || portalContainer.ownerDocument !== ownerDocument) {\n closeWhenPositioningIsUnsafe();\n return;\n }\n\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target as Node;\n const currentTrigger = triggerRef.current;\n const popoverEl = positionerRef.current;\n if (!currentTrigger || !popoverEl) return;\n if (currentTrigger.contains(target)) return;\n if (popoverEl.contains(target)) return;\n if (target instanceof ownerWindow.Element && target.closest(\"[data-popover]\")) return;\n setIsOpen(false);\n };\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n setIsOpen(false);\n }\n };\n\n ownerDocument.addEventListener(\"mousedown\", handleClickOutside);\n ownerDocument.addEventListener(\"keydown\", handleEscape);\n\n return () => {\n ownerDocument.removeEventListener(\"mousedown\", handleClickOutside);\n ownerDocument.removeEventListener(\"keydown\", handleEscape);\n };\n }, [closeWhenPositioningIsUnsafe, isOpen, portalContainer, setIsOpen]);\n\n const handleTriggerClick = () => {\n if (!disabled) {\n setIsOpen(!isOpen);\n }\n };\n\n const triggerProps = trigger.props as React.HTMLAttributes<HTMLElement> & {\n ref?: React.Ref<HTMLElement>;\n \"aria-haspopup\"?: React.AriaAttributes[\"aria-haspopup\"];\n };\n const childRef = triggerProps.ref;\n const setTriggerNode = React.useCallback((node: HTMLElement | null) => {\n triggerRef.current = node;\n if (node) {\n setTriggerDocument((currentDocument) => currentDocument === node.ownerDocument ? currentDocument : node.ownerDocument);\n }\n }, []);\n const composedTriggerRef = React.useMemo(\n () => mergeRefs<HTMLElement>(childRef, setTriggerNode),\n [childRef, setTriggerNode],\n );\n\n const popoverContent =\n isOpen && portalContainer\n ? createPortal(\n <div\n ref={positionerRef}\n data-popover\n style={{\n position: \"fixed\",\n top: 0,\n left: 0,\n transform: \"translate3d(0, 0, 0)\",\n zIndex: 99999,\n visibility: \"hidden\",\n pointerEvents: \"none\",\n willChange: \"transform\",\n }}\n className=\"z-[99999]\"\n >\n <div\n ref={panelRef}\n data-state=\"open\"\n role={modal ? \"dialog\" : undefined}\n aria-modal={modal || undefined}\n style={{\n transformOrigin: getTransformOrigin(initialPlacement.side, initialPlacement.align),\n }}\n className={cn(\n // shadcn-like enter animation\n \"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95\",\n className,\n )}\n >\n <div\n {...contentProps}\n \n className={cn(\n resolvedBorderMode ? getPanelBorderRadiusClass(resolvedBorderMode) : \"rounded-2xl md:rounded-3xl\",\n \"border bg-popover text-popover-foreground shadow-md\",\n \"backdrop-blur-sm bg-popover/95 border-border/60 p-4\",\n contentProps?.className,\n contentClassName,\n )}\n tabIndex={contentProps?.tabIndex ?? -1}\n >\n {children}\n </div>\n </div>\n </div>,\n portalContainer,\n )\n : null;\n\n return (\n <>\n {(() => {\n return React.cloneElement(trigger as React.ReactElement<any>, {\n ...triggerProps,\n ref: composedTriggerRef,\n onClick: chainEventHandlers<React.MouseEvent<HTMLElement>>(\n (e) => {\n triggerRef.current = e.currentTarget as HTMLElement;\n e.preventDefault();\n e.stopPropagation();\n handleTriggerClick();\n },\n triggerProps.onClick,\n ),\n onFocus: chainEventHandlers<React.FocusEvent<HTMLElement>>(\n (e) => {\n triggerRef.current = e.currentTarget as HTMLElement;\n },\n triggerProps.onFocus,\n ),\n \"aria-expanded\": isOpen,\n \"aria-haspopup\": triggerProps[\"aria-haspopup\"] ?? \"dialog\",\n });\n })()}\n {popoverContent}\n </>\n );\n};\n"],"mappings":"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","names":["React","Fragment","jsx"]}
@@ -1,15 +1,17 @@
1
1
  import {
2
2
  EmojiGridButton
3
- } from "./chunk-W3QTP2DM.js";
3
+ } from "./chunk-TSBKJELM.js";
4
4
  import {
5
5
  EMOJI_LIST
6
6
  } from "./chunk-4TYW5K4J.js";
7
7
  import {
8
- Tooltip,
8
+ Tooltip
9
+ } from "./chunk-EN33T3LJ.js";
10
+ import {
9
11
  cn,
10
12
  formControlOutlineClass,
11
13
  useSmartTranslations
12
- } from "./chunk-6FAHXNDQ.js";
14
+ } from "./chunk-6XQTRIP6.js";
13
15
 
14
16
  // src/components/EmojiPicker.tsx
15
17
  import { useEffect, useMemo, useRef, useState } from "react";
@@ -205,4 +207,4 @@ export {
205
207
  EmojiPicker,
206
208
  EmojiPicker_default
207
209
  };
208
- //# sourceMappingURL=chunk-L73HBI6E.js.map
210
+ //# sourceMappingURL=chunk-5VCM2Z7M.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/EmojiPicker.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport { Search, X, Smile, Leaf, Utensils, Dumbbell, Lightbulb, Hash, Flag } from \"lucide-react\";\nimport { useSmartTranslations } from \"../hooks/useSmartTranslations\";\nimport { cn } from \"../utils/cn\";\nimport { EmojiGridButton } from \"./emoji-ui\";\nimport { Tooltip } from \"./Tooltip\";\nimport { EMOJI_LIST } from \"./UEditor/emojis\";\nimport { formControlOutlineClass } from \"../constants/form-control-size\";\n\n/** Public props for the `EmojiPicker` component. */\nexport interface EmojiPickerProps {\n onEmojiSelect: (emoji: string) => void;\n className?: string;\n searchPlaceholder?: string;\n emptyText?: string;\n emptyHint?: string;\n showSearch?: boolean;\n showCategoryNav?: boolean;\n columns?: number;\n maxHeight?: string;\n chrome?: \"standalone\" | \"embedded\";\n}\n\nconst CATEGORY_ICONS: Record<string, React.ComponentType<{ className?: string }>> = {\n smileys_people: Smile,\n animals_nature: Leaf,\n food_drink: Utensils,\n activity: Dumbbell,\n objects: Lightbulb,\n symbols: Hash,\n flags: Flag,\n};\n\nexport const EmojiPicker: React.FC<EmojiPickerProps> = ({\n onEmojiSelect,\n className,\n searchPlaceholder,\n emptyText,\n emptyHint,\n showSearch = true,\n showCategoryNav = true,\n columns = 9,\n maxHeight = \"20rem\",\n chrome = \"standalone\",\n}) => {\n const t = useSmartTranslations(\"UEditor\");\n const [search, setSearch] = useState(\"\");\n const [activeCategory, setActiveCategory] = useState(EMOJI_LIST[0]?.id || \"\");\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n const categoryRefs = useRef<Record<string, HTMLDivElement | null>>({});\n const isUserScrolling = useRef(false);\n \n const resolvedSearchPlaceholder = searchPlaceholder ?? t(\"emojiPicker.searchPlaceholder\");\n const resolvedEmptyText = emptyText ?? t(\"emojiPicker.noResults\");\n const resolvedEmptyHint = emptyHint ?? t(\"emojiPicker.tryDifferentSearch\");\n const resolvedColumns = Math.max(1, Math.floor(columns));\n const isEmbedded = chrome === \"embedded\";\n \n const gridStyle = {\n gridTemplateColumns: `repeat(${resolvedColumns}, minmax(0, 1fr))`,\n } satisfies React.CSSProperties;\n\n const filteredCategories = useMemo(() => {\n if (!search.trim()) return EMOJI_LIST;\n\n const query = search.toLowerCase();\n return EMOJI_LIST.map((category) => ({\n ...category,\n emojis: category.emojis.filter((emoji) => emoji.name.toLowerCase().includes(query) || emoji.emoji.includes(search)),\n })).filter((category) => category.emojis.length > 0);\n }, [search]);\n\n useEffect(() => {\n if (search) return;\n\n const container = scrollContainerRef.current;\n if (!container) return;\n\n const handleScroll = () => {\n if (!isUserScrolling.current) return;\n\n let maxVisibility = 0;\n let mostVisibleCategory = EMOJI_LIST[0]?.id || \"\";\n\n EMOJI_LIST.forEach((category) => {\n const element = categoryRefs.current[category.id];\n if (!element) return;\n\n const rect = element.getBoundingClientRect();\n const containerRect = container.getBoundingClientRect();\n const visibleTop = Math.max(rect.top, containerRect.top);\n const visibleBottom = Math.min(rect.bottom, containerRect.bottom);\n const visibleHeight = Math.max(0, visibleBottom - visibleTop);\n\n if (visibleHeight > maxVisibility) {\n maxVisibility = visibleHeight;\n mostVisibleCategory = category.id;\n }\n });\n\n if (mostVisibleCategory !== activeCategory) {\n setActiveCategory(mostVisibleCategory);\n }\n };\n\n container.addEventListener(\"scroll\", handleScroll);\n return () => container.removeEventListener(\"scroll\", handleScroll);\n }, [activeCategory, search]);\n\n useEffect(() => {\n isUserScrolling.current = true;\n }, []);\n\n const renderEmojiCategory = (category: (typeof EMOJI_LIST)[number], assignRef = false) => (\n <div\n key={category.id}\n ref={\n assignRef\n ? (el) => {\n categoryRefs.current[category.id] = el;\n }\n : undefined\n }\n className=\"scroll-mt-3 mb-2\"\n >\n <div className=\"sticky top-0 z-10 bg-card/85 backdrop-blur-md py-1.5 px-2 text-[10px] font-bold uppercase tracking-wider text-muted-foreground/90 border-b border-border/5 mb-2 flex items-center gap-1.5 rounded-lg select-none\">\n <span className=\"w-1.5 h-1.5 rounded-full bg-primary/70 animate-pulse\" />\n {category.name}\n </div>\n <div className=\"grid gap-1.5 p-1\" style={gridStyle}>\n {category.emojis.map((emoji) => (\n <EmojiGridButton\n key={emoji.name}\n emoji={emoji.emoji}\n name={emoji.name}\n onClick={() => handleEmojiClick(emoji.emoji)}\n className=\"text-2xl\"\n />\n ))}\n </div>\n </div>\n );\n\n const searchResultContent =\n filteredCategories.length > 0 ? (\n filteredCategories.map((category) => (\n <div key={category.id} className=\"mb-4 animate-fade-in\">\n {renderEmojiCategory(category)}\n </div>\n ))\n ) : (\n <div className=\"flex h-full flex-col items-center justify-center text-center py-12 animate-fade-in\">\n <div className=\"mb-3 text-4xl animate-bounce\">🔍</div>\n <div className=\"text-sm font-semibold text-muted-foreground\">{resolvedEmptyText}</div>\n <div className=\"mt-1 text-xs text-muted-foreground/80\">{resolvedEmptyHint}</div>\n </div>\n );\n\n const handleEmojiClick = (emoji: string) => {\n onEmojiSelect(emoji);\n setSearch(\"\");\n };\n\n const handleCategoryClick = (categoryId: string) => {\n const element = categoryRefs.current[categoryId];\n if (!element || !scrollContainerRef.current) return;\n\n isUserScrolling.current = false;\n setActiveCategory(categoryId);\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n\n window.setTimeout(() => {\n isUserScrolling.current = true;\n }, 500);\n };\n\n return (\n <div\n className={cn(\n \"flex max-h-128 w-96 flex-col overflow-hidden transition-all duration-300\",\n isEmbedded\n ? \"bg-transparent\"\n : \"rounded-3xl border border-border/10 bg-gradient-to-b from-card/98 to-card/95 backdrop-blur-2xl shadow-[0_20px_50px_rgba(0,0,0,0.18)] dark:shadow-[0_20px_50px_rgba(0,0,0,0.45)] shadow-primary/2\",\n className,\n )}\n >\n {showSearch && (\n <div className=\"shrink-0 border-b border-border/10 p-3.5 bg-card/10\">\n <div className=\"relative group\">\n <Search className=\"absolute left-3.5 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground/60 transition-colors group-focus-within:text-primary\" />\n <input\n type=\"text\"\n placeholder={resolvedSearchPlaceholder}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className={cn(\n \"w-full rounded-2xl bg-muted/20 py-2 pl-9.5 pr-9 text-sm transition-all duration-300\",\n formControlOutlineClass,\n \"placeholder:text-muted-foreground/60\",\n \"focus:bg-background/90 focus:shadow-[0_0_12px_rgba(var(--color-primary-rgb),0.04)]\",\n )}\n />\n {search && (\n <button\n type=\"button\"\n onClick={() => setSearch(\"\")}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground/60 hover:text-foreground transition-colors\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* Styled custom scrollbar container */}\n <div \n ref={scrollContainerRef} \n className=\"shrink overflow-y-auto px-4 py-3 scrollbar-thin scrollbar-thumb-muted-foreground/15 hover:scrollbar-thumb-muted-foreground/25 scrollbar-track-transparent transition-all duration-200\" \n style={{ height: maxHeight }}\n >\n {search ? searchResultContent : <div className=\"space-y-3\">{EMOJI_LIST.map((category) => renderEmojiCategory(category, true))}</div>}\n </div>\n\n {!search && showCategoryNav && (\n <div className={cn(\"flex shrink-0 items-center justify-around border-t border-border/10 px-3 py-2 backdrop-blur-md bg-muted/5\")}>\n {EMOJI_LIST.map((category) => {\n const IconComponent = CATEGORY_ICONS[category.id] || Smile;\n return (\n <button\n key={category.id}\n type=\"button\"\n onClick={() => handleCategoryClick(category.id)}\n className={cn(\n \"rounded-2xl p-2.5 transition-all duration-300\",\n activeCategory === category.id\n ? \"bg-primary/10 text-primary scale-115 shadow-sm shadow-primary/5\"\n : \"text-muted-foreground/60 hover:bg-muted/40 hover:text-foreground hover:scale-105\",\n )}\n >\n <Tooltip placement=\"top\" content={<span className=\"text-xs font-semibold\">{category.name}</span>}>\n <span className=\"inline-flex\">\n <IconComponent className=\"h-4 w-4\" />\n </span>\n </Tooltip>\n </button>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n\nexport default EmojiPicker;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/components/EmojiPicker.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport { Search, X, Smile, Leaf, Utensils, Dumbbell, Lightbulb, Hash, Flag } from \"lucide-react\";\nimport { useSmartTranslations } from \"../hooks/useSmartTranslations\";\nimport { cn } from \"../utils/cn\";\nimport { EmojiGridButton } from \"./emoji-ui\";\nimport { Tooltip } from \"./Tooltip\";\nimport { EMOJI_LIST } from \"./UEditor/emojis\";\nimport { formControlOutlineClass } from \"../constants/form-control-size\";\n\n/** Public props for the `EmojiPicker` component. */\nexport interface EmojiPickerProps {\n onEmojiSelect: (emoji: string) => void;\n className?: string;\n searchPlaceholder?: string;\n emptyText?: string;\n emptyHint?: string;\n showSearch?: boolean;\n showCategoryNav?: boolean;\n columns?: number;\n maxHeight?: string;\n chrome?: \"standalone\" | \"embedded\";\n}\n\nconst CATEGORY_ICONS: Record<string, React.ComponentType<{ className?: string }>> = {\n smileys_people: Smile,\n animals_nature: Leaf,\n food_drink: Utensils,\n activity: Dumbbell,\n objects: Lightbulb,\n symbols: Hash,\n flags: Flag,\n};\n\nexport const EmojiPicker: React.FC<EmojiPickerProps> = ({\n onEmojiSelect,\n className,\n searchPlaceholder,\n emptyText,\n emptyHint,\n showSearch = true,\n showCategoryNav = true,\n columns = 9,\n maxHeight = \"20rem\",\n chrome = \"standalone\",\n}) => {\n const t = useSmartTranslations(\"UEditor\");\n const [search, setSearch] = useState(\"\");\n const [activeCategory, setActiveCategory] = useState(EMOJI_LIST[0]?.id || \"\");\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n const categoryRefs = useRef<Record<string, HTMLDivElement | null>>({});\n const isUserScrolling = useRef(false);\n \n const resolvedSearchPlaceholder = searchPlaceholder ?? t(\"emojiPicker.searchPlaceholder\");\n const resolvedEmptyText = emptyText ?? t(\"emojiPicker.noResults\");\n const resolvedEmptyHint = emptyHint ?? t(\"emojiPicker.tryDifferentSearch\");\n const resolvedColumns = Math.max(1, Math.floor(columns));\n const isEmbedded = chrome === \"embedded\";\n \n const gridStyle = {\n gridTemplateColumns: `repeat(${resolvedColumns}, minmax(0, 1fr))`,\n } satisfies React.CSSProperties;\n\n const filteredCategories = useMemo(() => {\n if (!search.trim()) return EMOJI_LIST;\n\n const query = search.toLowerCase();\n return EMOJI_LIST.map((category) => ({\n ...category,\n emojis: category.emojis.filter((emoji) => emoji.name.toLowerCase().includes(query) || emoji.emoji.includes(search)),\n })).filter((category) => category.emojis.length > 0);\n }, [search]);\n\n useEffect(() => {\n if (search) return;\n\n const container = scrollContainerRef.current;\n if (!container) return;\n\n const handleScroll = () => {\n if (!isUserScrolling.current) return;\n\n let maxVisibility = 0;\n let mostVisibleCategory = EMOJI_LIST[0]?.id || \"\";\n\n EMOJI_LIST.forEach((category) => {\n const element = categoryRefs.current[category.id];\n if (!element) return;\n\n const rect = element.getBoundingClientRect();\n const containerRect = container.getBoundingClientRect();\n const visibleTop = Math.max(rect.top, containerRect.top);\n const visibleBottom = Math.min(rect.bottom, containerRect.bottom);\n const visibleHeight = Math.max(0, visibleBottom - visibleTop);\n\n if (visibleHeight > maxVisibility) {\n maxVisibility = visibleHeight;\n mostVisibleCategory = category.id;\n }\n });\n\n if (mostVisibleCategory !== activeCategory) {\n setActiveCategory(mostVisibleCategory);\n }\n };\n\n container.addEventListener(\"scroll\", handleScroll);\n return () => container.removeEventListener(\"scroll\", handleScroll);\n }, [activeCategory, search]);\n\n useEffect(() => {\n isUserScrolling.current = true;\n }, []);\n\n const renderEmojiCategory = (category: (typeof EMOJI_LIST)[number], assignRef = false) => (\n <div\n key={category.id}\n ref={\n assignRef\n ? (el) => {\n categoryRefs.current[category.id] = el;\n }\n : undefined\n }\n className=\"scroll-mt-3 mb-2\"\n >\n <div className=\"sticky top-0 z-10 bg-card/85 backdrop-blur-md py-1.5 px-2 text-[10px] font-bold uppercase tracking-wider text-muted-foreground/90 border-b border-border/5 mb-2 flex items-center gap-1.5 rounded-lg select-none\">\n <span className=\"w-1.5 h-1.5 rounded-full bg-primary/70 animate-pulse\" />\n {category.name}\n </div>\n <div className=\"grid gap-1.5 p-1\" style={gridStyle}>\n {category.emojis.map((emoji) => (\n <EmojiGridButton\n key={emoji.name}\n emoji={emoji.emoji}\n name={emoji.name}\n onClick={() => handleEmojiClick(emoji.emoji)}\n className=\"text-2xl\"\n />\n ))}\n </div>\n </div>\n );\n\n const searchResultContent =\n filteredCategories.length > 0 ? (\n filteredCategories.map((category) => (\n <div key={category.id} className=\"mb-4 animate-fade-in\">\n {renderEmojiCategory(category)}\n </div>\n ))\n ) : (\n <div className=\"flex h-full flex-col items-center justify-center text-center py-12 animate-fade-in\">\n <div className=\"mb-3 text-4xl animate-bounce\">🔍</div>\n <div className=\"text-sm font-semibold text-muted-foreground\">{resolvedEmptyText}</div>\n <div className=\"mt-1 text-xs text-muted-foreground/80\">{resolvedEmptyHint}</div>\n </div>\n );\n\n const handleEmojiClick = (emoji: string) => {\n onEmojiSelect(emoji);\n setSearch(\"\");\n };\n\n const handleCategoryClick = (categoryId: string) => {\n const element = categoryRefs.current[categoryId];\n if (!element || !scrollContainerRef.current) return;\n\n isUserScrolling.current = false;\n setActiveCategory(categoryId);\n element.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n\n window.setTimeout(() => {\n isUserScrolling.current = true;\n }, 500);\n };\n\n return (\n <div\n className={cn(\n \"flex max-h-128 w-96 flex-col overflow-hidden transition-all duration-300\",\n isEmbedded\n ? \"bg-transparent\"\n : \"rounded-3xl border border-border/10 bg-gradient-to-b from-card/98 to-card/95 backdrop-blur-2xl shadow-[0_20px_50px_rgba(0,0,0,0.18)] dark:shadow-[0_20px_50px_rgba(0,0,0,0.45)] shadow-primary/2\",\n className,\n )}\n >\n {showSearch && (\n <div className=\"shrink-0 border-b border-border/10 p-3.5 bg-card/10\">\n <div className=\"relative group\">\n <Search className=\"absolute left-3.5 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground/60 transition-colors group-focus-within:text-primary\" />\n <input\n type=\"text\"\n placeholder={resolvedSearchPlaceholder}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className={cn(\n \"w-full rounded-2xl bg-muted/20 py-2 pl-9.5 pr-9 text-sm transition-all duration-300\",\n formControlOutlineClass,\n \"placeholder:text-muted-foreground/60\",\n \"focus:bg-background/90 focus:shadow-[0_0_12px_rgba(var(--color-primary-rgb),0.04)]\",\n )}\n />\n {search && (\n <button\n type=\"button\"\n onClick={() => setSearch(\"\")}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground/60 hover:text-foreground transition-colors\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n </div>\n )}\n\n {/* Styled custom scrollbar container */}\n <div \n ref={scrollContainerRef} \n className=\"shrink overflow-y-auto px-4 py-3 scrollbar-thin scrollbar-thumb-muted-foreground/15 hover:scrollbar-thumb-muted-foreground/25 scrollbar-track-transparent transition-all duration-200\" \n style={{ height: maxHeight }}\n >\n {search ? searchResultContent : <div className=\"space-y-3\">{EMOJI_LIST.map((category) => renderEmojiCategory(category, true))}</div>}\n </div>\n\n {!search && showCategoryNav && (\n <div className={cn(\"flex shrink-0 items-center justify-around border-t border-border/10 px-3 py-2 backdrop-blur-md bg-muted/5\")}>\n {EMOJI_LIST.map((category) => {\n const IconComponent = CATEGORY_ICONS[category.id] || Smile;\n return (\n <button\n key={category.id}\n type=\"button\"\n onClick={() => handleCategoryClick(category.id)}\n className={cn(\n \"rounded-2xl p-2.5 transition-all duration-300\",\n activeCategory === category.id\n ? \"bg-primary/10 text-primary scale-115 shadow-sm shadow-primary/5\"\n : \"text-muted-foreground/60 hover:bg-muted/40 hover:text-foreground hover:scale-105\",\n )}\n >\n <Tooltip placement=\"top\" content={<span className=\"text-xs font-semibold\">{category.name}</span>}>\n <span className=\"inline-flex\">\n <IconComponent className=\"h-4 w-4\" />\n </span>\n </Tooltip>\n </button>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n\nexport default EmojiPicker;\n"],"mappings":"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","names":[]}
@@ -289,6 +289,8 @@ var en_default = {
289
289
  codeBlockDesc: "Code with syntax highlighting",
290
290
  divider: "Divider",
291
291
  dividerDesc: "Visual divider",
292
+ date: "Date",
293
+ dateDesc: "Insert a date from the calendar",
292
294
  table: "Table",
293
295
  tableDesc: "Add a table",
294
296
  noResults: "No matching blocks found",
@@ -751,6 +753,8 @@ var vi_default = {
751
753
  codeBlockDesc: "M\xE3 v\u1EDBi t\xF4 m\xE0u c\xFA ph\xE1p",
752
754
  divider: "Ph\xE2n c\xE1ch",
753
755
  dividerDesc: "\u0110\u01B0\u1EDDng k\u1EBB ngang",
756
+ date: "Ng\xE0y",
757
+ dateDesc: "Ch\xE8n ng\xE0y t\u1EEB l\u1ECBch",
754
758
  table: "B\u1EA3ng",
755
759
  tableDesc: "Th\xEAm b\u1EA3ng",
756
760
  noResults: "Kh\xF4ng t\xECm th\u1EA5y kh\u1ED1i ph\xF9 h\u1EE3p",
@@ -1213,6 +1217,8 @@ var ko_default = {
1213
1217
  codeBlockDesc: "\uAD6C\uBB38 \uAC15\uC870\uAC00 \uC788\uB294 \uCF54\uB4DC",
1214
1218
  divider: "\uAD6C\uBD84\uC120",
1215
1219
  dividerDesc: "\uC2DC\uAC01\uC801 \uAD6C\uBD84\uC120",
1220
+ date: "\uB0A0\uC9DC",
1221
+ dateDesc: "\uB2EC\uB825\uC5D0\uC11C \uB0A0\uC9DC \uC0BD\uC785",
1216
1222
  table: "\uD45C",
1217
1223
  tableDesc: "\uD45C \uCD94\uAC00",
1218
1224
  noResults: "\uC77C\uCE58\uD558\uB294 \uBE14\uB85D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4",
@@ -1675,6 +1681,8 @@ var ja_default = {
1675
1681
  codeBlockDesc: "\u30B7\u30F3\u30BF\u30C3\u30AF\u30B9\u30CF\u30A4\u30E9\u30A4\u30C8\u4ED8\u304D\u30B3\u30FC\u30C9",
1676
1682
  divider: "\u533A\u5207\u308A\u7DDA",
1677
1683
  dividerDesc: "\u8996\u899A\u7684\u306A\u533A\u5207\u308A\u7DDA",
1684
+ date: "\u65E5\u4ED8",
1685
+ dateDesc: "\u30AB\u30EC\u30F3\u30C0\u30FC\u304B\u3089\u65E5\u4ED8\u3092\u633F\u5165",
1678
1686
  table: "\u8868",
1679
1687
  tableDesc: "\u8868\u3092\u8FFD\u52A0",
1680
1688
  noResults: "\u4E00\u81F4\u3059\u308B\u30D6\u30ED\u30C3\u30AF\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
@@ -2199,20 +2207,6 @@ function resolveUEditorPortalContainer(getPortalContainer, fallbackGetPortalCont
2199
2207
  return typeof document !== "undefined" ? document.body : null;
2200
2208
  }
2201
2209
 
2202
- // src/components/Tooltip.tsx
2203
- import * as React6 from "react";
2204
- import { createPortal } from "react-dom";
2205
-
2206
- // src/hooks/useHydrated.ts
2207
- import { useSyncExternalStore } from "react";
2208
- var subscribe = () => () => {
2209
- };
2210
- var getSnapshot = () => true;
2211
- var getServerSnapshot = () => false;
2212
- function useHydrated() {
2213
- return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
2214
- }
2215
-
2216
2210
  // src/utils/react-compose.ts
2217
2211
  function chainEventHandlers(...handlers) {
2218
2212
  return (event) => {
@@ -2233,337 +2227,6 @@ function mergeRefs(...refs) {
2233
2227
  };
2234
2228
  }
2235
2229
 
2236
- // src/components/Tooltip.tsx
2237
- import { Fragment as Fragment2, jsx as jsx6, jsxs } from "react/jsx-runtime";
2238
- var variantStyles = {
2239
- default: "bg-popover text-popover-foreground border-border/50",
2240
- info: "bg-info text-info-foreground border-info/20",
2241
- warning: "bg-warning text-warning-foreground border-warning/20",
2242
- error: "bg-destructive text-destructive-foreground border-destructive/20",
2243
- success: "bg-success text-success-foreground border-success/20"
2244
- };
2245
- var clamp = (value, min, max) => Math.max(min, Math.min(max, value));
2246
- function getTransformOrigin(side) {
2247
- switch (side) {
2248
- case "top":
2249
- return "center bottom";
2250
- case "bottom":
2251
- return "center top";
2252
- case "left":
2253
- return "right center";
2254
- case "right":
2255
- return "left center";
2256
- }
2257
- }
2258
- function computeTooltipPosition(args) {
2259
- const { triggerRect, contentSize, placement, offset, padding, viewport } = args;
2260
- let side = placement;
2261
- const fitsTop = triggerRect.top - offset - contentSize.height >= padding;
2262
- const fitsBottom = triggerRect.bottom + offset + contentSize.height <= viewport.height - padding;
2263
- const fitsLeft = triggerRect.left - offset - contentSize.width >= padding;
2264
- const fitsRight = triggerRect.right + offset + contentSize.width <= viewport.width - padding;
2265
- if (side === "top" && !fitsTop && fitsBottom) side = "bottom";
2266
- if (side === "bottom" && !fitsBottom && fitsTop) side = "top";
2267
- if (side === "left" && !fitsLeft && fitsRight) side = "right";
2268
- if (side === "right" && !fitsRight && fitsLeft) side = "left";
2269
- const centerX = triggerRect.left + triggerRect.width / 2;
2270
- const centerY = triggerRect.top + triggerRect.height / 2;
2271
- let left = 0;
2272
- let top = 0;
2273
- if (side === "top") {
2274
- top = triggerRect.top - offset - contentSize.height;
2275
- left = centerX - contentSize.width / 2;
2276
- } else if (side === "bottom") {
2277
- top = triggerRect.bottom + offset;
2278
- left = centerX - contentSize.width / 2;
2279
- } else if (side === "left") {
2280
- top = centerY - contentSize.height / 2;
2281
- left = triggerRect.left - offset - contentSize.width;
2282
- } else {
2283
- top = centerY - contentSize.height / 2;
2284
- left = triggerRect.right + offset;
2285
- }
2286
- left = clamp(left, padding, viewport.width - contentSize.width - padding);
2287
- top = clamp(top, padding, viewport.height - contentSize.height - padding);
2288
- return { top, left, side };
2289
- }
2290
- var Tooltip = React6.forwardRef(({
2291
- children,
2292
- content,
2293
- placement = "top",
2294
- delay = { open: 200, close: 300 },
2295
- className,
2296
- disabled = false,
2297
- variant = "default",
2298
- asChild = true,
2299
- ...triggerPassthroughProps
2300
- }, forwardedRef) => {
2301
- const [isOpen, setIsOpen] = React6.useState(false);
2302
- const isMounted = useHydrated();
2303
- const triggerRef = React6.useRef(null);
2304
- const positionerRef = React6.useRef(null);
2305
- const panelRef = React6.useRef(null);
2306
- const timeoutRef = React6.useRef(void 0);
2307
- const lastAppliedRef = React6.useRef(null);
2308
- const openedByPointerRef = React6.useRef(false);
2309
- const triggerSelector = React6.useId();
2310
- const tooltipId = React6.useId();
2311
- const getPortalContainer = useUEditorPortalContainerGetter();
2312
- const portalContainer = isOpen ? resolveUEditorPortalContainer(getPortalContainer) : null;
2313
- const portalDocument = portalContainer?.ownerDocument ?? null;
2314
- const portalWindow = portalDocument?.defaultView ?? null;
2315
- const delayOpen = typeof delay === "object" ? delay.open || 700 : delay;
2316
- const delayClose = typeof delay === "object" ? delay.close || 300 : delay;
2317
- const offset = 8;
2318
- const padding = 8;
2319
- const updatePosition = React6.useCallback(() => {
2320
- const triggerEl = triggerRef.current;
2321
- const positionerEl = positionerRef.current;
2322
- const panelEl = panelRef.current;
2323
- if (!triggerEl || !positionerEl || !panelEl) return;
2324
- const triggerRect = triggerEl.getBoundingClientRect();
2325
- const measuredWidth = panelEl.offsetWidth;
2326
- const measuredHeight = panelEl.offsetHeight;
2327
- const rect = panelEl.getBoundingClientRect();
2328
- const contentWidth = measuredWidth || rect.width;
2329
- const contentHeight = measuredHeight || rect.height;
2330
- const next = computeTooltipPosition({
2331
- triggerRect,
2332
- contentSize: { width: contentWidth, height: contentHeight },
2333
- placement,
2334
- offset,
2335
- padding,
2336
- viewport: {
2337
- width: portalWindow?.innerWidth ?? window.innerWidth,
2338
- height: portalWindow?.innerHeight ?? window.innerHeight
2339
- }
2340
- });
2341
- const top = Math.round(next.top);
2342
- const left = Math.round(next.left);
2343
- const prev = lastAppliedRef.current;
2344
- const same = prev && Math.abs(prev.top - top) < 0.5 && Math.abs(prev.left - left) < 0.5 && prev.side === next.side;
2345
- if (same) return;
2346
- lastAppliedRef.current = { top, left, side: next.side };
2347
- positionerEl.style.transform = `translate3d(${left}px, ${top}px, 0)`;
2348
- panelEl.style.transformOrigin = getTransformOrigin(next.side);
2349
- if (positionerEl.style.visibility !== "visible") positionerEl.style.visibility = "visible";
2350
- }, [placement, portalWindow]);
2351
- const handleMouseEnter = () => {
2352
- if (disabled) return;
2353
- openedByPointerRef.current = true;
2354
- clearTimeout(timeoutRef.current);
2355
- timeoutRef.current = setTimeout(() => {
2356
- setIsOpen(true);
2357
- }, delayOpen);
2358
- };
2359
- const handleMouseLeave = () => {
2360
- clearTimeout(timeoutRef.current);
2361
- timeoutRef.current = setTimeout(() => {
2362
- setIsOpen(false);
2363
- }, delayClose);
2364
- };
2365
- const closeNow = React6.useCallback(() => {
2366
- clearTimeout(timeoutRef.current);
2367
- openedByPointerRef.current = false;
2368
- setIsOpen(false);
2369
- }, []);
2370
- const handleFocus = () => {
2371
- if (disabled) return;
2372
- openedByPointerRef.current = false;
2373
- setIsOpen(true);
2374
- };
2375
- const handleBlur = () => {
2376
- openedByPointerRef.current = false;
2377
- setIsOpen(false);
2378
- };
2379
- React6.useEffect(() => {
2380
- return () => clearTimeout(timeoutRef.current);
2381
- }, []);
2382
- React6.useEffect(() => {
2383
- if (isOpen) return;
2384
- clearTimeout(timeoutRef.current);
2385
- }, [isOpen]);
2386
- React6.useLayoutEffect(() => {
2387
- if (!isOpen || !portalWindow) {
2388
- lastAppliedRef.current = null;
2389
- return;
2390
- }
2391
- updatePosition();
2392
- let raf1 = 0;
2393
- let raf2 = 0;
2394
- raf1 = portalWindow.requestAnimationFrame(() => {
2395
- updatePosition();
2396
- raf2 = portalWindow.requestAnimationFrame(() => updatePosition());
2397
- });
2398
- return () => {
2399
- portalWindow.cancelAnimationFrame(raf1);
2400
- portalWindow.cancelAnimationFrame(raf2);
2401
- };
2402
- }, [isOpen, portalWindow, updatePosition]);
2403
- React6.useEffect(() => {
2404
- if (!isOpen || !portalDocument || !portalWindow) return;
2405
- let raf = 0;
2406
- const handler = () => {
2407
- portalWindow.cancelAnimationFrame(raf);
2408
- raf = portalWindow.requestAnimationFrame(() => updatePosition());
2409
- };
2410
- handler();
2411
- portalWindow.addEventListener("resize", handler);
2412
- portalWindow.addEventListener("scroll", handler, true);
2413
- portalDocument.addEventListener("scroll", handler, true);
2414
- return () => {
2415
- portalWindow.cancelAnimationFrame(raf);
2416
- portalWindow.removeEventListener("resize", handler);
2417
- portalWindow.removeEventListener("scroll", handler, true);
2418
- portalDocument.removeEventListener("scroll", handler, true);
2419
- };
2420
- }, [isOpen, portalDocument, portalWindow, updatePosition]);
2421
- React6.useEffect(() => {
2422
- if (!isOpen || !portalWindow) return;
2423
- const ResizeObserverCtor = portalWindow.ResizeObserver;
2424
- if (!ResizeObserverCtor) return;
2425
- const ro = new ResizeObserverCtor(() => updatePosition());
2426
- if (triggerRef.current) ro.observe(triggerRef.current);
2427
- if (panelRef.current) ro.observe(panelRef.current);
2428
- return () => ro.disconnect();
2429
- }, [isOpen, portalWindow, updatePosition]);
2430
- React6.useEffect(() => {
2431
- if (!isOpen || !portalDocument) return;
2432
- const handleDocumentKeyDown = (event) => {
2433
- if (event.key === "Escape") closeNow();
2434
- };
2435
- const handleDocumentPointerMove = (event) => {
2436
- if (!openedByPointerRef.current) return;
2437
- const triggerEl = triggerRef.current;
2438
- if (!triggerEl) {
2439
- closeNow();
2440
- return;
2441
- }
2442
- const rect = triggerEl.getBoundingClientRect();
2443
- const tolerance = 2;
2444
- const insideTrigger = event.clientX >= rect.left - tolerance && event.clientX <= rect.right + tolerance && event.clientY >= rect.top - tolerance && event.clientY <= rect.bottom + tolerance;
2445
- if (!insideTrigger) closeNow();
2446
- };
2447
- portalDocument.addEventListener("pointerdown", closeNow, true);
2448
- portalDocument.addEventListener("keydown", handleDocumentKeyDown);
2449
- portalDocument.addEventListener("pointermove", handleDocumentPointerMove, true);
2450
- return () => {
2451
- portalDocument.removeEventListener("pointerdown", closeNow, true);
2452
- portalDocument.removeEventListener("keydown", handleDocumentKeyDown);
2453
- portalDocument.removeEventListener("pointermove", handleDocumentPointerMove, true);
2454
- };
2455
- }, [closeNow, isOpen, portalDocument]);
2456
- const childProps = children.props;
2457
- const childRef = childProps.ref;
2458
- const passthroughRef = mergeRefs(forwardedRef, childRef, (node) => {
2459
- triggerRef.current = node;
2460
- });
2461
- if (disabled || !content) {
2462
- if (!asChild) return children;
2463
- return React6.cloneElement(children, {
2464
- ...triggerPassthroughProps,
2465
- ref: passthroughRef
2466
- });
2467
- }
2468
- const triggerProps = {
2469
- ...triggerPassthroughProps,
2470
- ref: passthroughRef,
2471
- "data-underverse-tooltip-trigger": triggerSelector,
2472
- "aria-describedby": isOpen ? [childProps["aria-describedby"], triggerPassthroughProps["aria-describedby"], tooltipId].filter(Boolean).join(" ") : childProps["aria-describedby"] ?? triggerPassthroughProps["aria-describedby"],
2473
- onMouseEnter: chainEventHandlers(
2474
- triggerPassthroughProps.onMouseEnter,
2475
- childProps.onMouseEnter,
2476
- (e) => {
2477
- triggerRef.current = e.currentTarget;
2478
- handleMouseEnter();
2479
- }
2480
- ),
2481
- onMouseLeave: chainEventHandlers(
2482
- triggerPassthroughProps.onMouseLeave,
2483
- childProps.onMouseLeave,
2484
- (e) => {
2485
- triggerRef.current = e.currentTarget;
2486
- handleMouseLeave();
2487
- }
2488
- ),
2489
- onPointerDown: chainEventHandlers(
2490
- triggerPassthroughProps.onPointerDown,
2491
- childProps.onPointerDown,
2492
- (e) => {
2493
- triggerRef.current = e.currentTarget;
2494
- closeNow();
2495
- }
2496
- ),
2497
- onClick: chainEventHandlers(
2498
- triggerPassthroughProps.onClick,
2499
- childProps.onClick,
2500
- (e) => {
2501
- triggerRef.current = e.currentTarget;
2502
- closeNow();
2503
- }
2504
- ),
2505
- onFocus: chainEventHandlers(
2506
- triggerPassthroughProps.onFocus,
2507
- childProps.onFocus,
2508
- (e) => {
2509
- triggerRef.current = e.currentTarget;
2510
- handleFocus();
2511
- }
2512
- ),
2513
- onBlur: chainEventHandlers(
2514
- triggerPassthroughProps.onBlur,
2515
- childProps.onBlur,
2516
- () => {
2517
- handleBlur();
2518
- }
2519
- )
2520
- };
2521
- const trigger = asChild ? React6.cloneElement(children, triggerProps) : /* @__PURE__ */ jsx6("span", { ...triggerProps, children });
2522
- return /* @__PURE__ */ jsxs(Fragment2, { children: [
2523
- trigger,
2524
- isMounted && isOpen && portalContainer && createPortal(
2525
- /* @__PURE__ */ jsx6(
2526
- "div",
2527
- {
2528
- ref: positionerRef,
2529
- style: {
2530
- position: "fixed",
2531
- top: 0,
2532
- left: 0,
2533
- transform: "translate3d(0, 0, 0)",
2534
- zIndex: 99999,
2535
- visibility: "hidden",
2536
- pointerEvents: "none",
2537
- willChange: "transform"
2538
- },
2539
- children: /* @__PURE__ */ jsx6(
2540
- "div",
2541
- {
2542
- ref: panelRef,
2543
- id: tooltipId,
2544
- role: "tooltip",
2545
- style: {
2546
- opacity: 1,
2547
- transition: "opacity 150ms",
2548
- transformOrigin: getTransformOrigin(placement)
2549
- },
2550
- className: cn(
2551
- "px-3 py-2 text-sm font-medium rounded-xl shadow-lg border",
2552
- "max-w-xs wrap-break-word backdrop-blur-sm",
2553
- variantStyles[variant],
2554
- className
2555
- ),
2556
- children: content
2557
- }
2558
- )
2559
- }
2560
- ),
2561
- portalContainer
2562
- )
2563
- ] });
2564
- });
2565
- Tooltip.displayName = "Tooltip";
2566
-
2567
2230
  export {
2568
2231
  formControlSizeStyles,
2569
2232
  formControlLabelClass,
@@ -2587,13 +2250,11 @@ export {
2587
2250
  ForceInternalTranslationsProvider,
2588
2251
  useSmartTranslations,
2589
2252
  useSmartLocale,
2590
- useHydrated,
2591
2253
  chainEventHandlers,
2592
2254
  setRefValue,
2593
2255
  mergeRefs,
2594
2256
  UEditorPortalProvider,
2595
2257
  useUEditorPortalContainerGetter,
2596
- resolveUEditorPortalContainer,
2597
- Tooltip
2258
+ resolveUEditorPortalContainer
2598
2259
  };
2599
- //# sourceMappingURL=chunk-6FAHXNDQ.js.map
2260
+ //# sourceMappingURL=chunk-6XQTRIP6.js.map