@humain/ui 2.2.6 → 2.2.9
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/index101.js +2 -2
- package/dist/index101.js.map +1 -1
- package/dist/index103.js +3 -3
- package/dist/index103.js.map +1 -1
- package/dist/index108.js +1 -1
- package/dist/index108.js.map +1 -1
- package/dist/index117.js +1 -1
- package/dist/index117.js.map +1 -1
- package/dist/index122.js +6 -6
- package/dist/index122.js.map +1 -1
- package/dist/index126.js +1 -1
- package/dist/index126.js.map +1 -1
- package/dist/index130.js +2 -2
- package/dist/index130.js.map +1 -1
- package/dist/index146.js +4 -4
- package/dist/index146.js.map +1 -1
- package/dist/index152.js +1 -1
- package/dist/index152.js.map +1 -1
- package/dist/index154.js +2 -2
- package/dist/index154.js.map +1 -1
- package/dist/index166.js +1 -1
- package/dist/index166.js.map +1 -1
- package/dist/index168.js +1 -1
- package/dist/index168.js.map +1 -1
- package/dist/index169.js +1 -1
- package/dist/index169.js.map +1 -1
- package/dist/index173.js +2 -2
- package/dist/index173.js.map +1 -1
- package/dist/index175.js +4 -4
- package/dist/index175.js.map +1 -1
- package/dist/index176.js +2 -2
- package/dist/index176.js.map +1 -1
- package/dist/index177.js +2 -2
- package/dist/index177.js.map +1 -1
- package/dist/index184.js +1 -1
- package/dist/index184.js.map +1 -1
- package/dist/index191.js +3 -3
- package/dist/index191.js.map +1 -1
- package/dist/index192.js +2 -2
- package/dist/index192.js.map +1 -1
- package/dist/index201.js +2 -2
- package/dist/index201.js.map +1 -1
- package/dist/index204.js +4 -4
- package/dist/index204.js.map +1 -1
- package/dist/index228.js +1 -1
- package/dist/index228.js.map +1 -1
- package/dist/index229.js +1 -1
- package/dist/index229.js.map +1 -1
- package/dist/index24.js +2 -2
- package/dist/index24.js.map +1 -1
- package/dist/index5.js +1 -1
- package/dist/index5.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/wc/AICodeBlock.js +41 -41
- package/dist/wc/AICodeBlock.js.map +1 -1
- package/dist/wc/AIMermaidDiagram.js +7 -7
- package/dist/wc/AIMermaidDiagram.js.map +1 -1
- package/dist/wc/AIMessage.js +6 -6
- package/dist/wc/AIMessage.js.map +1 -1
- package/dist/wc/AISource.js +2 -2
- package/dist/wc/AISource.js.map +1 -1
- package/dist/wc/AIToolCall.js +1 -1
- package/dist/wc/AIToolCall.js.map +1 -1
- package/dist/wc/Breadcrumb.js +43 -43
- package/dist/wc/Breadcrumb.js.map +1 -1
- package/dist/wc/DropdownMenu.js +9 -9
- package/dist/wc/DropdownMenu.js.map +1 -1
- package/dist/wc/Kbd.js +22 -22
- package/dist/wc/Kbd.js.map +1 -1
- package/dist/wc/button.js +7 -7
- package/dist/wc/button.js.map +1 -1
- package/dist/wc/close-button.js +19 -19
- package/dist/wc/close-button.js.map +1 -1
- package/dist/wc/hf-ai-prompt-suggestion.js +14 -14
- package/dist/wc/hf-ai-prompt-suggestion.js.map +1 -1
- package/dist/wc/hf-ai-reasoning-block.js +13 -13
- package/dist/wc/hf-ai-reasoning-block.js.map +1 -1
- package/dist/wc/hf-ai-steps.js +53 -53
- package/dist/wc/hf-ai-steps.js.map +1 -1
- package/dist/wc/hf-ai-system-message.js +26 -26
- package/dist/wc/hf-ai-system-message.js.map +1 -1
- package/dist/wc/hf-code-snippet.js +35 -35
- package/dist/wc/hf-code-snippet.js.map +1 -1
- package/dist/wc/hf-command-menu.js +39 -39
- package/dist/wc/hf-command-menu.js.map +1 -1
- package/dist/wc/hf-data-table.js +3 -3
- package/dist/wc/hf-data-table.js.map +1 -1
- package/dist/wc/hf-display-value.js +50 -50
- package/dist/wc/hf-display-value.js.map +1 -1
- package/dist/wc/hf-nav-account-menu.js +5 -5
- package/dist/wc/hf-nav-account-menu.js.map +1 -1
- package/dist/wc/hf-rich-textarea.js +1 -1
- package/dist/wc/hf-rich-textarea.js.map +1 -1
- package/dist/wc/hf-steps.js +8 -8
- package/dist/wc/hf-steps.js.map +1 -1
- package/dist/wc/markdown-renderer.js +1 -1
- package/dist/wc/markdown-renderer.js.map +1 -1
- package/dist/wc/selection-group.js +26 -26
- package/dist/wc/selection-group.js.map +1 -1
- package/dist/wc/syntax-highlight.js +4 -4
- package/dist/wc/syntax-highlight.js.map +1 -1
- package/dist/wc/workflow-step-renderer.js +51 -51
- package/dist/wc/workflow-step-renderer.js.map +1 -1
- package/dist/wc-react/AICodeBlock.js +17 -17
- package/dist/wc-react/AICodeBlock.js.map +1 -1
- package/dist/wc-react/AIMermaidDiagram.js +16 -16
- package/dist/wc-react/AIMermaidDiagram.js.map +1 -1
- package/dist/wc-react/AIMessage.js +7 -7
- package/dist/wc-react/AIMessage.js.map +1 -1
- package/dist/wc-react/AISource.js +41 -41
- package/dist/wc-react/AISource.js.map +1 -1
- package/dist/wc-react/AIToolCall.js +6 -6
- package/dist/wc-react/AIToolCall.js.map +1 -1
- package/dist/wc-react/Breadcrumb.js +18 -18
- package/dist/wc-react/Breadcrumb.js.map +1 -1
- package/dist/wc-react/DropdownMenu.js +27 -27
- package/dist/wc-react/DropdownMenu.js.map +1 -1
- package/dist/wc-react/Kbd.js +17 -17
- package/dist/wc-react/Kbd.js.map +1 -1
- package/dist/wc-react/button.js +12 -12
- package/dist/wc-react/button.js.map +1 -1
- package/dist/wc-react/close-button.js +19 -19
- package/dist/wc-react/close-button.js.map +1 -1
- package/dist/wc-react/hf-ai-prompt-suggestion.js +1 -1
- package/dist/wc-react/hf-ai-prompt-suggestion.js.map +1 -1
- package/dist/wc-react/hf-ai-reasoning-block.js +1 -1
- package/dist/wc-react/hf-ai-reasoning-block.js.map +1 -1
- package/dist/wc-react/hf-ai-steps.js +33 -33
- package/dist/wc-react/hf-ai-steps.js.map +1 -1
- package/dist/wc-react/hf-ai-system-message.js +9 -9
- package/dist/wc-react/hf-ai-system-message.js.map +1 -1
- package/dist/wc-react/hf-code-snippet.js +3 -3
- package/dist/wc-react/hf-code-snippet.js.map +1 -1
- package/dist/wc-react/hf-command-menu.js +56 -56
- package/dist/wc-react/hf-command-menu.js.map +1 -1
- package/dist/wc-react/hf-data-table.js +3 -3
- package/dist/wc-react/hf-data-table.js.map +1 -1
- package/dist/wc-react/hf-display-value.js +58 -58
- package/dist/wc-react/hf-display-value.js.map +1 -1
- package/dist/wc-react/hf-nav-account-menu.js +7 -7
- package/dist/wc-react/hf-nav-account-menu.js.map +1 -1
- package/dist/wc-react/hf-rich-textarea.js +5 -5
- package/dist/wc-react/hf-rich-textarea.js.map +1 -1
- package/dist/wc-react/hf-steps.js +2 -2
- package/dist/wc-react/hf-steps.js.map +1 -1
- package/dist/wc-react/markdown-renderer.js +1 -1
- package/dist/wc-react/markdown-renderer.js.map +1 -1
- package/dist/wc-react/selection-group.js +7 -7
- package/dist/wc-react/selection-group.js.map +1 -1
- package/dist/wc-react/syntax-highlight.js +4 -4
- package/dist/wc-react/syntax-highlight.js.map +1 -1
- package/dist/wc-react/workflow-step-renderer.js +44 -44
- package/dist/wc-react/workflow-step-renderer.js.map +1 -1
- package/package.json +1 -1
- package/skills/humain-ui/SKILL.md +1 -1
- package/skills/humain-ui-wc/SKILL.md +1 -1
- package/skills/humain-ui-wc.skill +0 -0
- package/skills/humain-ui.skill +0 -0
- package/src/tokens.css +4 -0
package/dist/index24.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index24.js","names":[],"sources":["../src/components/ui/selection-group.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { Minus } from 'lucide-react';\nimport * as React from 'react';\nimport { cn } from '@/lib/utils';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type SelectionColor =\n | 'primary'\n | 'secondary'\n | 'success'\n | 'warning'\n | 'info'\n | 'destructive';\n\nexport type SelectionSize = 'sm' | 'md' | 'lg';\n\nexport type SelectionVariant =\n | 'default'\n | 'card'\n | 'pill'\n | 'stacked'\n | 'icon-simple'\n | 'icon-card'\n | 'avatar'\n | 'payment'\n | 'simple'\n | 'chip';\n\nexport interface SelectionItem {\n /** Unique value for the option */\n value: string;\n /** Display label */\n label: string;\n /** Whether this option is disabled */\n disabled?: boolean;\n /** Secondary text (e.g., \"$10/month\") */\n subtext?: string;\n /** Supporting description text */\n description?: string;\n /** Leading icon component */\n icon?: React.ReactNode;\n /** Avatar element */\n avatar?: React.ReactNode;\n /** Image URL */\n image?: string;\n /** Alt text for the image (defaults to \"\" if omitted) */\n imageAlt?: string;\n /** Position of the image */\n imagePosition?: 'top' | 'left' | 'trailing';\n /** Badge element */\n badge?: React.ReactNode;\n /** Dot color for chip variant (named color or hex) */\n dotColor?: string;\n /** Price display (e.g., \"$10\") */\n price?: string;\n /** Price period (e.g., \"per month\") */\n pricePeriod?: string;\n /** Payment icon element */\n paymentIcon?: React.ReactNode;\n /** Action buttons */\n actions?: React.ReactNode;\n}\n\n// =============================================================================\n// Hooks\n// =============================================================================\n\ninterface UseSelectionStateOptions {\n /** Controlled value */\n value?: string;\n /** Default value for uncontrolled mode */\n defaultValue?: string;\n /** Callback when value changes */\n onValueChange?: (value: string) => void;\n}\n\n/**\n * Hook for managing single selection state (radio behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useSelectionState(\n options: UseSelectionStateOptions = {},\n): [string | undefined, (value: string) => void] {\n const { value: controlledValue, defaultValue, onValueChange } = options;\n\n const [internalValue, setInternalValue] = React.useState<string | undefined>(\n defaultValue,\n );\n\n const isControlled = controlledValue !== undefined;\n const selectedValue = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (newValue: string) => {\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, onValueChange],\n );\n\n return [selectedValue, setValue];\n}\n\ninterface UseMultiSelectionStateOptions {\n /** Controlled value */\n value?: string[];\n /** Default value for uncontrolled mode */\n defaultValue?: string[];\n /** Callback when value changes */\n onValueChange?: (value: string[]) => void;\n}\n\n/**\n * Hook for managing multi selection state (checkbox behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useMultiSelectionState(\n options: UseMultiSelectionStateOptions = {},\n): [string[], (value: string, checked: boolean) => void] {\n const { value: controlledValue, defaultValue = [], onValueChange } = options;\n\n const [internalValue, setInternalValue] =\n React.useState<string[]>(defaultValue);\n\n const isControlled = controlledValue !== undefined;\n const selectedValues = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (itemValue: string, checked: boolean) => {\n const newValue = checked\n ? [...selectedValues, itemValue]\n : selectedValues.filter((v) => v !== itemValue);\n\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, selectedValues, onValueChange],\n );\n\n return [selectedValues, setValue];\n}\n\n// =============================================================================\n// Color Mappings\n// =============================================================================\n\nexport const selectionColorClasses: Record<\n SelectionColor,\n {\n indicator: string;\n indicatorChecked: string;\n border: string;\n bg: string;\n text: string;\n }\n> = {\n primary: {\n indicator: 'border-primary',\n indicatorChecked: 'bg-primary',\n border: 'border-primary',\n bg: 'bg-primary',\n text: 'text-primary-foreground',\n },\n secondary: {\n indicator: 'border-secondary',\n indicatorChecked: 'bg-secondary',\n border: 'border-secondary',\n bg: 'bg-secondary',\n text: 'text-secondary-foreground',\n },\n success: {\n indicator: 'border-success',\n indicatorChecked: 'bg-success',\n border: 'border-success',\n bg: 'bg-success',\n text: 'text-primary-foreground',\n },\n warning: {\n indicator: 'border-warning',\n indicatorChecked: 'bg-warning',\n border: 'border-warning',\n bg: 'bg-warning',\n text: 'text-primary-foreground',\n },\n info: {\n indicator: 'border-info',\n indicatorChecked: 'bg-info',\n border: 'border-info',\n bg: 'bg-info',\n text: 'text-primary-foreground',\n },\n destructive: {\n indicator: 'border-destructive',\n indicatorChecked: 'bg-destructive',\n border: 'border-destructive',\n bg: 'bg-destructive',\n text: 'text-primary-foreground',\n },\n};\n\n// =============================================================================\n// CVA Variants\n// =============================================================================\n\n/**\n * Selection group container variants.\n * Used for the outer wrapper of a group of selection items.\n */\nexport const selectionGroupVariants = cva('flex', {\n variants: {\n orientation: {\n horizontal: 'flex-row flex-wrap',\n vertical: 'flex-col',\n },\n gap: {\n sm: 'gap-2',\n md: 'gap-3',\n lg: 'gap-4',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n gap: 'md',\n },\n});\n\n/**\n * Selection indicator variants (for both radio and checkbox).\n * Renders as a rounded indicator with border.\n */\nexport const selectionIndicatorVariants = cva(\n 'shrink-0 rounded-full border-2 transition-all flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Checkbox indicator variants (square with rounded corners).\n */\nexport const checkboxIndicatorVariants = cva(\n 'shrink-0 border transition-[border-color,background-color,color,box-shadow] duration-200 ease-out motion-reduce:transition-none flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4 rounded-[4px]',\n md: 'size-5 rounded-[5px]',\n lg: 'size-6 rounded-[6px]',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Inner dot sizes for radio indicators when checked.\n */\nexport const innerDotSizes: Record<SelectionSize, string> = {\n sm: 'size-1.5',\n md: 'size-2',\n lg: 'size-2.5',\n};\n\n/**\n * Text size classes for selection labels.\n */\nexport const textSizeClasses: Record<SelectionSize, string> = {\n sm: 'text-sm',\n md: 'text-sm',\n lg: 'text-base',\n};\n\n/**\n * Icon size classes for checkbox indicators.\n */\nexport const iconSizeClasses: Record<SelectionSize, string> = {\n sm: 'size-3',\n md: 'size-3.5',\n lg: 'size-4',\n};\n\n// =============================================================================\n// Draw-on checkmark SVG (shared delight animation)\n// =============================================================================\n\nexport const CHECKMARK_PATH = 'M4 12l5 5L20 6';\n\nexport function DrawCheck({ className }: { className?: string }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={3}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn(className, 'delight-check-draw')}\n >\n <path d={CHECKMARK_PATH} />\n </svg>\n );\n}\n\n// =============================================================================\n// SelectionIndicator Component\n// =============================================================================\n\nexport interface SelectionIndicatorProps {\n /** Type of indicator to render */\n type: 'checkbox' | 'radio';\n /** Whether the indicator is checked */\n checked?: boolean;\n /** Whether the indicator is disabled */\n disabled?: boolean;\n /** Size of the indicator */\n size?: SelectionSize;\n /** Color of the indicator */\n color?: SelectionColor;\n /** Additional CSS classes */\n className?: string;\n /** Whether the checkbox is in indeterminate state (checkbox only) */\n indeterminate?: boolean;\n}\n\n/**\n * SelectionIndicator renders either a checkbox or radio indicator based on type.\n * For checkbox: renders a check icon when checked.\n * For radio: renders an inner dot when checked.\n */\nconst SelectionIndicator = React.forwardRef<\n HTMLSpanElement,\n SelectionIndicatorProps\n>(\n (\n {\n type,\n checked = false,\n disabled = false,\n size = 'sm',\n color = 'primary',\n className,\n indeterminate = false,\n },\n ref,\n ) => {\n const colors = selectionColorClasses[color];\n\n if (type === 'checkbox') {\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"checkbox\"\n data-checked={checked}\n className={cn(\n checkboxIndicatorVariants({ size }),\n checked\n ? cn(\n colors.indicatorChecked,\n colors.border,\n colors.text,\n 'border',\n 'delight-check-bounce',\n )\n : 'border-border bg-background',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n {checked &&\n (indeterminate ? (\n <Minus\n className={cn(\n iconSizeClasses[size],\n 'animate-[scale-in_150ms_ease-out] motion-reduce:animate-none',\n )}\n strokeWidth={3}\n />\n ) : (\n <DrawCheck className={iconSizeClasses[size]} />\n ))}\n </span>\n );\n }\n\n // Radio type\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"radio\"\n data-checked={checked}\n className={cn(\n selectionIndicatorVariants({ size }),\n 'transition-[background-color,border-color] duration-150 motion-reduce:transition-none',\n checked\n ? cn(colors.indicatorChecked, 'border-transparent')\n : 'border-border bg-background',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n <span\n className={cn(\n 'bg-background rounded-full transition-transform duration-150 ease-out motion-reduce:transition-none',\n innerDotSizes[size],\n checked ? 'scale-100' : 'scale-0',\n )}\n />\n </span>\n );\n },\n);\n\nSelectionIndicator.displayName = 'SelectionIndicator';\n\n// =============================================================================\n// FeaturedIcon Component\n// =============================================================================\n\nexport interface FeaturedIconProps {\n /** The icon content to display */\n children: React.ReactNode;\n /** Size of the featured icon container */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n// Hoisted outside component to avoid recreation on every render\nconst featuredIconContainerSizes: Record<SelectionSize, string> = {\n sm: 'size-8',\n md: 'size-10',\n lg: 'size-12',\n};\n\nconst featuredIconInnerSizes: Record<SelectionSize, string> = {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n};\n\n/**\n * FeaturedIcon is a container for icons with border and shadow.\n * Used in icon-simple and icon-card variants.\n */\nconst FeaturedIcon = React.forwardRef<HTMLDivElement, FeaturedIconProps>(\n ({ children, size = 'sm', className }, ref) => {\n const containerSize = featuredIconContainerSizes[size];\n const innerSize = featuredIconInnerSizes[size];\n\n return (\n <div\n ref={ref}\n data-slot=\"featured-icon\"\n className={cn(\n 'shrink-0 rounded-md border border-border bg-card/60',\n 'flex items-center justify-center',\n 'dark:bg-foreground/60 dark:border-border',\n containerSize,\n className,\n )}\n style={{\n boxShadow: 'var(--shadow-inset-ring)',\n }}\n >\n <div\n className={cn(\n 'text-secondary-foreground dark:text-text-quaternary',\n innerSize,\n )}\n >\n {children}\n </div>\n </div>\n );\n },\n);\n\nFeaturedIcon.displayName = 'FeaturedIcon';\n\n// =============================================================================\n// ColorDot Component\n// =============================================================================\n\nexport type ColorDotColor =\n | 'gray'\n | 'orange'\n | 'red'\n | 'darkRed'\n | 'brand'\n | 'success'\n | 'warning'\n | 'error'\n | string; // Allow custom hex colors\n\nconst dotColorMap: Record<string, string> = {\n gray: 'bg-muted',\n orange: 'bg-warning',\n red: 'bg-destructive',\n darkRed: 'bg-destructive-hover',\n brand: 'bg-primary/10',\n success: 'bg-success/10',\n warning: 'bg-warning/10',\n error: 'bg-destructive/10',\n};\n\nconst dotSizeMap: Record<SelectionSize, string> = {\n sm: 'size-[10px]',\n md: 'size-3',\n lg: 'size-3.5',\n};\n\nexport interface ColorDotProps {\n /** Color of the dot (named color or hex) */\n color?: ColorDotColor;\n /** Size of the dot */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * ColorDot renders a colored dot for chip variant.\n * Supports named colors (gray, orange, red, etc.) and hex colors.\n */\nconst ColorDot = React.forwardRef<HTMLSpanElement, ColorDotProps>(\n ({ color, size = 'sm', className }, ref) => {\n if (!color) return null;\n\n const colorClass = dotColorMap[color];\n const isHexColor = color.startsWith('#');\n\n return (\n <span\n ref={ref}\n data-slot=\"color-dot\"\n className={cn(\n 'shrink-0 rounded-full',\n dotSizeMap[size],\n !isHexColor && colorClass,\n className,\n )}\n style={isHexColor ? { backgroundColor: color } : undefined}\n aria-hidden=\"true\"\n />\n );\n },\n);\n\nColorDot.displayName = 'ColorDot';\n\n// =============================================================================\n// Exports\n// =============================================================================\n\nexport { ColorDot, FeaturedIcon, SelectionIndicator };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index24.js","names":[],"sources":["../src/components/ui/selection-group.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { Minus } from 'lucide-react';\nimport * as React from 'react';\nimport { cn } from '@/lib/utils';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type SelectionColor =\n | 'primary'\n | 'secondary'\n | 'success'\n | 'warning'\n | 'info'\n | 'destructive';\n\nexport type SelectionSize = 'sm' | 'md' | 'lg';\n\nexport type SelectionVariant =\n | 'default'\n | 'card'\n | 'pill'\n | 'stacked'\n | 'icon-simple'\n | 'icon-card'\n | 'avatar'\n | 'payment'\n | 'simple'\n | 'chip';\n\nexport interface SelectionItem {\n /** Unique value for the option */\n value: string;\n /** Display label */\n label: string;\n /** Whether this option is disabled */\n disabled?: boolean;\n /** Secondary text (e.g., \"$10/month\") */\n subtext?: string;\n /** Supporting description text */\n description?: string;\n /** Leading icon component */\n icon?: React.ReactNode;\n /** Avatar element */\n avatar?: React.ReactNode;\n /** Image URL */\n image?: string;\n /** Alt text for the image (defaults to \"\" if omitted) */\n imageAlt?: string;\n /** Position of the image */\n imagePosition?: 'top' | 'left' | 'trailing';\n /** Badge element */\n badge?: React.ReactNode;\n /** Dot color for chip variant (named color or hex) */\n dotColor?: string;\n /** Price display (e.g., \"$10\") */\n price?: string;\n /** Price period (e.g., \"per month\") */\n pricePeriod?: string;\n /** Payment icon element */\n paymentIcon?: React.ReactNode;\n /** Action buttons */\n actions?: React.ReactNode;\n}\n\n// =============================================================================\n// Hooks\n// =============================================================================\n\ninterface UseSelectionStateOptions {\n /** Controlled value */\n value?: string;\n /** Default value for uncontrolled mode */\n defaultValue?: string;\n /** Callback when value changes */\n onValueChange?: (value: string) => void;\n}\n\n/**\n * Hook for managing single selection state (radio behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useSelectionState(\n options: UseSelectionStateOptions = {},\n): [string | undefined, (value: string) => void] {\n const { value: controlledValue, defaultValue, onValueChange } = options;\n\n const [internalValue, setInternalValue] = React.useState<string | undefined>(\n defaultValue,\n );\n\n const isControlled = controlledValue !== undefined;\n const selectedValue = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (newValue: string) => {\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, onValueChange],\n );\n\n return [selectedValue, setValue];\n}\n\ninterface UseMultiSelectionStateOptions {\n /** Controlled value */\n value?: string[];\n /** Default value for uncontrolled mode */\n defaultValue?: string[];\n /** Callback when value changes */\n onValueChange?: (value: string[]) => void;\n}\n\n/**\n * Hook for managing multi selection state (checkbox behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useMultiSelectionState(\n options: UseMultiSelectionStateOptions = {},\n): [string[], (value: string, checked: boolean) => void] {\n const { value: controlledValue, defaultValue = [], onValueChange } = options;\n\n const [internalValue, setInternalValue] =\n React.useState<string[]>(defaultValue);\n\n const isControlled = controlledValue !== undefined;\n const selectedValues = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (itemValue: string, checked: boolean) => {\n const newValue = checked\n ? [...selectedValues, itemValue]\n : selectedValues.filter((v) => v !== itemValue);\n\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, selectedValues, onValueChange],\n );\n\n return [selectedValues, setValue];\n}\n\n// =============================================================================\n// Color Mappings\n// =============================================================================\n\nexport const selectionColorClasses: Record<\n SelectionColor,\n {\n indicator: string;\n indicatorChecked: string;\n border: string;\n bg: string;\n text: string;\n }\n> = {\n primary: {\n indicator: 'border-primary',\n indicatorChecked: 'bg-primary',\n border: 'border-primary',\n bg: 'bg-primary',\n text: 'text-primary-foreground',\n },\n secondary: {\n indicator: 'border-secondary',\n indicatorChecked: 'bg-secondary',\n border: 'border-secondary',\n bg: 'bg-secondary',\n text: 'text-secondary-foreground',\n },\n success: {\n indicator: 'border-success',\n indicatorChecked: 'bg-success',\n border: 'border-success',\n bg: 'bg-success',\n text: 'text-primary-foreground',\n },\n warning: {\n indicator: 'border-warning',\n indicatorChecked: 'bg-warning',\n border: 'border-warning',\n bg: 'bg-warning',\n text: 'text-primary-foreground',\n },\n info: {\n indicator: 'border-info',\n indicatorChecked: 'bg-info',\n border: 'border-info',\n bg: 'bg-info',\n text: 'text-primary-foreground',\n },\n destructive: {\n indicator: 'border-destructive',\n indicatorChecked: 'bg-destructive',\n border: 'border-destructive',\n bg: 'bg-destructive',\n text: 'text-primary-foreground',\n },\n};\n\n// =============================================================================\n// CVA Variants\n// =============================================================================\n\n/**\n * Selection group container variants.\n * Used for the outer wrapper of a group of selection items.\n */\nexport const selectionGroupVariants = cva('flex', {\n variants: {\n orientation: {\n horizontal: 'flex-row flex-wrap',\n vertical: 'flex-col',\n },\n gap: {\n sm: 'gap-2',\n md: 'gap-3',\n lg: 'gap-4',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n gap: 'md',\n },\n});\n\n/**\n * Selection indicator variants (for both radio and checkbox).\n * Renders as a rounded indicator with border.\n */\nexport const selectionIndicatorVariants = cva(\n 'shrink-0 rounded-full border-2 transition-all flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Checkbox indicator variants (square with rounded corners).\n */\nexport const checkboxIndicatorVariants = cva(\n 'shrink-0 border transition-[border-color,background-color,color,box-shadow] duration-200 ease-out motion-reduce:transition-none flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4 rounded-[4px]',\n md: 'size-5 rounded-[5px]',\n lg: 'size-6 rounded-[6px]',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Inner dot sizes for radio indicators when checked.\n */\nexport const innerDotSizes: Record<SelectionSize, string> = {\n sm: 'size-1.5',\n md: 'size-2',\n lg: 'size-2.5',\n};\n\n/**\n * Text size classes for selection labels.\n */\nexport const textSizeClasses: Record<SelectionSize, string> = {\n sm: 'text-sm',\n md: 'text-sm',\n lg: 'text-base',\n};\n\n/**\n * Icon size classes for checkbox indicators.\n */\nexport const iconSizeClasses: Record<SelectionSize, string> = {\n sm: 'size-3',\n md: 'size-3.5',\n lg: 'size-4',\n};\n\n// =============================================================================\n// Draw-on checkmark SVG (shared delight animation)\n// =============================================================================\n\nexport const CHECKMARK_PATH = 'M4 12l5 5L20 6';\n\nexport function DrawCheck({ className }: { className?: string }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={3}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn(className, 'delight-check-draw')}\n >\n <path d={CHECKMARK_PATH} />\n </svg>\n );\n}\n\n// =============================================================================\n// SelectionIndicator Component\n// =============================================================================\n\nexport interface SelectionIndicatorProps {\n /** Type of indicator to render */\n type: 'checkbox' | 'radio';\n /** Whether the indicator is checked */\n checked?: boolean;\n /** Whether the indicator is disabled */\n disabled?: boolean;\n /** Size of the indicator */\n size?: SelectionSize;\n /** Color of the indicator */\n color?: SelectionColor;\n /** Additional CSS classes */\n className?: string;\n /** Whether the checkbox is in indeterminate state (checkbox only) */\n indeterminate?: boolean;\n}\n\n/**\n * SelectionIndicator renders either a checkbox or radio indicator based on type.\n * For checkbox: renders a check icon when checked.\n * For radio: renders an inner dot when checked.\n */\nconst SelectionIndicator = React.forwardRef<\n HTMLSpanElement,\n SelectionIndicatorProps\n>(\n (\n {\n type,\n checked = false,\n disabled = false,\n size = 'sm',\n color = 'primary',\n className,\n indeterminate = false,\n },\n ref,\n ) => {\n const colors = selectionColorClasses[color];\n\n if (type === 'checkbox') {\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"checkbox\"\n data-checked={checked}\n className={cn(\n checkboxIndicatorVariants({ size }),\n checked\n ? cn(\n colors.indicatorChecked,\n colors.border,\n colors.text,\n 'border',\n 'delight-check-bounce',\n )\n : 'border-border bg-background',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n {checked &&\n (indeterminate ? (\n <Minus\n className={cn(\n iconSizeClasses[size],\n 'animate-[scale-in_150ms_ease-out] motion-reduce:animate-none',\n )}\n strokeWidth={3}\n />\n ) : (\n <DrawCheck className={iconSizeClasses[size]} />\n ))}\n </span>\n );\n }\n\n // Radio type\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"radio\"\n data-checked={checked}\n className={cn(\n selectionIndicatorVariants({ size }),\n 'transition-[background-color,border-color] duration-150 motion-reduce:transition-none',\n checked\n ? cn(colors.indicatorChecked, 'border-transparent')\n : 'border-border bg-background',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n <span\n className={cn(\n 'bg-background rounded-full transition-transform duration-150 ease-out motion-reduce:transition-none',\n innerDotSizes[size],\n checked ? 'scale-100' : 'scale-0',\n )}\n />\n </span>\n );\n },\n);\n\nSelectionIndicator.displayName = 'SelectionIndicator';\n\n// =============================================================================\n// FeaturedIcon Component\n// =============================================================================\n\nexport interface FeaturedIconProps {\n /** The icon content to display */\n children: React.ReactNode;\n /** Size of the featured icon container */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n// Hoisted outside component to avoid recreation on every render\nconst featuredIconContainerSizes: Record<SelectionSize, string> = {\n sm: 'size-8',\n md: 'size-10',\n lg: 'size-12',\n};\n\nconst featuredIconInnerSizes: Record<SelectionSize, string> = {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n};\n\n/**\n * FeaturedIcon is a container for icons with border and shadow.\n * Used in icon-simple and icon-card variants.\n */\nconst FeaturedIcon = React.forwardRef<HTMLDivElement, FeaturedIconProps>(\n ({ children, size = 'sm', className }, ref) => {\n const containerSize = featuredIconContainerSizes[size];\n const innerSize = featuredIconInnerSizes[size];\n\n return (\n <div\n ref={ref}\n data-slot=\"featured-icon\"\n className={cn(\n 'shrink-0 rounded-md border border-border bg-card/60',\n 'flex items-center justify-center',\n 'dark:border-border',\n containerSize,\n className,\n )}\n style={{\n boxShadow: 'var(--shadow-inset-ring)',\n }}\n >\n <div className={cn('text-secondary-foreground', innerSize)}>\n {children}\n </div>\n </div>\n );\n },\n);\n\nFeaturedIcon.displayName = 'FeaturedIcon';\n\n// =============================================================================\n// ColorDot Component\n// =============================================================================\n\nexport type ColorDotColor =\n | 'gray'\n | 'orange'\n | 'red'\n | 'darkRed'\n | 'brand'\n | 'success'\n | 'warning'\n | 'error'\n | string; // Allow custom hex colors\n\nconst dotColorMap: Record<string, string> = {\n gray: 'bg-muted',\n orange: 'bg-warning',\n red: 'bg-destructive',\n darkRed: 'bg-destructive-hover',\n brand: 'bg-primary/10',\n success: 'bg-success/10',\n warning: 'bg-warning/10',\n error: 'bg-destructive/10',\n};\n\nconst dotSizeMap: Record<SelectionSize, string> = {\n sm: 'size-[10px]',\n md: 'size-3',\n lg: 'size-3.5',\n};\n\nexport interface ColorDotProps {\n /** Color of the dot (named color or hex) */\n color?: ColorDotColor;\n /** Size of the dot */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * ColorDot renders a colored dot for chip variant.\n * Supports named colors (gray, orange, red, etc.) and hex colors.\n */\nconst ColorDot = React.forwardRef<HTMLSpanElement, ColorDotProps>(\n ({ color, size = 'sm', className }, ref) => {\n if (!color) return null;\n\n const colorClass = dotColorMap[color];\n const isHexColor = color.startsWith('#');\n\n return (\n <span\n ref={ref}\n data-slot=\"color-dot\"\n className={cn(\n 'shrink-0 rounded-full',\n dotSizeMap[size],\n !isHexColor && colorClass,\n className,\n )}\n style={isHexColor ? { backgroundColor: color } : undefined}\n aria-hidden=\"true\"\n />\n );\n },\n);\n\nColorDot.displayName = 'ColorDot';\n\n// =============================================================================\n// Exports\n// =============================================================================\n\nexport { ColorDot, FeaturedIcon, SelectionIndicator };\n"],"mappings":"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"}
|
package/dist/index5.js
CHANGED
|
@@ -438,7 +438,7 @@ function ClearButton({ className, size = "icon-sm", ...props }) {
|
|
|
438
438
|
variant: "secondary",
|
|
439
439
|
size,
|
|
440
440
|
iconOnly: true,
|
|
441
|
-
className: cn("text-
|
|
441
|
+
className: cn("text-muted-foreground hover:text-secondary-foreground", className),
|
|
442
442
|
"aria-label": "Clear",
|
|
443
443
|
...props,
|
|
444
444
|
children: /* @__PURE__ */ jsx(X, {})
|
package/dist/index5.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index5.js","names":[],"sources":["../src/components/ui/button.tsx"],"sourcesContent":["import { Button as ButtonPrimitive } from '@base-ui/react/button';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { Check, X } from 'lucide-react';\nimport * as React from 'react';\nimport { GradientBorder } from '@/components/ui/gradient-border';\nimport { Spinner } from '@/components/ui/spinner';\nimport { cn } from '@/lib/utils';\n\nconst buttonFocusExpansionClassName =\n 'focus-visible:scale-[1.015] motion-reduce:focus-visible:scale-100';\n\nconst buttonVariants = cva(\n \"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] [&_svg:not([class*='size-'])]:size-4 inline-flex origin-center items-center justify-center whitespace-nowrap transition-[color,background-color,border-color,box-shadow,transform,opacity] duration-200 ease-smooth motion-reduce:transition-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none\",\n {\n variants: {\n appearance: {\n solid: `${buttonFocusExpansionClassName} delight-click-ripple`,\n gradient: `${buttonFocusExpansionClassName} bg-linear-[113deg] hover:opacity-80 delight-click-ripple`,\n soft: `${buttonFocusExpansionClassName} delight-click-ripple`,\n outline: `${buttonFocusExpansionClassName} bg-background shadow-xs`,\n ghost: `${buttonFocusExpansionClassName} bg-transparent`,\n link: 'border-none bg-transparent p-0 h-auto underline-offset-4 hover:underline focus-visible:ring-0 focus-visible:border-transparent',\n ai: `${buttonFocusExpansionClassName} bg-transparent border-0`,\n },\n variant: {\n primary: '',\n secondary: '',\n info: '',\n success: '',\n warning: '',\n destructive: '',\n },\n size: {\n default:\n 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2',\n xs: \"h-6 gap-1 px-2 text-xs has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: 'h-8 gap-1 px-2.5 has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5',\n md: 'h-10 gap-1.5 px-3.5 has-data-[icon=inline-end]:pe-3 has-data-[icon=inline-start]:ps-3',\n lg: 'h-11 gap-2 px-4 has-data-[icon=inline-end]:pe-3.5 has-data-[icon=inline-start]:ps-3.5',\n xl: \"h-12 gap-2 px-4.5 text-base has-data-[icon=inline-end]:pe-4 has-data-[icon=inline-start]:ps-4 [&_svg:not([class*='size-'])]:size-5\",\n '2xl':\n \"h-14 gap-2.5 px-5 text-lg has-data-[icon=inline-end]:pe-4.5 has-data-[icon=inline-start]:ps-4.5 [&_svg:not([class*='size-'])]:size-6\",\n icon: 'size-9',\n 'icon-xs': \"size-6 [&_svg:not([class*='size-'])]:size-3\",\n 'icon-sm': 'size-8',\n 'icon-lg': 'size-10',\n 'icon-xl': \"size-12 [&_svg:not([class*='size-'])]:size-5\",\n 'icon-2xl': \"size-14 [&_svg:not([class*='size-'])]:size-6\",\n },\n shape: {\n rounded: 'rounded-md',\n round: 'rounded-full',\n },\n },\n compoundVariants: [\n // ===== SOLID =====\n {\n appearance: 'solid',\n variant: 'primary',\n className: 'bg-primary text-primary-foreground hover:bg-primary-hover',\n },\n {\n appearance: 'solid',\n variant: 'secondary',\n className:\n 'bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground',\n },\n {\n appearance: 'solid',\n variant: 'info',\n className: 'bg-info text-info-foreground hover:bg-info/80',\n },\n {\n appearance: 'solid',\n variant: 'success',\n className: 'bg-success text-success-foreground hover:bg-success/80',\n },\n {\n appearance: 'solid',\n variant: 'warning',\n className: 'bg-warning text-warning-foreground hover:bg-warning/80',\n },\n {\n appearance: 'solid',\n variant: 'destructive',\n className:\n 'bg-destructive text-destructive-foreground hover:bg-destructive/80',\n },\n\n // ===== GRADIENT =====\n {\n appearance: 'gradient',\n variant: 'primary',\n className:\n 'from-custom-tw-gradient-from to-custom-tw-gradient-to text-primary-foreground hover:from-custom-tw-gradient-to hover:to-custom-tw-gradient-from',\n },\n {\n appearance: 'gradient',\n variant: 'secondary',\n className:\n 'from-secondary to-secondary/60 text-secondary-foreground hover:from-secondary/60 hover:to-secondary',\n },\n {\n appearance: 'gradient',\n variant: 'info',\n className:\n 'from-info to-info/60 text-info-foreground hover:from-info/60 hover:to-info',\n },\n {\n appearance: 'gradient',\n variant: 'success',\n className:\n 'from-success to-success/60 text-success-foreground hover:from-success/60 hover:to-success',\n },\n {\n appearance: 'gradient',\n variant: 'warning',\n className:\n 'from-warning to-warning/60 text-warning-foreground hover:from-warning/60 hover:to-warning',\n },\n {\n appearance: 'gradient',\n variant: 'destructive',\n className:\n 'from-destructive to-destructive/60 text-destructive-foreground hover:from-destructive/60 hover:to-destructive',\n },\n\n // ===== SOFT =====\n {\n appearance: 'soft',\n variant: 'primary',\n className:\n 'bg-primary/10 border-primary text-primary hover:bg-primary/20 hover:text-primary dark:bg-primary/30 dark:border-primary dark:text-primary dark:hover:bg-primary/50 shadow-xs',\n },\n {\n appearance: 'soft',\n variant: 'secondary',\n className:\n 'bg-secondary/10 text-secondary-foreground hover:bg-secondary/20',\n },\n {\n appearance: 'soft',\n variant: 'info',\n className: 'bg-info/10 text-info hover:bg-info/20',\n },\n {\n appearance: 'soft',\n variant: 'success',\n className: 'bg-success/10 text-success hover:bg-success/20',\n },\n {\n appearance: 'soft',\n variant: 'warning',\n className: 'bg-warning/10 text-warning hover:bg-warning/20',\n },\n {\n appearance: 'soft',\n variant: 'destructive',\n className:\n 'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',\n },\n\n // ===== OUTLINE =====\n {\n appearance: 'outline',\n className:\n 'bg-card border-border backdrop-blur-[2px] shadow-none supports-backdrop-filter:backdrop-blur-[2px]',\n },\n {\n appearance: 'outline',\n shape: 'rounded',\n className: 'rounded-xl',\n },\n {\n appearance: 'outline',\n size: 'xs',\n className: 'h-[26px] gap-1 px-2',\n },\n {\n appearance: 'outline',\n size: 'sm',\n className: 'h-8 gap-1.5 px-2.5',\n },\n {\n appearance: 'outline',\n size: 'default',\n className: 'h-9 gap-2 px-4',\n },\n {\n appearance: 'outline',\n size: 'md',\n className: 'h-10 gap-2 px-4',\n },\n {\n appearance: 'outline',\n size: 'lg',\n className: 'h-10 gap-2 px-4.5',\n },\n {\n appearance: 'outline',\n variant: 'primary',\n className: 'border-border text-foreground hover:bg-muted/50',\n },\n {\n appearance: 'outline',\n variant: 'secondary',\n className:\n 'border-border text-secondary-foreground hover:bg-muted/50 aria-expanded:bg-muted/50 aria-expanded:text-foreground',\n },\n {\n appearance: 'outline',\n variant: 'info',\n className: 'border-border text-info hover:bg-info/10',\n },\n {\n appearance: 'outline',\n variant: 'success',\n className: 'border-border text-success hover:bg-success/10',\n },\n {\n appearance: 'outline',\n variant: 'warning',\n className: 'border-border text-warning hover:bg-warning/10',\n },\n {\n appearance: 'outline',\n variant: 'destructive',\n className: 'border-border text-destructive hover:bg-destructive/10',\n },\n\n // ===== GHOST =====\n {\n appearance: 'ghost',\n variant: 'primary',\n className: 'text-primary hover:bg-primary/10',\n },\n {\n appearance: 'ghost',\n variant: 'secondary',\n className:\n 'hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground',\n },\n {\n appearance: 'ghost',\n variant: 'info',\n className: 'text-info hover:bg-info/10',\n },\n {\n appearance: 'ghost',\n variant: 'success',\n className: 'text-success hover:bg-success/10',\n },\n {\n appearance: 'ghost',\n variant: 'warning',\n className: 'text-warning hover:bg-warning/10',\n },\n {\n appearance: 'ghost',\n variant: 'destructive',\n className: 'text-destructive hover:bg-destructive/10',\n },\n\n // ===== AI (inner button styling — GradientBorder wraps externally) =====\n {\n appearance: 'ai',\n variant: 'primary',\n className: 'text-primary hover:bg-primary/10',\n },\n {\n appearance: 'ai',\n variant: 'secondary',\n className: 'text-secondary-foreground hover:bg-muted',\n },\n\n // ===== LINK =====\n { appearance: 'link', variant: 'primary', className: 'text-primary' },\n {\n appearance: 'link',\n variant: 'secondary',\n className: 'text-secondary-foreground',\n },\n { appearance: 'link', variant: 'info', className: 'text-info' },\n { appearance: 'link', variant: 'success', className: 'text-success' },\n { appearance: 'link', variant: 'warning', className: 'text-warning' },\n {\n appearance: 'link',\n variant: 'destructive',\n className: 'text-destructive hover:text-destructive/80',\n },\n ],\n defaultVariants: {\n appearance: 'solid',\n variant: 'primary',\n size: 'default',\n shape: 'rounded',\n },\n },\n);\n\ntype DotColor = 'success' | 'error' | 'warning' | 'brand' | 'gray';\n\ntype ButtonAppearance =\n | 'solid'\n | 'gradient'\n | 'soft'\n | 'outline'\n | 'ghost'\n | 'link'\n | 'ai';\ntype ButtonVariant =\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'destructive';\ntype ButtonShape = 'rounded' | 'round';\n\n/**\n * Render prop type for polymorphic rendering.\n * Accepts either a React element or a function that receives props and returns an element.\n * @template Props The props to be passed to the rendered element\n */\ntype RenderProp<Props> =\n | React.ReactElement\n | ((props: Props) => React.ReactElement);\n\nexport interface ButtonProps\n extends React.ComponentProps<'button'>,\n Pick<VariantProps<typeof buttonVariants>, 'size'> {\n /** Visual appearance - how the button renders */\n appearance?: ButtonAppearance;\n /** Semantic variant - what the button means */\n variant?: ButtonVariant;\n /** Shape of the button corners */\n shape?: ButtonShape;\n /** Shows a loading spinner and disables the button */\n loading?: boolean;\n /** Set to false when render targets a non-button element. */\n nativeButton?: boolean;\n /** Icon displayed at the start (inline-start) of the button text - respects RTL */\n startIcon?: React.ReactNode;\n /** Icon displayed at the end (inline-end) of the button text - respects RTL */\n endIcon?: React.ReactNode;\n /** Shows a colored dot indicator before the button text */\n dotIndicator?: boolean;\n /** Color of the dot indicator */\n dotColor?: DotColor;\n /** Badge content displayed after the button label. Text badges are styled from the button appearance and variant. */\n badge?: React.ReactNode;\n /** For icon-only buttons - renders just the icon without text wrapper */\n iconOnly?: boolean;\n /** Enables animated gradient border (only for appearance=\"ai\"). Auto-true when loading. */\n animated?: boolean;\n /**\n * Render prop for polymorphic rendering. Accepts either a React element or a render function.\n * Use this to render the button as a different element (e.g., link) while preserving button styles.\n * Note: When render is provided, loading/startIcon/endIcon/dotIndicator/badge are ignored.\n */\n render?: RenderProp<React.ComponentProps<'button'>>;\n}\n\nconst dotColorClasses: Record<DotColor, string> = {\n success: 'bg-success',\n error: 'bg-destructive',\n warning: 'bg-warning',\n brand: 'bg-primary',\n gray: 'bg-muted',\n};\n\nconst devWarnings = new Set<string>();\n\n/** Icon-only size variants for type-safe detection */\nconst ICON_SIZES = [\n 'icon',\n 'icon-xs',\n 'icon-sm',\n 'icon-lg',\n 'icon-xl',\n 'icon-2xl',\n] as const;\n\nconst SUCCESS_FLASH_DURATION_MS = 600;\n\nconst buttonBadgeShapeClasses: Record<ButtonShape, string> = {\n round: 'rounded-full',\n rounded: 'rounded-sm',\n};\n\nconst buttonBadgeWhiteColorClasses: Record<ButtonVariant, string> = {\n primary: 'text-primary',\n secondary: 'text-secondary-foreground',\n info: 'text-info',\n success: 'text-success',\n warning: 'text-warning',\n destructive: 'text-destructive',\n};\n\nconst buttonBadgeSoftColorClasses: Record<ButtonVariant, string> = {\n primary:\n 'bg-soft-primary text-soft-primary-foreground hover:bg-opacity-primary-20 dark:bg-soft-primary dark:text-soft-primary-foreground',\n secondary:\n 'bg-soft-secondary text-soft-secondary-foreground hover:bg-opacity-secondary-20 dark:bg-soft-secondary dark:text-soft-secondary-foreground',\n info: 'bg-soft-info text-soft-info-foreground hover:bg-opacity-info-20 dark:bg-soft-info dark:text-soft-info-foreground',\n success:\n 'bg-soft-success text-soft-success-foreground hover:bg-opacity-success-20 dark:bg-soft-success dark:text-soft-success-foreground',\n warning:\n 'bg-soft-warning text-soft-warning-foreground hover:bg-opacity-warning-20 dark:bg-soft-warning dark:text-soft-warning-foreground',\n destructive:\n 'bg-soft-destructive text-soft-destructive-foreground hover:bg-opacity-destructive-20 dark:bg-soft-destructive dark:text-soft-destructive-foreground',\n};\n\ntype LoadingSuccessState = {\n wasLoading: boolean;\n visible: boolean;\n token: number;\n};\n\nconst Dot = ({\n color = 'success',\n className,\n}: {\n color?: DotColor;\n className?: string;\n}) => (\n <span\n aria-hidden=\"true\"\n className={cn(\n 'size-2 rounded-full shrink-0 delight-breathing',\n dotColorClasses[color],\n className,\n )}\n />\n);\n\nfunction ButtonBadge({\n appearance,\n badge,\n shape,\n variant,\n}: {\n appearance: ButtonAppearance;\n badge: React.ReactNode;\n shape: ButtonShape;\n variant: ButtonVariant;\n}) {\n if (React.isValidElement(badge)) {\n return badge;\n }\n\n if (badge === true || badge === false || badge == null) {\n return null;\n }\n\n const badgeVariant =\n (appearance === 'solid' || appearance === 'gradient') &&\n variant !== 'secondary'\n ? 'white'\n : 'soft';\n\n return (\n <span\n data-slot=\"badge\"\n className={cn(\n 'inline-flex h-5 shrink-0 items-center justify-center gap-1.5 whitespace-nowrap px-2 py-0.5 text-xs font-medium transition-colors [&>svg]:size-3 [&>svg]:shrink-0 [&>svg]:pointer-events-none',\n buttonBadgeShapeClasses[shape],\n badgeVariant === 'white'\n ? 'bg-opacity-white-80 transition-opacity hover:opacity-80 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-current/50'\n : buttonBadgeSoftColorClasses[variant],\n badgeVariant === 'white' && buttonBadgeWhiteColorClasses[variant],\n )}\n >\n {badge}\n </span>\n );\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n children,\n loading = false,\n disabled,\n startIcon,\n endIcon,\n dotIndicator = false,\n dotColor = 'success',\n badge,\n iconOnly = false,\n animated,\n render,\n className,\n appearance = 'solid',\n variant = 'primary',\n shape = 'rounded',\n size = 'default',\n ...props\n },\n ref,\n ) => {\n // Dev-mode warning for icon-only buttons missing accessible label (once)\n if (\n process.env.NODE_ENV !== 'production' &&\n !devWarnings.has('icon-a11y')\n ) {\n const hasIconSize = ICON_SIZES.includes(\n size as (typeof ICON_SIZES)[number],\n );\n if (\n (iconOnly || hasIconSize) &&\n !props['aria-label'] &&\n !props['aria-labelledby']\n ) {\n devWarnings.add('icon-a11y');\n console.warn(\n 'Button: Icon-only buttons require an `aria-label` or `aria-labelledby` for accessibility.',\n );\n }\n }\n\n // Track loading→done transition before paint so the button never commits a\n // stale success state after the loading prop changes.\n const [successState, setSuccessState] = React.useState<LoadingSuccessState>(\n () => ({\n wasLoading: loading,\n visible: false,\n token: 0,\n }),\n );\n\n if (successState.wasLoading !== loading) {\n const shouldFlash = successState.wasLoading && !loading;\n setSuccessState({\n wasLoading: loading,\n visible: shouldFlash,\n token: shouldFlash ? successState.token + 1 : successState.token,\n });\n }\n\n React.useEffect(() => {\n if (!successState.visible) return;\n const token = successState.token;\n const timer = setTimeout(() => {\n setSuccessState((current) =>\n current.token === token ? { ...current, visible: false } : current,\n );\n }, SUCCESS_FLASH_DURATION_MS);\n return () => clearTimeout(timer);\n }, [successState.visible, successState.token]);\n\n const showSuccess = successState.visible && !loading;\n\n const isAi = appearance === 'ai';\n const isAnimated = isAi ? (animated ?? loading) : false;\n\n const buttonClassName = cn(\n buttonVariants({ appearance, variant, shape, size }),\n className,\n );\n\n // When render prop is provided, pass through to primitive\n // (ignores loading/startIcon/endIcon/dotIndicator/badge)\n if (render) {\n return (\n <ButtonPrimitive\n ref={ref}\n data-slot=\"button\"\n className={buttonClassName}\n render={render}\n {...props}\n >\n {children}\n </ButtonPrimitive>\n );\n }\n\n // Determine if this is an icon-only button based on size or explicit prop\n const isIconOnly =\n iconOnly || ICON_SIZES.includes(size as (typeof ICON_SIZES)[number]);\n const shouldComposeBadgeLabel =\n !isIconOnly &&\n !props['aria-label'] &&\n !props['aria-labelledby'] &&\n (typeof children === 'string' || typeof children === 'number') &&\n (typeof badge === 'string' || typeof badge === 'number');\n const buttonProps = shouldComposeBadgeLabel\n ? { ...props, 'aria-label': `${children} ${badge}` }\n : props;\n const buttonBadge = !isIconOnly ? (\n <ButtonBadge\n appearance={appearance}\n badge={badge}\n shape={shape}\n variant={variant}\n />\n ) : null;\n\n // Build the button element (icon-only or full)\n const buttonElement = isIconOnly ? (\n <ButtonPrimitive\n ref={isAi ? undefined : ref}\n data-slot=\"button\"\n disabled={disabled || loading}\n className={cn(buttonClassName, loading && 'relative')}\n {...buttonProps}\n >\n {loading ? (\n <Spinner className=\"delight-fade-in\" />\n ) : showSuccess ? (\n <Check className=\"delight-bounce-in\" />\n ) : (\n children\n )}\n </ButtonPrimitive>\n ) : (\n <ButtonPrimitive\n ref={isAi ? undefined : ref}\n data-slot=\"button\"\n disabled={disabled || loading}\n className={cn(buttonClassName, (loading || showSuccess) && 'relative')}\n {...buttonProps}\n >\n {loading && <Spinner className=\"absolute delight-fade-in\" />}\n {showSuccess && !loading && (\n <Check className=\"absolute delight-bounce-in\" />\n )}\n <span\n className={cn(\n 'flex items-center gap-2',\n (loading || showSuccess) && 'invisible',\n )}\n >\n {dotIndicator && <Dot color={dotColor} />}\n {startIcon}\n {children}\n {endIcon}\n {buttonBadge}\n </span>\n </ButtonPrimitive>\n );\n\n if (isAi) {\n return (\n <GradientBorder\n ref={ref as React.Ref<HTMLDivElement>}\n animated={isAnimated}\n active\n disabled={disabled}\n className=\"w-auto inline-flex motion-reduce:animate-none\"\n innerClassName=\"flex\"\n >\n {buttonElement}\n </GradientBorder>\n );\n }\n\n return buttonElement;\n },\n);\n\nButton.displayName = 'Button';\n\n/**\n * Clear/Close icon button - a ghost button specifically for close/clear actions\n * Commonly used in tags, dialogs, and dismissible elements\n */\nexport interface ClearButtonProps\n extends Omit<\n ButtonProps,\n | 'appearance'\n | 'variant'\n | 'children'\n | 'startIcon'\n | 'endIcon'\n | 'dotIndicator'\n > {\n /** Size of the clear button */\n size?: 'icon-xs' | 'icon-sm' | 'icon' | 'icon-lg' | 'icon-xl' | 'icon-2xl';\n}\n\nfunction ClearButton({\n className,\n size = 'icon-sm',\n ...props\n}: ClearButtonProps) {\n return (\n <Button\n appearance=\"ghost\"\n variant=\"secondary\"\n size={size}\n iconOnly\n className={cn(\n 'text-text-quaternary hover:text-secondary-foreground',\n className,\n )}\n aria-label=\"Clear\"\n {...props}\n >\n <X />\n </Button>\n );\n}\n\nClearButton.displayName = 'ClearButton';\n\nexport type { ButtonAppearance, ButtonShape, ButtonVariant };\nexport { Button, buttonVariants, ClearButton, Dot };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index5.js","names":[],"sources":["../src/components/ui/button.tsx"],"sourcesContent":["import { Button as ButtonPrimitive } from '@base-ui/react/button';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { Check, X } from 'lucide-react';\nimport * as React from 'react';\nimport { GradientBorder } from '@/components/ui/gradient-border';\nimport { Spinner } from '@/components/ui/spinner';\nimport { cn } from '@/lib/utils';\n\nconst buttonFocusExpansionClassName =\n 'focus-visible:scale-[1.015] motion-reduce:focus-visible:scale-100';\n\nconst buttonVariants = cva(\n \"focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] [&_svg:not([class*='size-'])]:size-4 inline-flex origin-center items-center justify-center whitespace-nowrap transition-[color,background-color,border-color,box-shadow,transform,opacity] duration-200 ease-smooth motion-reduce:transition-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none\",\n {\n variants: {\n appearance: {\n solid: `${buttonFocusExpansionClassName} delight-click-ripple`,\n gradient: `${buttonFocusExpansionClassName} bg-linear-[113deg] hover:opacity-80 delight-click-ripple`,\n soft: `${buttonFocusExpansionClassName} delight-click-ripple`,\n outline: `${buttonFocusExpansionClassName} bg-background shadow-xs`,\n ghost: `${buttonFocusExpansionClassName} bg-transparent`,\n link: 'border-none bg-transparent p-0 h-auto underline-offset-4 hover:underline focus-visible:ring-0 focus-visible:border-transparent',\n ai: `${buttonFocusExpansionClassName} bg-transparent border-0`,\n },\n variant: {\n primary: '',\n secondary: '',\n info: '',\n success: '',\n warning: '',\n destructive: '',\n },\n size: {\n default:\n 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pe-2 has-data-[icon=inline-start]:ps-2',\n xs: \"h-6 gap-1 px-2 text-xs has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: 'h-8 gap-1 px-2.5 has-data-[icon=inline-end]:pe-1.5 has-data-[icon=inline-start]:ps-1.5',\n md: 'h-10 gap-1.5 px-3.5 has-data-[icon=inline-end]:pe-3 has-data-[icon=inline-start]:ps-3',\n lg: 'h-11 gap-2 px-4 has-data-[icon=inline-end]:pe-3.5 has-data-[icon=inline-start]:ps-3.5',\n xl: \"h-12 gap-2 px-4.5 text-base has-data-[icon=inline-end]:pe-4 has-data-[icon=inline-start]:ps-4 [&_svg:not([class*='size-'])]:size-5\",\n '2xl':\n \"h-14 gap-2.5 px-5 text-lg has-data-[icon=inline-end]:pe-4.5 has-data-[icon=inline-start]:ps-4.5 [&_svg:not([class*='size-'])]:size-6\",\n icon: 'size-9',\n 'icon-xs': \"size-6 [&_svg:not([class*='size-'])]:size-3\",\n 'icon-sm': 'size-8',\n 'icon-lg': 'size-10',\n 'icon-xl': \"size-12 [&_svg:not([class*='size-'])]:size-5\",\n 'icon-2xl': \"size-14 [&_svg:not([class*='size-'])]:size-6\",\n },\n shape: {\n rounded: 'rounded-md',\n round: 'rounded-full',\n },\n },\n compoundVariants: [\n // ===== SOLID =====\n {\n appearance: 'solid',\n variant: 'primary',\n className: 'bg-primary text-primary-foreground hover:bg-primary-hover',\n },\n {\n appearance: 'solid',\n variant: 'secondary',\n className:\n 'bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground',\n },\n {\n appearance: 'solid',\n variant: 'info',\n className: 'bg-info text-info-foreground hover:bg-info/80',\n },\n {\n appearance: 'solid',\n variant: 'success',\n className: 'bg-success text-success-foreground hover:bg-success/80',\n },\n {\n appearance: 'solid',\n variant: 'warning',\n className: 'bg-warning text-warning-foreground hover:bg-warning/80',\n },\n {\n appearance: 'solid',\n variant: 'destructive',\n className:\n 'bg-destructive text-destructive-foreground hover:bg-destructive/80',\n },\n\n // ===== GRADIENT =====\n {\n appearance: 'gradient',\n variant: 'primary',\n className:\n 'from-custom-tw-gradient-from to-custom-tw-gradient-to text-primary-foreground hover:from-custom-tw-gradient-to hover:to-custom-tw-gradient-from',\n },\n {\n appearance: 'gradient',\n variant: 'secondary',\n className:\n 'from-secondary to-secondary/60 text-secondary-foreground hover:from-secondary/60 hover:to-secondary',\n },\n {\n appearance: 'gradient',\n variant: 'info',\n className:\n 'from-info to-info/60 text-info-foreground hover:from-info/60 hover:to-info',\n },\n {\n appearance: 'gradient',\n variant: 'success',\n className:\n 'from-success to-success/60 text-success-foreground hover:from-success/60 hover:to-success',\n },\n {\n appearance: 'gradient',\n variant: 'warning',\n className:\n 'from-warning to-warning/60 text-warning-foreground hover:from-warning/60 hover:to-warning',\n },\n {\n appearance: 'gradient',\n variant: 'destructive',\n className:\n 'from-destructive to-destructive/60 text-destructive-foreground hover:from-destructive/60 hover:to-destructive',\n },\n\n // ===== SOFT =====\n {\n appearance: 'soft',\n variant: 'primary',\n className:\n 'bg-primary/10 border-primary text-primary hover:bg-primary/20 hover:text-primary dark:bg-primary/30 dark:border-primary dark:text-primary dark:hover:bg-primary/50 shadow-xs',\n },\n {\n appearance: 'soft',\n variant: 'secondary',\n className:\n 'bg-secondary/10 text-secondary-foreground hover:bg-secondary/20',\n },\n {\n appearance: 'soft',\n variant: 'info',\n className: 'bg-info/10 text-info hover:bg-info/20',\n },\n {\n appearance: 'soft',\n variant: 'success',\n className: 'bg-success/10 text-success hover:bg-success/20',\n },\n {\n appearance: 'soft',\n variant: 'warning',\n className: 'bg-warning/10 text-warning hover:bg-warning/20',\n },\n {\n appearance: 'soft',\n variant: 'destructive',\n className:\n 'bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30',\n },\n\n // ===== OUTLINE =====\n {\n appearance: 'outline',\n className:\n 'bg-card border-border backdrop-blur-[2px] shadow-none supports-backdrop-filter:backdrop-blur-[2px]',\n },\n {\n appearance: 'outline',\n shape: 'rounded',\n className: 'rounded-xl',\n },\n {\n appearance: 'outline',\n size: 'xs',\n className: 'h-[26px] gap-1 px-2',\n },\n {\n appearance: 'outline',\n size: 'sm',\n className: 'h-8 gap-1.5 px-2.5',\n },\n {\n appearance: 'outline',\n size: 'default',\n className: 'h-9 gap-2 px-4',\n },\n {\n appearance: 'outline',\n size: 'md',\n className: 'h-10 gap-2 px-4',\n },\n {\n appearance: 'outline',\n size: 'lg',\n className: 'h-10 gap-2 px-4.5',\n },\n {\n appearance: 'outline',\n variant: 'primary',\n className: 'border-border text-foreground hover:bg-muted/50',\n },\n {\n appearance: 'outline',\n variant: 'secondary',\n className:\n 'border-border text-secondary-foreground hover:bg-muted/50 aria-expanded:bg-muted/50 aria-expanded:text-foreground',\n },\n {\n appearance: 'outline',\n variant: 'info',\n className: 'border-border text-info hover:bg-info/10',\n },\n {\n appearance: 'outline',\n variant: 'success',\n className: 'border-border text-success hover:bg-success/10',\n },\n {\n appearance: 'outline',\n variant: 'warning',\n className: 'border-border text-warning hover:bg-warning/10',\n },\n {\n appearance: 'outline',\n variant: 'destructive',\n className: 'border-border text-destructive hover:bg-destructive/10',\n },\n\n // ===== GHOST =====\n {\n appearance: 'ghost',\n variant: 'primary',\n className: 'text-primary hover:bg-primary/10',\n },\n {\n appearance: 'ghost',\n variant: 'secondary',\n className:\n 'hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground',\n },\n {\n appearance: 'ghost',\n variant: 'info',\n className: 'text-info hover:bg-info/10',\n },\n {\n appearance: 'ghost',\n variant: 'success',\n className: 'text-success hover:bg-success/10',\n },\n {\n appearance: 'ghost',\n variant: 'warning',\n className: 'text-warning hover:bg-warning/10',\n },\n {\n appearance: 'ghost',\n variant: 'destructive',\n className: 'text-destructive hover:bg-destructive/10',\n },\n\n // ===== AI (inner button styling — GradientBorder wraps externally) =====\n {\n appearance: 'ai',\n variant: 'primary',\n className: 'text-primary hover:bg-primary/10',\n },\n {\n appearance: 'ai',\n variant: 'secondary',\n className: 'text-secondary-foreground hover:bg-muted',\n },\n\n // ===== LINK =====\n { appearance: 'link', variant: 'primary', className: 'text-primary' },\n {\n appearance: 'link',\n variant: 'secondary',\n className: 'text-secondary-foreground',\n },\n { appearance: 'link', variant: 'info', className: 'text-info' },\n { appearance: 'link', variant: 'success', className: 'text-success' },\n { appearance: 'link', variant: 'warning', className: 'text-warning' },\n {\n appearance: 'link',\n variant: 'destructive',\n className: 'text-destructive hover:text-destructive/80',\n },\n ],\n defaultVariants: {\n appearance: 'solid',\n variant: 'primary',\n size: 'default',\n shape: 'rounded',\n },\n },\n);\n\ntype DotColor = 'success' | 'error' | 'warning' | 'brand' | 'gray';\n\ntype ButtonAppearance =\n | 'solid'\n | 'gradient'\n | 'soft'\n | 'outline'\n | 'ghost'\n | 'link'\n | 'ai';\ntype ButtonVariant =\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'destructive';\ntype ButtonShape = 'rounded' | 'round';\n\n/**\n * Render prop type for polymorphic rendering.\n * Accepts either a React element or a function that receives props and returns an element.\n * @template Props The props to be passed to the rendered element\n */\ntype RenderProp<Props> =\n | React.ReactElement\n | ((props: Props) => React.ReactElement);\n\nexport interface ButtonProps\n extends React.ComponentProps<'button'>,\n Pick<VariantProps<typeof buttonVariants>, 'size'> {\n /** Visual appearance - how the button renders */\n appearance?: ButtonAppearance;\n /** Semantic variant - what the button means */\n variant?: ButtonVariant;\n /** Shape of the button corners */\n shape?: ButtonShape;\n /** Shows a loading spinner and disables the button */\n loading?: boolean;\n /** Set to false when render targets a non-button element. */\n nativeButton?: boolean;\n /** Icon displayed at the start (inline-start) of the button text - respects RTL */\n startIcon?: React.ReactNode;\n /** Icon displayed at the end (inline-end) of the button text - respects RTL */\n endIcon?: React.ReactNode;\n /** Shows a colored dot indicator before the button text */\n dotIndicator?: boolean;\n /** Color of the dot indicator */\n dotColor?: DotColor;\n /** Badge content displayed after the button label. Text badges are styled from the button appearance and variant. */\n badge?: React.ReactNode;\n /** For icon-only buttons - renders just the icon without text wrapper */\n iconOnly?: boolean;\n /** Enables animated gradient border (only for appearance=\"ai\"). Auto-true when loading. */\n animated?: boolean;\n /**\n * Render prop for polymorphic rendering. Accepts either a React element or a render function.\n * Use this to render the button as a different element (e.g., link) while preserving button styles.\n * Note: When render is provided, loading/startIcon/endIcon/dotIndicator/badge are ignored.\n */\n render?: RenderProp<React.ComponentProps<'button'>>;\n}\n\nconst dotColorClasses: Record<DotColor, string> = {\n success: 'bg-success',\n error: 'bg-destructive',\n warning: 'bg-warning',\n brand: 'bg-primary',\n gray: 'bg-muted',\n};\n\nconst devWarnings = new Set<string>();\n\n/** Icon-only size variants for type-safe detection */\nconst ICON_SIZES = [\n 'icon',\n 'icon-xs',\n 'icon-sm',\n 'icon-lg',\n 'icon-xl',\n 'icon-2xl',\n] as const;\n\nconst SUCCESS_FLASH_DURATION_MS = 600;\n\nconst buttonBadgeShapeClasses: Record<ButtonShape, string> = {\n round: 'rounded-full',\n rounded: 'rounded-sm',\n};\n\nconst buttonBadgeWhiteColorClasses: Record<ButtonVariant, string> = {\n primary: 'text-primary',\n secondary: 'text-secondary-foreground',\n info: 'text-info',\n success: 'text-success',\n warning: 'text-warning',\n destructive: 'text-destructive',\n};\n\nconst buttonBadgeSoftColorClasses: Record<ButtonVariant, string> = {\n primary:\n 'bg-soft-primary text-soft-primary-foreground hover:bg-opacity-primary-20 dark:bg-soft-primary dark:text-soft-primary-foreground',\n secondary:\n 'bg-soft-secondary text-soft-secondary-foreground hover:bg-opacity-secondary-20 dark:bg-soft-secondary dark:text-soft-secondary-foreground',\n info: 'bg-soft-info text-soft-info-foreground hover:bg-opacity-info-20 dark:bg-soft-info dark:text-soft-info-foreground',\n success:\n 'bg-soft-success text-soft-success-foreground hover:bg-opacity-success-20 dark:bg-soft-success dark:text-soft-success-foreground',\n warning:\n 'bg-soft-warning text-soft-warning-foreground hover:bg-opacity-warning-20 dark:bg-soft-warning dark:text-soft-warning-foreground',\n destructive:\n 'bg-soft-destructive text-soft-destructive-foreground hover:bg-opacity-destructive-20 dark:bg-soft-destructive dark:text-soft-destructive-foreground',\n};\n\ntype LoadingSuccessState = {\n wasLoading: boolean;\n visible: boolean;\n token: number;\n};\n\nconst Dot = ({\n color = 'success',\n className,\n}: {\n color?: DotColor;\n className?: string;\n}) => (\n <span\n aria-hidden=\"true\"\n className={cn(\n 'size-2 rounded-full shrink-0 delight-breathing',\n dotColorClasses[color],\n className,\n )}\n />\n);\n\nfunction ButtonBadge({\n appearance,\n badge,\n shape,\n variant,\n}: {\n appearance: ButtonAppearance;\n badge: React.ReactNode;\n shape: ButtonShape;\n variant: ButtonVariant;\n}) {\n if (React.isValidElement(badge)) {\n return badge;\n }\n\n if (badge === true || badge === false || badge == null) {\n return null;\n }\n\n const badgeVariant =\n (appearance === 'solid' || appearance === 'gradient') &&\n variant !== 'secondary'\n ? 'white'\n : 'soft';\n\n return (\n <span\n data-slot=\"badge\"\n className={cn(\n 'inline-flex h-5 shrink-0 items-center justify-center gap-1.5 whitespace-nowrap px-2 py-0.5 text-xs font-medium transition-colors [&>svg]:size-3 [&>svg]:shrink-0 [&>svg]:pointer-events-none',\n buttonBadgeShapeClasses[shape],\n badgeVariant === 'white'\n ? 'bg-opacity-white-80 transition-opacity hover:opacity-80 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-current/50'\n : buttonBadgeSoftColorClasses[variant],\n badgeVariant === 'white' && buttonBadgeWhiteColorClasses[variant],\n )}\n >\n {badge}\n </span>\n );\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n children,\n loading = false,\n disabled,\n startIcon,\n endIcon,\n dotIndicator = false,\n dotColor = 'success',\n badge,\n iconOnly = false,\n animated,\n render,\n className,\n appearance = 'solid',\n variant = 'primary',\n shape = 'rounded',\n size = 'default',\n ...props\n },\n ref,\n ) => {\n // Dev-mode warning for icon-only buttons missing accessible label (once)\n if (\n process.env.NODE_ENV !== 'production' &&\n !devWarnings.has('icon-a11y')\n ) {\n const hasIconSize = ICON_SIZES.includes(\n size as (typeof ICON_SIZES)[number],\n );\n if (\n (iconOnly || hasIconSize) &&\n !props['aria-label'] &&\n !props['aria-labelledby']\n ) {\n devWarnings.add('icon-a11y');\n console.warn(\n 'Button: Icon-only buttons require an `aria-label` or `aria-labelledby` for accessibility.',\n );\n }\n }\n\n // Track loading→done transition before paint so the button never commits a\n // stale success state after the loading prop changes.\n const [successState, setSuccessState] = React.useState<LoadingSuccessState>(\n () => ({\n wasLoading: loading,\n visible: false,\n token: 0,\n }),\n );\n\n if (successState.wasLoading !== loading) {\n const shouldFlash = successState.wasLoading && !loading;\n setSuccessState({\n wasLoading: loading,\n visible: shouldFlash,\n token: shouldFlash ? successState.token + 1 : successState.token,\n });\n }\n\n React.useEffect(() => {\n if (!successState.visible) return;\n const token = successState.token;\n const timer = setTimeout(() => {\n setSuccessState((current) =>\n current.token === token ? { ...current, visible: false } : current,\n );\n }, SUCCESS_FLASH_DURATION_MS);\n return () => clearTimeout(timer);\n }, [successState.visible, successState.token]);\n\n const showSuccess = successState.visible && !loading;\n\n const isAi = appearance === 'ai';\n const isAnimated = isAi ? (animated ?? loading) : false;\n\n const buttonClassName = cn(\n buttonVariants({ appearance, variant, shape, size }),\n className,\n );\n\n // When render prop is provided, pass through to primitive\n // (ignores loading/startIcon/endIcon/dotIndicator/badge)\n if (render) {\n return (\n <ButtonPrimitive\n ref={ref}\n data-slot=\"button\"\n className={buttonClassName}\n render={render}\n {...props}\n >\n {children}\n </ButtonPrimitive>\n );\n }\n\n // Determine if this is an icon-only button based on size or explicit prop\n const isIconOnly =\n iconOnly || ICON_SIZES.includes(size as (typeof ICON_SIZES)[number]);\n const shouldComposeBadgeLabel =\n !isIconOnly &&\n !props['aria-label'] &&\n !props['aria-labelledby'] &&\n (typeof children === 'string' || typeof children === 'number') &&\n (typeof badge === 'string' || typeof badge === 'number');\n const buttonProps = shouldComposeBadgeLabel\n ? { ...props, 'aria-label': `${children} ${badge}` }\n : props;\n const buttonBadge = !isIconOnly ? (\n <ButtonBadge\n appearance={appearance}\n badge={badge}\n shape={shape}\n variant={variant}\n />\n ) : null;\n\n // Build the button element (icon-only or full)\n const buttonElement = isIconOnly ? (\n <ButtonPrimitive\n ref={isAi ? undefined : ref}\n data-slot=\"button\"\n disabled={disabled || loading}\n className={cn(buttonClassName, loading && 'relative')}\n {...buttonProps}\n >\n {loading ? (\n <Spinner className=\"delight-fade-in\" />\n ) : showSuccess ? (\n <Check className=\"delight-bounce-in\" />\n ) : (\n children\n )}\n </ButtonPrimitive>\n ) : (\n <ButtonPrimitive\n ref={isAi ? undefined : ref}\n data-slot=\"button\"\n disabled={disabled || loading}\n className={cn(buttonClassName, (loading || showSuccess) && 'relative')}\n {...buttonProps}\n >\n {loading && <Spinner className=\"absolute delight-fade-in\" />}\n {showSuccess && !loading && (\n <Check className=\"absolute delight-bounce-in\" />\n )}\n <span\n className={cn(\n 'flex items-center gap-2',\n (loading || showSuccess) && 'invisible',\n )}\n >\n {dotIndicator && <Dot color={dotColor} />}\n {startIcon}\n {children}\n {endIcon}\n {buttonBadge}\n </span>\n </ButtonPrimitive>\n );\n\n if (isAi) {\n return (\n <GradientBorder\n ref={ref as React.Ref<HTMLDivElement>}\n animated={isAnimated}\n active\n disabled={disabled}\n className=\"w-auto inline-flex motion-reduce:animate-none\"\n innerClassName=\"flex\"\n >\n {buttonElement}\n </GradientBorder>\n );\n }\n\n return buttonElement;\n },\n);\n\nButton.displayName = 'Button';\n\n/**\n * Clear/Close icon button - a ghost button specifically for close/clear actions\n * Commonly used in tags, dialogs, and dismissible elements\n */\nexport interface ClearButtonProps\n extends Omit<\n ButtonProps,\n | 'appearance'\n | 'variant'\n | 'children'\n | 'startIcon'\n | 'endIcon'\n | 'dotIndicator'\n > {\n /** Size of the clear button */\n size?: 'icon-xs' | 'icon-sm' | 'icon' | 'icon-lg' | 'icon-xl' | 'icon-2xl';\n}\n\nfunction ClearButton({\n className,\n size = 'icon-sm',\n ...props\n}: ClearButtonProps) {\n return (\n <Button\n appearance=\"ghost\"\n variant=\"secondary\"\n size={size}\n iconOnly\n className={cn(\n 'text-muted-foreground hover:text-secondary-foreground',\n className,\n )}\n aria-label=\"Clear\"\n {...props}\n >\n <X />\n </Button>\n );\n}\n\nClearButton.displayName = 'ClearButton';\n\nexport type { ButtonAppearance, ButtonShape, ButtonVariant };\nexport { Button, buttonVariants, ClearButton, Dot };\n"],"mappings":"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"}
|