@aloudata/aloudata-design 3.1.2 → 3.1.4
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/dist/Tabs/index.js +2 -2
- package/dist/Tabs/index.js.map +1 -1
- package/dist/Tooltip/index.js +2 -2
- package/dist/Tooltip/index.js.map +1 -1
- package/dist/_utils/floatingLayer.d.ts +2 -0
- package/dist/_utils/floatingLayer.js +6 -1
- package/dist/_utils/floatingLayer.js.map +1 -1
- package/dist/aloudata-design.css +1 -1
- package/package.json +1 -1
package/dist/Tabs/index.js
CHANGED
|
@@ -186,10 +186,10 @@ function Tabs(props) {
|
|
|
186
186
|
const closeLabel = typeof item.label === "string" || typeof item.label === "number" ? `Remove ${item.label}` : "Remove tab";
|
|
187
187
|
return /* @__PURE__ */ jsxs("div", {
|
|
188
188
|
className: cn("ald-tabs-tab ant-tabs-tab tw-relative tw-flex tw-shrink-0 tw-items-center tw-gap-2 tw-whitespace-nowrap tw-transition-colors", isVertical && "tw-w-full tw-self-stretch", isCard ? cn("tw-h-10 tw-rounded-t-[6px] tw-border tw-border-b-0 tw-border-solid tw-px-4 tw-text-sm tw-leading-5", "tw-gap-sp-75", isActive ? "tw-border-[var(--border-default)] tw-bg-[var(--background-default)] tw-font-medium tw-text-[var(--content-brand-primary)]" : "tw-border-[var(--border-default)] tw-bg-[var(--background-default)] tw-text-[var(--content-secondary)] hover:tw-text-inherit") : cn(size === "small" ? "tw-py-2 tw-text-xs tw-leading-4" : "tw-py-2.5 tw-text-sm tw-leading-5", monospace && "tw-justify-center", isActive ? "tw-font-medium tw-text-[var(--content-brand-primary)]" : "tw-font-medium tw-text-[var(--content-secondary)] hover:tw-text-inherit"), item.disabled && "tw-pointer-events-none tw-cursor-default tw-opacity-50", !item.disabled && [
|
|
189
|
-
"has-[.ald-tabs-tab-trigger:focus-visible]:tw-shadow-[
|
|
189
|
+
"has-[.ald-tabs-tab-trigger:focus-visible]:tw-shadow-[inset_0_0_0_2px_var(--focus-ring)]",
|
|
190
190
|
"forced-colors:has-[.ald-tabs-tab-trigger:focus-visible]:tw-outline",
|
|
191
191
|
"forced-colors:has-[.ald-tabs-tab-trigger:focus-visible]:tw-outline-2",
|
|
192
|
-
"forced-colors:has-[.ald-tabs-tab-trigger:focus-visible]:tw-outline-offset-
|
|
192
|
+
"forced-colors:has-[.ald-tabs-tab-trigger:focus-visible]:tw-outline-offset-[-2px]",
|
|
193
193
|
"forced-colors:has-[.ald-tabs-tab-trigger:focus-visible]:tw-outline-[Highlight]"
|
|
194
194
|
]),
|
|
195
195
|
children: [
|
package/dist/Tabs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/Tabs/index.tsx"],"sourcesContent":["import React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { cn } from '../lib/utils';\nimport { ChevronLeftLine, ChevronRightLine, CloseLightLine } from '../Icon';\nimport TabPane from './TabPane';\n\nexport type TabsSize = 'default' | 'small';\n\ninterface TabItem {\n key: string;\n label: React.ReactNode;\n children?: React.ReactNode;\n disabled?: boolean;\n closable?: boolean;\n icon?: React.ReactNode;\n forceRender?: boolean;\n className?: string;\n}\n\nexport interface ITabsProps {\n size?: TabsSize;\n activeKey?: string;\n defaultActiveKey?: string;\n onChange?: (activeKey: string) => void;\n onTabClick?: (activeKey: string, e: React.MouseEvent) => void;\n destroyInactiveTabPane?: boolean;\n centered?: boolean;\n adaptHeight?: boolean;\n tabPosition?: 'left' | 'right' | 'top' | 'bottom';\n className?: string;\n children?: React.ReactNode;\n headerBackgroundColor?: string;\n monospace?: boolean;\n padding?: boolean | number;\n compact?: boolean;\n hasDividing?: boolean;\n items?: TabItem[];\n type?: 'line' | 'card' | 'editable-card';\n tabBarExtraContent?:\n | React.ReactNode\n | { left?: React.ReactNode; right?: React.ReactNode };\n onEdit?: (\n targetKey: string | React.MouseEvent | React.KeyboardEvent,\n action: 'add' | 'remove',\n ) => void;\n hideAdd?: boolean;\n style?: React.CSSProperties;\n tabBarStyle?: React.CSSProperties;\n popupClassName?: string;\n tabBarGutter?: number;\n moreIcon?: React.ReactNode;\n /** 透传到 Tabs 根容器的 data-testid,用于自动化测试定位 */\n 'data-testid'?: string;\n /** 透传到 tablist 的 aria-label,用于可访问性与自动化测试定位 */\n 'aria-label'?: string;\n}\n\nexport default function Tabs(props: ITabsProps) {\n const {\n size,\n className,\n adaptHeight,\n style = {},\n monospace: propsMonospace,\n tabPosition = 'top',\n padding: propsPadding = false,\n compact,\n hasDividing = true,\n items,\n activeKey: controlledActiveKey,\n defaultActiveKey,\n onChange,\n onTabClick,\n destroyInactiveTabPane,\n centered,\n tabBarExtraContent,\n headerBackgroundColor,\n children,\n type,\n onEdit,\n hideAdd,\n tabBarStyle,\n 'data-testid': dataTestId,\n 'aria-label': ariaLabel,\n } = props;\n\n const isEditable = type === 'editable-card';\n const isCard = type === 'card' || type === 'editable-card';\n\n // Derive items from children if not provided\n const resolvedItems: TabItem[] = useMemo(() => {\n if (items) return items;\n return React.Children.toArray(children)\n .filter(React.isValidElement)\n .map((child: any) => ({\n key: child.key || child.props.key || '',\n label: child.props.tab,\n children: child.props.children,\n disabled: child.props.disabled,\n closable: child.props.closable,\n forceRender: child.props.forceRender,\n }));\n }, [items, children]);\n\n const firstKey = resolvedItems[0]?.key || '';\n const [innerActiveKey, setInnerActiveKey] = useState(\n defaultActiveKey || firstKey,\n );\n const mergedActiveKey =\n controlledActiveKey !== undefined ? controlledActiveKey : innerActiveKey;\n const activeKey = resolvedItems.some((item) => item.key === mergedActiveKey)\n ? mergedActiveKey\n : firstKey;\n\n const tabsId = React.useId();\n const tabRefs = useRef<Record<string, HTMLDivElement | null>>({});\n const pendingFocusKeyRef = useRef<string | null>(null);\n const getPreferredFocusKey = useCallback(\n (items: TabItem[] = resolvedItems) =>\n items.find((item) => item.key === activeKey && !item.disabled)?.key ||\n items.find((item) => !item.disabled)?.key ||\n '',\n [activeKey, resolvedItems],\n );\n const [focusedKey, setFocusedKey] = useState(() => getPreferredFocusKey());\n\n const getTabId = (key: string) => `${tabsId}-tab-${key}`;\n const getPanelId = (key: string) => `${tabsId}-panel-${key}`;\n\n const focusTab = useCallback((key: string) => {\n setFocusedKey(key);\n tabRefs.current[key]?.focus();\n }, []);\n\n useEffect(() => {\n const pendingFocusKey = pendingFocusKeyRef.current;\n if (\n pendingFocusKey &&\n resolvedItems.some(\n (item) => item.key === pendingFocusKey && !item.disabled,\n )\n ) {\n pendingFocusKeyRef.current = null;\n focusTab(pendingFocusKey);\n return;\n }\n\n setFocusedKey((currentFocusedKey) => {\n const focusedItem = resolvedItems.find(\n (item) => item.key === currentFocusedKey,\n );\n return focusedItem && !focusedItem.disabled\n ? currentFocusedKey\n : getPreferredFocusKey();\n });\n }, [focusTab, getPreferredFocusKey, resolvedItems]);\n\n const activateTab = useCallback(\n (key: string) => {\n if (controlledActiveKey === undefined) {\n setInnerActiveKey(key);\n }\n onChange?.(key);\n },\n [controlledActiveKey, onChange],\n );\n\n const handleTabClick = (key: string, e: React.MouseEvent) => {\n setFocusedKey(key);\n activateTab(key);\n onTabClick?.(key, e);\n };\n\n const handleRemove = (key: string, e: React.MouseEvent) => {\n e.stopPropagation();\n const itemIndex = resolvedItems.findIndex((item) => item.key === key);\n const nextFocusableItem = [\n ...resolvedItems.slice(itemIndex + 1),\n ...resolvedItems.slice(0, itemIndex).reverse(),\n ].find((item) => !item.disabled);\n pendingFocusKeyRef.current = nextFocusableItem?.key || null;\n onEdit?.(key, 'remove');\n };\n\n const handleTabKeyDown = (\n item: TabItem,\n e: React.KeyboardEvent<HTMLDivElement>,\n ) => {\n const enabledItems = resolvedItems.filter(\n (candidate) => !candidate.disabled,\n );\n const currentIndex = enabledItems.findIndex(\n (candidate) => candidate.key === item.key,\n );\n if (currentIndex === -1) return;\n\n let nextIndex: number | undefined;\n if (\n (!isVertical && e.key === 'ArrowRight') ||\n (isVertical && e.key === 'ArrowDown')\n ) {\n nextIndex = (currentIndex + 1) % enabledItems.length;\n } else if (\n (!isVertical && e.key === 'ArrowLeft') ||\n (isVertical && e.key === 'ArrowUp')\n ) {\n nextIndex =\n (currentIndex - 1 + enabledItems.length) % enabledItems.length;\n } else if (e.key === 'Home') {\n nextIndex = 0;\n } else if (e.key === 'End') {\n nextIndex = enabledItems.length - 1;\n }\n\n if (nextIndex !== undefined) {\n e.preventDefault();\n focusTab(enabledItems[nextIndex].key);\n return;\n }\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n activateTab(item.key);\n }\n };\n\n const handleAdd = (e: React.MouseEvent) => {\n onEdit?.(e, 'add');\n };\n\n const monospace = tabPosition !== 'top' ? false : propsMonospace;\n const paddingVal = useMemo(() => {\n if (tabPosition !== 'top') return 0;\n if (typeof propsPadding === 'number') return propsPadding;\n if (typeof propsPadding === 'boolean' && propsPadding) return 20;\n return 0;\n }, [propsPadding, tabPosition]);\n\n const isTop = tabPosition === 'top';\n const isBottom = tabPosition === 'bottom';\n const isLeft = tabPosition === 'left';\n const isRight = tabPosition === 'right';\n const isVertical = tabPosition === 'left' || tabPosition === 'right';\n const rootDirectionClass = isRight\n ? 'tw-flex-row-reverse'\n : isLeft\n ? 'tw-flex-row'\n : isBottom\n ? 'tw-flex-col-reverse'\n : 'tw-flex-col';\n\n const extraLeft =\n tabBarExtraContent &&\n typeof tabBarExtraContent === 'object' &&\n 'left' in tabBarExtraContent\n ? tabBarExtraContent.left\n : null;\n const extraRight = tabBarExtraContent\n ? typeof tabBarExtraContent === 'object' && 'right' in tabBarExtraContent\n ? tabBarExtraContent.right\n : React.isValidElement(tabBarExtraContent)\n ? tabBarExtraContent\n : null\n : null;\n\n // Scroll state for overflow\n const navListRef = useRef<HTMLDivElement>(null);\n const [canScrollLeft, setCanScrollLeft] = useState(false);\n const [canScrollRight, setCanScrollRight] = useState(false);\n\n const checkScroll = useCallback(() => {\n const el = navListRef.current;\n if (!el || isVertical) {\n setCanScrollLeft(false);\n setCanScrollRight(false);\n return;\n }\n const { scrollLeft, scrollWidth, clientWidth } = el;\n setCanScrollLeft(scrollLeft > 1);\n setCanScrollRight(scrollLeft + clientWidth < scrollWidth - 1);\n }, [isVertical]);\n\n useEffect(() => {\n checkScroll();\n const el = navListRef.current;\n if (!el) return;\n // Use ResizeObserver to detect size changes\n let ro: ResizeObserver | undefined;\n if (typeof ResizeObserver !== 'undefined') {\n ro = new ResizeObserver(() => checkScroll());\n ro.observe(el);\n }\n el.addEventListener('scroll', checkScroll, { passive: true });\n return () => {\n el.removeEventListener('scroll', checkScroll);\n ro?.disconnect();\n };\n }, [checkScroll, resolvedItems.length]);\n\n const scrollBy = (delta: number) => {\n const el = navListRef.current;\n if (el) {\n el.scrollBy({ left: delta, behavior: 'smooth' });\n }\n };\n\n const showScrollButtons = canScrollLeft || canScrollRight;\n\n return (\n <div\n data-testid={dataTestId}\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs ant-tabs tw-flex',\n rootDirectionClass,\n adaptHeight && 'ald-adapt-height tw-h-full',\n size !== 'small' && 'ald-tabs-default',\n monospace && 'ald-tabs-monospace',\n compact && 'ald-tabs-compact',\n !hasDividing && 'ald-tabs-no-dividing',\n className,\n )}\n style={\n {\n ...style,\n '--header-bg-color': headerBackgroundColor,\n '--tabs-padding': `${paddingVal}px`,\n } as React.CSSProperties\n }\n >\n {/* Tab nav */}\n <div\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-nav ant-tabs-nav tw-flex',\n isVertical ? 'tw-shrink-0 tw-items-stretch' : 'tw-items-center',\n isTop && 'tw-mb-5',\n isBottom && 'tw-mt-5',\n isTop &&\n hasDividing &&\n 'tw-border-0 tw-border-b tw-border-solid tw-border-b-[var(--border-default)]',\n isBottom &&\n hasDividing &&\n 'tw-border-0 tw-border-t tw-border-solid tw-border-t-[var(--border-default)]',\n isTop && compact && '!tw-mb-0',\n isBottom && compact && '!tw-mt-0',\n isLeft &&\n 'tw-flex-col tw-border-0 tw-border-r tw-border-solid tw-border-r-[var(--border-default)]',\n isRight &&\n 'tw-flex-col tw-border-0 tw-border-l tw-border-solid tw-border-l-[var(--border-default)]',\n )}\n style={\n headerBackgroundColor || tabBarStyle\n ? {\n ...tabBarStyle,\n ...(headerBackgroundColor\n ? { backgroundColor: headerBackgroundColor }\n : {}),\n }\n : undefined\n }\n >\n {extraLeft}\n\n {/* Scroll left button */}\n {showScrollButtons && !isVertical && (\n <button\n type=\"button\"\n className={cn(\n 'ald-tabs-scroll-btn tw-flex tw-shrink-0 tw-items-center tw-justify-center tw-border-none tw-bg-[var(--action-ghost-normal)] tw-p-1 tw-text-[var(--content-secondary)] tw-transition-colors hover:tw-text-[var(--content-primary)]',\n !canScrollLeft && 'tw-invisible',\n )}\n onClick={() => scrollBy(-200)}\n aria-label=\"Scroll tabs left\"\n >\n <ChevronLeftLine size={16} />\n </button>\n )}\n\n <div\n className={cn(\n 'ald-tabs-nav-wrap ant-tabs-nav-wrap',\n isVertical\n ? 'tw-w-full tw-shrink-0 tw-self-stretch'\n : 'tw-min-w-0 tw-flex-1',\n )}\n style={paddingVal ? { margin: `0 ${paddingVal}px` } : undefined}\n >\n <div\n ref={navListRef}\n role=\"tablist\"\n aria-label={ariaLabel}\n aria-orientation={isVertical ? 'vertical' : 'horizontal'}\n onBlur={(e) => {\n if (!e.currentTarget.contains(e.relatedTarget as Node | null)) {\n setFocusedKey(getPreferredFocusKey());\n }\n }}\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-nav-list ant-tabs-nav-list tw-flex tw-overflow-hidden',\n isVertical && 'tw-w-full tw-shrink-0 tw-flex-col tw-self-stretch',\n centered && !isVertical && 'tw-justify-center',\n monospace && '[&>*]:tw-flex-1',\n isCard ? 'tw-gap-1' : !isVertical && !monospace && 'tw-gap-8',\n )}\n style={\n !isVertical\n ? { scrollbarWidth: 'none', msOverflowStyle: 'none' }\n : undefined\n }\n >\n {resolvedItems.map((item) => {\n const isActive = activeKey === item.key;\n // For editable-card, closable defaults to true unless explicitly set to false\n const showClose = isEditable && item.closable !== false;\n const closeLabel =\n typeof item.label === 'string' || typeof item.label === 'number'\n ? `Remove ${item.label}`\n : 'Remove tab';\n\n return (\n <div\n key={item.key}\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-tab ant-tabs-tab tw-relative tw-flex tw-shrink-0 tw-items-center tw-gap-2 tw-whitespace-nowrap tw-transition-colors',\n isVertical && 'tw-w-full tw-self-stretch',\n // Card / editable-card styling\n isCard\n ? cn(\n 'tw-h-10 tw-rounded-t-[6px] tw-border tw-border-b-0 tw-border-solid tw-px-4 tw-text-sm tw-leading-5',\n 'tw-gap-sp-75',\n isActive\n ? 'tw-border-[var(--border-default)] tw-bg-[var(--background-default)] tw-font-medium tw-text-[var(--content-brand-primary)]'\n : 'tw-border-[var(--border-default)] tw-bg-[var(--background-default)] tw-text-[var(--content-secondary)] hover:tw-text-inherit',\n )\n : cn(\n size === 'small'\n ? 'tw-py-2 tw-text-xs tw-leading-4'\n : 'tw-py-2.5 tw-text-sm tw-leading-5',\n monospace && 'tw-justify-center',\n isActive\n ? 'tw-font-medium tw-text-[var(--content-brand-primary)]'\n : 'tw-font-medium tw-text-[var(--content-secondary)] hover:tw-text-inherit',\n ),\n item.disabled &&\n 'tw-pointer-events-none tw-cursor-default tw-opacity-50',\n // Focus belongs to the roving tab trigger, not to the\n // selected/active state. Render it on the tab envelope so\n // card and line tab geometry remain unchanged.\n !item.disabled && [\n 'has-[.ald-tabs-tab-trigger:focus-visible]:tw-shadow-[0_0_0_2px_var(--focus-ring)]',\n 'forced-colors:has-[.ald-tabs-tab-trigger:focus-visible]:tw-outline',\n 'forced-colors:has-[.ald-tabs-tab-trigger:focus-visible]:tw-outline-2',\n 'forced-colors:has-[.ald-tabs-tab-trigger:focus-visible]:tw-outline-offset-2',\n 'forced-colors:has-[.ald-tabs-tab-trigger:focus-visible]:tw-outline-[Highlight]',\n ],\n )}\n >\n <div\n ref={(node) => {\n tabRefs.current[item.key] = node;\n }}\n id={getTabId(item.key)}\n role=\"tab\"\n aria-selected={isActive}\n aria-controls={getPanelId(item.key)}\n aria-disabled={item.disabled || undefined}\n tabIndex={\n !item.disabled && focusedKey === item.key ? 0 : -1\n }\n className={cn(\n 'ald-tabs-tab-trigger tw-flex tw-min-w-0 tw-flex-1 tw-cursor-pointer tw-items-center tw-whitespace-nowrap',\n isCard ? 'tw-gap-sp-75' : 'tw-gap-2',\n monospace && 'tw-justify-center',\n )}\n onClick={\n item.disabled\n ? undefined\n : (e) => handleTabClick(item.key, e)\n }\n onFocus={() => setFocusedKey(item.key)}\n onKeyDown={(e) => handleTabKeyDown(item, e)}\n >\n {item.icon}\n {/* antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器 */}\n <span className=\"ant-tabs-tab-btn\">{item.label}</span>\n </div>\n {/* Close button for editable-card */}\n {showClose && (\n <button\n type=\"button\"\n className=\"ald-tabs-tab-remove tw-m-0 tw-grid tw-size-4 tw-cursor-pointer tw-place-items-center tw-border-0 tw-bg-transparent tw-p-0 tw-text-[var(--content-secondary)] tw-transition-colors hover:tw-text-[var(--content-primary)]\"\n onClick={(e) => handleRemove(item.key, e)}\n aria-label={closeLabel}\n >\n <CloseLightLine size={12} />\n </button>\n )}\n {/* Active indicator for non-card line tabs */}\n {/* antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器 */}\n {!isCard && isActive && isTop && (\n <div className=\"ant-tabs-ink-bar tw-absolute tw-inset-x-0 tw--bottom-px tw-h-[2px] tw-rounded-[2px] tw-bg-[var(--border-brand-strong)]\" />\n )}\n {!isCard && isActive && isBottom && (\n <div className=\"ant-tabs-ink-bar tw-absolute tw-inset-x-0 tw--top-px tw-h-[2px] tw-rounded-[2px] tw-bg-[var(--border-brand-strong)]\" />\n )}\n {!isCard && isActive && isLeft && (\n <div className=\"tw-absolute tw-inset-y-0 tw--right-px tw-w-[2px] tw-rounded-[2px] tw-bg-[var(--border-brand-strong)]\" />\n )}\n {!isCard && isActive && isRight && (\n <div className=\"tw-absolute tw-inset-y-0 tw--left-px tw-w-[2px] tw-rounded-[2px] tw-bg-[var(--border-brand-strong)]\" />\n )}\n </div>\n );\n })}\n </div>\n </div>\n\n {/* Scroll right button */}\n {showScrollButtons && !isVertical && (\n <button\n type=\"button\"\n className={cn(\n 'ald-tabs-scroll-btn tw-flex tw-shrink-0 tw-items-center tw-justify-center tw-border-none tw-bg-[var(--action-ghost-normal)] tw-p-1 tw-text-[var(--content-secondary)] tw-transition-colors hover:tw-text-[var(--content-primary)]',\n !canScrollRight && 'tw-invisible',\n )}\n onClick={() => scrollBy(200)}\n aria-label=\"Scroll tabs right\"\n >\n <ChevronRightLine size={16} />\n </button>\n )}\n\n {/* Add button for editable-card */}\n {isEditable && !hideAdd && (\n <button\n type=\"button\"\n className=\"ald-tabs-nav-add tw-ml-1 tw-flex tw-shrink-0 tw-cursor-pointer tw-items-center tw-justify-center tw-rounded tw-border tw-border-solid tw-border-[var(--border-default)] tw-bg-[var(--background-default)] tw-px-2 tw-py-1 tw-text-[var(--content-secondary)] tw-transition-colors hover:tw-text-[var(--content-primary)]\"\n onClick={handleAdd}\n aria-label=\"Add tab\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n </button>\n )}\n\n {extraRight}\n </div>\n\n {/* Tab content */}\n {/* antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器 */}\n <div\n className={cn(\n 'ald-tabs-content ant-tabs-content ant-tabs-content-holder tw-min-h-0 tw-flex-1',\n adaptHeight && 'tw-h-full',\n )}\n style={\n paddingVal\n ? { padding: `0 ${paddingVal}px ${paddingVal}px` }\n : undefined\n }\n >\n {resolvedItems.map((item) => {\n const isActive = item.key === activeKey;\n if (!isActive && destroyInactiveTabPane && !item.forceRender) {\n return null;\n }\n return (\n <div\n key={item.key}\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-tabpane ant-tabs-tabpane',\n // v2 行为:adaptHeight 时 tabpane 撑满内容区,子元素的百分比高度才能解析\n adaptHeight && 'tw-h-full tw-overflow-y-auto',\n isActive ? 'ant-tabs-tabpane-active tw-block' : 'tw-hidden',\n )}\n role=\"tabpanel\"\n id={getPanelId(item.key)}\n aria-labelledby={getTabId(item.key)}\n aria-hidden={!isActive || undefined}\n >\n {item.children}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\nTabs.TabPane = TabPane;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/Tabs/index.tsx"],"sourcesContent":["import React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { cn } from '../lib/utils';\nimport { ChevronLeftLine, ChevronRightLine, CloseLightLine } from '../Icon';\nimport TabPane from './TabPane';\n\nexport type TabsSize = 'default' | 'small';\n\ninterface TabItem {\n key: string;\n label: React.ReactNode;\n children?: React.ReactNode;\n disabled?: boolean;\n closable?: boolean;\n icon?: React.ReactNode;\n forceRender?: boolean;\n className?: string;\n}\n\nexport interface ITabsProps {\n size?: TabsSize;\n activeKey?: string;\n defaultActiveKey?: string;\n onChange?: (activeKey: string) => void;\n onTabClick?: (activeKey: string, e: React.MouseEvent) => void;\n destroyInactiveTabPane?: boolean;\n centered?: boolean;\n adaptHeight?: boolean;\n tabPosition?: 'left' | 'right' | 'top' | 'bottom';\n className?: string;\n children?: React.ReactNode;\n headerBackgroundColor?: string;\n monospace?: boolean;\n padding?: boolean | number;\n compact?: boolean;\n hasDividing?: boolean;\n items?: TabItem[];\n type?: 'line' | 'card' | 'editable-card';\n tabBarExtraContent?:\n | React.ReactNode\n | { left?: React.ReactNode; right?: React.ReactNode };\n onEdit?: (\n targetKey: string | React.MouseEvent | React.KeyboardEvent,\n action: 'add' | 'remove',\n ) => void;\n hideAdd?: boolean;\n style?: React.CSSProperties;\n tabBarStyle?: React.CSSProperties;\n popupClassName?: string;\n tabBarGutter?: number;\n moreIcon?: React.ReactNode;\n /** 透传到 Tabs 根容器的 data-testid,用于自动化测试定位 */\n 'data-testid'?: string;\n /** 透传到 tablist 的 aria-label,用于可访问性与自动化测试定位 */\n 'aria-label'?: string;\n}\n\nexport default function Tabs(props: ITabsProps) {\n const {\n size,\n className,\n adaptHeight,\n style = {},\n monospace: propsMonospace,\n tabPosition = 'top',\n padding: propsPadding = false,\n compact,\n hasDividing = true,\n items,\n activeKey: controlledActiveKey,\n defaultActiveKey,\n onChange,\n onTabClick,\n destroyInactiveTabPane,\n centered,\n tabBarExtraContent,\n headerBackgroundColor,\n children,\n type,\n onEdit,\n hideAdd,\n tabBarStyle,\n 'data-testid': dataTestId,\n 'aria-label': ariaLabel,\n } = props;\n\n const isEditable = type === 'editable-card';\n const isCard = type === 'card' || type === 'editable-card';\n\n // Derive items from children if not provided\n const resolvedItems: TabItem[] = useMemo(() => {\n if (items) return items;\n return React.Children.toArray(children)\n .filter(React.isValidElement)\n .map((child: any) => ({\n key: child.key || child.props.key || '',\n label: child.props.tab,\n children: child.props.children,\n disabled: child.props.disabled,\n closable: child.props.closable,\n forceRender: child.props.forceRender,\n }));\n }, [items, children]);\n\n const firstKey = resolvedItems[0]?.key || '';\n const [innerActiveKey, setInnerActiveKey] = useState(\n defaultActiveKey || firstKey,\n );\n const mergedActiveKey =\n controlledActiveKey !== undefined ? controlledActiveKey : innerActiveKey;\n const activeKey = resolvedItems.some((item) => item.key === mergedActiveKey)\n ? mergedActiveKey\n : firstKey;\n\n const tabsId = React.useId();\n const tabRefs = useRef<Record<string, HTMLDivElement | null>>({});\n const pendingFocusKeyRef = useRef<string | null>(null);\n const getPreferredFocusKey = useCallback(\n (items: TabItem[] = resolvedItems) =>\n items.find((item) => item.key === activeKey && !item.disabled)?.key ||\n items.find((item) => !item.disabled)?.key ||\n '',\n [activeKey, resolvedItems],\n );\n const [focusedKey, setFocusedKey] = useState(() => getPreferredFocusKey());\n\n const getTabId = (key: string) => `${tabsId}-tab-${key}`;\n const getPanelId = (key: string) => `${tabsId}-panel-${key}`;\n\n const focusTab = useCallback((key: string) => {\n setFocusedKey(key);\n tabRefs.current[key]?.focus();\n }, []);\n\n useEffect(() => {\n const pendingFocusKey = pendingFocusKeyRef.current;\n if (\n pendingFocusKey &&\n resolvedItems.some(\n (item) => item.key === pendingFocusKey && !item.disabled,\n )\n ) {\n pendingFocusKeyRef.current = null;\n focusTab(pendingFocusKey);\n return;\n }\n\n setFocusedKey((currentFocusedKey) => {\n const focusedItem = resolvedItems.find(\n (item) => item.key === currentFocusedKey,\n );\n return focusedItem && !focusedItem.disabled\n ? currentFocusedKey\n : getPreferredFocusKey();\n });\n }, [focusTab, getPreferredFocusKey, resolvedItems]);\n\n const activateTab = useCallback(\n (key: string) => {\n if (controlledActiveKey === undefined) {\n setInnerActiveKey(key);\n }\n onChange?.(key);\n },\n [controlledActiveKey, onChange],\n );\n\n const handleTabClick = (key: string, e: React.MouseEvent) => {\n setFocusedKey(key);\n activateTab(key);\n onTabClick?.(key, e);\n };\n\n const handleRemove = (key: string, e: React.MouseEvent) => {\n e.stopPropagation();\n const itemIndex = resolvedItems.findIndex((item) => item.key === key);\n const nextFocusableItem = [\n ...resolvedItems.slice(itemIndex + 1),\n ...resolvedItems.slice(0, itemIndex).reverse(),\n ].find((item) => !item.disabled);\n pendingFocusKeyRef.current = nextFocusableItem?.key || null;\n onEdit?.(key, 'remove');\n };\n\n const handleTabKeyDown = (\n item: TabItem,\n e: React.KeyboardEvent<HTMLDivElement>,\n ) => {\n const enabledItems = resolvedItems.filter(\n (candidate) => !candidate.disabled,\n );\n const currentIndex = enabledItems.findIndex(\n (candidate) => candidate.key === item.key,\n );\n if (currentIndex === -1) return;\n\n let nextIndex: number | undefined;\n if (\n (!isVertical && e.key === 'ArrowRight') ||\n (isVertical && e.key === 'ArrowDown')\n ) {\n nextIndex = (currentIndex + 1) % enabledItems.length;\n } else if (\n (!isVertical && e.key === 'ArrowLeft') ||\n (isVertical && e.key === 'ArrowUp')\n ) {\n nextIndex =\n (currentIndex - 1 + enabledItems.length) % enabledItems.length;\n } else if (e.key === 'Home') {\n nextIndex = 0;\n } else if (e.key === 'End') {\n nextIndex = enabledItems.length - 1;\n }\n\n if (nextIndex !== undefined) {\n e.preventDefault();\n focusTab(enabledItems[nextIndex].key);\n return;\n }\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n activateTab(item.key);\n }\n };\n\n const handleAdd = (e: React.MouseEvent) => {\n onEdit?.(e, 'add');\n };\n\n const monospace = tabPosition !== 'top' ? false : propsMonospace;\n const paddingVal = useMemo(() => {\n if (tabPosition !== 'top') return 0;\n if (typeof propsPadding === 'number') return propsPadding;\n if (typeof propsPadding === 'boolean' && propsPadding) return 20;\n return 0;\n }, [propsPadding, tabPosition]);\n\n const isTop = tabPosition === 'top';\n const isBottom = tabPosition === 'bottom';\n const isLeft = tabPosition === 'left';\n const isRight = tabPosition === 'right';\n const isVertical = tabPosition === 'left' || tabPosition === 'right';\n const rootDirectionClass = isRight\n ? 'tw-flex-row-reverse'\n : isLeft\n ? 'tw-flex-row'\n : isBottom\n ? 'tw-flex-col-reverse'\n : 'tw-flex-col';\n\n const extraLeft =\n tabBarExtraContent &&\n typeof tabBarExtraContent === 'object' &&\n 'left' in tabBarExtraContent\n ? tabBarExtraContent.left\n : null;\n const extraRight = tabBarExtraContent\n ? typeof tabBarExtraContent === 'object' && 'right' in tabBarExtraContent\n ? tabBarExtraContent.right\n : React.isValidElement(tabBarExtraContent)\n ? tabBarExtraContent\n : null\n : null;\n\n // Scroll state for overflow\n const navListRef = useRef<HTMLDivElement>(null);\n const [canScrollLeft, setCanScrollLeft] = useState(false);\n const [canScrollRight, setCanScrollRight] = useState(false);\n\n const checkScroll = useCallback(() => {\n const el = navListRef.current;\n if (!el || isVertical) {\n setCanScrollLeft(false);\n setCanScrollRight(false);\n return;\n }\n const { scrollLeft, scrollWidth, clientWidth } = el;\n setCanScrollLeft(scrollLeft > 1);\n setCanScrollRight(scrollLeft + clientWidth < scrollWidth - 1);\n }, [isVertical]);\n\n useEffect(() => {\n checkScroll();\n const el = navListRef.current;\n if (!el) return;\n // Use ResizeObserver to detect size changes\n let ro: ResizeObserver | undefined;\n if (typeof ResizeObserver !== 'undefined') {\n ro = new ResizeObserver(() => checkScroll());\n ro.observe(el);\n }\n el.addEventListener('scroll', checkScroll, { passive: true });\n return () => {\n el.removeEventListener('scroll', checkScroll);\n ro?.disconnect();\n };\n }, [checkScroll, resolvedItems.length]);\n\n const scrollBy = (delta: number) => {\n const el = navListRef.current;\n if (el) {\n el.scrollBy({ left: delta, behavior: 'smooth' });\n }\n };\n\n const showScrollButtons = canScrollLeft || canScrollRight;\n\n return (\n <div\n data-testid={dataTestId}\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs ant-tabs tw-flex',\n rootDirectionClass,\n adaptHeight && 'ald-adapt-height tw-h-full',\n size !== 'small' && 'ald-tabs-default',\n monospace && 'ald-tabs-monospace',\n compact && 'ald-tabs-compact',\n !hasDividing && 'ald-tabs-no-dividing',\n className,\n )}\n style={\n {\n ...style,\n '--header-bg-color': headerBackgroundColor,\n '--tabs-padding': `${paddingVal}px`,\n } as React.CSSProperties\n }\n >\n {/* Tab nav */}\n <div\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-nav ant-tabs-nav tw-flex',\n isVertical ? 'tw-shrink-0 tw-items-stretch' : 'tw-items-center',\n isTop && 'tw-mb-5',\n isBottom && 'tw-mt-5',\n isTop &&\n hasDividing &&\n 'tw-border-0 tw-border-b tw-border-solid tw-border-b-[var(--border-default)]',\n isBottom &&\n hasDividing &&\n 'tw-border-0 tw-border-t tw-border-solid tw-border-t-[var(--border-default)]',\n isTop && compact && '!tw-mb-0',\n isBottom && compact && '!tw-mt-0',\n isLeft &&\n 'tw-flex-col tw-border-0 tw-border-r tw-border-solid tw-border-r-[var(--border-default)]',\n isRight &&\n 'tw-flex-col tw-border-0 tw-border-l tw-border-solid tw-border-l-[var(--border-default)]',\n )}\n style={\n headerBackgroundColor || tabBarStyle\n ? {\n ...tabBarStyle,\n ...(headerBackgroundColor\n ? { backgroundColor: headerBackgroundColor }\n : {}),\n }\n : undefined\n }\n >\n {extraLeft}\n\n {/* Scroll left button */}\n {showScrollButtons && !isVertical && (\n <button\n type=\"button\"\n className={cn(\n 'ald-tabs-scroll-btn tw-flex tw-shrink-0 tw-items-center tw-justify-center tw-border-none tw-bg-[var(--action-ghost-normal)] tw-p-1 tw-text-[var(--content-secondary)] tw-transition-colors hover:tw-text-[var(--content-primary)]',\n !canScrollLeft && 'tw-invisible',\n )}\n onClick={() => scrollBy(-200)}\n aria-label=\"Scroll tabs left\"\n >\n <ChevronLeftLine size={16} />\n </button>\n )}\n\n <div\n className={cn(\n 'ald-tabs-nav-wrap ant-tabs-nav-wrap',\n isVertical\n ? 'tw-w-full tw-shrink-0 tw-self-stretch'\n : 'tw-min-w-0 tw-flex-1',\n )}\n style={paddingVal ? { margin: `0 ${paddingVal}px` } : undefined}\n >\n <div\n ref={navListRef}\n role=\"tablist\"\n aria-label={ariaLabel}\n aria-orientation={isVertical ? 'vertical' : 'horizontal'}\n onBlur={(e) => {\n if (!e.currentTarget.contains(e.relatedTarget as Node | null)) {\n setFocusedKey(getPreferredFocusKey());\n }\n }}\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-nav-list ant-tabs-nav-list tw-flex tw-overflow-hidden',\n isVertical && 'tw-w-full tw-shrink-0 tw-flex-col tw-self-stretch',\n centered && !isVertical && 'tw-justify-center',\n monospace && '[&>*]:tw-flex-1',\n isCard ? 'tw-gap-1' : !isVertical && !monospace && 'tw-gap-8',\n )}\n style={\n !isVertical\n ? { scrollbarWidth: 'none', msOverflowStyle: 'none' }\n : undefined\n }\n >\n {resolvedItems.map((item) => {\n const isActive = activeKey === item.key;\n // For editable-card, closable defaults to true unless explicitly set to false\n const showClose = isEditable && item.closable !== false;\n const closeLabel =\n typeof item.label === 'string' || typeof item.label === 'number'\n ? `Remove ${item.label}`\n : 'Remove tab';\n\n return (\n <div\n key={item.key}\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-tab ant-tabs-tab tw-relative tw-flex tw-shrink-0 tw-items-center tw-gap-2 tw-whitespace-nowrap tw-transition-colors',\n isVertical && 'tw-w-full tw-self-stretch',\n // Card / editable-card styling\n isCard\n ? cn(\n 'tw-h-10 tw-rounded-t-[6px] tw-border tw-border-b-0 tw-border-solid tw-px-4 tw-text-sm tw-leading-5',\n 'tw-gap-sp-75',\n isActive\n ? 'tw-border-[var(--border-default)] tw-bg-[var(--background-default)] tw-font-medium tw-text-[var(--content-brand-primary)]'\n : 'tw-border-[var(--border-default)] tw-bg-[var(--background-default)] tw-text-[var(--content-secondary)] hover:tw-text-inherit',\n )\n : cn(\n size === 'small'\n ? 'tw-py-2 tw-text-xs tw-leading-4'\n : 'tw-py-2.5 tw-text-sm tw-leading-5',\n monospace && 'tw-justify-center',\n isActive\n ? 'tw-font-medium tw-text-[var(--content-brand-primary)]'\n : 'tw-font-medium tw-text-[var(--content-secondary)] hover:tw-text-inherit',\n ),\n item.disabled &&\n 'tw-pointer-events-none tw-cursor-default tw-opacity-50',\n // Focus belongs to the roving tab trigger, not to the\n // selected/active state. Render it on the tab envelope so\n // card and line tab geometry remain unchanged.\n !item.disabled && [\n 'has-[.ald-tabs-tab-trigger:focus-visible]:tw-shadow-[inset_0_0_0_2px_var(--focus-ring)]',\n 'forced-colors:has-[.ald-tabs-tab-trigger:focus-visible]:tw-outline',\n 'forced-colors:has-[.ald-tabs-tab-trigger:focus-visible]:tw-outline-2',\n 'forced-colors:has-[.ald-tabs-tab-trigger:focus-visible]:tw-outline-offset-[-2px]',\n 'forced-colors:has-[.ald-tabs-tab-trigger:focus-visible]:tw-outline-[Highlight]',\n ],\n )}\n >\n <div\n ref={(node) => {\n tabRefs.current[item.key] = node;\n }}\n id={getTabId(item.key)}\n role=\"tab\"\n aria-selected={isActive}\n aria-controls={getPanelId(item.key)}\n aria-disabled={item.disabled || undefined}\n tabIndex={\n !item.disabled && focusedKey === item.key ? 0 : -1\n }\n className={cn(\n 'ald-tabs-tab-trigger tw-flex tw-min-w-0 tw-flex-1 tw-cursor-pointer tw-items-center tw-whitespace-nowrap',\n isCard ? 'tw-gap-sp-75' : 'tw-gap-2',\n monospace && 'tw-justify-center',\n )}\n onClick={\n item.disabled\n ? undefined\n : (e) => handleTabClick(item.key, e)\n }\n onFocus={() => setFocusedKey(item.key)}\n onKeyDown={(e) => handleTabKeyDown(item, e)}\n >\n {item.icon}\n {/* antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器 */}\n <span className=\"ant-tabs-tab-btn\">{item.label}</span>\n </div>\n {/* Close button for editable-card */}\n {showClose && (\n <button\n type=\"button\"\n className=\"ald-tabs-tab-remove tw-m-0 tw-grid tw-size-4 tw-cursor-pointer tw-place-items-center tw-border-0 tw-bg-transparent tw-p-0 tw-text-[var(--content-secondary)] tw-transition-colors hover:tw-text-[var(--content-primary)]\"\n onClick={(e) => handleRemove(item.key, e)}\n aria-label={closeLabel}\n >\n <CloseLightLine size={12} />\n </button>\n )}\n {/* Active indicator for non-card line tabs */}\n {/* antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器 */}\n {!isCard && isActive && isTop && (\n <div className=\"ant-tabs-ink-bar tw-absolute tw-inset-x-0 tw--bottom-px tw-h-[2px] tw-rounded-[2px] tw-bg-[var(--border-brand-strong)]\" />\n )}\n {!isCard && isActive && isBottom && (\n <div className=\"ant-tabs-ink-bar tw-absolute tw-inset-x-0 tw--top-px tw-h-[2px] tw-rounded-[2px] tw-bg-[var(--border-brand-strong)]\" />\n )}\n {!isCard && isActive && isLeft && (\n <div className=\"tw-absolute tw-inset-y-0 tw--right-px tw-w-[2px] tw-rounded-[2px] tw-bg-[var(--border-brand-strong)]\" />\n )}\n {!isCard && isActive && isRight && (\n <div className=\"tw-absolute tw-inset-y-0 tw--left-px tw-w-[2px] tw-rounded-[2px] tw-bg-[var(--border-brand-strong)]\" />\n )}\n </div>\n );\n })}\n </div>\n </div>\n\n {/* Scroll right button */}\n {showScrollButtons && !isVertical && (\n <button\n type=\"button\"\n className={cn(\n 'ald-tabs-scroll-btn tw-flex tw-shrink-0 tw-items-center tw-justify-center tw-border-none tw-bg-[var(--action-ghost-normal)] tw-p-1 tw-text-[var(--content-secondary)] tw-transition-colors hover:tw-text-[var(--content-primary)]',\n !canScrollRight && 'tw-invisible',\n )}\n onClick={() => scrollBy(200)}\n aria-label=\"Scroll tabs right\"\n >\n <ChevronRightLine size={16} />\n </button>\n )}\n\n {/* Add button for editable-card */}\n {isEditable && !hideAdd && (\n <button\n type=\"button\"\n className=\"ald-tabs-nav-add tw-ml-1 tw-flex tw-shrink-0 tw-cursor-pointer tw-items-center tw-justify-center tw-rounded tw-border tw-border-solid tw-border-[var(--border-default)] tw-bg-[var(--background-default)] tw-px-2 tw-py-1 tw-text-[var(--content-secondary)] tw-transition-colors hover:tw-text-[var(--content-primary)]\"\n onClick={handleAdd}\n aria-label=\"Add tab\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" />\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" />\n </svg>\n </button>\n )}\n\n {extraRight}\n </div>\n\n {/* Tab content */}\n {/* antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器 */}\n <div\n className={cn(\n 'ald-tabs-content ant-tabs-content ant-tabs-content-holder tw-min-h-0 tw-flex-1',\n adaptHeight && 'tw-h-full',\n )}\n style={\n paddingVal\n ? { padding: `0 ${paddingVal}px ${paddingVal}px` }\n : undefined\n }\n >\n {resolvedItems.map((item) => {\n const isActive = item.key === activeKey;\n if (!isActive && destroyInactiveTabPane && !item.forceRender) {\n return null;\n }\n return (\n <div\n key={item.key}\n className={cn(\n // antd 兼容:保留 ant-* class,消费方 CSS 可能依赖该选择器\n 'ald-tabs-tabpane ant-tabs-tabpane',\n // v2 行为:adaptHeight 时 tabpane 撑满内容区,子元素的百分比高度才能解析\n adaptHeight && 'tw-h-full tw-overflow-y-auto',\n isActive ? 'ant-tabs-tabpane-active tw-block' : 'tw-hidden',\n )}\n role=\"tabpanel\"\n id={getPanelId(item.key)}\n aria-labelledby={getTabId(item.key)}\n aria-hidden={!isActive || undefined}\n >\n {item.children}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\nTabs.TabPane = TabPane;\n"],"mappings":"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"}
|
package/dist/Tooltip/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cn } from "../lib/utils.js";
|
|
2
|
-
import {
|
|
2
|
+
import { useFloatingTooltipZIndex } from "../_utils/floatingLayer.js";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
@@ -105,7 +105,7 @@ function ClickTooltip({ children, title, open, onOpenChange, placement = "top",
|
|
|
105
105
|
function Tooltip(props) {
|
|
106
106
|
const { children, title, content, open, onOpenChange, placement = "top", mouseEnterDelay = 0, mouseLeaveDelay = 0, overlayClassName, trigger, getPopupContainer, getTooltipContainer, zIndex } = props;
|
|
107
107
|
const { triggerRef, container } = usePortalContainer(getPopupContainer, getTooltipContainer);
|
|
108
|
-
const resolvedZIndex =
|
|
108
|
+
const resolvedZIndex = useFloatingTooltipZIndex(zIndex);
|
|
109
109
|
const tooltipIdBase = React.useId().replace(/:/g, "");
|
|
110
110
|
const mergedTitle = title ?? content;
|
|
111
111
|
if (!mergedTitle && mergedTitle !== 0) return /* @__PURE__ */ jsx(Fragment, { children });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/Tooltip/index.tsx"],"sourcesContent":["import * as PopoverPrimitive from '@radix-ui/react-popover';\nimport * as TooltipPrimitive from '@radix-ui/react-tooltip';\nimport React from 'react';\nimport { useFloatingPopupZIndex } from '../_utils/floatingLayer';\nimport { cn } from '../lib/utils';\n\nexport type ActionType = 'hover' | 'focus' | 'click' | 'contextMenu';\n\nexport interface ITooltipProps {\n title?: React.ReactNode;\n /** Alias for title, for Popover-style usage */\n content?: React.ReactNode;\n destroyTooltipOnHide?: boolean;\n getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;\n mouseEnterDelay?: number;\n mouseLeaveDelay?: number;\n placement?:\n | 'top'\n | 'left'\n | 'right'\n | 'bottom'\n | 'topLeft'\n | 'topRight'\n | 'bottomLeft'\n | 'bottomRight'\n | 'leftTop'\n | 'leftBottom'\n | 'rightTop'\n | 'rightBottom';\n trigger?: ActionType | ActionType[];\n zIndex?: number;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n overlayClassName?: string;\n /** Custom class for the root element */\n rootClassName?: string;\n getTooltipContainer?: (node: HTMLElement) => HTMLElement;\n children?: React.ReactNode;\n className?: string;\n style?: React.CSSProperties;\n}\n\nconst sideMap: Record<string, 'top' | 'bottom' | 'left' | 'right'> = {\n top: 'top',\n bottom: 'bottom',\n left: 'left',\n right: 'right',\n topLeft: 'top',\n topRight: 'top',\n bottomLeft: 'bottom',\n bottomRight: 'bottom',\n leftTop: 'left',\n leftBottom: 'left',\n rightTop: 'right',\n rightBottom: 'right',\n};\n\nconst alignMap: Record<string, 'start' | 'end' | 'center'> = {\n topLeft: 'start',\n topRight: 'end',\n bottomLeft: 'start',\n bottomRight: 'end',\n leftTop: 'start',\n leftBottom: 'end',\n rightTop: 'start',\n rightBottom: 'end',\n};\n\nfunction isClickTrigger(trigger?: ActionType | ActionType[]): boolean {\n if (!trigger) return false;\n if (Array.isArray(trigger)) return trigger.includes('click');\n return trigger === 'click';\n}\n\nfunction isTriggerDisabled(trigger?: ActionType | ActionType[]): boolean {\n return Array.isArray(trigger) && trigger.length === 0;\n}\n\nconst contentClasses =\n 'ald-tooltip-overlay tw-z-50 tw-min-h-[28px] tw-rounded-r-50 tw-px-2 tw-py-1.5 tw-text-xs tw-leading-4 tw-bg-[var(--background-inverted)] tw-text-[var(--content-inverted-primary)] tw-animate-in tw-fade-in-0 tw-zoom-in-95';\n\nfunction usePortalContainer(\n getPopupContainer?: (node: HTMLElement) => HTMLElement,\n getTooltipContainer?: (node: HTMLElement) => HTMLElement,\n) {\n const triggerRef = React.useRef<HTMLElement | null>(null);\n const [container, setContainer] = React.useState<HTMLElement | undefined>(\n undefined,\n );\n\n React.useEffect(() => {\n const getter = getPopupContainer || getTooltipContainer;\n if (getter && triggerRef.current) {\n setContainer(getter(triggerRef.current));\n }\n }, [getPopupContainer, getTooltipContainer]);\n\n return { triggerRef, container };\n}\n\nfunction ClickTooltip({\n children,\n title,\n open,\n onOpenChange,\n placement = 'top',\n overlayClassName,\n zIndex,\n container,\n triggerRef,\n}: Pick<\n ITooltipProps,\n | 'children'\n | 'title'\n | 'open'\n | 'onOpenChange'\n | 'placement'\n | 'overlayClassName'\n | 'zIndex'\n> & {\n container?: HTMLElement;\n triggerRef: React.RefObject<HTMLElement | null>;\n}) {\n const side = sideMap[placement] || 'top';\n const align = alignMap[placement] || 'center';\n const idBase = React.useId().replace(/:/g, '');\n const contentId = `ald-popover-tooltip-${idBase}`;\n const titleId = `ald-popover-tooltip-title-${idBase}`;\n const contentRef = React.useRef<HTMLDivElement>(null);\n\n const trigger = React.isValidElement(children) ? (\n React.cloneElement(children as React.ReactElement, {\n ref: triggerRef,\n 'aria-controls': contentId,\n 'aria-haspopup': false,\n })\n ) : (\n <span\n ref={triggerRef as React.RefObject<HTMLSpanElement>}\n aria-controls={contentId}\n aria-haspopup={false}\n >\n {children}\n </span>\n );\n\n return (\n <PopoverPrimitive.Root\n open={open}\n onOpenChange={onOpenChange}\n modal={false}\n >\n <PopoverPrimitive.Trigger asChild>{trigger}</PopoverPrimitive.Trigger>\n <PopoverPrimitive.Portal container={container}>\n <PopoverPrimitive.Content\n id={contentId}\n ref={contentRef}\n role=\"region\"\n aria-labelledby={title ? titleId : undefined}\n side={side}\n align={align}\n sideOffset={4}\n className={cn(contentClasses, overlayClassName)}\n style={{ zIndex }}\n onOpenAutoFocus={(event) => {\n event.preventDefault();\n contentRef.current\n ?.querySelector<HTMLElement>(\n 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex=\"-1\"])',\n )\n ?.focus();\n }}\n onCloseAutoFocus={(event) => {\n event.preventDefault();\n if (triggerRef.current?.isConnected) {\n triggerRef.current.focus();\n }\n }}\n >\n {title && <div id={titleId}>{title}</div>}\n <PopoverPrimitive.Arrow className=\"tw-fill-[var(--background-inverted)]\" />\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n );\n}\n\nexport default function Tooltip(props: ITooltipProps) {\n const {\n children,\n title,\n content,\n open,\n onOpenChange,\n placement = 'top',\n mouseEnterDelay = 0,\n mouseLeaveDelay = 0,\n overlayClassName,\n trigger,\n getPopupContainer,\n getTooltipContainer,\n zIndex,\n } = props;\n\n const { triggerRef, container } = usePortalContainer(\n getPopupContainer,\n getTooltipContainer,\n );\n const resolvedZIndex = useFloatingPopupZIndex(zIndex);\n const tooltipIdBase = React.useId().replace(/:/g, '');\n const mergedTitle = title ?? content;\n\n if (!mergedTitle && mergedTitle !== 0) {\n return <>{children}</>;\n }\n\n if (isTriggerDisabled(trigger)) {\n return <>{children}</>;\n }\n\n if (isClickTrigger(trigger)) {\n return (\n <ClickTooltip\n title={mergedTitle}\n open={open}\n onOpenChange={onOpenChange}\n placement={placement}\n overlayClassName={overlayClassName}\n zIndex={resolvedZIndex}\n container={container}\n triggerRef={triggerRef}\n >\n {children}\n </ClickTooltip>\n );\n }\n\n const side = sideMap[placement] || 'top';\n const align = alignMap[placement] || 'center';\n\n return (\n <TooltipPrimitive.Provider\n delayDuration={mouseEnterDelay * 1000}\n skipDelayDuration={mouseLeaveDelay * 1000}\n >\n <TooltipPrimitive.Root open={open} onOpenChange={onOpenChange}>\n <TooltipPrimitive.Trigger asChild>\n {React.isValidElement(children) ? (\n React.cloneElement(children as React.ReactElement, {\n ref: triggerRef,\n })\n ) : (\n <span ref={triggerRef as React.RefObject<HTMLSpanElement>}>\n {children}\n </span>\n )}\n </TooltipPrimitive.Trigger>\n <TooltipPrimitive.Portal container={container}>\n <TooltipPrimitive.Content\n id={`ald-tooltip-${tooltipIdBase}`}\n side={side}\n align={align}\n sideOffset={4}\n className={cn(contentClasses, overlayClassName)}\n style={{ zIndex: resolvedZIndex }}\n >\n {mergedTitle}\n <TooltipPrimitive.Arrow className=\"tw-fill-[var(--background-inverted)]\" />\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n </TooltipPrimitive.Root>\n </TooltipPrimitive.Provider>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/Tooltip/index.tsx"],"sourcesContent":["import * as PopoverPrimitive from '@radix-ui/react-popover';\nimport * as TooltipPrimitive from '@radix-ui/react-tooltip';\nimport React from 'react';\nimport { useFloatingTooltipZIndex } from '../_utils/floatingLayer';\nimport { cn } from '../lib/utils';\n\nexport type ActionType = 'hover' | 'focus' | 'click' | 'contextMenu';\n\nexport interface ITooltipProps {\n title?: React.ReactNode;\n /** Alias for title, for Popover-style usage */\n content?: React.ReactNode;\n destroyTooltipOnHide?: boolean;\n getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;\n mouseEnterDelay?: number;\n mouseLeaveDelay?: number;\n placement?:\n | 'top'\n | 'left'\n | 'right'\n | 'bottom'\n | 'topLeft'\n | 'topRight'\n | 'bottomLeft'\n | 'bottomRight'\n | 'leftTop'\n | 'leftBottom'\n | 'rightTop'\n | 'rightBottom';\n trigger?: ActionType | ActionType[];\n zIndex?: number;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n overlayClassName?: string;\n /** Custom class for the root element */\n rootClassName?: string;\n getTooltipContainer?: (node: HTMLElement) => HTMLElement;\n children?: React.ReactNode;\n className?: string;\n style?: React.CSSProperties;\n}\n\nconst sideMap: Record<string, 'top' | 'bottom' | 'left' | 'right'> = {\n top: 'top',\n bottom: 'bottom',\n left: 'left',\n right: 'right',\n topLeft: 'top',\n topRight: 'top',\n bottomLeft: 'bottom',\n bottomRight: 'bottom',\n leftTop: 'left',\n leftBottom: 'left',\n rightTop: 'right',\n rightBottom: 'right',\n};\n\nconst alignMap: Record<string, 'start' | 'end' | 'center'> = {\n topLeft: 'start',\n topRight: 'end',\n bottomLeft: 'start',\n bottomRight: 'end',\n leftTop: 'start',\n leftBottom: 'end',\n rightTop: 'start',\n rightBottom: 'end',\n};\n\nfunction isClickTrigger(trigger?: ActionType | ActionType[]): boolean {\n if (!trigger) return false;\n if (Array.isArray(trigger)) return trigger.includes('click');\n return trigger === 'click';\n}\n\nfunction isTriggerDisabled(trigger?: ActionType | ActionType[]): boolean {\n return Array.isArray(trigger) && trigger.length === 0;\n}\n\nconst contentClasses =\n 'ald-tooltip-overlay tw-z-50 tw-min-h-[28px] tw-rounded-r-50 tw-px-2 tw-py-1.5 tw-text-xs tw-leading-4 tw-bg-[var(--background-inverted)] tw-text-[var(--content-inverted-primary)] tw-animate-in tw-fade-in-0 tw-zoom-in-95';\n\nfunction usePortalContainer(\n getPopupContainer?: (node: HTMLElement) => HTMLElement,\n getTooltipContainer?: (node: HTMLElement) => HTMLElement,\n) {\n const triggerRef = React.useRef<HTMLElement | null>(null);\n const [container, setContainer] = React.useState<HTMLElement | undefined>(\n undefined,\n );\n\n React.useEffect(() => {\n const getter = getPopupContainer || getTooltipContainer;\n if (getter && triggerRef.current) {\n setContainer(getter(triggerRef.current));\n }\n }, [getPopupContainer, getTooltipContainer]);\n\n return { triggerRef, container };\n}\n\nfunction ClickTooltip({\n children,\n title,\n open,\n onOpenChange,\n placement = 'top',\n overlayClassName,\n zIndex,\n container,\n triggerRef,\n}: Pick<\n ITooltipProps,\n | 'children'\n | 'title'\n | 'open'\n | 'onOpenChange'\n | 'placement'\n | 'overlayClassName'\n | 'zIndex'\n> & {\n container?: HTMLElement;\n triggerRef: React.RefObject<HTMLElement | null>;\n}) {\n const side = sideMap[placement] || 'top';\n const align = alignMap[placement] || 'center';\n const idBase = React.useId().replace(/:/g, '');\n const contentId = `ald-popover-tooltip-${idBase}`;\n const titleId = `ald-popover-tooltip-title-${idBase}`;\n const contentRef = React.useRef<HTMLDivElement>(null);\n\n const trigger = React.isValidElement(children) ? (\n React.cloneElement(children as React.ReactElement, {\n ref: triggerRef,\n 'aria-controls': contentId,\n 'aria-haspopup': false,\n })\n ) : (\n <span\n ref={triggerRef as React.RefObject<HTMLSpanElement>}\n aria-controls={contentId}\n aria-haspopup={false}\n >\n {children}\n </span>\n );\n\n return (\n <PopoverPrimitive.Root\n open={open}\n onOpenChange={onOpenChange}\n modal={false}\n >\n <PopoverPrimitive.Trigger asChild>{trigger}</PopoverPrimitive.Trigger>\n <PopoverPrimitive.Portal container={container}>\n <PopoverPrimitive.Content\n id={contentId}\n ref={contentRef}\n role=\"region\"\n aria-labelledby={title ? titleId : undefined}\n side={side}\n align={align}\n sideOffset={4}\n className={cn(contentClasses, overlayClassName)}\n style={{ zIndex }}\n onOpenAutoFocus={(event) => {\n event.preventDefault();\n contentRef.current\n ?.querySelector<HTMLElement>(\n 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex=\"-1\"])',\n )\n ?.focus();\n }}\n onCloseAutoFocus={(event) => {\n event.preventDefault();\n if (triggerRef.current?.isConnected) {\n triggerRef.current.focus();\n }\n }}\n >\n {title && <div id={titleId}>{title}</div>}\n <PopoverPrimitive.Arrow className=\"tw-fill-[var(--background-inverted)]\" />\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n );\n}\n\nexport default function Tooltip(props: ITooltipProps) {\n const {\n children,\n title,\n content,\n open,\n onOpenChange,\n placement = 'top',\n mouseEnterDelay = 0,\n mouseLeaveDelay = 0,\n overlayClassName,\n trigger,\n getPopupContainer,\n getTooltipContainer,\n zIndex,\n } = props;\n\n const { triggerRef, container } = usePortalContainer(\n getPopupContainer,\n getTooltipContainer,\n );\n const resolvedZIndex = useFloatingTooltipZIndex(zIndex);\n const tooltipIdBase = React.useId().replace(/:/g, '');\n const mergedTitle = title ?? content;\n\n if (!mergedTitle && mergedTitle !== 0) {\n return <>{children}</>;\n }\n\n if (isTriggerDisabled(trigger)) {\n return <>{children}</>;\n }\n\n if (isClickTrigger(trigger)) {\n return (\n <ClickTooltip\n title={mergedTitle}\n open={open}\n onOpenChange={onOpenChange}\n placement={placement}\n overlayClassName={overlayClassName}\n zIndex={resolvedZIndex}\n container={container}\n triggerRef={triggerRef}\n >\n {children}\n </ClickTooltip>\n );\n }\n\n const side = sideMap[placement] || 'top';\n const align = alignMap[placement] || 'center';\n\n return (\n <TooltipPrimitive.Provider\n delayDuration={mouseEnterDelay * 1000}\n skipDelayDuration={mouseLeaveDelay * 1000}\n >\n <TooltipPrimitive.Root open={open} onOpenChange={onOpenChange}>\n <TooltipPrimitive.Trigger asChild>\n {React.isValidElement(children) ? (\n React.cloneElement(children as React.ReactElement, {\n ref: triggerRef,\n })\n ) : (\n <span ref={triggerRef as React.RefObject<HTMLSpanElement>}>\n {children}\n </span>\n )}\n </TooltipPrimitive.Trigger>\n <TooltipPrimitive.Portal container={container}>\n <TooltipPrimitive.Content\n id={`ald-tooltip-${tooltipIdBase}`}\n side={side}\n align={align}\n sideOffset={4}\n className={cn(contentClasses, overlayClassName)}\n style={{ zIndex: resolvedZIndex }}\n >\n {mergedTitle}\n <TooltipPrimitive.Arrow className=\"tw-fill-[var(--background-inverted)]\" />\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n </TooltipPrimitive.Root>\n </TooltipPrimitive.Provider>\n );\n}\n"],"mappings":"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"}
|
|
@@ -6,9 +6,11 @@ export declare function useFloatingLayer(baseZIndex?: number): {
|
|
|
6
6
|
maskZIndex: number;
|
|
7
7
|
contentZIndex: number;
|
|
8
8
|
popupZIndex: number;
|
|
9
|
+
tooltipZIndex: number;
|
|
9
10
|
nextLevel: number;
|
|
10
11
|
};
|
|
11
12
|
export declare function useFloatingPopupZIndex(zIndex?: number): number;
|
|
13
|
+
export declare function useFloatingTooltipZIndex(zIndex?: number): number;
|
|
12
14
|
export declare function FloatingLayerProvider({ children, value, }: {
|
|
13
15
|
children: React.ReactNode;
|
|
14
16
|
value: number;
|
|
@@ -11,6 +11,7 @@ function useFloatingLayer(baseZIndex = FLOATING_LAYER_BASE_Z_INDEX) {
|
|
|
11
11
|
maskZIndex,
|
|
12
12
|
contentZIndex: maskZIndex + 1,
|
|
13
13
|
popupZIndex: maskZIndex + 2,
|
|
14
|
+
tooltipZIndex: maskZIndex + 3,
|
|
14
15
|
nextLevel: level + 1
|
|
15
16
|
};
|
|
16
17
|
}
|
|
@@ -18,6 +19,10 @@ function useFloatingPopupZIndex(zIndex) {
|
|
|
18
19
|
const { popupZIndex } = useFloatingLayer();
|
|
19
20
|
return zIndex ?? popupZIndex;
|
|
20
21
|
}
|
|
22
|
+
function useFloatingTooltipZIndex(zIndex) {
|
|
23
|
+
const { tooltipZIndex } = useFloatingLayer();
|
|
24
|
+
return zIndex ?? tooltipZIndex;
|
|
25
|
+
}
|
|
21
26
|
function FloatingLayerProvider({ children, value }) {
|
|
22
27
|
return /* @__PURE__ */ jsx(FloatingLayerContext.Provider, {
|
|
23
28
|
value,
|
|
@@ -25,6 +30,6 @@ function FloatingLayerProvider({ children, value }) {
|
|
|
25
30
|
});
|
|
26
31
|
}
|
|
27
32
|
//#endregion
|
|
28
|
-
export { FLOATING_LAYER_BASE_Z_INDEX, FloatingLayerProvider, useFloatingLayer, useFloatingPopupZIndex };
|
|
33
|
+
export { FLOATING_LAYER_BASE_Z_INDEX, FloatingLayerProvider, useFloatingLayer, useFloatingPopupZIndex, useFloatingTooltipZIndex };
|
|
29
34
|
|
|
30
35
|
//# sourceMappingURL=floatingLayer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floatingLayer.js","names":[],"sources":["../../src/_utils/floatingLayer.tsx"],"sourcesContent":["import React, { createContext, useContext } from 'react';\n\nexport const FLOATING_LAYER_BASE_Z_INDEX = 1000;\nexport const FLOATING_LAYER_STEP = 10;\n\nconst FloatingLayerContext = createContext(0);\n\nexport function useFloatingLayer(baseZIndex = FLOATING_LAYER_BASE_Z_INDEX) {\n const level = useContext(FloatingLayerContext);\n const maskZIndex = baseZIndex + level * FLOATING_LAYER_STEP;\n\n return {\n level,\n maskZIndex,\n contentZIndex: maskZIndex + 1,\n popupZIndex: maskZIndex + 2,\n nextLevel: level + 1,\n };\n}\n\nexport function useFloatingPopupZIndex(zIndex?: number) {\n const { popupZIndex } = useFloatingLayer();\n return zIndex ?? popupZIndex;\n}\n\nexport function FloatingLayerProvider({\n children,\n value,\n}: {\n children: React.ReactNode;\n value: number;\n}) {\n return (\n <FloatingLayerContext.Provider value={value}>\n {children}\n </FloatingLayerContext.Provider>\n );\n}\n"],"mappings":";;;AAEA,IAAa,8BAA8B;AAG3C,IAAM,uBAAuB,cAAc,EAAE;AAE7C,SAAgB,iBAAiB,aAAa,6BAA6B;CACzE,MAAM,QAAQ,WAAW,qBAAqB;CAC9C,MAAM,aAAa,aAAa,QAAA;AAEhC,QAAO;EACL;EACA;EACA,eAAe,aAAa;EAC5B,aAAa,aAAa;EAC1B,WAAW,QAAQ;EACpB;;AAGH,SAAgB,uBAAuB,QAAiB;CACtD,MAAM,EAAE,gBAAgB,kBAAkB;AAC1C,QAAO,UAAU;;AAGnB,SAAgB,sBAAsB,EACpC,UACA,SAIC;AACD,QACE,oBAAC,qBAAqB,UAAtB;EAAsC;EACnC;EAC6B,CAAA"}
|
|
1
|
+
{"version":3,"file":"floatingLayer.js","names":[],"sources":["../../src/_utils/floatingLayer.tsx"],"sourcesContent":["import React, { createContext, useContext } from 'react';\n\nexport const FLOATING_LAYER_BASE_Z_INDEX = 1000;\nexport const FLOATING_LAYER_STEP = 10;\n\nconst FloatingLayerContext = createContext(0);\n\nexport function useFloatingLayer(baseZIndex = FLOATING_LAYER_BASE_Z_INDEX) {\n const level = useContext(FloatingLayerContext);\n const maskZIndex = baseZIndex + level * FLOATING_LAYER_STEP;\n\n return {\n level,\n maskZIndex,\n contentZIndex: maskZIndex + 1,\n popupZIndex: maskZIndex + 2,\n tooltipZIndex: maskZIndex + 3,\n nextLevel: level + 1,\n };\n}\n\nexport function useFloatingPopupZIndex(zIndex?: number) {\n const { popupZIndex } = useFloatingLayer();\n return zIndex ?? popupZIndex;\n}\n\nexport function useFloatingTooltipZIndex(zIndex?: number) {\n const { tooltipZIndex } = useFloatingLayer();\n return zIndex ?? tooltipZIndex;\n}\n\nexport function FloatingLayerProvider({\n children,\n value,\n}: {\n children: React.ReactNode;\n value: number;\n}) {\n return (\n <FloatingLayerContext.Provider value={value}>\n {children}\n </FloatingLayerContext.Provider>\n );\n}\n"],"mappings":";;;AAEA,IAAa,8BAA8B;AAG3C,IAAM,uBAAuB,cAAc,EAAE;AAE7C,SAAgB,iBAAiB,aAAa,6BAA6B;CACzE,MAAM,QAAQ,WAAW,qBAAqB;CAC9C,MAAM,aAAa,aAAa,QAAA;AAEhC,QAAO;EACL;EACA;EACA,eAAe,aAAa;EAC5B,aAAa,aAAa;EAC1B,eAAe,aAAa;EAC5B,WAAW,QAAQ;EACpB;;AAGH,SAAgB,uBAAuB,QAAiB;CACtD,MAAM,EAAE,gBAAgB,kBAAkB;AAC1C,QAAO,UAAU;;AAGnB,SAAgB,yBAAyB,QAAiB;CACxD,MAAM,EAAE,kBAAkB,kBAAkB;AAC5C,QAAO,UAAU;;AAGnB,SAAgB,sBAAsB,EACpC,UACA,SAIC;AACD,QACE,oBAAC,qBAAqB,UAAtB;EAAsC;EACnC;EAC6B,CAAA"}
|