@humain/ui 2.2.3 → 2.2.5
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/components/templates/AppShell/AppShell.d.ts +1 -1
- package/dist/components/templates/AppSidebar/AppSidebar.constants.d.ts +1 -1
- package/dist/index11.js +4 -4
- package/dist/index11.js.map +1 -1
- package/dist/index110.js +4 -4
- package/dist/index110.js.map +1 -1
- package/dist/index134.js +4 -4
- package/dist/index134.js.map +1 -1
- package/dist/index135.js +2 -2
- package/dist/index135.js.map +1 -1
- package/dist/index151.js +3 -3
- package/dist/index151.js.map +1 -1
- package/dist/index152.js +2 -2
- package/dist/index152.js.map +1 -1
- package/dist/index155.js +1 -1
- package/dist/index155.js.map +1 -1
- package/dist/index173.js +1 -1
- package/dist/index173.js.map +1 -1
- package/dist/index184.js +1 -1
- package/dist/index184.js.map +1 -1
- package/dist/index188.js +4 -4
- package/dist/index188.js.map +1 -1
- package/dist/index201.js +1 -1
- package/dist/index201.js.map +1 -1
- package/dist/index217.js +1 -1
- package/dist/index217.js.map +1 -1
- package/dist/index223.js.map +1 -1
- package/dist/index225.js +3 -3
- package/dist/index225.js.map +1 -1
- package/dist/index228.js +1 -1
- package/dist/index228.js.map +1 -1
- package/dist/index24.js +1 -1
- package/dist/index24.js.map +1 -1
- package/dist/index25.js +4 -4
- package/dist/index25.js.map +1 -1
- package/dist/index39.js +2 -2
- package/dist/index39.js.map +1 -1
- package/dist/index5.js +8 -8
- package/dist/index5.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/wc/AIScrollButton.js +8 -8
- package/dist/wc/AIScrollButton.js.map +1 -1
- package/dist/wc/AISource.js +46 -46
- package/dist/wc/AISource.js.map +1 -1
- package/dist/wc/AIToolCall.js +9 -9
- package/dist/wc/AIToolCall.js.map +1 -1
- package/dist/wc/AppSidebar.constants.js +1 -1
- package/dist/wc/AppSidebar.constants.js.map +1 -1
- package/dist/wc/Badge.js +9 -9
- package/dist/wc/Badge.js.map +1 -1
- package/dist/wc/Checkbox.js +22 -22
- package/dist/wc/Checkbox.js.map +1 -1
- package/dist/wc/Pagination.js +4 -4
- package/dist/wc/Pagination.js.map +1 -1
- package/dist/wc/Switch.js +23 -23
- package/dist/wc/Switch.js.map +1 -1
- package/dist/wc/Tabs.js +110 -110
- package/dist/wc/Tabs.js.map +1 -1
- package/dist/wc/Tooltip.js +28 -28
- package/dist/wc/Tooltip.js.map +1 -1
- package/dist/wc/button.js +33 -33
- package/dist/wc/button.js.map +1 -1
- package/dist/wc/hf-alert.js +10 -10
- package/dist/wc/hf-alert.js.map +1 -1
- package/dist/wc/hf-app-shell.js.map +1 -1
- package/dist/wc/hf-app-sidebar.js +3 -3
- package/dist/wc/hf-app-sidebar.js.map +1 -1
- package/dist/wc/hf-nav-account-menu.js +8 -8
- package/dist/wc/hf-nav-account-menu.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 +5 -5
- package/dist/wc/markdown-renderer.js.map +1 -1
- package/dist/wc/selection-group.js +6 -6
- package/dist/wc/selection-group.js.map +1 -1
- package/dist/wc-react/AIScrollButton.js +18 -18
- package/dist/wc-react/AIScrollButton.js.map +1 -1
- package/dist/wc-react/AISource.js +8 -8
- package/dist/wc-react/AISource.js.map +1 -1
- package/dist/wc-react/AIToolCall.js +42 -42
- package/dist/wc-react/AIToolCall.js.map +1 -1
- package/dist/wc-react/AppSidebar.constants.js +1 -1
- package/dist/wc-react/AppSidebar.constants.js.map +1 -1
- package/dist/wc-react/Badge.js +16 -16
- package/dist/wc-react/Badge.js.map +1 -1
- package/dist/wc-react/Checkbox.js +14 -14
- package/dist/wc-react/Checkbox.js.map +1 -1
- package/dist/wc-react/Pagination.js +130 -130
- package/dist/wc-react/Pagination.js.map +1 -1
- package/dist/wc-react/Switch.js +2 -2
- package/dist/wc-react/Switch.js.map +1 -1
- package/dist/wc-react/Tabs.js +38 -38
- package/dist/wc-react/Tabs.js.map +1 -1
- package/dist/wc-react/Tooltip.js +22 -22
- package/dist/wc-react/Tooltip.js.map +1 -1
- package/dist/wc-react/button.js +8 -8
- package/dist/wc-react/button.js.map +1 -1
- package/dist/wc-react/hf-alert.js +28 -28
- package/dist/wc-react/hf-alert.js.map +1 -1
- package/dist/wc-react/hf-app-shell.js.map +1 -1
- package/dist/wc-react/hf-app-sidebar.js +3 -3
- package/dist/wc-react/hf-app-sidebar.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-steps.js +16 -16
- package/dist/wc-react/hf-steps.js.map +1 -1
- package/dist/wc-react/markdown-renderer.js +5 -5
- package/dist/wc-react/markdown-renderer.js.map +1 -1
- package/dist/wc-react/selection-group.js +1 -1
- package/dist/wc-react/selection-group.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 +10 -2
package/dist/index25.js
CHANGED
|
@@ -48,22 +48,22 @@ var checkboxVariants = cva("relative flex shrink-0 items-center justify-center b
|
|
|
48
48
|
{
|
|
49
49
|
variant: "info",
|
|
50
50
|
checked: true,
|
|
51
|
-
className: "border-info bg-info text-
|
|
51
|
+
className: "border-info bg-info text-info-foreground hover:bg-info/90"
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
variant: "success",
|
|
55
55
|
checked: true,
|
|
56
|
-
className: "border-success bg-success text-
|
|
56
|
+
className: "border-success bg-success text-success-foreground hover:bg-success/90"
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
59
|
variant: "warning",
|
|
60
60
|
checked: true,
|
|
61
|
-
className: "border-warning bg-warning text-
|
|
61
|
+
className: "border-warning bg-warning text-warning-foreground hover:bg-warning/90"
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
64
|
variant: "destructive",
|
|
65
65
|
checked: true,
|
|
66
|
-
className: "border-destructive bg-destructive text-
|
|
66
|
+
className: "border-destructive bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
|
67
67
|
}
|
|
68
68
|
],
|
|
69
69
|
defaultVariants: {
|
package/dist/index25.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index25.js","names":[],"sources":["../src/components/atoms/forms/Checkbox/Checkbox.tsx"],"sourcesContent":["'use client';\n\nimport { Checkbox as CheckboxPrimitive } from '@base-ui/react/checkbox';\nimport { cva } from 'class-variance-authority';\nimport { Minus } from 'lucide-react';\nimport * as React from 'react';\nimport {\n type FieldProps,\n FieldTooltip,\n hasFieldProps,\n splitFieldProps,\n} from '@/components/atoms/forms/_shared';\nimport {\n Field,\n FieldBottom,\n FieldDescription,\n FieldError,\n FieldLabel,\n useFieldContextOptional,\n} from '@/components/ui/form-field';\nimport { DrawCheck } from '@/components/ui/selection-group';\nimport { cn } from '@/lib/utils';\n\n// ============================================\n// CVA Variants\n// ============================================\n\nconst checkboxVariants = cva(\n // Base styles\n 'relative flex shrink-0 items-center justify-center border shadow-xs transition-[border-color,background-color,color,box-shadow] duration-200 ease-out motion-reduce:transition-none focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',\n {\n variants: {\n variant: {\n primary: '',\n secondary: '',\n info: '',\n success: '',\n warning: '',\n destructive: '',\n },\n size: {\n sm: 'size-4 rounded-[4px]',\n md: 'size-5 rounded-[5px]',\n lg: 'size-6 rounded-[6px]',\n },\n checked: {\n true: '',\n false: '',\n },\n },\n compoundVariants: [\n // ===== UNCHECKED (all variants) =====\n {\n checked: false,\n className:\n 'bg-background border-border hover:border-primary hover:bg-primary/10',\n },\n // ===== PRIMARY CHECKED =====\n {\n variant: 'primary',\n checked: true,\n className:\n 'border-primary bg-primary text-primary-foreground hover:bg-primary/90',\n },\n // ===== SECONDARY CHECKED (outline style) =====\n {\n variant: 'secondary',\n checked: true,\n className: 'border-border bg-background text-foreground hover:bg-muted',\n },\n // ===== INFO CHECKED =====\n {\n variant: 'info',\n checked: true,\n className:\n 'border-info bg-info text-primary-foreground hover:bg-info/90',\n },\n // ===== SUCCESS CHECKED =====\n {\n variant: 'success',\n checked: true,\n className:\n 'border-success bg-success text-primary-foreground hover:bg-success/90',\n },\n // ===== WARNING CHECKED =====\n {\n variant: 'warning',\n checked: true,\n className:\n 'border-warning bg-warning text-primary-foreground hover:bg-warning/90',\n },\n // ===== DESTRUCTIVE CHECKED =====\n {\n variant: 'destructive',\n checked: true,\n className:\n 'border-destructive bg-destructive text-primary-foreground hover:bg-destructive/90',\n },\n ],\n defaultVariants: {\n variant: 'primary',\n size: 'sm',\n checked: false,\n },\n },\n);\n\n// ============================================\n// Types\n// ============================================\n\ntype CheckboxVariant =\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'destructive';\ntype CheckboxSize = 'sm' | 'md' | 'lg';\n\n/**\n * Checkbox is a pure atom component that renders ONLY the checkbox element.\n * It does NOT render label, description, or error.\n *\n * Supports 6 color variants and 3 sizes matching Figma design.\n * When used inside a Field with an error, automatically uses destructive variant.\n *\n * @example\n * ```tsx\n * // Simple checkbox\n * <Checkbox />\n *\n * // With variant and size\n * <Checkbox variant=\"success\" size=\"lg\" />\n *\n * // Auto-destructive when Field has error\n * <Field error=\"Required\">\n * <Checkbox /> // automatically uses destructive variant\n * </Field>\n * ```\n */\ntype CheckboxControlProps = Omit<\n CheckboxPrimitive.Root.Props,\n 'onCheckedChange'\n> & {\n /** Color variant for the checkbox */\n variant?: CheckboxVariant;\n /** Size variant for the checkbox */\n size?: CheckboxSize;\n /** Controlled checked state. When provided, component is controlled. */\n checked?: boolean;\n /** Initial checked state for uncontrolled mode */\n defaultChecked?: boolean;\n /** Callback when checked state changes */\n onCheckedChange?: (checked: boolean) => void;\n};\n\nexport interface CheckboxProps\n extends CheckboxControlProps,\n Omit<FieldProps, 'topRight' | 'bottomRight'> {}\n\nexport type { CheckboxSize, CheckboxVariant };\n\n// ============================================\n// Size configuration\n// ============================================\n\nconst iconClasses = {\n sm: 'size-3',\n md: 'size-3.5',\n lg: 'size-4',\n};\n\n// ============================================\n// Checkbox (pure atom)\n// ============================================\n\nconst CheckboxControl = React.forwardRef<\n HTMLButtonElement,\n CheckboxControlProps\n>(\n (\n {\n className,\n variant: variantProp,\n size = 'sm',\n checked: controlledChecked,\n defaultChecked = false,\n onCheckedChange,\n ...props\n },\n ref,\n ) => {\n // Internal state for uncontrolled mode\n const [internalChecked, setInternalChecked] =\n React.useState(defaultChecked);\n\n // Use controlled value if provided, otherwise use internal state\n const isControlled = controlledChecked !== undefined;\n const checked = isControlled ? controlledChecked : internalChecked;\n\n // Field context integration - auto-destructive on error\n const fieldContext = useFieldContextOptional();\n const hasFieldError = fieldContext?.state === 'destructive';\n const variant = variantProp ?? (hasFieldError ? 'destructive' : 'primary');\n\n const handleCheckedChange = React.useCallback(\n (newChecked: boolean) => {\n if (!isControlled) {\n setInternalChecked(newChecked);\n }\n onCheckedChange?.(newChecked);\n },\n [isControlled, onCheckedChange],\n );\n\n return (\n <CheckboxPrimitive.Root\n ref={ref}\n data-slot=\"checkbox\"\n data-size={size}\n data-variant={variant}\n checked={checked}\n onCheckedChange={handleCheckedChange}\n className={cn(\n checkboxVariants({ variant, size, checked }),\n // Touch target expansion (ensures ≥24px hit area)\n 'before:content-[\"\"] before:absolute before:-inset-[4px] before:rounded-[inherit]',\n // Focus state - double ring effect\n 'focus-visible:ring-4 focus-visible:ring-bg-secondary focus-visible:shadow-[0_0_0_2px_var(--card),0_0_0_4px_var(--border)]',\n 'dark:focus-visible:ring-bg-tertiary dark:focus-visible:shadow-[0_0_0_2px_var(--card),0_0_0_4px_var(--border)]',\n checked && 'delight-check-bounce',\n className,\n )}\n {...props}\n >\n <CheckboxPrimitive.Indicator\n data-slot=\"checkbox-indicator\"\n className=\"flex items-center justify-center text-current\"\n >\n {props.indeterminate ? (\n <Minus\n className={cn(\n iconClasses[size],\n 'animate-[scale-in_150ms_ease-out] motion-reduce:animate-none',\n )}\n strokeWidth={3}\n />\n ) : (\n <DrawCheck className={iconClasses[size]} />\n )}\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n );\n },\n);\n\nCheckboxControl.displayName = 'CheckboxControl';\n\n// =============================================================================\n// Checkbox — public API with smart field mode (inline layout)\n// =============================================================================\n\nconst Checkbox = React.forwardRef<HTMLButtonElement, CheckboxProps>(\n (props, forwardedRef) => {\n const [fieldPropsObj, controlProps] = splitFieldProps(props);\n const { ref: _ref, ...cp } = controlProps as CheckboxControlProps & {\n ref?: unknown;\n };\n\n if (!hasFieldProps(fieldPropsObj)) {\n return (\n <CheckboxControl\n ref={forwardedRef}\n {...cp}\n required={fieldPropsObj.required}\n />\n );\n }\n\n const {\n label,\n required,\n labelIcon,\n tooltip,\n description,\n error,\n fieldClassName,\n } = fieldPropsObj;\n\n return (\n <Field\n layout=\"inline\"\n state={error ? 'destructive' : undefined}\n disabled={cp.disabled}\n className={fieldClassName}\n >\n <CheckboxControl ref={forwardedRef} {...cp} required={required} />\n {label && (\n <FieldLabel required={required} labelIcon={labelIcon}>\n {label}\n {tooltip && <FieldTooltip content={tooltip} />}\n </FieldLabel>\n )}\n {(error || description) && (\n <FieldBottom>\n {error && <FieldError>{error}</FieldError>}\n {!error && description && (\n <FieldDescription>{description}</FieldDescription>\n )}\n </FieldBottom>\n )}\n </Field>\n );\n },\n);\nCheckbox.displayName = 'Checkbox';\n\nexport { Checkbox };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index25.js","names":[],"sources":["../src/components/atoms/forms/Checkbox/Checkbox.tsx"],"sourcesContent":["'use client';\n\nimport { Checkbox as CheckboxPrimitive } from '@base-ui/react/checkbox';\nimport { cva } from 'class-variance-authority';\nimport { Minus } from 'lucide-react';\nimport * as React from 'react';\nimport {\n type FieldProps,\n FieldTooltip,\n hasFieldProps,\n splitFieldProps,\n} from '@/components/atoms/forms/_shared';\nimport {\n Field,\n FieldBottom,\n FieldDescription,\n FieldError,\n FieldLabel,\n useFieldContextOptional,\n} from '@/components/ui/form-field';\nimport { DrawCheck } from '@/components/ui/selection-group';\nimport { cn } from '@/lib/utils';\n\n// ============================================\n// CVA Variants\n// ============================================\n\nconst checkboxVariants = cva(\n // Base styles\n 'relative flex shrink-0 items-center justify-center border shadow-xs transition-[border-color,background-color,color,box-shadow] duration-200 ease-out motion-reduce:transition-none focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50',\n {\n variants: {\n variant: {\n primary: '',\n secondary: '',\n info: '',\n success: '',\n warning: '',\n destructive: '',\n },\n size: {\n sm: 'size-4 rounded-[4px]',\n md: 'size-5 rounded-[5px]',\n lg: 'size-6 rounded-[6px]',\n },\n checked: {\n true: '',\n false: '',\n },\n },\n compoundVariants: [\n // ===== UNCHECKED (all variants) =====\n {\n checked: false,\n className:\n 'bg-background border-border hover:border-primary hover:bg-primary/10',\n },\n // ===== PRIMARY CHECKED =====\n {\n variant: 'primary',\n checked: true,\n className:\n 'border-primary bg-primary text-primary-foreground hover:bg-primary/90',\n },\n // ===== SECONDARY CHECKED (outline style) =====\n {\n variant: 'secondary',\n checked: true,\n className: 'border-border bg-background text-foreground hover:bg-muted',\n },\n // ===== INFO CHECKED =====\n {\n variant: 'info',\n checked: true,\n className: 'border-info bg-info text-info-foreground hover:bg-info/90',\n },\n // ===== SUCCESS CHECKED =====\n {\n variant: 'success',\n checked: true,\n className:\n 'border-success bg-success text-success-foreground hover:bg-success/90',\n },\n // ===== WARNING CHECKED =====\n {\n variant: 'warning',\n checked: true,\n className:\n 'border-warning bg-warning text-warning-foreground hover:bg-warning/90',\n },\n // ===== DESTRUCTIVE CHECKED =====\n {\n variant: 'destructive',\n checked: true,\n className:\n 'border-destructive bg-destructive text-destructive-foreground hover:bg-destructive/90',\n },\n ],\n defaultVariants: {\n variant: 'primary',\n size: 'sm',\n checked: false,\n },\n },\n);\n\n// ============================================\n// Types\n// ============================================\n\ntype CheckboxVariant =\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'destructive';\ntype CheckboxSize = 'sm' | 'md' | 'lg';\n\n/**\n * Checkbox is a pure atom component that renders ONLY the checkbox element.\n * It does NOT render label, description, or error.\n *\n * Supports 6 color variants and 3 sizes matching Figma design.\n * When used inside a Field with an error, automatically uses destructive variant.\n *\n * @example\n * ```tsx\n * // Simple checkbox\n * <Checkbox />\n *\n * // With variant and size\n * <Checkbox variant=\"success\" size=\"lg\" />\n *\n * // Auto-destructive when Field has error\n * <Field error=\"Required\">\n * <Checkbox /> // automatically uses destructive variant\n * </Field>\n * ```\n */\ntype CheckboxControlProps = Omit<\n CheckboxPrimitive.Root.Props,\n 'onCheckedChange'\n> & {\n /** Color variant for the checkbox */\n variant?: CheckboxVariant;\n /** Size variant for the checkbox */\n size?: CheckboxSize;\n /** Controlled checked state. When provided, component is controlled. */\n checked?: boolean;\n /** Initial checked state for uncontrolled mode */\n defaultChecked?: boolean;\n /** Callback when checked state changes */\n onCheckedChange?: (checked: boolean) => void;\n};\n\nexport interface CheckboxProps\n extends CheckboxControlProps,\n Omit<FieldProps, 'topRight' | 'bottomRight'> {}\n\nexport type { CheckboxSize, CheckboxVariant };\n\n// ============================================\n// Size configuration\n// ============================================\n\nconst iconClasses = {\n sm: 'size-3',\n md: 'size-3.5',\n lg: 'size-4',\n};\n\n// ============================================\n// Checkbox (pure atom)\n// ============================================\n\nconst CheckboxControl = React.forwardRef<\n HTMLButtonElement,\n CheckboxControlProps\n>(\n (\n {\n className,\n variant: variantProp,\n size = 'sm',\n checked: controlledChecked,\n defaultChecked = false,\n onCheckedChange,\n ...props\n },\n ref,\n ) => {\n // Internal state for uncontrolled mode\n const [internalChecked, setInternalChecked] =\n React.useState(defaultChecked);\n\n // Use controlled value if provided, otherwise use internal state\n const isControlled = controlledChecked !== undefined;\n const checked = isControlled ? controlledChecked : internalChecked;\n\n // Field context integration - auto-destructive on error\n const fieldContext = useFieldContextOptional();\n const hasFieldError = fieldContext?.state === 'destructive';\n const variant = variantProp ?? (hasFieldError ? 'destructive' : 'primary');\n\n const handleCheckedChange = React.useCallback(\n (newChecked: boolean) => {\n if (!isControlled) {\n setInternalChecked(newChecked);\n }\n onCheckedChange?.(newChecked);\n },\n [isControlled, onCheckedChange],\n );\n\n return (\n <CheckboxPrimitive.Root\n ref={ref}\n data-slot=\"checkbox\"\n data-size={size}\n data-variant={variant}\n checked={checked}\n onCheckedChange={handleCheckedChange}\n className={cn(\n checkboxVariants({ variant, size, checked }),\n // Touch target expansion (ensures ≥24px hit area)\n 'before:content-[\"\"] before:absolute before:-inset-[4px] before:rounded-[inherit]',\n // Focus state - double ring effect\n 'focus-visible:ring-4 focus-visible:ring-bg-secondary focus-visible:shadow-[0_0_0_2px_var(--card),0_0_0_4px_var(--border)]',\n 'dark:focus-visible:ring-bg-tertiary dark:focus-visible:shadow-[0_0_0_2px_var(--card),0_0_0_4px_var(--border)]',\n checked && 'delight-check-bounce',\n className,\n )}\n {...props}\n >\n <CheckboxPrimitive.Indicator\n data-slot=\"checkbox-indicator\"\n className=\"flex items-center justify-center text-current\"\n >\n {props.indeterminate ? (\n <Minus\n className={cn(\n iconClasses[size],\n 'animate-[scale-in_150ms_ease-out] motion-reduce:animate-none',\n )}\n strokeWidth={3}\n />\n ) : (\n <DrawCheck className={iconClasses[size]} />\n )}\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n );\n },\n);\n\nCheckboxControl.displayName = 'CheckboxControl';\n\n// =============================================================================\n// Checkbox — public API with smart field mode (inline layout)\n// =============================================================================\n\nconst Checkbox = React.forwardRef<HTMLButtonElement, CheckboxProps>(\n (props, forwardedRef) => {\n const [fieldPropsObj, controlProps] = splitFieldProps(props);\n const { ref: _ref, ...cp } = controlProps as CheckboxControlProps & {\n ref?: unknown;\n };\n\n if (!hasFieldProps(fieldPropsObj)) {\n return (\n <CheckboxControl\n ref={forwardedRef}\n {...cp}\n required={fieldPropsObj.required}\n />\n );\n }\n\n const {\n label,\n required,\n labelIcon,\n tooltip,\n description,\n error,\n fieldClassName,\n } = fieldPropsObj;\n\n return (\n <Field\n layout=\"inline\"\n state={error ? 'destructive' : undefined}\n disabled={cp.disabled}\n className={fieldClassName}\n >\n <CheckboxControl ref={forwardedRef} {...cp} required={required} />\n {label && (\n <FieldLabel required={required} labelIcon={labelIcon}>\n {label}\n {tooltip && <FieldTooltip content={tooltip} />}\n </FieldLabel>\n )}\n {(error || description) && (\n <FieldBottom>\n {error && <FieldError>{error}</FieldError>}\n {!error && description && (\n <FieldDescription>{description}</FieldDescription>\n )}\n </FieldBottom>\n )}\n </Field>\n );\n },\n);\nCheckbox.displayName = 'Checkbox';\n\nexport { Checkbox };\n"],"mappings":"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"}
|
package/dist/index39.js
CHANGED
|
@@ -244,7 +244,7 @@ function ThemeSwitchToggle({ isLight, onThemeChange, sizes }) {
|
|
|
244
244
|
"aria-label": `Switch to ${isLight ? "dark" : "light"} theme`,
|
|
245
245
|
onClick: () => onThemeChange(isLight ? "dark" : "light"),
|
|
246
246
|
className: cn("relative rounded-full transition-[colors,box-shadow] hover:shadow-[0_0_0_3px_var(--ring)/0.1] active:scale-[0.97]", sizes.track, themeTransitionClasses, themeFocusRingClasses, isLight ? "bg-input" : "bg-primary"),
|
|
247
|
-
children: /* @__PURE__ */ jsx("div", { className: cn("absolute top-1/2 -translate-y-1/2 rounded-full shadow-md group-active:shadow-sm transition-all", sizes.indicator, themeTransitionClasses, isLight ? "bg-card" : "bg-
|
|
247
|
+
children: /* @__PURE__ */ jsx("div", { className: cn("absolute top-1/2 -translate-y-1/2 rounded-full shadow-md group-active:shadow-sm transition-all", sizes.indicator, themeTransitionClasses, isLight ? "bg-card" : "bg-background", isLight ? "left-0.5" : "right-0.5") })
|
|
248
248
|
}), /* @__PURE__ */ jsx("div", {
|
|
249
249
|
className: cn(sizes.icon, "text-[var(--muted-foreground)]"),
|
|
250
250
|
children: isLight ? /* @__PURE__ */ jsx(Moon, { className: "size-full" }) : /* @__PURE__ */ jsx(Sun, { className: "size-full" })
|
|
@@ -428,7 +428,7 @@ var SwitchControl = React$1.forwardRef(({ label, description, labelPosition = "r
|
|
|
428
428
|
const activeSizeClasses = hasLabels ? sizeWithLabelClasses : sizeClasses;
|
|
429
429
|
const activeThumbTranslate = hasLabels ? thumbTranslateWithLabelClasses : thumbTranslateClasses;
|
|
430
430
|
const trackClasses = switchStyle === "solid" ? cn("data-unchecked:bg-input dark:data-unchecked:bg-input/80 border-transparent", solidVariantClasses[colorVariant]) : cn("data-unchecked:bg-transparent data-checked:bg-transparent border-input", outlineVariantClasses[colorVariant]);
|
|
431
|
-
const thumbClasses = switchStyle === "solid" ? "bg-background dark:data-unchecked:bg-foreground dark:data-checked:bg-
|
|
431
|
+
const thumbClasses = switchStyle === "solid" ? "bg-background dark:data-unchecked:bg-foreground dark:data-checked:bg-background" : cn("bg-input dark:bg-foreground", outlineThumbVariantClasses[colorVariant]);
|
|
432
432
|
const showThumbIcon = withIcon || thumbIconOn || thumbIconOff;
|
|
433
433
|
const checkedIcon = showThumbIcon ? thumbIconOn || /* @__PURE__ */ jsx(Check, { className: iconSizeClasses[size] }) : null;
|
|
434
434
|
const uncheckedIcon = showThumbIcon ? thumbIconOff || /* @__PURE__ */ jsx(X, { className: iconSizeClasses[size] }) : null;
|
package/dist/index39.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index39.js","names":[],"sources":["../src/components/atoms/forms/Switch/Switch.tsx"],"sourcesContent":["/** biome-ignore-all lint/a11y/useSemanticElements: Theme toggles use button-based radio controls for animated segmented UI while preserving radiogroup semantics. */\n'use client';\n\nimport { Switch as SwitchPrimitive } from '@base-ui/react/switch';\nimport { Check, Moon, Sun, X } from 'lucide-react';\nimport * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport {\n type FieldProps,\n FieldTooltip,\n} from '@/components/atoms/forms/_shared';\nimport { useThemeOptional } from '@/components/ThemeProvider';\nimport {\n Field,\n FieldBottom,\n FieldDescription,\n FieldError,\n FieldLabel,\n} from '@/components/ui/form-field';\nimport { cn } from '@/lib/utils';\n\n// ============================================\n// Types\n// ============================================\n\n/** Color variants for the standard switch */\ntype ColorVariant =\n | 'primary'\n | 'secondary'\n | 'warning'\n | 'info'\n | 'success'\n | 'destructive';\n\n/** Theme variants that render theme toggle UIs */\ntype ThemeVariant =\n | 'theme-gradient'\n | 'theme-switch'\n | 'theme-pill'\n | 'theme-segmented';\n\n/** All switch variants */\nexport type SwitchVariant = ColorVariant | ThemeVariant;\n\n// ============================================\n// Switch (with controlled/uncontrolled support)\n// ============================================\n\ninterface SwitchControlProps\n extends Omit<SwitchPrimitive.Root.Props, 'onCheckedChange'> {\n // Variants\n size?: 'sm' | 'md' | 'lg';\n variant?: SwitchVariant;\n /** Visual style of the switch (solid = filled track, outline = bordered track). Only applies to color variants. */\n switchStyle?: 'solid' | 'outline';\n\n // Thumb icons (color variants only)\n withIcon?: boolean;\n thumbIconOn?: React.ReactNode;\n thumbIconOff?: React.ReactNode;\n\n // Track labels (ON/OFF inside track, color variants only)\n showOnOff?: boolean;\n onLabel?: string;\n offLabel?: string;\n\n // External label\n label?: React.ReactNode;\n description?: string;\n labelPosition?: 'left' | 'right';\n\n /** Layout orientation for label (theme variants only) */\n orientation?: 'horizontal' | 'vertical';\n\n // Core (keep existing)\n checked?: boolean;\n defaultChecked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n}\n\nexport interface SwitchProps\n extends Omit<SwitchControlProps, 'label' | 'description'>,\n Omit<FieldProps, 'label' | 'description' | 'topRight' | 'bottomRight'> {\n /** Label text or ReactNode (inline with switch, or in FieldLabel when field props are set) */\n label?: React.ReactNode;\n /** Description text (inline below label, or in FieldDescription when field props are set) */\n description?: React.ReactNode;\n}\n\n// ============================================\n// Color Switch Constants\n// ============================================\n\n// Icon size classes for thumb icons\nconst iconSizeClasses = {\n sm: 'size-2', // 8px\n md: 'size-2.5', // 10px\n lg: 'size-3', // 12px\n};\n\n// Size classes for the track\nconst sizeClasses = {\n sm: 'h-[18px] w-[32px]',\n md: 'h-[22px] w-[40px]',\n lg: 'h-[26px] w-[48px]',\n};\n\n// Size classes for the thumb\nconst thumbSizeClasses = {\n sm: 'size-[14px]',\n md: 'size-[18px]',\n lg: 'size-[22px]',\n};\n\n// Thumb translation when checked (track width - thumb size - 2px padding on each side)\nconst thumbTranslateClasses = {\n sm: 'data-checked:ltr:translate-x-[14px] data-checked:rtl:-translate-x-[14px]',\n md: 'data-checked:ltr:translate-x-[18px] data-checked:rtl:-translate-x-[18px]',\n lg: 'data-checked:ltr:translate-x-[22px] data-checked:rtl:-translate-x-[22px]',\n};\n\n// Wider track sizes when ON/OFF labels are shown (extra space for text)\nconst sizeWithLabelClasses = {\n sm: 'h-[18px] w-[40px]',\n md: 'h-[22px] w-[48px]',\n lg: 'h-[26px] w-[56px]',\n};\n\n// Thumb translation for wider tracks with labels\nconst thumbTranslateWithLabelClasses = {\n sm: 'data-checked:ltr:translate-x-[22px] data-checked:rtl:-translate-x-[22px]',\n md: 'data-checked:ltr:translate-x-[26px] data-checked:rtl:-translate-x-[26px]',\n lg: 'data-checked:ltr:translate-x-[30px] data-checked:rtl:-translate-x-[30px]',\n};\n\n// Font sizes for track labels (ON/OFF)\nconst labelFontSizes = {\n sm: 'text-[8px]',\n md: 'text-[10px]',\n lg: 'text-xs', // 12px\n};\n\n// Solid style: colored track when checked\nconst solidVariantClasses: Record<ColorVariant, string> = {\n primary: 'data-checked:bg-primary',\n secondary: 'data-checked:bg-secondary',\n warning: 'data-checked:bg-warning',\n info: 'data-checked:bg-info',\n success: 'data-checked:bg-success',\n destructive: 'data-checked:bg-destructive',\n};\n\n// Outline style: colored border when checked\nconst outlineVariantClasses: Record<ColorVariant, string> = {\n primary: 'data-checked:border-primary',\n secondary: 'data-checked:border-secondary',\n warning: 'data-checked:border-warning',\n info: 'data-checked:border-info',\n success: 'data-checked:border-success',\n destructive: 'data-checked:border-destructive',\n};\n\n// Outline style: colored thumb when checked\nconst outlineThumbVariantClasses: Record<ColorVariant, string> = {\n primary: 'group-data-checked/switch:bg-primary',\n secondary: 'group-data-checked/switch:bg-secondary',\n warning: 'group-data-checked/switch:bg-warning',\n info: 'group-data-checked/switch:bg-info',\n success: 'group-data-checked/switch:bg-success',\n destructive: 'group-data-checked/switch:bg-destructive',\n};\n\n// ============================================\n// Theme Variant Constants & Config\n// ============================================\n\nconst themeSizeConfig = {\n sm: {\n gradient: {\n width: 'w-[64px]',\n height: 'h-6',\n indicator: 'size-5',\n icon: 'size-3',\n text: 'text-xs',\n padding: 'p-0.5',\n skeletonWidth: 'w-[64px]',\n skeletonHeight: 'h-6',\n },\n switch: {\n track: 'w-[30px] h-4',\n indicator: 'size-3.5',\n icon: 'size-3.5',\n gap: 'gap-1.5',\n skeletonWidth: 'w-[50px]',\n skeletonHeight: 'h-4',\n },\n pill: {\n width: 'w-[42px]',\n height: 'h-6',\n indicator: 'size-5',\n icon: 'size-3',\n padding: 'p-0.5',\n skeletonWidth: 'w-[42px]',\n skeletonHeight: 'h-6',\n },\n segmented: {\n height: 'h-6',\n segmentHeight: 'h-4',\n icon: 'size-3',\n text: 'text-xs',\n padding: 'p-1',\n gap: 'gap-0.5',\n skeletonWidth: 'w-[100px]',\n skeletonHeight: 'h-6',\n },\n },\n md: {\n gradient: {\n width: 'w-[76px]',\n height: 'h-7',\n indicator: 'size-6',\n icon: 'size-3.5',\n text: 'text-sm',\n padding: 'p-0.5',\n skeletonWidth: 'w-[76px]',\n skeletonHeight: 'h-7',\n },\n switch: {\n track: 'w-9 h-[18px]',\n indicator: 'size-4',\n icon: 'size-4',\n gap: 'gap-2',\n skeletonWidth: 'w-[58px]',\n skeletonHeight: 'h-[18px]',\n },\n pill: {\n width: 'w-[50px]',\n height: 'h-7',\n indicator: 'size-6',\n icon: 'size-3.5',\n padding: 'p-0.5',\n skeletonWidth: 'w-[50px]',\n skeletonHeight: 'h-7',\n },\n segmented: {\n height: 'h-7',\n segmentHeight: 'h-5',\n icon: 'size-3.5',\n text: 'text-sm',\n padding: 'p-1',\n gap: 'gap-1',\n skeletonWidth: 'w-[120px]',\n skeletonHeight: 'h-7',\n },\n },\n lg: {\n gradient: {\n width: 'w-[88px]',\n height: 'h-8',\n indicator: 'size-7',\n icon: 'size-4',\n text: 'text-sm',\n padding: 'p-0.5',\n skeletonWidth: 'w-[88px]',\n skeletonHeight: 'h-8',\n },\n switch: {\n track: 'w-[42px] h-5',\n indicator: 'size-[18px]',\n icon: 'size-[18px]',\n gap: 'gap-2.5',\n skeletonWidth: 'w-[66px]',\n skeletonHeight: 'h-5',\n },\n pill: {\n width: 'w-[58px]',\n height: 'h-8',\n indicator: 'size-7',\n icon: 'size-4',\n padding: 'p-0.5',\n skeletonWidth: 'w-[58px]',\n skeletonHeight: 'h-8',\n },\n segmented: {\n height: 'h-8',\n segmentHeight: 'h-6',\n icon: 'size-4',\n text: 'text-sm',\n padding: 'p-1',\n gap: 'gap-1',\n skeletonWidth: 'w-[140px]',\n skeletonHeight: 'h-8',\n },\n },\n} as const;\n\n// Gradient directions matching Figma design\nconst GRADIENT_LIGHT =\n 'linear-gradient(247deg, var(--destructive) 10%, var(--orange-500) 50%, var(--warning) 90%)';\nconst GRADIENT_DARK =\n 'linear-gradient(264deg, var(--blue-200) 3%, var(--indigo-400) 60%, var(--blue-800) 98%)';\n\n// Shared theme style constants\nconst themeFocusRingClasses =\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2';\nconst themeTransitionClasses =\n 'duration-300 ease-smooth motion-reduce:duration-0';\n\n// ============================================\n// Theme Variant Renderers\n// ============================================\n\nfunction GradientToggle({\n isLight,\n onThemeChange,\n sizes,\n}: {\n isLight: boolean;\n onThemeChange: (theme: 'light' | 'dark') => void;\n sizes: (typeof themeSizeConfig)['md']['gradient'];\n}) {\n return (\n <div\n data-slot=\"switch\"\n className={cn(\n 'relative flex items-center rounded-full transition-all overflow-hidden',\n sizes.width,\n sizes.height,\n sizes.padding,\n themeTransitionClasses,\n )}\n style={{\n background: isLight ? GRADIENT_LIGHT : GRADIENT_DARK,\n }}\n role=\"radiogroup\"\n aria-label=\"Theme selector\"\n >\n {/* Sliding indicator */}\n <div\n className={cn(\n 'absolute flex items-center justify-center rounded-full bg-card shadow-md hover:shadow-lg active:scale-95 transition-all z-10',\n sizes.indicator,\n themeTransitionClasses,\n isLight ? 'left-0.5' : 'right-0.5',\n )}\n >\n {isLight ? (\n <Sun className={cn(sizes.icon, 'text-warning')} />\n ) : (\n <Moon className={cn(sizes.icon, 'text-info')} />\n )}\n </div>\n\n {/* Clickable areas */}\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={isLight}\n aria-label=\"Light theme\"\n onClick={() => onThemeChange('light')}\n className={cn('flex-1 h-full rounded-full z-20', themeFocusRingClasses)}\n />\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={!isLight}\n aria-label=\"Dark theme\"\n onClick={() => onThemeChange('dark')}\n className={cn('flex-1 h-full rounded-full z-20', themeFocusRingClasses)}\n />\n\n {/* Label text */}\n <span\n className={cn(\n 'absolute pointer-events-none font-medium text-white transition-opacity',\n sizes.text,\n themeTransitionClasses,\n isLight ? 'right-2 opacity-100' : 'right-2 opacity-0',\n )}\n >\n Light\n </span>\n <span\n className={cn(\n 'absolute pointer-events-none font-medium text-white transition-opacity',\n sizes.text,\n themeTransitionClasses,\n !isLight ? 'left-2 opacity-100' : 'left-2 opacity-0',\n )}\n >\n Dark\n </span>\n </div>\n );\n}\n\nfunction ThemeSwitchToggle({\n isLight,\n onThemeChange,\n sizes,\n}: {\n isLight: boolean;\n onThemeChange: (theme: 'light' | 'dark') => void;\n sizes: (typeof themeSizeConfig)['md']['switch'];\n}) {\n return (\n <div\n className={cn('flex items-center', sizes.gap)}\n role=\"radiogroup\"\n aria-label=\"Theme selector\"\n data-slot=\"switch\"\n >\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={isLight}\n aria-label={`Switch to ${isLight ? 'dark' : 'light'} theme`}\n onClick={() => onThemeChange(isLight ? 'dark' : 'light')}\n className={cn(\n 'relative rounded-full transition-[colors,box-shadow] hover:shadow-[0_0_0_3px_var(--ring)/0.1] active:scale-[0.97]',\n sizes.track,\n themeTransitionClasses,\n themeFocusRingClasses,\n isLight ? 'bg-input' : 'bg-primary',\n )}\n >\n <div\n className={cn(\n 'absolute top-1/2 -translate-y-1/2 rounded-full shadow-md group-active:shadow-sm transition-all',\n sizes.indicator,\n themeTransitionClasses,\n isLight ? 'bg-card' : 'bg-primary-foreground',\n isLight ? 'left-0.5' : 'right-0.5',\n )}\n />\n </button>\n <div className={cn(sizes.icon, 'text-[var(--muted-foreground)]')}>\n {isLight ? (\n <Moon className=\"size-full\" />\n ) : (\n <Sun className=\"size-full\" />\n )}\n </div>\n </div>\n );\n}\n\nfunction PillToggle({\n isLight,\n onThemeChange,\n sizes,\n}: {\n isLight: boolean;\n onThemeChange: (theme: 'light' | 'dark') => void;\n sizes: (typeof themeSizeConfig)['md']['pill'];\n}) {\n return (\n <div\n className={cn(\n 'relative flex items-center justify-between rounded-full bg-input',\n sizes.width,\n sizes.height,\n sizes.padding,\n )}\n role=\"radiogroup\"\n aria-label=\"Theme selector\"\n data-slot=\"switch\"\n >\n {/* Moon icon (left) */}\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={!isLight}\n aria-label=\"Dark theme\"\n tabIndex={!isLight ? -1 : 0}\n aria-hidden={!isLight ? true : undefined}\n onClick={() => onThemeChange('dark')}\n className={cn(\n 'z-10 flex items-center justify-center rounded-full transition-opacity',\n sizes.indicator,\n themeTransitionClasses,\n themeFocusRingClasses,\n isLight ? 'opacity-50' : 'opacity-0',\n )}\n >\n <Moon className={cn(sizes.icon, 'text-[var(--foreground)]')} />\n </button>\n\n {/* Sun icon (right) */}\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={isLight}\n aria-label=\"Light theme\"\n tabIndex={isLight ? -1 : 0}\n aria-hidden={isLight ? true : undefined}\n onClick={() => onThemeChange('light')}\n className={cn(\n 'z-10 flex items-center justify-center rounded-full transition-opacity',\n sizes.indicator,\n themeTransitionClasses,\n themeFocusRingClasses,\n !isLight ? 'opacity-50' : 'opacity-0',\n )}\n >\n <Sun className={cn(sizes.icon, 'text-[var(--foreground)]')} />\n </button>\n\n {/* Sliding indicator with icon */}\n <div\n className={cn(\n 'absolute top-1/2 -translate-y-1/2 flex items-center justify-center rounded-full bg-card shadow-md hover:shadow-lg active:scale-95 transition-all',\n sizes.indicator,\n themeTransitionClasses,\n isLight ? 'right-0.5' : 'left-0.5',\n )}\n >\n {isLight ? (\n <Sun className={cn(sizes.icon, 'text-warning')} />\n ) : (\n <Moon className={cn(sizes.icon, 'text-info')} />\n )}\n </div>\n </div>\n );\n}\n\nfunction SegmentedToggle({\n isLight,\n onThemeChange,\n sizes,\n}: {\n isLight: boolean;\n onThemeChange: (theme: 'light' | 'dark') => void;\n sizes: (typeof themeSizeConfig)['md']['segmented'];\n}) {\n return (\n <div\n className={cn(\n 'inline-flex items-center rounded bg-input',\n sizes.height,\n sizes.padding,\n sizes.gap,\n )}\n role=\"radiogroup\"\n aria-label=\"Theme selector\"\n data-slot=\"switch\"\n >\n {/* Light segment */}\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={isLight}\n aria-label=\"Light theme\"\n onClick={() => onThemeChange('light')}\n className={cn(\n 'flex items-center justify-center gap-1 rounded px-2 whitespace-nowrap transition-all',\n sizes.segmentHeight,\n sizes.text,\n themeTransitionClasses,\n themeFocusRingClasses,\n isLight\n ? 'bg-card text-foreground shadow-sm'\n : 'text-[var(--foreground)] opacity-50 hover:opacity-70 active:scale-[0.97]',\n )}\n >\n <Sun className={sizes.icon} />\n <span>Light</span>\n </button>\n\n {/* Dark segment */}\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={!isLight}\n aria-label=\"Dark theme\"\n onClick={() => onThemeChange('dark')}\n className={cn(\n 'flex items-center justify-center gap-1 rounded px-2 whitespace-nowrap transition-all',\n sizes.segmentHeight,\n sizes.text,\n themeTransitionClasses,\n themeFocusRingClasses,\n !isLight\n ? 'bg-[var(--primary)] text-[var(--primary-foreground)] shadow-sm'\n : 'text-[var(--foreground)] opacity-50 hover:opacity-70 active:scale-[0.97]',\n )}\n >\n <Moon className={sizes.icon} />\n <span>Dark</span>\n </button>\n </div>\n );\n}\n\n// ============================================\n// Theme Variant Renderer (auto-connects to ThemeProvider)\n// ============================================\n\nconst themeVariantKeyMap: Record<\n ThemeVariant,\n 'gradient' | 'switch' | 'pill' | 'segmented'\n> = {\n 'theme-gradient': 'gradient',\n 'theme-switch': 'switch',\n 'theme-pill': 'pill',\n 'theme-segmented': 'segmented',\n};\n\nconst ThemeVariantRenderer = React.forwardRef<\n HTMLDivElement,\n SwitchControlProps\n>(\n (\n {\n variant,\n size = 'md',\n label,\n orientation = 'vertical',\n checked: controlledChecked,\n onCheckedChange,\n className: classNameProp,\n description: _description,\n labelPosition: _labelPosition,\n switchStyle: _switchStyle,\n withIcon: _withIcon,\n thumbIconOn: _thumbIconOn,\n thumbIconOff: _thumbIconOff,\n showOnOff: _showOnOff,\n onLabel: _onLabel,\n offLabel: _offLabel,\n defaultChecked: _defaultChecked,\n ...restProps\n },\n ref,\n ) => {\n // className from base-ui can be string | function; theme variants only use string\n const className =\n typeof classNameProp === 'function' ? undefined : classNameProp;\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n const themeContext = useThemeOptional();\n const contextTheme = themeContext?.theme;\n const contextSetTheme = themeContext?.setTheme;\n\n // Auto-connect to ThemeProvider when no explicit checked/onCheckedChange\n const isControlled = controlledChecked !== undefined;\n const activeTheme: 'light' | 'dark' = isControlled\n ? controlledChecked\n ? 'dark'\n : 'light'\n : ((contextTheme ?? 'light') as 'light' | 'dark');\n\n const handleThemeChange = React.useCallback(\n (newTheme: 'light' | 'dark') => {\n const newChecked = newTheme === 'dark';\n if (isControlled) {\n onCheckedChange?.(newChecked);\n } else if (contextSetTheme) {\n contextSetTheme(newTheme);\n }\n },\n [isControlled, onCheckedChange, contextSetTheme],\n );\n\n const key = themeVariantKeyMap[variant as ThemeVariant];\n\n const sizes = themeSizeConfig[size][key];\n\n // SSR placeholder - show skeleton during hydration\n if (!mounted && !isControlled) {\n return (\n <div className={cn('inline-flex', className)}>\n <div\n className={cn(\n 'rounded-full bg-[var(--surface-1)] animate-pulse',\n sizes.skeletonWidth,\n sizes.skeletonHeight,\n )}\n role=\"radiogroup\"\n aria-label={typeof label === 'string' ? label : 'Theme selector'}\n />\n </div>\n );\n }\n\n const isLight = activeTheme === 'light';\n\n let toggle: React.ReactNode;\n switch (key) {\n case 'gradient':\n toggle = (\n <GradientToggle\n isLight={isLight}\n onThemeChange={handleThemeChange}\n sizes={sizes as (typeof themeSizeConfig)['md']['gradient']}\n />\n );\n break;\n case 'switch':\n toggle = (\n <ThemeSwitchToggle\n isLight={isLight}\n onThemeChange={handleThemeChange}\n sizes={sizes as (typeof themeSizeConfig)['md']['switch']}\n />\n );\n break;\n case 'pill':\n toggle = (\n <PillToggle\n isLight={isLight}\n onThemeChange={handleThemeChange}\n sizes={sizes as (typeof themeSizeConfig)['md']['pill']}\n />\n );\n break;\n case 'segmented':\n toggle = (\n <SegmentedToggle\n isLight={isLight}\n onThemeChange={handleThemeChange}\n sizes={sizes as (typeof themeSizeConfig)['md']['segmented']}\n />\n );\n break;\n }\n\n // Pick standard HTML attributes safe for div (aria-*, data-*, id)\n const divProps = restProps as React.HTMLAttributes<HTMLDivElement>;\n\n if (!label) {\n return (\n <div ref={ref} className={className} {...divProps}>\n {toggle}\n </div>\n );\n }\n\n return (\n <div\n ref={ref}\n className={cn(\n 'inline-flex',\n orientation === 'vertical'\n ? 'flex-col items-start gap-2'\n : 'flex-row items-center gap-3',\n className,\n )}\n {...divProps}\n >\n <span className=\"text-xs font-semibold text-[var(--muted-foreground)]\">\n {label}\n </span>\n {toggle}\n </div>\n );\n },\n);\n\nThemeVariantRenderer.displayName = 'ThemeVariantRenderer';\n\n// ============================================\n// Main Switch Component\n// ============================================\n\n/** Type guard: is the variant a color variant? */\nfunction isColorVariant(v: SwitchVariant): v is ColorVariant {\n return !v.startsWith('theme-');\n}\n\nconst SwitchControl = React.forwardRef<HTMLButtonElement, SwitchControlProps>(\n (\n {\n label,\n description,\n labelPosition = 'right',\n orientation,\n className,\n id,\n size = 'md',\n variant = 'primary',\n switchStyle = 'solid',\n withIcon,\n thumbIconOn,\n thumbIconOff,\n showOnOff,\n onLabel,\n offLabel,\n checked: controlledChecked,\n defaultChecked = false,\n onCheckedChange,\n ...props\n },\n ref,\n ) => {\n const generatedId = React.useId();\n const switchId = id || generatedId;\n\n const [internalChecked, setInternalChecked] =\n React.useState(defaultChecked);\n const isControlled = controlledChecked !== undefined;\n const checked = isControlled ? controlledChecked : internalChecked;\n\n const handleCheckedChange = React.useCallback(\n (newChecked: boolean) => {\n if (!isControlled) {\n setInternalChecked(newChecked);\n }\n onCheckedChange?.(newChecked);\n },\n [isControlled, onCheckedChange],\n );\n\n // Dispatch to theme variant renderer if applicable\n if (!isColorVariant(variant)) {\n return (\n <ThemeVariantRenderer\n ref={ref as React.Ref<HTMLDivElement>}\n variant={variant}\n size={size}\n label={label}\n orientation={orientation}\n checked={controlledChecked}\n onCheckedChange={onCheckedChange}\n className={className}\n {...props}\n />\n );\n }\n\n // --- Color variant rendering (unchanged) ---\n const colorVariant: ColorVariant = variant;\n\n // Use wider track when labels are present to prevent text cutoff\n const hasLabels = showOnOff || !!onLabel || !!offLabel;\n const activeSizeClasses = hasLabels ? sizeWithLabelClasses : sizeClasses;\n const activeThumbTranslate = hasLabels\n ? thumbTranslateWithLabelClasses\n : thumbTranslateClasses;\n\n // Build track classes based on style\n const trackClasses =\n switchStyle === 'solid'\n ? cn(\n 'data-unchecked:bg-input dark:data-unchecked:bg-input/80 border-transparent',\n solidVariantClasses[colorVariant],\n )\n : cn(\n 'data-unchecked:bg-transparent data-checked:bg-transparent border-input',\n outlineVariantClasses[colorVariant],\n );\n\n // Build thumb classes based on style\n const thumbClasses =\n switchStyle === 'solid'\n ? 'bg-background dark:data-unchecked:bg-foreground dark:data-checked:bg-primary-foreground'\n : cn(\n 'bg-input dark:bg-foreground',\n outlineThumbVariantClasses[colorVariant],\n );\n\n // Thumb icon logic\n const showThumbIcon = withIcon || thumbIconOn || thumbIconOff;\n const checkedIcon = showThumbIcon\n ? thumbIconOn || <Check className={iconSizeClasses[size]} />\n : null;\n const uncheckedIcon = showThumbIcon\n ? thumbIconOff || <X className={iconSizeClasses[size]} />\n : null;\n\n const switchElement = (\n <SwitchPrimitive.Root\n ref={ref}\n id={switchId}\n data-slot=\"switch\"\n data-size={size}\n data-variant={colorVariant}\n data-style={switchStyle}\n className={cn(\n // Base styles\n 'peer group/switch relative inline-flex items-center shrink-0 rounded-full border shadow-xs',\n 'transition-[colors,box-shadow,border-color] duration-200 ease-smooth motion-reduce:transition-none outline-none',\n 'after:absolute after:-inset-x-3 after:-inset-y-[13px]',\n 'data-disabled:cursor-not-allowed data-disabled:opacity-50',\n // Hover: subtle track glow\n 'not-data-disabled:hover:shadow-[0_0_0_3px_var(--ring)/0.08] not-data-disabled:active:scale-[0.97]',\n 'motion-reduce:active:scale-100',\n // Focus styles\n 'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',\n // Invalid styles\n 'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 aria-invalid:ring-[3px]',\n // Size classes (wider when labels are shown)\n activeSizeClasses[size],\n // Variant/style classes\n trackClasses,\n className,\n )}\n checked={checked}\n onCheckedChange={handleCheckedChange}\n {...props}\n >\n {hasLabels && (\n <>\n <span\n aria-hidden=\"true\"\n className={cn(\n 'absolute font-semibold transition-opacity duration-200 ease-smooth motion-reduce:transition-none',\n labelFontSizes[size],\n 'start-1.5',\n checked ? 'opacity-100' : 'opacity-0',\n switchStyle === 'solid'\n ? 'text-primary-foreground'\n : 'text-current',\n )}\n >\n {onLabel || 'ON'}\n </span>\n <span\n aria-hidden=\"true\"\n className={cn(\n 'absolute font-semibold transition-opacity duration-200 ease-smooth motion-reduce:transition-none',\n labelFontSizes[size],\n 'end-1.5',\n checked ? 'opacity-0' : 'opacity-100',\n switchStyle === 'solid'\n ? 'text-muted-foreground'\n : 'text-current',\n )}\n >\n {offLabel || 'OFF'}\n </span>\n </>\n )}\n <SwitchPrimitive.Thumb\n data-slot=\"switch-thumb\"\n className={cn(\n 'pointer-events-none block rounded-full ring-0',\n 'shadow-sm group-hover/switch:shadow-md group-active/switch:shadow-sm',\n 'transition-[transform,box-shadow,background-color] duration-200 motion-reduce:transition-none',\n 'ease-smooth',\n 'group-active/switch:scale-95',\n 'data-unchecked:translate-x-0',\n // Size classes\n thumbSizeClasses[size],\n // Translation classes (wider when labels are shown)\n activeThumbTranslate[size],\n // Color classes based on style\n thumbClasses,\n // Flex for centering icons\n showThumbIcon && 'flex items-center justify-center',\n )}\n >\n {showThumbIcon && (\n <span\n aria-hidden=\"true\"\n className={cn(\n 'flex items-center justify-center transition-colors duration-200 ease-smooth motion-reduce:transition-none',\n // Icon colors based on style\n switchStyle === 'solid'\n ? 'text-muted-foreground group-data-checked/switch:text-primary'\n : 'text-background group-data-checked/switch:text-primary-foreground',\n )}\n >\n {checked ? checkedIcon : uncheckedIcon}\n </span>\n )}\n </SwitchPrimitive.Thumb>\n </SwitchPrimitive.Root>\n );\n\n if (!label) {\n return switchElement;\n }\n\n return (\n <div\n className={cn(\n 'flex items-center gap-3',\n labelPosition === 'left' && 'flex-row-reverse justify-end',\n )}\n >\n {switchElement}\n <div className=\"flex flex-col gap-0.5\">\n <label\n htmlFor={switchId}\n className=\"text-sm font-medium leading-none cursor-pointer peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n >\n {label}\n </label>\n {description && (\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n </div>\n );\n },\n);\n\nSwitchControl.displayName = 'SwitchControl';\n\n// =============================================================================\n// Switch — public API with smart field mode (inline layout)\n// =============================================================================\n\nconst Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(\n (props, ref) => {\n // Extract field-specific props (error, tooltip, required, labelIcon, fieldClassName)\n // label and description are shared — we handle them manually\n const {\n label,\n description,\n error,\n tooltip,\n required,\n labelIcon,\n fieldClassName,\n ...controlProps\n } = props;\n\n const isFieldMode = !!(error || tooltip || required || labelIcon);\n\n if (!isFieldMode) {\n // Bare mode: pass label/description to control for inline rendering\n return (\n <SwitchControl\n ref={ref}\n label={label}\n description={description as string}\n {...controlProps}\n />\n );\n }\n\n // Field mode: label goes to FieldLabel, switch renders bare\n return (\n <Field\n layout=\"inline\"\n state={error ? 'destructive' : undefined}\n disabled={controlProps.disabled}\n className={fieldClassName}\n >\n <SwitchControl ref={ref} {...controlProps} />\n {label && (\n <FieldLabel required={required} labelIcon={labelIcon}>\n {label}\n {tooltip && <FieldTooltip content={tooltip} />}\n </FieldLabel>\n )}\n {(error || description) && (\n <FieldBottom>\n {error && <FieldError>{error}</FieldError>}\n {!error && description && (\n <FieldDescription>{description}</FieldDescription>\n )}\n </FieldBottom>\n )}\n </Field>\n );\n },\n);\nSwitch.displayName = 'Switch';\n\nexport { Switch };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index39.js","names":[],"sources":["../src/components/atoms/forms/Switch/Switch.tsx"],"sourcesContent":["/** biome-ignore-all lint/a11y/useSemanticElements: Theme toggles use button-based radio controls for animated segmented UI while preserving radiogroup semantics. */\n'use client';\n\nimport { Switch as SwitchPrimitive } from '@base-ui/react/switch';\nimport { Check, Moon, Sun, X } from 'lucide-react';\nimport * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport {\n type FieldProps,\n FieldTooltip,\n} from '@/components/atoms/forms/_shared';\nimport { useThemeOptional } from '@/components/ThemeProvider';\nimport {\n Field,\n FieldBottom,\n FieldDescription,\n FieldError,\n FieldLabel,\n} from '@/components/ui/form-field';\nimport { cn } from '@/lib/utils';\n\n// ============================================\n// Types\n// ============================================\n\n/** Color variants for the standard switch */\ntype ColorVariant =\n | 'primary'\n | 'secondary'\n | 'warning'\n | 'info'\n | 'success'\n | 'destructive';\n\n/** Theme variants that render theme toggle UIs */\ntype ThemeVariant =\n | 'theme-gradient'\n | 'theme-switch'\n | 'theme-pill'\n | 'theme-segmented';\n\n/** All switch variants */\nexport type SwitchVariant = ColorVariant | ThemeVariant;\n\n// ============================================\n// Switch (with controlled/uncontrolled support)\n// ============================================\n\ninterface SwitchControlProps\n extends Omit<SwitchPrimitive.Root.Props, 'onCheckedChange'> {\n // Variants\n size?: 'sm' | 'md' | 'lg';\n variant?: SwitchVariant;\n /** Visual style of the switch (solid = filled track, outline = bordered track). Only applies to color variants. */\n switchStyle?: 'solid' | 'outline';\n\n // Thumb icons (color variants only)\n withIcon?: boolean;\n thumbIconOn?: React.ReactNode;\n thumbIconOff?: React.ReactNode;\n\n // Track labels (ON/OFF inside track, color variants only)\n showOnOff?: boolean;\n onLabel?: string;\n offLabel?: string;\n\n // External label\n label?: React.ReactNode;\n description?: string;\n labelPosition?: 'left' | 'right';\n\n /** Layout orientation for label (theme variants only) */\n orientation?: 'horizontal' | 'vertical';\n\n // Core (keep existing)\n checked?: boolean;\n defaultChecked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n}\n\nexport interface SwitchProps\n extends Omit<SwitchControlProps, 'label' | 'description'>,\n Omit<FieldProps, 'label' | 'description' | 'topRight' | 'bottomRight'> {\n /** Label text or ReactNode (inline with switch, or in FieldLabel when field props are set) */\n label?: React.ReactNode;\n /** Description text (inline below label, or in FieldDescription when field props are set) */\n description?: React.ReactNode;\n}\n\n// ============================================\n// Color Switch Constants\n// ============================================\n\n// Icon size classes for thumb icons\nconst iconSizeClasses = {\n sm: 'size-2', // 8px\n md: 'size-2.5', // 10px\n lg: 'size-3', // 12px\n};\n\n// Size classes for the track\nconst sizeClasses = {\n sm: 'h-[18px] w-[32px]',\n md: 'h-[22px] w-[40px]',\n lg: 'h-[26px] w-[48px]',\n};\n\n// Size classes for the thumb\nconst thumbSizeClasses = {\n sm: 'size-[14px]',\n md: 'size-[18px]',\n lg: 'size-[22px]',\n};\n\n// Thumb translation when checked (track width - thumb size - 2px padding on each side)\nconst thumbTranslateClasses = {\n sm: 'data-checked:ltr:translate-x-[14px] data-checked:rtl:-translate-x-[14px]',\n md: 'data-checked:ltr:translate-x-[18px] data-checked:rtl:-translate-x-[18px]',\n lg: 'data-checked:ltr:translate-x-[22px] data-checked:rtl:-translate-x-[22px]',\n};\n\n// Wider track sizes when ON/OFF labels are shown (extra space for text)\nconst sizeWithLabelClasses = {\n sm: 'h-[18px] w-[40px]',\n md: 'h-[22px] w-[48px]',\n lg: 'h-[26px] w-[56px]',\n};\n\n// Thumb translation for wider tracks with labels\nconst thumbTranslateWithLabelClasses = {\n sm: 'data-checked:ltr:translate-x-[22px] data-checked:rtl:-translate-x-[22px]',\n md: 'data-checked:ltr:translate-x-[26px] data-checked:rtl:-translate-x-[26px]',\n lg: 'data-checked:ltr:translate-x-[30px] data-checked:rtl:-translate-x-[30px]',\n};\n\n// Font sizes for track labels (ON/OFF)\nconst labelFontSizes = {\n sm: 'text-[8px]',\n md: 'text-[10px]',\n lg: 'text-xs', // 12px\n};\n\n// Solid style: colored track when checked\nconst solidVariantClasses: Record<ColorVariant, string> = {\n primary: 'data-checked:bg-primary',\n secondary: 'data-checked:bg-secondary',\n warning: 'data-checked:bg-warning',\n info: 'data-checked:bg-info',\n success: 'data-checked:bg-success',\n destructive: 'data-checked:bg-destructive',\n};\n\n// Outline style: colored border when checked\nconst outlineVariantClasses: Record<ColorVariant, string> = {\n primary: 'data-checked:border-primary',\n secondary: 'data-checked:border-secondary',\n warning: 'data-checked:border-warning',\n info: 'data-checked:border-info',\n success: 'data-checked:border-success',\n destructive: 'data-checked:border-destructive',\n};\n\n// Outline style: colored thumb when checked\nconst outlineThumbVariantClasses: Record<ColorVariant, string> = {\n primary: 'group-data-checked/switch:bg-primary',\n secondary: 'group-data-checked/switch:bg-secondary',\n warning: 'group-data-checked/switch:bg-warning',\n info: 'group-data-checked/switch:bg-info',\n success: 'group-data-checked/switch:bg-success',\n destructive: 'group-data-checked/switch:bg-destructive',\n};\n\n// ============================================\n// Theme Variant Constants & Config\n// ============================================\n\nconst themeSizeConfig = {\n sm: {\n gradient: {\n width: 'w-[64px]',\n height: 'h-6',\n indicator: 'size-5',\n icon: 'size-3',\n text: 'text-xs',\n padding: 'p-0.5',\n skeletonWidth: 'w-[64px]',\n skeletonHeight: 'h-6',\n },\n switch: {\n track: 'w-[30px] h-4',\n indicator: 'size-3.5',\n icon: 'size-3.5',\n gap: 'gap-1.5',\n skeletonWidth: 'w-[50px]',\n skeletonHeight: 'h-4',\n },\n pill: {\n width: 'w-[42px]',\n height: 'h-6',\n indicator: 'size-5',\n icon: 'size-3',\n padding: 'p-0.5',\n skeletonWidth: 'w-[42px]',\n skeletonHeight: 'h-6',\n },\n segmented: {\n height: 'h-6',\n segmentHeight: 'h-4',\n icon: 'size-3',\n text: 'text-xs',\n padding: 'p-1',\n gap: 'gap-0.5',\n skeletonWidth: 'w-[100px]',\n skeletonHeight: 'h-6',\n },\n },\n md: {\n gradient: {\n width: 'w-[76px]',\n height: 'h-7',\n indicator: 'size-6',\n icon: 'size-3.5',\n text: 'text-sm',\n padding: 'p-0.5',\n skeletonWidth: 'w-[76px]',\n skeletonHeight: 'h-7',\n },\n switch: {\n track: 'w-9 h-[18px]',\n indicator: 'size-4',\n icon: 'size-4',\n gap: 'gap-2',\n skeletonWidth: 'w-[58px]',\n skeletonHeight: 'h-[18px]',\n },\n pill: {\n width: 'w-[50px]',\n height: 'h-7',\n indicator: 'size-6',\n icon: 'size-3.5',\n padding: 'p-0.5',\n skeletonWidth: 'w-[50px]',\n skeletonHeight: 'h-7',\n },\n segmented: {\n height: 'h-7',\n segmentHeight: 'h-5',\n icon: 'size-3.5',\n text: 'text-sm',\n padding: 'p-1',\n gap: 'gap-1',\n skeletonWidth: 'w-[120px]',\n skeletonHeight: 'h-7',\n },\n },\n lg: {\n gradient: {\n width: 'w-[88px]',\n height: 'h-8',\n indicator: 'size-7',\n icon: 'size-4',\n text: 'text-sm',\n padding: 'p-0.5',\n skeletonWidth: 'w-[88px]',\n skeletonHeight: 'h-8',\n },\n switch: {\n track: 'w-[42px] h-5',\n indicator: 'size-[18px]',\n icon: 'size-[18px]',\n gap: 'gap-2.5',\n skeletonWidth: 'w-[66px]',\n skeletonHeight: 'h-5',\n },\n pill: {\n width: 'w-[58px]',\n height: 'h-8',\n indicator: 'size-7',\n icon: 'size-4',\n padding: 'p-0.5',\n skeletonWidth: 'w-[58px]',\n skeletonHeight: 'h-8',\n },\n segmented: {\n height: 'h-8',\n segmentHeight: 'h-6',\n icon: 'size-4',\n text: 'text-sm',\n padding: 'p-1',\n gap: 'gap-1',\n skeletonWidth: 'w-[140px]',\n skeletonHeight: 'h-8',\n },\n },\n} as const;\n\n// Gradient directions matching Figma design\nconst GRADIENT_LIGHT =\n 'linear-gradient(247deg, var(--destructive) 10%, var(--orange-500) 50%, var(--warning) 90%)';\nconst GRADIENT_DARK =\n 'linear-gradient(264deg, var(--blue-200) 3%, var(--indigo-400) 60%, var(--blue-800) 98%)';\n\n// Shared theme style constants\nconst themeFocusRingClasses =\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2';\nconst themeTransitionClasses =\n 'duration-300 ease-smooth motion-reduce:duration-0';\n\n// ============================================\n// Theme Variant Renderers\n// ============================================\n\nfunction GradientToggle({\n isLight,\n onThemeChange,\n sizes,\n}: {\n isLight: boolean;\n onThemeChange: (theme: 'light' | 'dark') => void;\n sizes: (typeof themeSizeConfig)['md']['gradient'];\n}) {\n return (\n <div\n data-slot=\"switch\"\n className={cn(\n 'relative flex items-center rounded-full transition-all overflow-hidden',\n sizes.width,\n sizes.height,\n sizes.padding,\n themeTransitionClasses,\n )}\n style={{\n background: isLight ? GRADIENT_LIGHT : GRADIENT_DARK,\n }}\n role=\"radiogroup\"\n aria-label=\"Theme selector\"\n >\n {/* Sliding indicator */}\n <div\n className={cn(\n 'absolute flex items-center justify-center rounded-full bg-card shadow-md hover:shadow-lg active:scale-95 transition-all z-10',\n sizes.indicator,\n themeTransitionClasses,\n isLight ? 'left-0.5' : 'right-0.5',\n )}\n >\n {isLight ? (\n <Sun className={cn(sizes.icon, 'text-warning')} />\n ) : (\n <Moon className={cn(sizes.icon, 'text-info')} />\n )}\n </div>\n\n {/* Clickable areas */}\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={isLight}\n aria-label=\"Light theme\"\n onClick={() => onThemeChange('light')}\n className={cn('flex-1 h-full rounded-full z-20', themeFocusRingClasses)}\n />\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={!isLight}\n aria-label=\"Dark theme\"\n onClick={() => onThemeChange('dark')}\n className={cn('flex-1 h-full rounded-full z-20', themeFocusRingClasses)}\n />\n\n {/* Label text */}\n <span\n className={cn(\n 'absolute pointer-events-none font-medium text-white transition-opacity',\n sizes.text,\n themeTransitionClasses,\n isLight ? 'right-2 opacity-100' : 'right-2 opacity-0',\n )}\n >\n Light\n </span>\n <span\n className={cn(\n 'absolute pointer-events-none font-medium text-white transition-opacity',\n sizes.text,\n themeTransitionClasses,\n !isLight ? 'left-2 opacity-100' : 'left-2 opacity-0',\n )}\n >\n Dark\n </span>\n </div>\n );\n}\n\nfunction ThemeSwitchToggle({\n isLight,\n onThemeChange,\n sizes,\n}: {\n isLight: boolean;\n onThemeChange: (theme: 'light' | 'dark') => void;\n sizes: (typeof themeSizeConfig)['md']['switch'];\n}) {\n return (\n <div\n className={cn('flex items-center', sizes.gap)}\n role=\"radiogroup\"\n aria-label=\"Theme selector\"\n data-slot=\"switch\"\n >\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={isLight}\n aria-label={`Switch to ${isLight ? 'dark' : 'light'} theme`}\n onClick={() => onThemeChange(isLight ? 'dark' : 'light')}\n className={cn(\n 'relative rounded-full transition-[colors,box-shadow] hover:shadow-[0_0_0_3px_var(--ring)/0.1] active:scale-[0.97]',\n sizes.track,\n themeTransitionClasses,\n themeFocusRingClasses,\n isLight ? 'bg-input' : 'bg-primary',\n )}\n >\n <div\n className={cn(\n 'absolute top-1/2 -translate-y-1/2 rounded-full shadow-md group-active:shadow-sm transition-all',\n sizes.indicator,\n themeTransitionClasses,\n isLight ? 'bg-card' : 'bg-background',\n isLight ? 'left-0.5' : 'right-0.5',\n )}\n />\n </button>\n <div className={cn(sizes.icon, 'text-[var(--muted-foreground)]')}>\n {isLight ? (\n <Moon className=\"size-full\" />\n ) : (\n <Sun className=\"size-full\" />\n )}\n </div>\n </div>\n );\n}\n\nfunction PillToggle({\n isLight,\n onThemeChange,\n sizes,\n}: {\n isLight: boolean;\n onThemeChange: (theme: 'light' | 'dark') => void;\n sizes: (typeof themeSizeConfig)['md']['pill'];\n}) {\n return (\n <div\n className={cn(\n 'relative flex items-center justify-between rounded-full bg-input',\n sizes.width,\n sizes.height,\n sizes.padding,\n )}\n role=\"radiogroup\"\n aria-label=\"Theme selector\"\n data-slot=\"switch\"\n >\n {/* Moon icon (left) */}\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={!isLight}\n aria-label=\"Dark theme\"\n tabIndex={!isLight ? -1 : 0}\n aria-hidden={!isLight ? true : undefined}\n onClick={() => onThemeChange('dark')}\n className={cn(\n 'z-10 flex items-center justify-center rounded-full transition-opacity',\n sizes.indicator,\n themeTransitionClasses,\n themeFocusRingClasses,\n isLight ? 'opacity-50' : 'opacity-0',\n )}\n >\n <Moon className={cn(sizes.icon, 'text-[var(--foreground)]')} />\n </button>\n\n {/* Sun icon (right) */}\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={isLight}\n aria-label=\"Light theme\"\n tabIndex={isLight ? -1 : 0}\n aria-hidden={isLight ? true : undefined}\n onClick={() => onThemeChange('light')}\n className={cn(\n 'z-10 flex items-center justify-center rounded-full transition-opacity',\n sizes.indicator,\n themeTransitionClasses,\n themeFocusRingClasses,\n !isLight ? 'opacity-50' : 'opacity-0',\n )}\n >\n <Sun className={cn(sizes.icon, 'text-[var(--foreground)]')} />\n </button>\n\n {/* Sliding indicator with icon */}\n <div\n className={cn(\n 'absolute top-1/2 -translate-y-1/2 flex items-center justify-center rounded-full bg-card shadow-md hover:shadow-lg active:scale-95 transition-all',\n sizes.indicator,\n themeTransitionClasses,\n isLight ? 'right-0.5' : 'left-0.5',\n )}\n >\n {isLight ? (\n <Sun className={cn(sizes.icon, 'text-warning')} />\n ) : (\n <Moon className={cn(sizes.icon, 'text-info')} />\n )}\n </div>\n </div>\n );\n}\n\nfunction SegmentedToggle({\n isLight,\n onThemeChange,\n sizes,\n}: {\n isLight: boolean;\n onThemeChange: (theme: 'light' | 'dark') => void;\n sizes: (typeof themeSizeConfig)['md']['segmented'];\n}) {\n return (\n <div\n className={cn(\n 'inline-flex items-center rounded bg-input',\n sizes.height,\n sizes.padding,\n sizes.gap,\n )}\n role=\"radiogroup\"\n aria-label=\"Theme selector\"\n data-slot=\"switch\"\n >\n {/* Light segment */}\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={isLight}\n aria-label=\"Light theme\"\n onClick={() => onThemeChange('light')}\n className={cn(\n 'flex items-center justify-center gap-1 rounded px-2 whitespace-nowrap transition-all',\n sizes.segmentHeight,\n sizes.text,\n themeTransitionClasses,\n themeFocusRingClasses,\n isLight\n ? 'bg-card text-foreground shadow-sm'\n : 'text-[var(--foreground)] opacity-50 hover:opacity-70 active:scale-[0.97]',\n )}\n >\n <Sun className={sizes.icon} />\n <span>Light</span>\n </button>\n\n {/* Dark segment */}\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={!isLight}\n aria-label=\"Dark theme\"\n onClick={() => onThemeChange('dark')}\n className={cn(\n 'flex items-center justify-center gap-1 rounded px-2 whitespace-nowrap transition-all',\n sizes.segmentHeight,\n sizes.text,\n themeTransitionClasses,\n themeFocusRingClasses,\n !isLight\n ? 'bg-[var(--primary)] text-[var(--primary-foreground)] shadow-sm'\n : 'text-[var(--foreground)] opacity-50 hover:opacity-70 active:scale-[0.97]',\n )}\n >\n <Moon className={sizes.icon} />\n <span>Dark</span>\n </button>\n </div>\n );\n}\n\n// ============================================\n// Theme Variant Renderer (auto-connects to ThemeProvider)\n// ============================================\n\nconst themeVariantKeyMap: Record<\n ThemeVariant,\n 'gradient' | 'switch' | 'pill' | 'segmented'\n> = {\n 'theme-gradient': 'gradient',\n 'theme-switch': 'switch',\n 'theme-pill': 'pill',\n 'theme-segmented': 'segmented',\n};\n\nconst ThemeVariantRenderer = React.forwardRef<\n HTMLDivElement,\n SwitchControlProps\n>(\n (\n {\n variant,\n size = 'md',\n label,\n orientation = 'vertical',\n checked: controlledChecked,\n onCheckedChange,\n className: classNameProp,\n description: _description,\n labelPosition: _labelPosition,\n switchStyle: _switchStyle,\n withIcon: _withIcon,\n thumbIconOn: _thumbIconOn,\n thumbIconOff: _thumbIconOff,\n showOnOff: _showOnOff,\n onLabel: _onLabel,\n offLabel: _offLabel,\n defaultChecked: _defaultChecked,\n ...restProps\n },\n ref,\n ) => {\n // className from base-ui can be string | function; theme variants only use string\n const className =\n typeof classNameProp === 'function' ? undefined : classNameProp;\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n const themeContext = useThemeOptional();\n const contextTheme = themeContext?.theme;\n const contextSetTheme = themeContext?.setTheme;\n\n // Auto-connect to ThemeProvider when no explicit checked/onCheckedChange\n const isControlled = controlledChecked !== undefined;\n const activeTheme: 'light' | 'dark' = isControlled\n ? controlledChecked\n ? 'dark'\n : 'light'\n : ((contextTheme ?? 'light') as 'light' | 'dark');\n\n const handleThemeChange = React.useCallback(\n (newTheme: 'light' | 'dark') => {\n const newChecked = newTheme === 'dark';\n if (isControlled) {\n onCheckedChange?.(newChecked);\n } else if (contextSetTheme) {\n contextSetTheme(newTheme);\n }\n },\n [isControlled, onCheckedChange, contextSetTheme],\n );\n\n const key = themeVariantKeyMap[variant as ThemeVariant];\n\n const sizes = themeSizeConfig[size][key];\n\n // SSR placeholder - show skeleton during hydration\n if (!mounted && !isControlled) {\n return (\n <div className={cn('inline-flex', className)}>\n <div\n className={cn(\n 'rounded-full bg-[var(--surface-1)] animate-pulse',\n sizes.skeletonWidth,\n sizes.skeletonHeight,\n )}\n role=\"radiogroup\"\n aria-label={typeof label === 'string' ? label : 'Theme selector'}\n />\n </div>\n );\n }\n\n const isLight = activeTheme === 'light';\n\n let toggle: React.ReactNode;\n switch (key) {\n case 'gradient':\n toggle = (\n <GradientToggle\n isLight={isLight}\n onThemeChange={handleThemeChange}\n sizes={sizes as (typeof themeSizeConfig)['md']['gradient']}\n />\n );\n break;\n case 'switch':\n toggle = (\n <ThemeSwitchToggle\n isLight={isLight}\n onThemeChange={handleThemeChange}\n sizes={sizes as (typeof themeSizeConfig)['md']['switch']}\n />\n );\n break;\n case 'pill':\n toggle = (\n <PillToggle\n isLight={isLight}\n onThemeChange={handleThemeChange}\n sizes={sizes as (typeof themeSizeConfig)['md']['pill']}\n />\n );\n break;\n case 'segmented':\n toggle = (\n <SegmentedToggle\n isLight={isLight}\n onThemeChange={handleThemeChange}\n sizes={sizes as (typeof themeSizeConfig)['md']['segmented']}\n />\n );\n break;\n }\n\n // Pick standard HTML attributes safe for div (aria-*, data-*, id)\n const divProps = restProps as React.HTMLAttributes<HTMLDivElement>;\n\n if (!label) {\n return (\n <div ref={ref} className={className} {...divProps}>\n {toggle}\n </div>\n );\n }\n\n return (\n <div\n ref={ref}\n className={cn(\n 'inline-flex',\n orientation === 'vertical'\n ? 'flex-col items-start gap-2'\n : 'flex-row items-center gap-3',\n className,\n )}\n {...divProps}\n >\n <span className=\"text-xs font-semibold text-[var(--muted-foreground)]\">\n {label}\n </span>\n {toggle}\n </div>\n );\n },\n);\n\nThemeVariantRenderer.displayName = 'ThemeVariantRenderer';\n\n// ============================================\n// Main Switch Component\n// ============================================\n\n/** Type guard: is the variant a color variant? */\nfunction isColorVariant(v: SwitchVariant): v is ColorVariant {\n return !v.startsWith('theme-');\n}\n\nconst SwitchControl = React.forwardRef<HTMLButtonElement, SwitchControlProps>(\n (\n {\n label,\n description,\n labelPosition = 'right',\n orientation,\n className,\n id,\n size = 'md',\n variant = 'primary',\n switchStyle = 'solid',\n withIcon,\n thumbIconOn,\n thumbIconOff,\n showOnOff,\n onLabel,\n offLabel,\n checked: controlledChecked,\n defaultChecked = false,\n onCheckedChange,\n ...props\n },\n ref,\n ) => {\n const generatedId = React.useId();\n const switchId = id || generatedId;\n\n const [internalChecked, setInternalChecked] =\n React.useState(defaultChecked);\n const isControlled = controlledChecked !== undefined;\n const checked = isControlled ? controlledChecked : internalChecked;\n\n const handleCheckedChange = React.useCallback(\n (newChecked: boolean) => {\n if (!isControlled) {\n setInternalChecked(newChecked);\n }\n onCheckedChange?.(newChecked);\n },\n [isControlled, onCheckedChange],\n );\n\n // Dispatch to theme variant renderer if applicable\n if (!isColorVariant(variant)) {\n return (\n <ThemeVariantRenderer\n ref={ref as React.Ref<HTMLDivElement>}\n variant={variant}\n size={size}\n label={label}\n orientation={orientation}\n checked={controlledChecked}\n onCheckedChange={onCheckedChange}\n className={className}\n {...props}\n />\n );\n }\n\n // --- Color variant rendering (unchanged) ---\n const colorVariant: ColorVariant = variant;\n\n // Use wider track when labels are present to prevent text cutoff\n const hasLabels = showOnOff || !!onLabel || !!offLabel;\n const activeSizeClasses = hasLabels ? sizeWithLabelClasses : sizeClasses;\n const activeThumbTranslate = hasLabels\n ? thumbTranslateWithLabelClasses\n : thumbTranslateClasses;\n\n // Build track classes based on style\n const trackClasses =\n switchStyle === 'solid'\n ? cn(\n 'data-unchecked:bg-input dark:data-unchecked:bg-input/80 border-transparent',\n solidVariantClasses[colorVariant],\n )\n : cn(\n 'data-unchecked:bg-transparent data-checked:bg-transparent border-input',\n outlineVariantClasses[colorVariant],\n );\n\n // Build thumb classes based on style\n const thumbClasses =\n switchStyle === 'solid'\n ? 'bg-background dark:data-unchecked:bg-foreground dark:data-checked:bg-background'\n : cn(\n 'bg-input dark:bg-foreground',\n outlineThumbVariantClasses[colorVariant],\n );\n\n // Thumb icon logic\n const showThumbIcon = withIcon || thumbIconOn || thumbIconOff;\n const checkedIcon = showThumbIcon\n ? thumbIconOn || <Check className={iconSizeClasses[size]} />\n : null;\n const uncheckedIcon = showThumbIcon\n ? thumbIconOff || <X className={iconSizeClasses[size]} />\n : null;\n\n const switchElement = (\n <SwitchPrimitive.Root\n ref={ref}\n id={switchId}\n data-slot=\"switch\"\n data-size={size}\n data-variant={colorVariant}\n data-style={switchStyle}\n className={cn(\n // Base styles\n 'peer group/switch relative inline-flex items-center shrink-0 rounded-full border shadow-xs',\n 'transition-[colors,box-shadow,border-color] duration-200 ease-smooth motion-reduce:transition-none outline-none',\n 'after:absolute after:-inset-x-3 after:-inset-y-[13px]',\n 'data-disabled:cursor-not-allowed data-disabled:opacity-50',\n // Hover: subtle track glow\n 'not-data-disabled:hover:shadow-[0_0_0_3px_var(--ring)/0.08] not-data-disabled:active:scale-[0.97]',\n 'motion-reduce:active:scale-100',\n // Focus styles\n 'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',\n // Invalid styles\n 'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 aria-invalid:ring-[3px]',\n // Size classes (wider when labels are shown)\n activeSizeClasses[size],\n // Variant/style classes\n trackClasses,\n className,\n )}\n checked={checked}\n onCheckedChange={handleCheckedChange}\n {...props}\n >\n {hasLabels && (\n <>\n <span\n aria-hidden=\"true\"\n className={cn(\n 'absolute font-semibold transition-opacity duration-200 ease-smooth motion-reduce:transition-none',\n labelFontSizes[size],\n 'start-1.5',\n checked ? 'opacity-100' : 'opacity-0',\n switchStyle === 'solid'\n ? 'text-primary-foreground'\n : 'text-current',\n )}\n >\n {onLabel || 'ON'}\n </span>\n <span\n aria-hidden=\"true\"\n className={cn(\n 'absolute font-semibold transition-opacity duration-200 ease-smooth motion-reduce:transition-none',\n labelFontSizes[size],\n 'end-1.5',\n checked ? 'opacity-0' : 'opacity-100',\n switchStyle === 'solid'\n ? 'text-muted-foreground'\n : 'text-current',\n )}\n >\n {offLabel || 'OFF'}\n </span>\n </>\n )}\n <SwitchPrimitive.Thumb\n data-slot=\"switch-thumb\"\n className={cn(\n 'pointer-events-none block rounded-full ring-0',\n 'shadow-sm group-hover/switch:shadow-md group-active/switch:shadow-sm',\n 'transition-[transform,box-shadow,background-color] duration-200 motion-reduce:transition-none',\n 'ease-smooth',\n 'group-active/switch:scale-95',\n 'data-unchecked:translate-x-0',\n // Size classes\n thumbSizeClasses[size],\n // Translation classes (wider when labels are shown)\n activeThumbTranslate[size],\n // Color classes based on style\n thumbClasses,\n // Flex for centering icons\n showThumbIcon && 'flex items-center justify-center',\n )}\n >\n {showThumbIcon && (\n <span\n aria-hidden=\"true\"\n className={cn(\n 'flex items-center justify-center transition-colors duration-200 ease-smooth motion-reduce:transition-none',\n // Icon colors based on style\n switchStyle === 'solid'\n ? 'text-muted-foreground group-data-checked/switch:text-primary'\n : 'text-background group-data-checked/switch:text-primary-foreground',\n )}\n >\n {checked ? checkedIcon : uncheckedIcon}\n </span>\n )}\n </SwitchPrimitive.Thumb>\n </SwitchPrimitive.Root>\n );\n\n if (!label) {\n return switchElement;\n }\n\n return (\n <div\n className={cn(\n 'flex items-center gap-3',\n labelPosition === 'left' && 'flex-row-reverse justify-end',\n )}\n >\n {switchElement}\n <div className=\"flex flex-col gap-0.5\">\n <label\n htmlFor={switchId}\n className=\"text-sm font-medium leading-none cursor-pointer peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n >\n {label}\n </label>\n {description && (\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n )}\n </div>\n </div>\n );\n },\n);\n\nSwitchControl.displayName = 'SwitchControl';\n\n// =============================================================================\n// Switch — public API with smart field mode (inline layout)\n// =============================================================================\n\nconst Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(\n (props, ref) => {\n // Extract field-specific props (error, tooltip, required, labelIcon, fieldClassName)\n // label and description are shared — we handle them manually\n const {\n label,\n description,\n error,\n tooltip,\n required,\n labelIcon,\n fieldClassName,\n ...controlProps\n } = props;\n\n const isFieldMode = !!(error || tooltip || required || labelIcon);\n\n if (!isFieldMode) {\n // Bare mode: pass label/description to control for inline rendering\n return (\n <SwitchControl\n ref={ref}\n label={label}\n description={description as string}\n {...controlProps}\n />\n );\n }\n\n // Field mode: label goes to FieldLabel, switch renders bare\n return (\n <Field\n layout=\"inline\"\n state={error ? 'destructive' : undefined}\n disabled={controlProps.disabled}\n className={fieldClassName}\n >\n <SwitchControl ref={ref} {...controlProps} />\n {label && (\n <FieldLabel required={required} labelIcon={labelIcon}>\n {label}\n {tooltip && <FieldTooltip content={tooltip} />}\n </FieldLabel>\n )}\n {(error || description) && (\n <FieldBottom>\n {error && <FieldError>{error}</FieldError>}\n {!error && description && (\n <FieldDescription>{description}</FieldDescription>\n )}\n </FieldBottom>\n )}\n </Field>\n );\n },\n);\nSwitch.displayName = 'Switch';\n\nexport { Switch };\n"],"mappings":"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"}
|
package/dist/index5.js
CHANGED
|
@@ -61,22 +61,22 @@ var buttonVariants = cva("focus-visible:border-ring focus-visible:ring-ring/50 a
|
|
|
61
61
|
{
|
|
62
62
|
appearance: "solid",
|
|
63
63
|
variant: "info",
|
|
64
|
-
className: "bg-info text-
|
|
64
|
+
className: "bg-info text-info-foreground hover:bg-info/80"
|
|
65
65
|
},
|
|
66
66
|
{
|
|
67
67
|
appearance: "solid",
|
|
68
68
|
variant: "success",
|
|
69
|
-
className: "bg-success text-
|
|
69
|
+
className: "bg-success text-success-foreground hover:bg-success/80"
|
|
70
70
|
},
|
|
71
71
|
{
|
|
72
72
|
appearance: "solid",
|
|
73
73
|
variant: "warning",
|
|
74
|
-
className: "bg-warning text-
|
|
74
|
+
className: "bg-warning text-warning-foreground hover:bg-warning/80"
|
|
75
75
|
},
|
|
76
76
|
{
|
|
77
77
|
appearance: "solid",
|
|
78
78
|
variant: "destructive",
|
|
79
|
-
className: "bg-destructive text-
|
|
79
|
+
className: "bg-destructive text-destructive-foreground hover:bg-destructive/80"
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
82
|
appearance: "gradient",
|
|
@@ -91,22 +91,22 @@ var buttonVariants = cva("focus-visible:border-ring focus-visible:ring-ring/50 a
|
|
|
91
91
|
{
|
|
92
92
|
appearance: "gradient",
|
|
93
93
|
variant: "info",
|
|
94
|
-
className: "from-info to-info/60 text-
|
|
94
|
+
className: "from-info to-info/60 text-info-foreground hover:from-info/60 hover:to-info"
|
|
95
95
|
},
|
|
96
96
|
{
|
|
97
97
|
appearance: "gradient",
|
|
98
98
|
variant: "success",
|
|
99
|
-
className: "from-success to-success/60 text-
|
|
99
|
+
className: "from-success to-success/60 text-success-foreground hover:from-success/60 hover:to-success"
|
|
100
100
|
},
|
|
101
101
|
{
|
|
102
102
|
appearance: "gradient",
|
|
103
103
|
variant: "warning",
|
|
104
|
-
className: "from-warning to-warning/60 text-
|
|
104
|
+
className: "from-warning to-warning/60 text-warning-foreground hover:from-warning/60 hover:to-warning"
|
|
105
105
|
},
|
|
106
106
|
{
|
|
107
107
|
appearance: "gradient",
|
|
108
108
|
variant: "destructive",
|
|
109
|
-
className: "from-destructive to-destructive/60 text-
|
|
109
|
+
className: "from-destructive to-destructive/60 text-destructive-foreground hover:from-destructive/60 hover:to-destructive"
|
|
110
110
|
},
|
|
111
111
|
{
|
|
112
112
|
appearance: "soft",
|
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-primary-foreground hover:bg-info/80',\n },\n {\n appearance: 'solid',\n variant: 'success',\n className: 'bg-success text-primary-foreground hover:bg-success/80',\n },\n {\n appearance: 'solid',\n variant: 'warning',\n className: 'bg-warning text-primary-foreground hover:bg-warning/80',\n },\n {\n appearance: 'solid',\n variant: 'destructive',\n className:\n 'bg-destructive text-primary-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-primary-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-primary-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-primary-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-primary-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-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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"}
|