@tribepad/themis 1.6.4 → 1.6.6
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/CHANGELOG.md +17 -0
- package/dist/elements/AlertDialog/index.js +1 -1
- package/dist/elements/AlertDialog/index.js.map +1 -1
- package/dist/elements/AlertDialog/index.mjs +1 -1
- package/dist/elements/AlertDialog/index.mjs.map +1 -1
- package/dist/elements/Breadcrumbs/index.js +1 -1
- package/dist/elements/Breadcrumbs/index.js.map +1 -1
- package/dist/elements/Breadcrumbs/index.mjs +1 -1
- package/dist/elements/Breadcrumbs/index.mjs.map +1 -1
- package/dist/elements/ColorPicker/index.js +1 -1
- package/dist/elements/ColorPicker/index.js.map +1 -1
- package/dist/elements/ColorPicker/index.mjs +1 -1
- package/dist/elements/ColorPicker/index.mjs.map +1 -1
- package/dist/elements/Combobox/Combobox.d.ts.map +1 -1
- package/dist/elements/Combobox/index.js +1 -1
- package/dist/elements/Combobox/index.js.map +1 -1
- package/dist/elements/Combobox/index.mjs +1 -1
- package/dist/elements/Combobox/index.mjs.map +1 -1
- package/dist/elements/DatePicker/DatePicker.d.ts.map +1 -1
- package/dist/elements/DatePicker/DateRangePicker.d.ts.map +1 -1
- package/dist/elements/DatePicker/index.js +1 -1
- package/dist/elements/DatePicker/index.js.map +1 -1
- package/dist/elements/DatePicker/index.mjs +1 -1
- package/dist/elements/DatePicker/index.mjs.map +1 -1
- package/dist/elements/Dropdown/Dropdown.d.ts.map +1 -1
- package/dist/elements/Dropdown/index.js +1 -1
- package/dist/elements/Dropdown/index.js.map +1 -1
- package/dist/elements/Dropdown/index.mjs +1 -1
- package/dist/elements/Dropdown/index.mjs.map +1 -1
- package/dist/elements/FileField/index.js +1 -1
- package/dist/elements/FileField/index.js.map +1 -1
- package/dist/elements/FileField/index.mjs +1 -1
- package/dist/elements/FileField/index.mjs.map +1 -1
- package/dist/elements/Filters/FilterPopover.d.ts.map +1 -1
- package/dist/elements/Filters/index.js +1 -1
- package/dist/elements/Filters/index.js.map +1 -1
- package/dist/elements/Filters/index.mjs +1 -1
- package/dist/elements/Filters/index.mjs.map +1 -1
- package/dist/elements/Modal/Modal.d.ts +2 -2
- package/dist/elements/Modal/Modal.d.ts.map +1 -1
- package/dist/elements/Modal/Modal.styles.d.ts +25 -0
- package/dist/elements/Modal/Modal.styles.d.ts.map +1 -1
- package/dist/elements/Modal/Modal.types.d.ts +29 -0
- package/dist/elements/Modal/Modal.types.d.ts.map +1 -1
- package/dist/elements/Modal/index.d.ts +3 -3
- package/dist/elements/Modal/index.d.ts.map +1 -1
- package/dist/elements/Modal/index.js +1 -1
- package/dist/elements/Modal/index.js.map +1 -1
- package/dist/elements/Modal/index.mjs +1 -1
- package/dist/elements/Modal/index.mjs.map +1 -1
- package/dist/elements/NumberField/index.js +1 -1
- package/dist/elements/NumberField/index.js.map +1 -1
- package/dist/elements/NumberField/index.mjs +1 -1
- package/dist/elements/NumberField/index.mjs.map +1 -1
- package/dist/elements/PageTitle/index.js +1 -1
- package/dist/elements/PageTitle/index.js.map +1 -1
- package/dist/elements/PageTitle/index.mjs +1 -1
- package/dist/elements/PageTitle/index.mjs.map +1 -1
- package/dist/elements/Panel/Panel.d.ts.map +1 -1
- package/dist/elements/Panel/index.js +1 -1
- package/dist/elements/Panel/index.js.map +1 -1
- package/dist/elements/Panel/index.mjs +1 -1
- package/dist/elements/Panel/index.mjs.map +1 -1
- package/dist/elements/PasswordField/index.js +1 -1
- package/dist/elements/PasswordField/index.js.map +1 -1
- package/dist/elements/PasswordField/index.mjs +1 -1
- package/dist/elements/PasswordField/index.mjs.map +1 -1
- package/dist/elements/Resizable/components/ResizablePopover.d.ts.map +1 -1
- package/dist/elements/Resizable/index.js +1 -1
- package/dist/elements/Resizable/index.js.map +1 -1
- package/dist/elements/Resizable/index.mjs +1 -1
- package/dist/elements/Resizable/index.mjs.map +1 -1
- package/dist/elements/SearchField/index.js +1 -1
- package/dist/elements/SearchField/index.js.map +1 -1
- package/dist/elements/SearchField/index.mjs +1 -1
- package/dist/elements/SearchField/index.mjs.map +1 -1
- package/dist/elements/Select/Select.d.ts.map +1 -1
- package/dist/elements/Select/index.js +1 -1
- package/dist/elements/Select/index.js.map +1 -1
- package/dist/elements/Select/index.mjs +1 -1
- package/dist/elements/Select/index.mjs.map +1 -1
- package/dist/elements/Sidebar/SidebarMobileDrawer.d.ts.map +1 -1
- package/dist/elements/Sidebar/index.js +1 -1
- package/dist/elements/Sidebar/index.js.map +1 -1
- package/dist/elements/Sidebar/index.mjs +1 -1
- package/dist/elements/Sidebar/index.mjs.map +1 -1
- package/dist/elements/Table/index.js +1 -1
- package/dist/elements/Table/index.js.map +1 -1
- package/dist/elements/Table/index.mjs +1 -1
- package/dist/elements/Table/index.mjs.map +1 -1
- package/dist/elements/TextField/index.js +1 -1
- package/dist/elements/TextField/index.js.map +1 -1
- package/dist/elements/TextField/index.mjs +1 -1
- package/dist/elements/TextField/index.mjs.map +1 -1
- package/dist/elements/TimeField/index.js +1 -1
- package/dist/elements/TimeField/index.js.map +1 -1
- package/dist/elements/TimeField/index.mjs +1 -1
- package/dist/elements/TimeField/index.mjs.map +1 -1
- package/dist/elements/Wizard/index.js +1 -1
- package/dist/elements/Wizard/index.js.map +1 -1
- package/dist/elements/Wizard/index.mjs +1 -1
- package/dist/elements/Wizard/index.mjs.map +1 -1
- package/dist/elements/index.js +1 -1
- package/dist/elements/index.js.map +1 -1
- package/dist/elements/index.mjs +1 -1
- package/dist/elements/index.mjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/styles/animations.css +32 -0
- package/dist/styles/index.js +1 -1
- package/dist/styles/index.js.map +1 -1
- package/dist/styles/index.mjs +1 -1
- package/dist/styles/index.mjs.map +1 -1
- package/dist/styles/shared-variants.d.ts +17 -0
- package/dist/styles/shared-variants.d.ts.map +1 -1
- package/dist/utils/browserExtensionOverlay.d.ts +36 -0
- package/dist/utils/browserExtensionOverlay.d.ts.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/index.mjs +1 -1
- package/dist/utils/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/elements/Modal/Modal.stories.tsx +106 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/utils/cn.ts","../../../src/elements/Dropdown/Dropdown.styles.ts","../../../src/elements/Dropdown/Dropdown.tsx"],"names":["cn","inputs","twMerge","clsx","menuVariants","cva","menuItemVariants","getDisplayName","type","DropdownRoot","forwardRef","defaultOpen","isOpen","onOpenChange","children","_ref","childArray","Children","hasTrigger","child","isValidElement","DropdownTrigger","hasMenu","DropdownMenu","jsx","AriaMenuTrigger","props","ref","cloneElement","AriaButton","align","side","className","placement","AriaPopover","AriaMenu","DropdownItem","onAction","isDisabled","shortcut","icon","iconRight","ariaLabel","isDropdownMenu","hasSubmenu","contentChildren","submenu","jsxs","AriaSubmenuTrigger","AriaMenuItem","ChevronRight","DropdownSeparator","memo","AriaSeparator","DropdownLabel","AriaHeader","Dropdown"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Class Name Utility\n * Merges Tailwind CSS classes with conflict resolution\n *\n * Combines clsx for conditional classes and tailwind-merge for deduplication\n *\n * @example\n * cn('px-2 py-1', 'px-4') // => 'py-1 px-4' (px-4 overrides px-2)\n * cn('text-red-500', condition && 'text-blue-500') // => conditional application\n */\n\nimport { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import { cva, type VariantProps } from 'class-variance-authority';\n\n/**\n * Menu variant styles using CVA\n * @see spec.md FR-040 (CVA for variant styling - single \"default\" variant for v1)\n */\nexport const menuVariants = cva(\n // Base styles - semantic tokens with fallbacks\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border border-[var(--menu-border)] bg-[var(--menu-background)] text-[var(--menu-foreground)] p-1\",\n {\n variants: {\n variant: {\n default: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/**\n * Menu Item variant styles using CVA\n * @see spec.md FR-041 (CVA for item states: hover, focus, active, disabled)\n */\nexport const menuItemVariants = cva(\n // Base styles - FR-014: 44x44px minimum touch targets\n \"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 min-h-[44px] data-[focused]:bg-[var(--menu-accent)] data-[focused]:text-[var(--menu-accent-foreground)] data-[pressed]:bg-[var(--menu-accent)] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/**\n * Type exports for variant props\n * Allows TypeScript inference of variant combinations\n */\nexport type MenuVariantProps = VariantProps<typeof menuVariants>;\nexport type MenuItemVariantProps = VariantProps<typeof menuItemVariants>;\n","\"use client\";\n\n/**\n * Dropdown Menu Component\n * Accessible dropdown menu with React Aria primitives, nested submenus, and CVA styling\n *\n * @see spec.md FR-001 to FR-054 (Dropdown Component Requirements)\n * @see spec.md FR-009 (WCAG 2.2 AAA - 7:1 contrast ratio)\n * @see spec.md FR-014 (44x44px minimum touch targets)\n * @see constitution.md Principle IV (Accessibility First)\n */\n\nimport { forwardRef, memo, Children, isValidElement, type ReactNode, type ReactElement, cloneElement, type ComponentType } from 'react';\nimport type { Placement } from 'react-aria';\nimport {\n MenuTrigger as AriaMenuTrigger,\n SubmenuTrigger as AriaSubmenuTrigger,\n Button as AriaButton,\n Menu as AriaMenu,\n MenuItem as AriaMenuItem,\n Separator as AriaSeparator,\n Header as AriaHeader,\n Popover as AriaPopover,\n} from 'react-aria-components';\nimport { ChevronRight } from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport { menuVariants, menuItemVariants } from './Dropdown.styles';\nimport type {\n DropdownProps,\n DropdownTriggerProps,\n DropdownMenuProps,\n DropdownItemProps,\n DropdownSeparatorProps,\n DropdownLabelProps,\n} from './Dropdown.types';\n\n/**\n * Type-safe helper to get displayName from a component type.\n */\nfunction getDisplayName(type: unknown): string | undefined {\n if (typeof type === 'function' || typeof type === 'object') {\n return (type as ComponentType)?.displayName;\n }\n return undefined;\n}\n\n/**\n * Dropdown Root Component\n * Manages open/close state and coordinates Trigger and Menu children\n *\n * @see spec.md FR-001 to FR-007\n */\ninterface InternalDropdownProps extends DropdownProps {\n children: ReactNode;\n}\n\nconst DropdownRoot = forwardRef<HTMLDivElement, InternalDropdownProps>(\n ({ defaultOpen = false, isOpen, onOpenChange, children }, _ref) => {\n // Validate children structure in development only\n if (process.env.NODE_ENV !== 'production') {\n const childArray = Children.toArray(children);\n const hasTrigger = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownTrigger || getDisplayName(child.type) === 'DropdownTrigger')\n );\n const hasMenu = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownMenu || getDisplayName(child.type) === 'DropdownMenu')\n );\n\n if (!hasTrigger || !hasMenu) {\n throw new Error(\n 'Dropdown requires exactly one Dropdown.Trigger and one Dropdown.Menu as children'\n );\n }\n }\n\n return (\n <AriaMenuTrigger defaultOpen={defaultOpen} isOpen={isOpen} onOpenChange={onOpenChange}>\n {children}\n </AriaMenuTrigger>\n );\n }\n);\n\nDropdownRoot.displayName = 'Dropdown';\n\n/**\n * Dropdown.Trigger Component\n * Wraps trigger element (typically Button) with proper ARIA attributes\n *\n * @see spec.md FR-008 to FR-012\n */\nconst DropdownTrigger = forwardRef<HTMLButtonElement, DropdownTriggerProps>(\n ({ children, ...props }, ref) => {\n // Clone child to forward props. Note: NO `slot: 'trigger'` here —\n // `MenuTrigger` (the parent provider) injects its press behaviour into\n // the child Button via the default ButtonContext slot, not a named\n // 'trigger' slot. Adding `slot=\"trigger\"` worked in older react-aria-\n // components but 1.17+ strict-validates slots and throws\n // `Invalid slot \"trigger\". Valid slot names are \"close\".` when the\n // Dropdown is rendered inside a Dialog/Modal subtree.\n //\n // The Disclosure pattern (see Accordion.tsx) DOES require\n // `slot=\"trigger\"` — that's a different react-aria contract where\n // Disclosure's context exposes a named `trigger` slot.\n if (isValidElement(children)) {\n return cloneElement(children as ReactElement<Record<string, unknown>>, props);\n }\n\n // Fallback: wrap in AriaButton if not a React element\n return (\n <AriaButton ref={ref} {...props}>\n {children}\n </AriaButton>\n );\n }\n);\n\nDropdownTrigger.displayName = 'DropdownTrigger';\n\n/**\n * Dropdown.Menu Component\n * Renders menu with positioning, collision detection, and focus management\n *\n * @see spec.md FR-014 to FR-024\n */\nconst DropdownMenu = forwardRef<HTMLDivElement, DropdownMenuProps>(\n ({ align = 'start', side = 'bottom', className, children, ...props }, _ref) => {\n // Map align to React Aria placement\n const placement = `${side} ${align}` as Placement;\n\n return (\n <AriaPopover\n placement={placement}\n className=\"data-[entering]:motion-safe:animate-in data-[entering]:motion-safe:fade-in-0 data-[entering]:motion-safe:slide-in-from-top-2 data-[entering]:[animation-duration:250ms] data-[entering]:[animation-timing-function:cubic-bezier(0.16,1,0.3,1)] data-[exiting]:motion-safe:animate-out data-[exiting]:motion-safe:fade-out-0 data-[exiting]:motion-safe:slide-out-to-top-2 data-[exiting]:[animation-duration:150ms]\"\n >\n <AriaMenu\n className={cn(menuVariants({ variant: 'default' }), className)}\n {...props}\n >\n {children}\n </AriaMenu>\n </AriaPopover>\n );\n }\n);\n\nDropdownMenu.displayName = 'DropdownMenu';\n\n/**\n * Dropdown.Item Component\n * Menu item with action callbacks, disabled state, shortcuts, icons, and nested submenu support\n *\n * @see spec.md FR-025 to FR-034\n */\nconst DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(\n (\n {\n children,\n onAction,\n isDisabled = false,\n shortcut,\n icon,\n iconRight,\n className,\n 'aria-label': ariaLabel,\n ...props\n },\n _ref\n ) => {\n // Check if this item contains a nested submenu\n const childArray = Children.toArray(children);\n const isDropdownMenu = (child: unknown): boolean =>\n isValidElement(child) &&\n (child.type === DropdownMenu || getDisplayName(child.type) === 'DropdownMenu');\n\n const hasSubmenu = childArray.some(isDropdownMenu);\n\n // Filter children to separate submenu from content\n const contentChildren = childArray.filter((child) => !isDropdownMenu(child));\n\n const submenu = childArray.find(isDropdownMenu);\n\n if (hasSubmenu && submenu) {\n // Render as submenu trigger using React Aria's SubmenuTrigger\n return (\n <AriaSubmenuTrigger>\n <AriaMenuItem\n aria-label={ariaLabel}\n className={cn(menuItemVariants({ variant: 'default' }), className)}\n {...props}\n >\n {icon && <span className=\"mr-2\">{icon}</span>}\n <span className=\"flex-1\">{contentChildren}</span>\n <ChevronRight className=\"ml-auto h-4 w-4\" aria-hidden=\"true\" />\n </AriaMenuItem>\n {submenu as ReactElement}\n </AriaSubmenuTrigger>\n );\n }\n\n // Regular menu item\n return (\n <AriaMenuItem\n onAction={onAction}\n isDisabled={isDisabled}\n aria-label={ariaLabel}\n className={cn(menuItemVariants({ variant: 'default' }), className)}\n {...props}\n >\n {icon && <span className=\"mr-2\">{icon}</span>}\n <span className=\"flex-1\">{children}</span>\n {iconRight && <span className=\"ml-auto\">{iconRight}</span>}\n {shortcut && (\n <kbd className=\"ml-auto pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-[var(--border)] bg-[var(--accent-background)] px-1.5 font-mono text-[10px] font-medium text-[var(--menu-muted)] opacity-100\">\n {shortcut}\n </kbd>\n )}\n </AriaMenuItem>\n );\n }\n);\n\nDropdownItem.displayName = 'DropdownItem';\n\n/**\n * Dropdown.Separator Component\n * Non-focusable visual divider\n *\n * @see spec.md FR-043 to FR-045\n */\nconst DropdownSeparator = memo(forwardRef<HTMLDivElement, DropdownSeparatorProps>(\n ({ className, ...props }, _ref) => {\n return (\n <AriaSeparator\n className={cn(\n '-mx-1 my-1 h-px bg-[var(--accent-background)]',\n className\n )}\n {...props}\n />\n );\n }\n));\n\nDropdownSeparator.displayName = 'DropdownSeparator';\n\n/**\n * Dropdown.Label Component\n * Non-interactive section header\n *\n * @see spec.md FR-046 to FR-048\n */\nconst DropdownLabel = memo(forwardRef<HTMLDivElement, DropdownLabelProps>(\n ({ children, className, ...props }, _ref) => {\n return (\n <AriaHeader\n className={cn(\n 'px-2 py-1.5 text-sm font-semibold text-[var(--menu-muted)]',\n className\n )}\n {...props}\n >\n {children}\n </AriaHeader>\n );\n }\n));\n\nDropdownLabel.displayName = 'DropdownLabel';\n\n/**\n * Export compound component via Object.assign for backwards compatibility.\n * Enables `<Dropdown.Trigger>`, `<Dropdown.Menu>`, etc.\n *\n * @deprecated v2 — Remove Object.assign pattern in favour of direct named exports\n * (DropdownTrigger, DropdownMenu, DropdownItem, DropdownSeparator, DropdownLabel)\n * for better tree-shaking. See named exports below.\n */\nexport const Dropdown = Object.assign(DropdownRoot, {\n Trigger: DropdownTrigger,\n Menu: DropdownMenu,\n Item: DropdownItem,\n Separator: DropdownSeparator,\n Label: DropdownLabel,\n});\n\n// Export individual components for flexibility\nexport { DropdownTrigger, DropdownMenu, DropdownItem, DropdownSeparator, DropdownLabel };\n\n// Export variant functions for external use\nexport { menuVariants, menuItemVariants };\n\n// Export types\nexport type {\n DropdownProps,\n DropdownTriggerProps,\n DropdownMenuProps,\n DropdownItemProps,\n DropdownSeparatorProps,\n DropdownLabelProps,\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/cn.ts","../../../src/utils/browserExtensionOverlay.ts","../../../src/elements/Dropdown/Dropdown.styles.ts","../../../src/elements/Dropdown/Dropdown.tsx"],"names":["cn","inputs","twMerge","clsx","isExtensionInjectedElement","element","node","depth","tag","root","custom","parent","createInteractOutsideGuard","consumerShouldClose","menuVariants","cva","menuItemVariants","getDisplayName","type","DropdownRoot","forwardRef","defaultOpen","isOpen","onOpenChange","children","_ref","childArray","Children","hasTrigger","child","isValidElement","DropdownTrigger","hasMenu","DropdownMenu","jsx","AriaMenuTrigger","props","ref","cloneElement","AriaButton","align","side","className","placement","AriaPopover","AriaMenu","DropdownItem","onAction","isDisabled","shortcut","icon","iconRight","ariaLabel","isDropdownMenu","hasSubmenu","contentChildren","submenu","jsxs","AriaSubmenuTrigger","AriaMenuItem","ChevronRight","DropdownSeparator","memo","AriaSeparator","DropdownLabel","AriaHeader","Dropdown"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Class Name Utility\n * Merges Tailwind CSS classes with conflict resolution\n *\n * Combines clsx for conditional classes and tailwind-merge for deduplication\n *\n * @example\n * cn('px-2 py-1', 'px-4') // => 'py-1 px-4' (px-4 overrides px-2)\n * cn('text-red-500', condition && 'text-blue-500') // => conditional application\n */\n\nimport { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Detection + dismissal guard for in-page writing-assistant browser extensions\n * (Grammarly, LanguageTool, Wordtune, …).\n *\n * These extensions inject their suggestion UI as elements appended to `<body>`,\n * outside any open overlay's DOM subtree. React Aria's `isDismissable` behaviour\n * treats a click on that injected UI as an \"outside click\" and dismisses the\n * overlay — so clicking a spelling suggestion silently closes the form pop-up\n * and discards the user's in-progress correction.\n *\n * The guard below lets overlays keep open when the interaction lands on an\n * extension-injected node, while every other outside click, Escape, and the\n * close button behave exactly as before.\n */\n\nconst MAX_ANCESTOR_DEPTH = 100;\n\n/**\n * Returns `true` when `element` belongs to an injected in-page writing\n * assistant (Grammarly, LanguageTool, Wordtune, …).\n *\n * UX-ONLY heuristic. This is a deliberately spoofable DOM sniff used solely to\n * keep a form pop-up open when a writing-assistant suggestion is clicked. It is\n * NOT a security/authorization control and must never gate access to data or\n * actions (the frontend is not a security boundary). Pure function — never log\n * the element (it can reference arbitrary DOM / user content).\n */\nexport function isExtensionInjectedElement(element: Element): boolean {\n if (!(element instanceof Element)) return false;\n\n // 1. Known-vendor markers (authoritative). Walk up via parentElement, and\n // climb shadow boundaries via getRootNode().host so detection still finds\n // the <grammarly-extension> host if React Aria's shadowDOM flag is ever\n // enabled (it defaults to false today → the document-level listener\n // already receives the retargeted host, so the parentElement walk alone\n // suffices currently). Depth-bounded as a defensive guard against a\n // crafted/overridden getRootNode/host returning a cycle (which would\n // otherwise hang the tab — a client-side DoS).\n let node: Element | null = element;\n for (let depth = 0; node && depth < MAX_ANCESTOR_DEPTH; depth++) {\n const tag = node.tagName?.toLowerCase() ?? '';\n if (tag.startsWith('grammarly-')) return true; // Grammarly\n if (tag.startsWith('lt-')) return true; // LanguageTool\n if (node.hasAttribute('data-grammarly-shadow-root')) return true;\n\n if (node.parentElement) {\n node = node.parentElement;\n } else {\n const root = node.getRootNode();\n node = root instanceof ShadowRoot ? root.host : null;\n }\n }\n\n // 2. Structural fallback (best-effort, future-proofs the long tail).\n // Extensions inject their UI as a custom element (hyphenated tag name)\n // mounted as a top-level sibling of the React root — i.e. a direct child\n // of <body>/<html>. Our app never renders body-level custom elements, and\n // React Aria portals render plain <div>s, so this stays safe for any\n // future first-party web component nested inside the app tree.\n let custom: Element | null = element;\n while (custom && !custom.tagName.includes('-')) {\n custom = custom.parentElement;\n }\n if (!custom) return false;\n\n const parent = custom.parentElement;\n return parent === document.body || parent === document.documentElement;\n}\n\n/**\n * Builds a `shouldCloseOnInteractOutside` predicate for React Aria overlays\n * that keeps the overlay open when the interaction targets an extension-injected\n * element, while preserving any consumer-supplied predicate.\n *\n * React Aria semantics: the predicate returns `true` ⇒ the overlay should\n * close. So we close only when the element is NOT extension-injected AND the\n * consumer (if any) also agrees it should close.\n */\nexport function createInteractOutsideGuard(\n consumerShouldClose?: (element: Element) => boolean,\n): (element: Element) => boolean {\n return (element: Element): boolean =>\n !isExtensionInjectedElement(element) && (consumerShouldClose?.(element) ?? true);\n}\n","import { cva, type VariantProps } from 'class-variance-authority';\n\n/**\n * Menu variant styles using CVA\n * @see spec.md FR-040 (CVA for variant styling - single \"default\" variant for v1)\n */\nexport const menuVariants = cva(\n // Base styles - semantic tokens with fallbacks\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border border-[var(--menu-border)] bg-[var(--menu-background)] text-[var(--menu-foreground)] p-1\",\n {\n variants: {\n variant: {\n default: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/**\n * Menu Item variant styles using CVA\n * @see spec.md FR-041 (CVA for item states: hover, focus, active, disabled)\n */\nexport const menuItemVariants = cva(\n // Base styles - FR-014: 44x44px minimum touch targets\n \"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 min-h-[44px] data-[focused]:bg-[var(--menu-accent)] data-[focused]:text-[var(--menu-accent-foreground)] data-[pressed]:bg-[var(--menu-accent)] [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\n/**\n * Type exports for variant props\n * Allows TypeScript inference of variant combinations\n */\nexport type MenuVariantProps = VariantProps<typeof menuVariants>;\nexport type MenuItemVariantProps = VariantProps<typeof menuItemVariants>;\n","\"use client\";\n\n/**\n * Dropdown Menu Component\n * Accessible dropdown menu with React Aria primitives, nested submenus, and CVA styling\n *\n * @see spec.md FR-001 to FR-054 (Dropdown Component Requirements)\n * @see spec.md FR-009 (WCAG 2.2 AAA - 7:1 contrast ratio)\n * @see spec.md FR-014 (44x44px minimum touch targets)\n * @see constitution.md Principle IV (Accessibility First)\n */\n\nimport { forwardRef, memo, Children, isValidElement, type ReactNode, type ReactElement, cloneElement, type ComponentType } from 'react';\nimport type { Placement } from 'react-aria';\nimport {\n MenuTrigger as AriaMenuTrigger,\n SubmenuTrigger as AriaSubmenuTrigger,\n Button as AriaButton,\n Menu as AriaMenu,\n MenuItem as AriaMenuItem,\n Separator as AriaSeparator,\n Header as AriaHeader,\n Popover as AriaPopover,\n} from 'react-aria-components';\nimport { ChevronRight } from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport { createInteractOutsideGuard } from '../../utils/browserExtensionOverlay';\nimport { menuVariants, menuItemVariants } from './Dropdown.styles';\nimport type {\n DropdownProps,\n DropdownTriggerProps,\n DropdownMenuProps,\n DropdownItemProps,\n DropdownSeparatorProps,\n DropdownLabelProps,\n} from './Dropdown.types';\n\n/**\n * Type-safe helper to get displayName from a component type.\n */\nfunction getDisplayName(type: unknown): string | undefined {\n if (typeof type === 'function' || typeof type === 'object') {\n return (type as ComponentType)?.displayName;\n }\n return undefined;\n}\n\n/**\n * Dropdown Root Component\n * Manages open/close state and coordinates Trigger and Menu children\n *\n * @see spec.md FR-001 to FR-007\n */\ninterface InternalDropdownProps extends DropdownProps {\n children: ReactNode;\n}\n\nconst DropdownRoot = forwardRef<HTMLDivElement, InternalDropdownProps>(\n ({ defaultOpen = false, isOpen, onOpenChange, children }, _ref) => {\n // Validate children structure in development only\n if (process.env.NODE_ENV !== 'production') {\n const childArray = Children.toArray(children);\n const hasTrigger = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownTrigger || getDisplayName(child.type) === 'DropdownTrigger')\n );\n const hasMenu = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === DropdownMenu || getDisplayName(child.type) === 'DropdownMenu')\n );\n\n if (!hasTrigger || !hasMenu) {\n throw new Error(\n 'Dropdown requires exactly one Dropdown.Trigger and one Dropdown.Menu as children'\n );\n }\n }\n\n return (\n <AriaMenuTrigger defaultOpen={defaultOpen} isOpen={isOpen} onOpenChange={onOpenChange}>\n {children}\n </AriaMenuTrigger>\n );\n }\n);\n\nDropdownRoot.displayName = 'Dropdown';\n\n/**\n * Dropdown.Trigger Component\n * Wraps trigger element (typically Button) with proper ARIA attributes\n *\n * @see spec.md FR-008 to FR-012\n */\nconst DropdownTrigger = forwardRef<HTMLButtonElement, DropdownTriggerProps>(\n ({ children, ...props }, ref) => {\n // Clone child to forward props. Note: NO `slot: 'trigger'` here —\n // `MenuTrigger` (the parent provider) injects its press behaviour into\n // the child Button via the default ButtonContext slot, not a named\n // 'trigger' slot. Adding `slot=\"trigger\"` worked in older react-aria-\n // components but 1.17+ strict-validates slots and throws\n // `Invalid slot \"trigger\". Valid slot names are \"close\".` when the\n // Dropdown is rendered inside a Dialog/Modal subtree.\n //\n // The Disclosure pattern (see Accordion.tsx) DOES require\n // `slot=\"trigger\"` — that's a different react-aria contract where\n // Disclosure's context exposes a named `trigger` slot.\n if (isValidElement(children)) {\n return cloneElement(children as ReactElement<Record<string, unknown>>, props);\n }\n\n // Fallback: wrap in AriaButton if not a React element\n return (\n <AriaButton ref={ref} {...props}>\n {children}\n </AriaButton>\n );\n }\n);\n\nDropdownTrigger.displayName = 'DropdownTrigger';\n\n/**\n * Dropdown.Menu Component\n * Renders menu with positioning, collision detection, and focus management\n *\n * @see spec.md FR-014 to FR-024\n */\nconst DropdownMenu = forwardRef<HTMLDivElement, DropdownMenuProps>(\n ({ align = 'start', side = 'bottom', className, children, ...props }, _ref) => {\n // Map align to React Aria placement\n const placement = `${side} ${align}` as Placement;\n\n return (\n <AriaPopover\n placement={placement}\n shouldCloseOnInteractOutside={createInteractOutsideGuard()}\n className=\"data-[entering]:motion-safe:animate-in data-[entering]:motion-safe:fade-in-0 data-[entering]:motion-safe:slide-in-from-top-2 data-[entering]:[animation-duration:250ms] data-[entering]:[animation-timing-function:cubic-bezier(0.16,1,0.3,1)] data-[exiting]:motion-safe:animate-out data-[exiting]:motion-safe:fade-out-0 data-[exiting]:motion-safe:slide-out-to-top-2 data-[exiting]:[animation-duration:150ms]\"\n >\n <AriaMenu\n className={cn(menuVariants({ variant: 'default' }), className)}\n {...props}\n >\n {children}\n </AriaMenu>\n </AriaPopover>\n );\n }\n);\n\nDropdownMenu.displayName = 'DropdownMenu';\n\n/**\n * Dropdown.Item Component\n * Menu item with action callbacks, disabled state, shortcuts, icons, and nested submenu support\n *\n * @see spec.md FR-025 to FR-034\n */\nconst DropdownItem = forwardRef<HTMLDivElement, DropdownItemProps>(\n (\n {\n children,\n onAction,\n isDisabled = false,\n shortcut,\n icon,\n iconRight,\n className,\n 'aria-label': ariaLabel,\n ...props\n },\n _ref\n ) => {\n // Check if this item contains a nested submenu\n const childArray = Children.toArray(children);\n const isDropdownMenu = (child: unknown): boolean =>\n isValidElement(child) &&\n (child.type === DropdownMenu || getDisplayName(child.type) === 'DropdownMenu');\n\n const hasSubmenu = childArray.some(isDropdownMenu);\n\n // Filter children to separate submenu from content\n const contentChildren = childArray.filter((child) => !isDropdownMenu(child));\n\n const submenu = childArray.find(isDropdownMenu);\n\n if (hasSubmenu && submenu) {\n // Render as submenu trigger using React Aria's SubmenuTrigger\n return (\n <AriaSubmenuTrigger>\n <AriaMenuItem\n aria-label={ariaLabel}\n className={cn(menuItemVariants({ variant: 'default' }), className)}\n {...props}\n >\n {icon && <span className=\"mr-2\">{icon}</span>}\n <span className=\"flex-1\">{contentChildren}</span>\n <ChevronRight className=\"ml-auto h-4 w-4\" aria-hidden=\"true\" />\n </AriaMenuItem>\n {submenu as ReactElement}\n </AriaSubmenuTrigger>\n );\n }\n\n // Regular menu item\n return (\n <AriaMenuItem\n onAction={onAction}\n isDisabled={isDisabled}\n aria-label={ariaLabel}\n className={cn(menuItemVariants({ variant: 'default' }), className)}\n {...props}\n >\n {icon && <span className=\"mr-2\">{icon}</span>}\n <span className=\"flex-1\">{children}</span>\n {iconRight && <span className=\"ml-auto\">{iconRight}</span>}\n {shortcut && (\n <kbd className=\"ml-auto pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border border-[var(--border)] bg-[var(--accent-background)] px-1.5 font-mono text-[10px] font-medium text-[var(--menu-muted)] opacity-100\">\n {shortcut}\n </kbd>\n )}\n </AriaMenuItem>\n );\n }\n);\n\nDropdownItem.displayName = 'DropdownItem';\n\n/**\n * Dropdown.Separator Component\n * Non-focusable visual divider\n *\n * @see spec.md FR-043 to FR-045\n */\nconst DropdownSeparator = memo(forwardRef<HTMLDivElement, DropdownSeparatorProps>(\n ({ className, ...props }, _ref) => {\n return (\n <AriaSeparator\n className={cn(\n '-mx-1 my-1 h-px bg-[var(--accent-background)]',\n className\n )}\n {...props}\n />\n );\n }\n));\n\nDropdownSeparator.displayName = 'DropdownSeparator';\n\n/**\n * Dropdown.Label Component\n * Non-interactive section header\n *\n * @see spec.md FR-046 to FR-048\n */\nconst DropdownLabel = memo(forwardRef<HTMLDivElement, DropdownLabelProps>(\n ({ children, className, ...props }, _ref) => {\n return (\n <AriaHeader\n className={cn(\n 'px-2 py-1.5 text-sm font-semibold text-[var(--menu-muted)]',\n className\n )}\n {...props}\n >\n {children}\n </AriaHeader>\n );\n }\n));\n\nDropdownLabel.displayName = 'DropdownLabel';\n\n/**\n * Export compound component via Object.assign for backwards compatibility.\n * Enables `<Dropdown.Trigger>`, `<Dropdown.Menu>`, etc.\n *\n * @deprecated v2 — Remove Object.assign pattern in favour of direct named exports\n * (DropdownTrigger, DropdownMenu, DropdownItem, DropdownSeparator, DropdownLabel)\n * for better tree-shaking. See named exports below.\n */\nexport const Dropdown = Object.assign(DropdownRoot, {\n Trigger: DropdownTrigger,\n Menu: DropdownMenu,\n Item: DropdownItem,\n Separator: DropdownSeparator,\n Label: DropdownLabel,\n});\n\n// Export individual components for flexibility\nexport { DropdownTrigger, DropdownMenu, DropdownItem, DropdownSeparator, DropdownLabel };\n\n// Export variant functions for external use\nexport { menuVariants, menuItemVariants };\n\n// Export types\nexport type {\n DropdownProps,\n DropdownTriggerProps,\n DropdownMenuProps,\n DropdownItemProps,\n DropdownSeparatorProps,\n DropdownLabelProps,\n};\n"]}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
'use strict';var react=require('react'),reactAriaComponents=require('react-aria-components'),lucideReact=require('lucide-react'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),classVarianceAuthority=require('class-variance-authority'),jsxRuntime=require('react/jsx-runtime'),zod=require('zod');function b(...e){return tailwindMerge.twMerge(clsx.clsx(e))}var me=classVarianceAuthority.cva("inline-flex justify-center min-h-[44px] min-w-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50",{variants:{fullWidth:{true:"w-full",false:""},inVerticalGroup:{true:"items-stretch",false:"items-center"}},defaultVariants:{fullWidth:false,inVerticalGroup:false}}),ge=classVarianceAuthority.cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-normal ring-offset-background motion-safe:transition-transform motion-safe:duration-200 motion-safe:[transition-timing-function:cubic-bezier(0.34,1.56,0.64,1)] motion-reduce:transition-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 relative cursor-pointer",{variants:{variant:{default:"bg-[var(--primary-action)] text-[var(--primary-action-foreground)] shadow-md hover:bg-[var(--primary-action-hover)] hover:-translate-y-1",destructive:"bg-[var(--destructive-background)] text-[var(--destructive-foreground)] hover:bg-[var(--destructive-background-hover,var(--destructive-background))] motion-safe:hover:btn-warn-shake",outline:"border border-[var(--input-border)] bg-[var(--page-background)] hover:bg-[var(--input-border)]",secondary:"bg-[var(--secondary)] text-[var(--secondary-foreground)] hover:bg-[var(--secondary-hover,var(--secondary))]",ghost:"hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)]",link:"text-[var(--text-link)] underline underline-offset-4 hover:bg-[var(--accent)] hover:text-[var(--text-link-hover)]"},fullWidth:{true:"w-full",false:""},visualSize:{default:"h-10 px-4 py-2",sm:"h-9 rounded-md px-3 text-xs",lg:"h-11 rounded-md px-6 text-base",icon:"h-10 w-10",dot:"h-5 w-5 rounded-full p-0 min-h-0 min-w-0"},paywall:{true:"!bg-[var(--paywall)] !text-[var(--paywall-foreground)] hover:!bg-[var(--paywall)]/90 !cursor-not-allowed !border-transparent",false:""}},defaultVariants:{variant:"default",visualSize:"default",paywall:false}});var ve="data-[pressed]:scale-[0.97]";var te="hc:data-[hovered]:outline hc:data-[hovered]:outline-2 hc:data-[hovered]:outline-foreground",re="hc:data-[pressed]:outline hc:data-[pressed]:outline-2 hc:data-[pressed]:outline-offset-1 hc:data-[pressed]:outline-foreground";var dt=react.createContext(null);dt.displayName="ButtonGroupContext";function ut(){return react.useContext(dt)}var ct=react.createContext(null);ct.displayName="ButtonGroupItemContext";function ft(){return react.useContext(ct)}classVarianceAuthority.cva("inline-flex items-center gap-0",{variants:{orientation:{horizontal:"flex-row",vertical:"flex-col w-full"}},defaultVariants:{orientation:"horizontal"}});var pt=classVarianceAuthority.cva("",{variants:{orientation:{horizontal:"min-w-[44px]",vertical:"flex min-h-[44px]"},position:{first:"",middle:"",last:"",only:""}},compoundVariants:[{orientation:"horizontal",position:"first",className:"rounded-r-none border-r-0"},{orientation:"horizontal",position:"middle",className:"rounded-none border-r-0"},{orientation:"horizontal",position:"last",className:"rounded-l-none"},{orientation:"vertical",position:"first",className:"rounded-b-none border-b-0"},{orientation:"vertical",position:"middle",className:"rounded-none border-b-0"},{orientation:"vertical",position:"last",className:"rounded-t-none"}],defaultVariants:{orientation:"horizontal",position:"only"}});classVarianceAuthority.cva("bg-[var(--border)]",{variants:{orientation:{horizontal:"w-px h-6 mx-1",vertical:"h-px w-full my-1"}},defaultVariants:{orientation:"horizontal"}});var L=react.memo(react.forwardRef(({className:e,buttonVisualClassName:r,variant:t,size:a,visualSize:i,fullWidth:o,loading:d=false,loadingText:m="Loading...",shortcut:u,children:c,isDisabled:g,paywall:s=false,paywallRedirect:E,paywallDescription:_,onPress:f,...I},de)=>{let Y=react.useId(),v=ut(),N=ft(),B=t??v?.variant??"default",ue=a??v?.size,U=g??v?.isDisabled??false,X=v?.orientation==="vertical",q=o||X,ce=N?pt({orientation:v?.orientation??"horizontal",position:N.position}):"",z=i??ue??"default";return process.env.NODE_ENV!=="production"&&(z==="dot"||z==="icon")&&!I["aria-label"]&&!c&&console.warn('[Button] visualSize="dot" or "icon" requires aria-label when no visible text is provided (WCAG 1.1.1)'),jsxRuntime.jsx(reactAriaComponents.Button,{ref:de,isDisabled:U||d||void 0,"aria-disabled":s?true:void 0,"aria-describedby":s?Y:void 0,onPress:R=>{if(s){E&&window.open(E,"_blank","noopener,noreferrer");return}f?.(R);},className:b(me({fullWidth:q,inVerticalGroup:X}),e),...I,children:R=>jsxRuntime.jsxs("span",{className:b(ge({variant:B,visualSize:z,paywall:s,fullWidth:q}),ce,r,ve,"",te,re),"data-pressed":R.isPressed||void 0,children:[d&&jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(lucideReact.Loader2,{className:"motion-safe:animate-spin","aria-hidden":"true"}),jsxRuntime.jsx("span",{className:"sr-only","aria-live":"polite",children:m})]}),!d&&c,s&&jsxRuntime.jsx(lucideReact.Zap,{"data-testid":"zap-icon","aria-hidden":"true",className:"ml-1"}),s&&jsxRuntime.jsxs("span",{id:Y,className:"sr-only",children:["Premium feature: ",_||"Upgrade required to access this feature"]}),R.isFocusVisible&&u&&jsxRuntime.jsx("kbd",{className:"ml-auto hidden text-xs opacity-60 lg:inline",children:u})]})})}));L.displayName="Button";var Se=["focus-within:outline-none","focus-within:ring-2","focus-within:ring-[var(--ring)]","focus-within:ring-offset-2"],Ee=["focus-visible:outline-none","focus-visible:ring-2","focus-visible:ring-[var(--ring)]","focus-visible:ring-offset-2"];var Ie=["disabled:pointer-events-none","disabled:opacity-50"];var C={sm:"text-xs",default:"text-sm",lg:"text-base"},ie={sm:"text-sm",default:"text-base",lg:"text-lg"},ne=["min-h-[44px]","min-w-[44px]"];var Fe=["flex","items-center","gap-1.5","text-[var(--destructive-background)]"],Ve=["flex","items-center","gap-1.5","text-[var(--success-background)]"],Te=["text-[var(--menu-muted)]"],_e=["font-medium","text-[var(--content-foreground)]"];var oe=["transition-colors","duration-200"];function A(...e){return e.flatMap(r=>Array.isArray(r)?[...r]:[r])}var Ne=classVarianceAuthority.cva("flex flex-col gap-1.5 w-full",{variants:{size:ie},defaultVariants:{size:"default"}}),ye=classVarianceAuthority.cva(A("flex flex-col items-center justify-center rounded-md border-2 border-dashed","bg-[var(--content-background)] text-[var(--content-foreground)]",oe,Se),{variants:{size:{sm:"min-h-[100px] p-4 gap-2",default:"min-h-[140px] p-6 gap-3",lg:"min-h-[180px] p-8 gap-4"},isDragOver:{true:"border-[var(--primary)] bg-[var(--primary)]/5",false:"border-[var(--input-border)] hover:border-[var(--primary)]/50"},isInvalid:{true:"border-[var(--destructive-background)] bg-[var(--destructive-background)]/5",false:""},isDisabled:{true:"opacity-50 cursor-not-allowed pointer-events-none",false:"cursor-pointer"}},compoundVariants:[{isInvalid:true,isDragOver:true,className:"border-[var(--destructive-background)] bg-[var(--destructive-background)]/5"}],defaultVariants:{size:"default",isDragOver:false,isInvalid:false,isDisabled:false}}),Pe=classVarianceAuthority.cva(A("inline-flex items-center justify-center gap-2 rounded-md font-medium",oe,ne,Ee,Ie),{variants:{size:{sm:"px-3 py-2 text-xs",default:"px-4 py-2 text-sm",lg:"px-6 py-3 text-base"},variant:{default:"bg-[var(--primary)] text-[var(--primary-foreground)] hover:bg-[var(--primary)]/90",outline:"border border-[var(--input-border)] bg-transparent hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)]"}},defaultVariants:{size:"default",variant:"default"}}),Re=classVarianceAuthority.cva("flex flex-col gap-2 mt-3",{variants:{size:{sm:"gap-1.5",default:"gap-2",lg:"gap-3"}},defaultVariants:{size:"default"}}),mt=classVarianceAuthority.cva("flex items-center justify-between mb-1",{variants:{size:C},defaultVariants:{size:"default"}}),Ae=classVarianceAuthority.cva("flex items-center justify-between gap-3 bg-[var(--accent-background)] rounded-md border border-[var(--border)]",{variants:{size:{sm:"px-2 py-1.5 text-xs",default:"px-3 py-2 text-sm",lg:"px-4 py-3 text-base"}},defaultVariants:{size:"default"}}),Oe=classVarianceAuthority.cva(A("inline-flex items-center justify-center rounded-full",ne,"-mr-2 -my-1","text-[var(--menu-muted)] hover:text-[var(--destructive-background)] hover:bg-[var(--destructive-background)]/10","transition-colors","focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]"),{variants:{size:{sm:"",default:"",lg:""}},defaultVariants:{size:"default"}}),we=classVarianceAuthority.cva(A(Fe,"font-medium"),{variants:{size:C},defaultVariants:{size:"default"}}),Le=classVarianceAuthority.cva(A(Ve,"font-medium"),{variants:{size:C},defaultVariants:{size:"default"}}),Ce=classVarianceAuthority.cva(Te,{variants:{size:C},defaultVariants:{size:"default"}}),De=classVarianceAuthority.cva(_e,{variants:{size:ie,isRequired:{true:"after:content-['*'] after:ml-0.5 after:text-[var(--destructive-background)]",false:""}},defaultVariants:{size:"default",isRequired:false}});function se(e){if(e===0)return "0 B";let r=1024,t=["B","KB","MB","GB"],a=Math.floor(Math.log(e)/Math.log(r)),i=parseFloat((e/Math.pow(r,a)).toFixed(1));return `${i%1===0?i.toFixed(0):i.toFixed(1)} ${t[a]}`}function $(e,r=30){if(e.length<=r)return e;let t=e.lastIndexOf(".");if(t===-1)return `${e.slice(0,r-3)}...`;let a=e.slice(t),i=e.slice(0,t),o=r-a.length-3;return o<1?`...${a}`:`${i.slice(0,o)}...${a}`}function Be(e,r){return !r||r.length===0?true:r.some(t=>{if(t.endsWith("/*")){let a=t.slice(0,-2);return e.type.startsWith(`${a}/`)}return t.includes("/")?e.type===t:t.startsWith(".")?e.name.toLowerCase().endsWith(t.toLowerCase()):false})}function j(e){return e.type.startsWith("image/")?"image":e.type.startsWith("video/")?"video":e.type.startsWith("audio/")?"audio":"file"}function W(e,r){let t=[...e];for(let a of r){let i=t.findIndex(o=>o.name===a.name);i>=0?t[i]=a:t.push(a);}return t}function Zt(e){return !e||e.length===0?"any file":e.map(t=>t==="image/*"?"images":t==="video/*"?"videos":t==="audio/*"?"audio":t.startsWith(".")?t.slice(1).toUpperCase():t.includes("/")?(t.split("/")[1]??t).toUpperCase():t).join(", ")}var gt=2*1024*1024;function Ue(e){return e.type.startsWith("image/")?true:/\.(jpg|jpeg|png|gif|webp|svg|bmp|ico|avif|heic|heif|tiff|tif)$/i.test(e.name)}async function vt(e,r=200){return new Promise((t,a)=>{let i=new window.Image,o=URL.createObjectURL(e);i.onload=()=>{URL.revokeObjectURL(o);let d=Math.min(r/i.width,r/i.height,1),m=Math.round(i.width*d),u=Math.round(i.height*d),c=document.createElement("canvas");c.width=m,c.height=u;let g=c.getContext("2d");if(!g){a(new Error("Canvas context unavailable"));return}g.drawImage(i,0,0,m,u),c.toBlob(s=>{s?t(URL.createObjectURL(s)):a(new Error("Failed to create blob"));},"image/jpeg",.8);},i.onerror=()=>{URL.revokeObjectURL(o),a(new Error("Failed to load image"));},i.src=o;})}async function ze(e,r=200){return e.size>gt?vt(e,r):URL.createObjectURL(e)}function Ge(e,r={}){let{enabled:t=true,maxBytes:a=10*1024*1024,maxDimension:i=200}=r,[o,d]=react.useState(null),[m,u]=react.useState(false),[c,g]=react.useState(null),s=Ue(e);return react.useEffect(()=>{if(!t||!s){d(null),u(false),g(null);return}if(e.size>a){d(null),u(false),g("File too large for preview");return}let E=true,_=null;return (async()=>{u(true),g(null);try{_=await ze(e,i),E?(d(_),u(!1)):URL.revokeObjectURL(_);}catch(I){E&&(g(I instanceof Error?I.message:"Failed to generate preview"),u(false),d(null));}})(),()=>{E=false,_&&URL.revokeObjectURL(_),d(I=>(I&&URL.revokeObjectURL(I),null));}},[e,t,a,i,s]),{preview:o,isLoading:m,error:c,isImage:s}}function Me({file:e,size:r=64,maxBytes:t=10*1024*1024,renderPreview:a,className:i}){let{preview:o,isLoading:d,error:m,isImage:u}=Ge(e,{enabled:true,maxBytes:t,maxDimension:r*2}),c={width:r,height:r,minWidth:r,minHeight:r};if(!u&&a)return jsxRuntime.jsx("div",{className:b("flex items-center justify-center rounded-md overflow-hidden","bg-[var(--accent-background)]",i),style:c,children:a(e)});if(d)return jsxRuntime.jsx("div",{className:b("flex items-center justify-center rounded-md overflow-hidden","bg-[var(--accent-background)]",i),style:c,"aria-busy":"true","aria-label":`Loading preview for ${e.name}`,children:jsxRuntime.jsx(lucideReact.Loader2,{className:"h-4 w-4 animate-spin text-[var(--menu-muted)]","aria-hidden":"true"})});if(u&&o&&!m)return jsxRuntime.jsx("div",{className:b("flex items-center justify-center rounded-md overflow-hidden","bg-[var(--accent-background)]",i),style:c,children:jsxRuntime.jsx("img",{src:o,alt:e.name,className:"w-full h-full object-cover",loading:"lazy"})});let g=j(e),s=er(g),E=Math.max(16,Math.floor(r*.4));return jsxRuntime.jsx("div",{className:b("flex items-center justify-center rounded-md overflow-hidden","bg-[var(--accent-background)]",i),style:c,"aria-label":m?`Preview unavailable for ${e.name}`:void 0,children:jsxRuntime.jsx(s,{className:"text-[var(--menu-muted)]",style:{width:E,height:E},"aria-hidden":"true"})})}function er(e){switch(e){case "image":return lucideReact.ImageIcon;case "video":return lucideReact.VideoIcon;case "audio":return lucideReact.AudioLines;default:return lucideReact.FileIcon}}var ke=classVarianceAuthority.cva(["flex","flex-col","gap-1","w-full"],{variants:{size:{sm:"text-xs",default:"text-sm",lg:"text-base"}},defaultVariants:{size:"default"}}),$e=classVarianceAuthority.cva(["rounded-full","bg-[var(--accent-background)]","overflow-hidden"],{variants:{size:{sm:"h-1.5",default:"h-2",lg:"h-3"}},defaultVariants:{size:"default"}}),je=classVarianceAuthority.cva(["h-full","rounded-full","transition-all","duration-300"],{variants:{status:{pending:["bg-gradient-to-r","from-[var(--menu-muted)]","via-[var(--accent-background)]","to-[var(--menu-muted)]","bg-[length:200%_100%]","animate-progress-shimmer"],uploading:"bg-[var(--primary)]",complete:"bg-[var(--success-background)]",error:"bg-[var(--destructive-background)]"}},defaultVariants:{status:"pending"}}),We=classVarianceAuthority.cva(["flex","items-center","justify-between","gap-2"],{variants:{size:{sm:"text-xs",default:"text-sm",lg:"text-base"}},defaultVariants:{size:"default"}}),Ze=classVarianceAuthority.cva(["flex","items-center","justify-between","gap-2","mt-1","text-[var(--destructive-background)]"],{variants:{size:{sm:"text-xs",default:"text-sm",lg:"text-base"}},defaultVariants:{size:"default"}}),Ye=classVarianceAuthority.cva(["underline","hover:no-underline","min-h-[44px]","min-w-[44px]","inline-flex","items-center","justify-center","-mr-3","-my-2","focus-visible:outline-none","focus-visible:ring-2","focus-visible:ring-[var(--ring)]","focus-visible:ring-offset-2","rounded"],{variants:{size:{sm:"text-xs",default:"text-sm",lg:"text-base"}},defaultVariants:{size:"default"}});function ar(e,r){switch(e){case "pending":return "Queued for upload\u2026";case "uploading":return `Uploading\u2026 ${r}%`;case "complete":return "Upload complete";case "error":return "Upload failed \u2014 try again"}}function le({file:e,progress:r,status:t,error:a,onRetry:i,size:o="default",className:d}){let m=t==="pending",u=`progress-error-${e.name.replace(/[^a-zA-Z0-9]/g,"-")}`,c=ar(t,r);return jsxRuntime.jsxs("div",{className:b(ke({size:o}),d),children:[jsxRuntime.jsx(reactAriaComponents.ProgressBar,{"aria-label":e.name,value:m?void 0:r,isIndeterminate:m,"aria-describedby":t==="error"&&a?u:void 0,children:({percentage:g,valueText:s})=>jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsxs("div",{className:We({size:o}),children:[jsxRuntime.jsx("span",{className:"truncate",title:e.name,children:$(e.name,30)}),jsxRuntime.jsx("span",{className:"text-[var(--menu-muted)] flex-shrink-0",children:t==="error"?c:s??c})]}),jsxRuntime.jsx("div",{className:$e({size:o}),children:jsxRuntime.jsx("div",{className:je({status:t}),style:{width:m?"100%":`${g??0}%`}})})]})}),t==="error"&&a&&jsxRuntime.jsxs("div",{id:u,className:Ze({size:o}),children:[jsxRuntime.jsx("span",{children:a}),i&&jsxRuntime.jsx(reactAriaComponents.Button,{onPress:i,className:Ye({size:o}),children:"Retry"})]}),jsxRuntime.jsxs("div",{"aria-live":"polite","aria-atomic":"true",className:"sr-only",children:[t==="complete"&&`${e.name} upload complete`,t==="error"&&`${e.name} upload failed${a?`: ${a}`:""}`]})]})}le.displayName="FileProgress";var bt=react.forwardRef(function({label:r,acceptedFileTypes:t,allowsMultiple:a=false,maxFileSize:i,maxFiles:o,description:d,errorMessage:m,successMessage:u,triggerText:c,isRequired:g,isDisabled:s,isInvalid:E,isValid:_,size:f="default",name:I,id:de,className:Y,value:v=[],onChange:N,validate:B,showPreviews:ue=false,previewSize:U=64,maxPreviewBytes:X=10*1024*1024,renderPreview:q,showProgress:ce=false,uploadProgress:z,uploadStatus:Xe,uploadErrors:qe,onRetry:R,"data-testid":Qe,"aria-label":xr,"aria-labelledby":br,"aria-describedby":Ke,...St},Et){let It=react.useId(),Q=de??It,Je=`${Q}-label`,et=`${Q}-description`,tt=`${Q}-error`,[rt,fe]=react.useState(false),[Ft,pe]=react.useState(null),K=react.useRef(0),H=m??Ft,Vt=E||!!H,G=[];Ke&&G.push(Ke),d&&G.push(et),H&&G.push(tt);let Tt=G.length>0?G.join(" "):void 0,at=react.useCallback((n,x=[])=>{let F=[],h=[];for(let S of n){if(t&&!Be(S,t)){h.push(`"${S.name}" is not a supported file type. Accepted: ${t}`);continue}if(i&&S.size>i){h.push(`"${S.name}" is too large (max ${se(i)}). Try compressing or resizing the file.`);continue}F.push(S);}return o&&a&&W(x,F).length>o?(h.push(`Maximum ${o} files allowed`),{valid:[],errors:h}):{valid:F,errors:h}},[t,i,o,a]),J=react.useCallback(n=>{if(!n||n.length===0)return;pe(null);let x=Array.from(n),F=a?v:[],{valid:h,errors:S}=at(x,F);if(S.length>0){pe(S[0]??"Invalid file");return}if(B&&h.length>0){let ee=B(a?W(F,h):h);if(ee){pe(ee);return}}let M;a?M=W(F,h):M=h.slice(0,1),N?.(M);},[a,v,at,B,N]),_t=react.useCallback(n=>{J(n);},[J]),Nt=react.useCallback(n=>{let x=v.filter(F=>F!==n);N?.(x);},[v,N]),yt=react.useCallback(()=>{N?.([]);},[N]),Pt=react.useCallback(n=>{n.preventDefault(),n.stopPropagation(),!s&&(K.current++,fe(true));},[s]),Rt=react.useCallback(n=>{n.preventDefault(),n.stopPropagation();},[]),At=react.useCallback(n=>{n.preventDefault(),n.stopPropagation(),K.current--,K.current===0&&fe(false);},[]),Ot=react.useCallback(n=>{if(n.preventDefault(),n.stopPropagation(),K.current=0,fe(false),s)return;let x=n.dataTransfer?.files;J(x??null);},[s,J]),wt=n=>{switch(j(n)){case "image":return lucideReact.ImageIcon;case "video":return lucideReact.VideoIcon;case "audio":return lucideReact.AudioLines;default:return lucideReact.FileIcon}},Lt=t?.join(",");return jsxRuntime.jsxs("div",{ref:Et,id:Q,className:b(Ne({size:f}),Y),"data-testid":Qe??"file-field",...St,children:[jsxRuntime.jsx("label",{id:Je,className:De({size:f,isRequired:g}),children:r}),jsxRuntime.jsxs("div",{role:"group","data-testid":`${Qe??"file-field"}-dropzone`,className:b("drop-zone",ye({size:f,isDragOver:rt,isInvalid:Vt,isDisabled:s})),onDragEnter:Pt,onDragOver:Rt,onDragLeave:At,onDrop:Ot,"aria-labelledby":Je,"aria-describedby":Tt,"aria-disabled":s||void 0,children:[jsxRuntime.jsx(reactAriaComponents.FileTrigger,{acceptedFileTypes:t,allowsMultiple:a,onSelect:_t,children:jsxRuntime.jsxs(L,{variant:"outline",isDisabled:s,buttonVisualClassName:Pe({size:f}),children:[jsxRuntime.jsx(lucideReact.Upload,{className:"h-4 w-4","aria-hidden":"true"}),rt?"Drop files here":c??(a?"Choose files":"Choose file")]})}),I&&jsxRuntime.jsx("input",{type:"file",name:I,accept:Lt,multiple:a,disabled:s,className:"sr-only",tabIndex:-1,"aria-hidden":"true"})]}),d&&jsxRuntime.jsx("p",{id:et,className:Ce({size:f}),children:d}),v.length>0&&jsxRuntime.jsxs("div",{className:Re({size:f}),children:[v.length>=2&&jsxRuntime.jsxs("div",{className:mt({size:f}),children:[jsxRuntime.jsxs("span",{className:"text-[var(--menu-muted)]",children:[v.length," files selected"]}),jsxRuntime.jsx(L,{variant:"link",visualSize:"sm",onPress:yt,buttonVisualClassName:b("text-[var(--menu-muted)] hover:text-[var(--destructive-background)]","underline-offset-4 hover:underline"),"aria-label":"Clear all files",children:"Clear all"})]}),jsxRuntime.jsx("ul",{className:"space-y-2",children:v.map((n,x)=>{let F=wt(n),h=f==="sm"?Math.min(U,40):f==="lg"?Math.min(U,80):Math.min(U,48),S=Xe?.[x],M=z?.[x]??0,ee=qe?.get(x),it=ce&&S!==void 0;return jsxRuntime.jsx("li",{className:it?"p-3":Ae({size:f}),children:it?jsxRuntime.jsx(le,{file:n,progress:M,status:S,error:ee,onRetry:R?()=>R(x):void 0,size:f}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[ue?jsxRuntime.jsx(Me,{file:n,size:h,maxBytes:X,renderPreview:q,className:"flex-shrink-0"}):jsxRuntime.jsx(F,{className:"h-4 w-4 flex-shrink-0 text-[var(--menu-muted)]","aria-hidden":"true"}),jsxRuntime.jsx("span",{className:"truncate",title:n.name,children:$(n.name,30)}),jsxRuntime.jsx("span",{className:"text-[var(--menu-muted)] flex-shrink-0",children:se(n.size)})]}),jsxRuntime.jsx(L,{variant:"ghost",visualSize:"icon",onPress:()=>Nt(n),buttonVisualClassName:Oe({size:f}),"aria-label":`Remove ${n.name}`,isDisabled:s,children:jsxRuntime.jsx(lucideReact.X,{className:"h-4 w-4","aria-hidden":"true"})})]})},`${n.name}-${x}`)})})]}),H&&jsxRuntime.jsx("p",{id:tt,role:"alert",className:we({size:f}),children:H}),!H&&_&&u&&jsxRuntime.jsx("p",{className:Le({size:f}),children:u})]})});bt.displayName="FileField";var ht=zod.z.object({className:zod.z.string().optional(),children:zod.z.any().optional(),id:zod.z.string().optional(),"aria-label":zod.z.string().optional(),"aria-labelledby":zod.z.string().optional(),"aria-describedby":zod.z.string().optional(),"aria-live":zod.z.enum(["off","polite","assertive"]).optional(),"aria-hidden":zod.z.boolean().optional(),"data-testid":zod.z.string().optional()});var vr=ht.extend({label:zod.z.string(),acceptedFileTypes:zod.z.array(zod.z.string()).optional(),allowsMultiple:zod.z.boolean().default(false),maxFileSize:zod.z.number().optional(),maxFiles:zod.z.number().optional(),description:zod.z.string().optional(),errorMessage:zod.z.string().optional(),successMessage:zod.z.string().optional(),triggerText:zod.z.string().optional(),isRequired:zod.z.boolean().optional(),isDisabled:zod.z.boolean().optional(),isInvalid:zod.z.boolean().optional(),isValid:zod.z.boolean().optional(),size:zod.z.enum(["sm","default","lg"]).default("default"),name:zod.z.string().optional(),showPreviews:zod.z.boolean().default(false),previewSize:zod.z.number().min(16).max(256).default(64),maxPreviewBytes:zod.z.number().default(10*1024*1024),showProgress:zod.z.boolean().default(false),uploadProgress:zod.z.array(zod.z.number().min(0).max(100)).optional(),uploadStatus:zod.z.array(zod.z.enum(["pending","uploading","complete","error"])).optional()}).refine(e=>!(e.successMessage&&e.errorMessage),{message:"Cannot provide both successMessage and errorMessage. Use one based on validation state.",path:["successMessage"]}).refine(e=>(typeof process<"u"&&process.env.NODE_ENV==="development"&&e.isValid&&e.isInvalid&&console.error("[FileField] Both isValid and isInvalid are true. isInvalid takes precedence."),true));exports.FileField=bt;exports.FileFieldPropsSchema=vr;exports.FilePreview=Me;exports.FileProgress=le;exports.RESIZE_THRESHOLD=gt;exports.createResizedPreview=vt;exports.deduplicateFiles=W;exports.fileFieldContainerVariants=Ne;exports.fileFieldDescriptionVariants=Ce;exports.fileFieldDropZoneVariants=ye;exports.fileFieldErrorVariants=we;exports.fileFieldItemVariants=Ae;exports.fileFieldLabelVariants=De;exports.fileFieldListVariants=Re;exports.fileFieldRemoveButtonVariants=Oe;exports.fileFieldSuccessVariants=Le;exports.fileFieldTriggerVariants=Pe;exports.fileProgressBarVariants=je;exports.fileProgressErrorVariants=Ze;exports.fileProgressHeaderVariants=We;exports.fileProgressRetryVariants=Ye;exports.fileProgressTrackVariants=$e;exports.fileProgressVariants=ke;exports.formatAcceptedTypes=Zt;exports.formatFileSize=se;exports.generatePreview=ze;exports.getFileIcon=j;exports.isFileTypeAccepted=Be;exports.isImageFile=Ue;exports.truncateFileName=$;exports.useFilePreview=Ge;//# sourceMappingURL=index.js.map
|
|
2
|
+
'use strict';var react=require('react'),reactAriaComponents=require('react-aria-components'),lucideReact=require('lucide-react'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),classVarianceAuthority=require('class-variance-authority'),jsxRuntime=require('react/jsx-runtime'),zod=require('zod');function b(...e){return tailwindMerge.twMerge(clsx.clsx(e))}var me=classVarianceAuthority.cva("inline-flex justify-center min-h-[44px] min-w-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50",{variants:{fullWidth:{true:"w-full",false:""},inVerticalGroup:{true:"items-stretch",false:"items-center"}},defaultVariants:{fullWidth:false,inVerticalGroup:false}}),ge=classVarianceAuthority.cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-normal ring-offset-background motion-safe:transition-transform motion-safe:duration-200 motion-safe:[transition-timing-function:cubic-bezier(0.34,1.56,0.64,1)] motion-reduce:transition-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 relative cursor-pointer",{variants:{variant:{default:"bg-[var(--primary-action)] text-[var(--primary-action-foreground)] shadow-md hover:bg-[var(--primary-action-hover)] hover:-translate-y-1",destructive:"bg-[var(--destructive-background)] text-[var(--destructive-foreground)] hover:bg-[var(--destructive-background-hover,var(--destructive-background))] motion-safe:hover:btn-warn-shake",outline:"border border-[var(--input-border)] bg-[var(--page-background)] hover:bg-[var(--input-border)]",secondary:"bg-[var(--secondary)] text-[var(--secondary-foreground)] hover:bg-[var(--secondary-hover,var(--secondary))]",ghost:"hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)]",link:"text-[var(--text-link)] underline underline-offset-4 hover:bg-[var(--accent)] hover:text-[var(--text-link-hover)]"},fullWidth:{true:"w-full",false:""},visualSize:{default:"h-10 px-4 py-2",sm:"h-9 rounded-md px-3 text-xs",lg:"h-11 rounded-md px-6 text-base",icon:"h-10 w-10",dot:"h-5 w-5 rounded-full p-0 min-h-0 min-w-0"},paywall:{true:"!bg-[var(--paywall)] !text-[var(--paywall-foreground)] hover:!bg-[var(--paywall)]/90 !cursor-not-allowed !border-transparent",false:""}},defaultVariants:{variant:"default",visualSize:"default",paywall:false}});var ve="data-[pressed]:scale-[0.97]";var te="hc:data-[hovered]:outline hc:data-[hovered]:outline-2 hc:data-[hovered]:outline-foreground",re="hc:data-[pressed]:outline hc:data-[pressed]:outline-2 hc:data-[pressed]:outline-offset-1 hc:data-[pressed]:outline-foreground";var dt=react.createContext(null);dt.displayName="ButtonGroupContext";function ut(){return react.useContext(dt)}var ct=react.createContext(null);ct.displayName="ButtonGroupItemContext";function ft(){return react.useContext(ct)}classVarianceAuthority.cva("inline-flex items-center gap-0",{variants:{orientation:{horizontal:"flex-row",vertical:"flex-col w-full"}},defaultVariants:{orientation:"horizontal"}});var pt=classVarianceAuthority.cva("",{variants:{orientation:{horizontal:"min-w-[44px]",vertical:"flex min-h-[44px]"},position:{first:"",middle:"",last:"",only:""}},compoundVariants:[{orientation:"horizontal",position:"first",className:"rounded-r-none border-r-0"},{orientation:"horizontal",position:"middle",className:"rounded-none border-r-0"},{orientation:"horizontal",position:"last",className:"rounded-l-none"},{orientation:"vertical",position:"first",className:"rounded-b-none border-b-0"},{orientation:"vertical",position:"middle",className:"rounded-none border-b-0"},{orientation:"vertical",position:"last",className:"rounded-t-none"}],defaultVariants:{orientation:"horizontal",position:"only"}});classVarianceAuthority.cva("bg-[var(--border)]",{variants:{orientation:{horizontal:"w-px h-6 mx-1",vertical:"h-px w-full my-1"}},defaultVariants:{orientation:"horizontal"}});var D=react.memo(react.forwardRef(({className:e,buttonVisualClassName:r,variant:t,size:a,visualSize:i,fullWidth:o,loading:d=false,loadingText:m="Loading...",shortcut:u,children:c,isDisabled:g,paywall:s=false,paywallRedirect:h,paywallDescription:V,onPress:f,...I},de)=>{let Y=react.useId(),v=ut(),N=ft(),B=t??v?.variant??"default",ue=a??v?.size,U=g??v?.isDisabled??false,X=v?.orientation==="vertical",q=o||X,ce=N?pt({orientation:v?.orientation??"horizontal",position:N.position}):"",M=i??ue??"default";return process.env.NODE_ENV!=="production"&&(M==="dot"||M==="icon")&&!I["aria-label"]&&!c&&console.warn('[Button] visualSize="dot" or "icon" requires aria-label when no visible text is provided (WCAG 1.1.1)'),jsxRuntime.jsx(reactAriaComponents.Button,{ref:de,isDisabled:U||d||void 0,"aria-disabled":s?true:void 0,"aria-describedby":s?Y:void 0,onPress:R=>{if(s){h&&window.open(h,"_blank","noopener,noreferrer");return}f?.(R);},className:b(me({fullWidth:q,inVerticalGroup:X}),e),...I,children:R=>jsxRuntime.jsxs("span",{className:b(ge({variant:B,visualSize:M,paywall:s,fullWidth:q}),ce,r,ve,"",te,re),"data-pressed":R.isPressed||void 0,children:[d&&jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(lucideReact.Loader2,{className:"motion-safe:animate-spin","aria-hidden":"true"}),jsxRuntime.jsx("span",{className:"sr-only","aria-live":"polite",children:m})]}),!d&&c,s&&jsxRuntime.jsx(lucideReact.Zap,{"data-testid":"zap-icon","aria-hidden":"true",className:"ml-1"}),s&&jsxRuntime.jsxs("span",{id:Y,className:"sr-only",children:["Premium feature: ",V||"Upgrade required to access this feature"]}),R.isFocusVisible&&u&&jsxRuntime.jsx("kbd",{className:"ml-auto hidden text-xs opacity-60 lg:inline",children:u})]})})}));D.displayName="Button";var Ee=["focus-within:outline-none","focus-within:ring-2","focus-within:ring-[var(--ring)]","focus-within:ring-offset-2"],he=["focus-visible:outline-none","focus-visible:ring-2","focus-visible:ring-[var(--ring)]","focus-visible:ring-offset-2"];var Ie=["disabled:pointer-events-none","disabled:opacity-50"];var w={sm:"text-xs",default:"text-sm",lg:"text-base"},ie={sm:"text-sm",default:"text-base",lg:"text-lg"},ne=["min-h-[44px]","min-w-[44px]"];var Fe=["flex","items-center","gap-1.5","text-[var(--destructive-background)]"],_e=["flex","items-center","gap-1.5","text-[var(--success-background)]"],Te=["text-[var(--menu-muted)]"],Ve=["font-medium","text-[var(--content-foreground)]"];var oe=["transition-colors","duration-200"];function O(...e){return e.flatMap(r=>Array.isArray(r)?[...r]:[r])}var Ne=classVarianceAuthority.cva("flex flex-col gap-1.5 w-full",{variants:{size:ie},defaultVariants:{size:"default"}}),ye=classVarianceAuthority.cva(O("flex flex-col items-center justify-center rounded-md border-2 border-dashed","bg-[var(--content-background)] text-[var(--content-foreground)]",oe,Ee),{variants:{size:{sm:"min-h-[100px] p-4 gap-2",default:"min-h-[140px] p-6 gap-3",lg:"min-h-[180px] p-8 gap-4"},isDragOver:{true:"border-[var(--primary)] bg-[var(--primary)]/5",false:"border-[var(--input-border)] hover:border-[var(--primary)]/50"},isInvalid:{true:"border-[var(--destructive-background)] bg-[var(--destructive-background)]/5",false:""},isDisabled:{true:"opacity-50 cursor-not-allowed pointer-events-none",false:"cursor-pointer"}},compoundVariants:[{isInvalid:true,isDragOver:true,className:"border-[var(--destructive-background)] bg-[var(--destructive-background)]/5"}],defaultVariants:{size:"default",isDragOver:false,isInvalid:false,isDisabled:false}}),Pe=classVarianceAuthority.cva(O("inline-flex items-center justify-center gap-2 rounded-md font-medium",oe,ne,he,Ie),{variants:{size:{sm:"px-3 py-2 text-xs",default:"px-4 py-2 text-sm",lg:"px-6 py-3 text-base"},variant:{default:"bg-[var(--primary)] text-[var(--primary-foreground)] hover:bg-[var(--primary)]/90",outline:"border border-[var(--input-border)] bg-transparent hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)]"}},defaultVariants:{size:"default",variant:"default"}}),Re=classVarianceAuthority.cva("flex flex-col gap-2 mt-3",{variants:{size:{sm:"gap-1.5",default:"gap-2",lg:"gap-3"}},defaultVariants:{size:"default"}}),mt=classVarianceAuthority.cva("flex items-center justify-between mb-1",{variants:{size:w},defaultVariants:{size:"default"}}),Oe=classVarianceAuthority.cva("flex items-center justify-between gap-3 bg-[var(--accent-background)] rounded-md border border-[var(--border)]",{variants:{size:{sm:"px-2 py-1.5 text-xs",default:"px-3 py-2 text-sm",lg:"px-4 py-3 text-base"}},defaultVariants:{size:"default"}}),Ae=classVarianceAuthority.cva(O("inline-flex items-center justify-center rounded-full",ne,"-mr-2 -my-1","text-[var(--menu-muted)] hover:text-[var(--destructive-background)] hover:bg-[var(--destructive-background)]/10","transition-colors","focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]"),{variants:{size:{sm:"",default:"",lg:""}},defaultVariants:{size:"default"}}),Le=classVarianceAuthority.cva(O(Fe,"font-medium"),{variants:{size:w},defaultVariants:{size:"default"}}),De=classVarianceAuthority.cva(O(_e,"font-medium"),{variants:{size:w},defaultVariants:{size:"default"}}),we=classVarianceAuthority.cva(Te,{variants:{size:w},defaultVariants:{size:"default"}}),Ce=classVarianceAuthority.cva(Ve,{variants:{size:ie,isRequired:{true:"after:content-['*'] after:ml-0.5 after:text-[var(--destructive-background)]",false:""}},defaultVariants:{size:"default",isRequired:false}});function se(e){if(e===0)return "0 B";let r=1024,t=["B","KB","MB","GB"],a=Math.floor(Math.log(e)/Math.log(r)),i=parseFloat((e/Math.pow(r,a)).toFixed(1));return `${i%1===0?i.toFixed(0):i.toFixed(1)} ${t[a]}`}function $(e,r=30){if(e.length<=r)return e;let t=e.lastIndexOf(".");if(t===-1)return `${e.slice(0,r-3)}...`;let a=e.slice(t),i=e.slice(0,t),o=r-a.length-3;return o<1?`...${a}`:`${i.slice(0,o)}...${a}`}function Be(e,r){return !r||r.length===0?true:r.some(t=>{if(t.endsWith("/*")){let a=t.slice(0,-2);return e.type.startsWith(`${a}/`)}return t.includes("/")?e.type===t:t.startsWith(".")?e.name.toLowerCase().endsWith(t.toLowerCase()):false})}function j(e){return e.type.startsWith("image/")?"image":e.type.startsWith("video/")?"video":e.type.startsWith("audio/")?"audio":"file"}function W(e,r){let t=[...e];for(let a of r){let i=t.findIndex(o=>o.name===a.name);i>=0?t[i]=a:t.push(a);}return t}function Zt(e){return !e||e.length===0?"any file":e.map(t=>t==="image/*"?"images":t==="video/*"?"videos":t==="audio/*"?"audio":t.startsWith(".")?t.slice(1).toUpperCase():t.includes("/")?(t.split("/")[1]??t).toUpperCase():t).join(", ")}var gt=2*1024*1024;function Ue(e){return e.type.startsWith("image/")?true:/\.(jpg|jpeg|png|gif|webp|svg|bmp|ico|avif|heic|heif|tiff|tif)$/i.test(e.name)}async function vt(e,r=200){return new Promise((t,a)=>{let i=new window.Image,o=URL.createObjectURL(e);i.onload=()=>{URL.revokeObjectURL(o);let d=Math.min(r/i.width,r/i.height,1),m=Math.round(i.width*d),u=Math.round(i.height*d),c=document.createElement("canvas");c.width=m,c.height=u;let g=c.getContext("2d");if(!g){a(new Error("Canvas context unavailable"));return}g.drawImage(i,0,0,m,u),c.toBlob(s=>{s?t(URL.createObjectURL(s)):a(new Error("Failed to create blob"));},"image/jpeg",.8);},i.onerror=()=>{URL.revokeObjectURL(o),a(new Error("Failed to load image"));},i.src=o;})}async function Me(e,r=200){return e.size>gt?vt(e,r):URL.createObjectURL(e)}function ze(e,r={}){let{enabled:t=true,maxBytes:a=10*1024*1024,maxDimension:i=200}=r,[o,d]=react.useState(null),[m,u]=react.useState(false),[c,g]=react.useState(null),s=Ue(e);return react.useEffect(()=>{if(!t||!s){d(null),u(false),g(null);return}if(e.size>a){d(null),u(false),g("File too large for preview");return}let h=true,V=null;return (async()=>{u(true),g(null);try{V=await Me(e,i),h?(d(V),u(!1)):URL.revokeObjectURL(V);}catch(I){h&&(g(I instanceof Error?I.message:"Failed to generate preview"),u(false),d(null));}})(),()=>{h=false,V&&URL.revokeObjectURL(V),d(I=>(I&&URL.revokeObjectURL(I),null));}},[e,t,a,i,s]),{preview:o,isLoading:m,error:c,isImage:s}}function Ge({file:e,size:r=64,maxBytes:t=10*1024*1024,renderPreview:a,className:i}){let{preview:o,isLoading:d,error:m,isImage:u}=ze(e,{enabled:true,maxBytes:t,maxDimension:r*2}),c={width:r,height:r,minWidth:r,minHeight:r};if(!u&&a)return jsxRuntime.jsx("div",{className:b("flex items-center justify-center rounded-md overflow-hidden","bg-[var(--accent-background)]",i),style:c,children:a(e)});if(d)return jsxRuntime.jsx("div",{className:b("flex items-center justify-center rounded-md overflow-hidden","bg-[var(--accent-background)]",i),style:c,"aria-busy":"true","aria-label":`Loading preview for ${e.name}`,children:jsxRuntime.jsx(lucideReact.Loader2,{className:"h-4 w-4 animate-spin text-[var(--menu-muted)]","aria-hidden":"true"})});if(u&&o&&!m)return jsxRuntime.jsx("div",{className:b("flex items-center justify-center rounded-md overflow-hidden","bg-[var(--accent-background)]",i),style:c,children:jsxRuntime.jsx("img",{src:o,alt:e.name,className:"w-full h-full object-cover",loading:"lazy"})});let g=j(e),s=er(g),h=Math.max(16,Math.floor(r*.4));return jsxRuntime.jsx("div",{className:b("flex items-center justify-center rounded-md overflow-hidden","bg-[var(--accent-background)]",i),style:c,"aria-label":m?`Preview unavailable for ${e.name}`:void 0,children:jsxRuntime.jsx(s,{className:"text-[var(--menu-muted)]",style:{width:h,height:h},"aria-hidden":"true"})})}function er(e){switch(e){case "image":return lucideReact.ImageIcon;case "video":return lucideReact.VideoIcon;case "audio":return lucideReact.AudioLines;default:return lucideReact.FileIcon}}var ke=classVarianceAuthority.cva(["flex","flex-col","gap-1","w-full"],{variants:{size:{sm:"text-xs",default:"text-sm",lg:"text-base"}},defaultVariants:{size:"default"}}),$e=classVarianceAuthority.cva(["rounded-full","bg-[var(--accent-background)]","overflow-hidden"],{variants:{size:{sm:"h-1.5",default:"h-2",lg:"h-3"}},defaultVariants:{size:"default"}}),je=classVarianceAuthority.cva(["h-full","rounded-full","transition-all","duration-300"],{variants:{status:{pending:["bg-gradient-to-r","from-[var(--menu-muted)]","via-[var(--accent-background)]","to-[var(--menu-muted)]","bg-[length:200%_100%]","animate-progress-shimmer"],uploading:"bg-[var(--primary)]",complete:"bg-[var(--success-background)]",error:"bg-[var(--destructive-background)]"}},defaultVariants:{status:"pending"}}),We=classVarianceAuthority.cva(["flex","items-center","justify-between","gap-2"],{variants:{size:{sm:"text-xs",default:"text-sm",lg:"text-base"}},defaultVariants:{size:"default"}}),Ze=classVarianceAuthority.cva(["flex","items-center","justify-between","gap-2","mt-1","text-[var(--destructive-background)]"],{variants:{size:{sm:"text-xs",default:"text-sm",lg:"text-base"}},defaultVariants:{size:"default"}}),Ye=classVarianceAuthority.cva(["underline","hover:no-underline","min-h-[44px]","min-w-[44px]","inline-flex","items-center","justify-center","-mr-3","-my-2","focus-visible:outline-none","focus-visible:ring-2","focus-visible:ring-[var(--ring)]","focus-visible:ring-offset-2","rounded"],{variants:{size:{sm:"text-xs",default:"text-sm",lg:"text-base"}},defaultVariants:{size:"default"}});function ar(e,r){switch(e){case "pending":return "Queued for upload\u2026";case "uploading":return `Uploading\u2026 ${r}%`;case "complete":return "Upload complete";case "error":return "Upload failed \u2014 try again"}}function le({file:e,progress:r,status:t,error:a,onRetry:i,size:o="default",className:d}){let m=t==="pending",u=`progress-error-${e.name.replace(/[^a-zA-Z0-9]/g,"-")}`,c=ar(t,r);return jsxRuntime.jsxs("div",{className:b(ke({size:o}),d),children:[jsxRuntime.jsx(reactAriaComponents.ProgressBar,{"aria-label":e.name,value:m?void 0:r,isIndeterminate:m,"aria-describedby":t==="error"&&a?u:void 0,children:({percentage:g,valueText:s})=>jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsxs("div",{className:We({size:o}),children:[jsxRuntime.jsx("span",{className:"truncate",title:e.name,children:$(e.name,30)}),jsxRuntime.jsx("span",{className:"text-[var(--menu-muted)] flex-shrink-0",children:t==="error"?c:s??c})]}),jsxRuntime.jsx("div",{className:$e({size:o}),children:jsxRuntime.jsx("div",{className:je({status:t}),style:{width:m?"100%":`${g??0}%`}})})]})}),t==="error"&&a&&jsxRuntime.jsxs("div",{id:u,className:Ze({size:o}),children:[jsxRuntime.jsx("span",{children:a}),i&&jsxRuntime.jsx(reactAriaComponents.Button,{onPress:i,className:Ye({size:o}),children:"Retry"})]}),jsxRuntime.jsxs("div",{"aria-live":"polite","aria-atomic":"true",className:"sr-only",children:[t==="complete"&&`${e.name} upload complete`,t==="error"&&`${e.name} upload failed${a?`: ${a}`:""}`]})]})}le.displayName="FileProgress";var bt=react.forwardRef(function({label:r,acceptedFileTypes:t,allowsMultiple:a=false,maxFileSize:i,maxFiles:o,description:d,errorMessage:m,successMessage:u,triggerText:c,isRequired:g,isDisabled:s,isInvalid:h,isValid:V,size:f="default",name:I,id:de,className:Y,value:v=[],onChange:N,validate:B,showPreviews:ue=false,previewSize:U=64,maxPreviewBytes:X=10*1024*1024,renderPreview:q,showProgress:ce=false,uploadProgress:M,uploadStatus:Xe,uploadErrors:qe,onRetry:R,"data-testid":Qe,"aria-label":xr,"aria-labelledby":br,"aria-describedby":Ke,...Et},ht){let It=react.useId(),Q=de??It,Je=`${Q}-label`,et=`${Q}-description`,tt=`${Q}-error`,[rt,fe]=react.useState(false),[Ft,pe]=react.useState(null),K=react.useRef(0),H=m??Ft,_t=h||!!H,z=[];Ke&&z.push(Ke),d&&z.push(et),H&&z.push(tt);let Tt=z.length>0?z.join(" "):void 0,at=react.useCallback((n,x=[])=>{let F=[],S=[];for(let E of n){if(t&&!Be(E,t)){S.push(`"${E.name}" is not a supported file type. Accepted: ${t}`);continue}if(i&&E.size>i){S.push(`"${E.name}" is too large (max ${se(i)}). Try compressing or resizing the file.`);continue}F.push(E);}return o&&a&&W(x,F).length>o?(S.push(`Maximum ${o} files allowed`),{valid:[],errors:S}):{valid:F,errors:S}},[t,i,o,a]),J=react.useCallback(n=>{if(!n||n.length===0)return;pe(null);let x=Array.from(n),F=a?v:[],{valid:S,errors:E}=at(x,F);if(E.length>0){pe(E[0]??"Invalid file");return}if(B&&S.length>0){let ee=B(a?W(F,S):S);if(ee){pe(ee);return}}let G;a?G=W(F,S):G=S.slice(0,1),N?.(G);},[a,v,at,B,N]),Vt=react.useCallback(n=>{J(n);},[J]),Nt=react.useCallback(n=>{let x=v.filter(F=>F!==n);N?.(x);},[v,N]),yt=react.useCallback(()=>{N?.([]);},[N]),Pt=react.useCallback(n=>{n.preventDefault(),n.stopPropagation(),!s&&(K.current++,fe(true));},[s]),Rt=react.useCallback(n=>{n.preventDefault(),n.stopPropagation();},[]),Ot=react.useCallback(n=>{n.preventDefault(),n.stopPropagation(),K.current--,K.current===0&&fe(false);},[]),At=react.useCallback(n=>{if(n.preventDefault(),n.stopPropagation(),K.current=0,fe(false),s)return;let x=n.dataTransfer?.files;J(x??null);},[s,J]),Lt=n=>{switch(j(n)){case "image":return lucideReact.ImageIcon;case "video":return lucideReact.VideoIcon;case "audio":return lucideReact.AudioLines;default:return lucideReact.FileIcon}},Dt=t?.join(",");return jsxRuntime.jsxs("div",{ref:ht,id:Q,className:b(Ne({size:f}),Y),"data-testid":Qe??"file-field",...Et,children:[jsxRuntime.jsx("label",{id:Je,className:Ce({size:f,isRequired:g}),children:r}),jsxRuntime.jsxs("div",{role:"group","data-testid":`${Qe??"file-field"}-dropzone`,className:b("drop-zone",ye({size:f,isDragOver:rt,isInvalid:_t,isDisabled:s})),onDragEnter:Pt,onDragOver:Rt,onDragLeave:Ot,onDrop:At,"aria-labelledby":Je,"aria-describedby":Tt,"aria-disabled":s||void 0,children:[jsxRuntime.jsx(reactAriaComponents.FileTrigger,{acceptedFileTypes:t,allowsMultiple:a,onSelect:Vt,children:jsxRuntime.jsxs(D,{variant:"outline",isDisabled:s,buttonVisualClassName:Pe({size:f}),children:[jsxRuntime.jsx(lucideReact.Upload,{className:"h-4 w-4","aria-hidden":"true"}),rt?"Drop files here":c??(a?"Choose files":"Choose file")]})}),I&&jsxRuntime.jsx("input",{type:"file",name:I,accept:Dt,multiple:a,disabled:s,className:"sr-only",tabIndex:-1,"aria-hidden":"true"})]}),d&&jsxRuntime.jsx("p",{id:et,className:we({size:f}),children:d}),v.length>0&&jsxRuntime.jsxs("div",{className:Re({size:f}),children:[v.length>=2&&jsxRuntime.jsxs("div",{className:mt({size:f}),children:[jsxRuntime.jsxs("span",{className:"text-[var(--menu-muted)]",children:[v.length," files selected"]}),jsxRuntime.jsx(D,{variant:"link",visualSize:"sm",onPress:yt,buttonVisualClassName:b("text-[var(--menu-muted)] hover:text-[var(--destructive-background)]","underline-offset-4 hover:underline"),"aria-label":"Clear all files",children:"Clear all"})]}),jsxRuntime.jsx("ul",{className:"space-y-2",children:v.map((n,x)=>{let F=Lt(n),S=f==="sm"?Math.min(U,40):f==="lg"?Math.min(U,80):Math.min(U,48),E=Xe?.[x],G=M?.[x]??0,ee=qe?.get(x),it=ce&&E!==void 0;return jsxRuntime.jsx("li",{className:it?"p-3":Oe({size:f}),children:it?jsxRuntime.jsx(le,{file:n,progress:G,status:E,error:ee,onRetry:R?()=>R(x):void 0,size:f}):jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[ue?jsxRuntime.jsx(Ge,{file:n,size:S,maxBytes:X,renderPreview:q,className:"flex-shrink-0"}):jsxRuntime.jsx(F,{className:"h-4 w-4 flex-shrink-0 text-[var(--menu-muted)]","aria-hidden":"true"}),jsxRuntime.jsx("span",{className:"truncate",title:n.name,children:$(n.name,30)}),jsxRuntime.jsx("span",{className:"text-[var(--menu-muted)] flex-shrink-0",children:se(n.size)})]}),jsxRuntime.jsx(D,{variant:"ghost",visualSize:"icon",onPress:()=>Nt(n),buttonVisualClassName:Ae({size:f}),"aria-label":`Remove ${n.name}`,isDisabled:s,children:jsxRuntime.jsx(lucideReact.X,{className:"h-4 w-4","aria-hidden":"true"})})]})},`${n.name}-${x}`)})})]}),H&&jsxRuntime.jsx("p",{id:tt,role:"alert",className:Le({size:f}),children:H}),!H&&V&&u&&jsxRuntime.jsx("p",{className:De({size:f}),children:u})]})});bt.displayName="FileField";var St=zod.z.object({className:zod.z.string().optional(),children:zod.z.any().optional(),id:zod.z.string().optional(),"aria-label":zod.z.string().optional(),"aria-labelledby":zod.z.string().optional(),"aria-describedby":zod.z.string().optional(),"aria-live":zod.z.enum(["off","polite","assertive"]).optional(),"aria-hidden":zod.z.boolean().optional(),"data-testid":zod.z.string().optional()});var vr=St.extend({label:zod.z.string(),acceptedFileTypes:zod.z.array(zod.z.string()).optional(),allowsMultiple:zod.z.boolean().default(false),maxFileSize:zod.z.number().optional(),maxFiles:zod.z.number().optional(),description:zod.z.string().optional(),errorMessage:zod.z.string().optional(),successMessage:zod.z.string().optional(),triggerText:zod.z.string().optional(),isRequired:zod.z.boolean().optional(),isDisabled:zod.z.boolean().optional(),isInvalid:zod.z.boolean().optional(),isValid:zod.z.boolean().optional(),size:zod.z.enum(["sm","default","lg"]).default("default"),name:zod.z.string().optional(),showPreviews:zod.z.boolean().default(false),previewSize:zod.z.number().min(16).max(256).default(64),maxPreviewBytes:zod.z.number().default(10*1024*1024),showProgress:zod.z.boolean().default(false),uploadProgress:zod.z.array(zod.z.number().min(0).max(100)).optional(),uploadStatus:zod.z.array(zod.z.enum(["pending","uploading","complete","error"])).optional()}).refine(e=>!(e.successMessage&&e.errorMessage),{message:"Cannot provide both successMessage and errorMessage. Use one based on validation state.",path:["successMessage"]}).refine(e=>(typeof process<"u"&&process.env.NODE_ENV==="development"&&e.isValid&&e.isInvalid&&console.error("[FileField] Both isValid and isInvalid are true. isInvalid takes precedence."),true));exports.FileField=bt;exports.FileFieldPropsSchema=vr;exports.FilePreview=Ge;exports.FileProgress=le;exports.RESIZE_THRESHOLD=gt;exports.createResizedPreview=vt;exports.deduplicateFiles=W;exports.fileFieldContainerVariants=Ne;exports.fileFieldDescriptionVariants=we;exports.fileFieldDropZoneVariants=ye;exports.fileFieldErrorVariants=Le;exports.fileFieldItemVariants=Oe;exports.fileFieldLabelVariants=Ce;exports.fileFieldListVariants=Re;exports.fileFieldRemoveButtonVariants=Ae;exports.fileFieldSuccessVariants=De;exports.fileFieldTriggerVariants=Pe;exports.fileProgressBarVariants=je;exports.fileProgressErrorVariants=Ze;exports.fileProgressHeaderVariants=We;exports.fileProgressRetryVariants=Ye;exports.fileProgressTrackVariants=$e;exports.fileProgressVariants=ke;exports.formatAcceptedTypes=Zt;exports.formatFileSize=se;exports.generatePreview=Me;exports.getFileIcon=j;exports.isFileTypeAccepted=Be;exports.isImageFile=Ue;exports.truncateFileName=$;exports.useFilePreview=ze;//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|