@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.
- package/api-reference.json +1 -1
- package/dist/DatePicker-FDOTQMNL.js +15 -0
- package/dist/{EmojiPicker-6H52Q4YE.js → EmojiPicker-Z7QPW4DA.js} +5 -4
- package/dist/EmojiPicker-Z7QPW4DA.js.map +1 -0
- package/dist/chunk-5GMQ23IU.js +719 -0
- package/dist/chunk-5GMQ23IU.js.map +1 -0
- package/dist/{chunk-L73HBI6E.js → chunk-5VCM2Z7M.js} +6 -4
- package/dist/{chunk-L73HBI6E.js.map → chunk-5VCM2Z7M.js.map} +1 -1
- package/dist/{chunk-6FAHXNDQ.js → chunk-6XQTRIP6.js} +10 -349
- package/dist/chunk-6XQTRIP6.js.map +1 -0
- package/dist/chunk-EN33T3LJ.js +358 -0
- package/dist/chunk-EN33T3LJ.js.map +1 -0
- package/dist/{chunk-UHUKUI5S.js → chunk-JABD2ONI.js} +3 -3
- package/dist/chunk-JG3U26V6.js +1692 -0
- package/dist/chunk-JG3U26V6.js.map +1 -0
- package/dist/{chunk-JYAEYUGM.js → chunk-SCW2XGCE.js} +466 -354
- package/dist/chunk-SCW2XGCE.js.map +1 -0
- package/dist/{chunk-W3QTP2DM.js → chunk-TSBKJELM.js} +2 -2
- package/dist/{chunk-OTPC2OTQ.js → chunk-V4VZZHV7.js} +324 -1031
- package/dist/chunk-V4VZZHV7.js.map +1 -0
- package/dist/index.cjs +13476 -13310
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +1942 -3570
- package/dist/index.js.map +1 -1
- package/dist/{menu-bar-HZBBRX42.js → menu-bar-MX3LXG6T.js} +6 -4
- package/dist/{menu-bar-HZBBRX42.js.map → menu-bar-MX3LXG6T.js.map} +1 -1
- package/dist/ueditor.cjs +2783 -1101
- package/dist/ueditor.cjs.map +1 -1
- package/dist/ueditor.d.cts +2 -0
- package/dist/ueditor.d.ts +2 -0
- package/dist/ueditor.js +6 -4
- package/package.json +1 -1
- package/dist/chunk-6FAHXNDQ.js.map +0 -1
- package/dist/chunk-JYAEYUGM.js.map +0 -1
- package/dist/chunk-OTPC2OTQ.js.map +0 -1
- /package/dist/{EmojiPicker-6H52Q4YE.js.map → DatePicker-FDOTQMNL.js.map} +0 -0
- /package/dist/{chunk-UHUKUI5S.js.map → chunk-JABD2ONI.js.map} +0 -0
- /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-
|
|
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-
|
|
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-
|
|
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-
|
|
2260
|
+
//# sourceMappingURL=chunk-6XQTRIP6.js.map
|