import { Platform } from 'react-native'; import { cva, type VariantProps } from 'class-variance-authority'; import { DISABLED_CURSOR, TRANSITION_COLORS } from '../../styles/constants'; // TODO: Validate that `dark:` syntax works with Uniwind `ScopedTheme` export const buttonRootVariants = cva( [ 'flex-row items-center justify-center', 'rounded-[var(--border-radius-button)]', 'web:outline-none web:focus:outline-none web:focus-visible:outline-none', TRANSITION_COLORS, 'data-[disabled=true]:opacity-[var(--opacity-disabled)]', DISABLED_CURSOR, 'web:data-[focus-visible=true]:ring-2 web:data-[focus-visible=true]:ring-stroke-focus web:data-[focus-visible=true]:ring-offset-2', ], { variants: { variant: { solid: ['border-b-1 border-black/75'], // TODO: Replace with token outline: ['bg-transparent', 'border border-stroke-primary'], ghost: ['bg-transparent'], }, color: { action: [], danger: [], warning: [], success: [], info: [], }, size: { default: 'h-11 px-4 gap-2', small: 'h-8 px-3 gap-1.5', }, fullWidth: { true: 'w-full', false: '', }, }, compoundVariants: [ // ── solid × color (filled surface) ────────────────────────────── { variant: 'solid', color: 'action', className: [ 'bg-surface-action-strong', Platform.select({ default: 'data-[active=true]:bg-surface-action-strong-active', web: 'data-[hover=true]:bg-surface-action-strong-hover data-[active=true]:data-[hover=true]:bg-surface-action-strong-active', }), ], }, { variant: 'solid', color: 'danger', className: [ 'bg-surface-danger-strong', Platform.select({ default: 'data-[active=true]:bg-surface-danger-strong-active', web: 'data-[hover=true]:bg-surface-danger-strong-hover data-[active=true]:data-[hover=true]:bg-surface-danger-strong-active', }), ], }, { variant: 'solid', color: 'warning', className: [ 'bg-surface-warning-strong', Platform.select({ default: 'data-[active=true]:bg-amber-600', web: 'data-[hover=true]:bg-amber-500 data-[active=true]:data-[hover=true]:bg-amber-600', }), ], }, { variant: 'solid', color: 'success', className: [ 'bg-surface-success-strong', Platform.select({ default: 'data-[active=true]:bg-green-800', web: 'data-[hover=true]:bg-green-700 data-[active=true]:data-[hover=true]:bg-green-800', }), ], }, { variant: 'solid', color: 'info', className: [ 'bg-surface-info-strong', Platform.select({ default: 'data-[active=true]:bg-sky-700', web: 'data-[hover=true]:bg-sky-600 data-[active=true]:data-[hover=true]:bg-sky-700', }), ], }, // ── outline × color (border + hover/active surface) ───────────── { variant: 'outline', color: 'action', className: [ 'border-stroke-action', Platform.select({ default: 'data-[active=true]:bg-surface-action-subtle-active', web: 'data-[hover=true]:bg-surface-action-tint-hover data-[active=true]:data-[hover=true]:bg-surface-action-subtle-active', }), ], }, { variant: 'outline', color: 'danger', className: [ 'border-stroke-danger', Platform.select({ default: 'data-[active=true]:bg-surface-danger-subtle-active', web: 'data-[hover=true]:bg-surface-danger-tint-hover data-[active=true]:data-[hover=true]:bg-surface-danger-subtle-active', }), ], }, { variant: 'outline', color: 'warning', className: [ 'border-stroke-warning', Platform.select({ default: 'data-[active=true]:bg-surface-warning-subtle', web: 'data-[hover=true]:bg-surface-warning-tint data-[active=true]:data-[hover=true]:bg-surface-warning-subtle', }), ], }, { variant: 'outline', color: 'success', className: [ 'border-stroke-success', Platform.select({ default: 'data-[active=true]:bg-surface-success-subtle', web: 'data-[hover=true]:bg-surface-success-tint data-[active=true]:data-[hover=true]:bg-surface-success-subtle', }), ], }, { variant: 'outline', color: 'info', className: [ 'border-stroke-info', Platform.select({ default: 'data-[active=true]:bg-surface-info-subtle', web: 'data-[hover=true]:bg-surface-info-tint data-[active=true]:data-[hover=true]:bg-surface-info-subtle', }), ], }, // ── ghost × color (hover/active surface fills) ────────────────── { variant: 'ghost', color: 'action', className: [ Platform.select({ default: 'data-[active=true]:bg-surface-action-subtle-active', web: 'data-[hover=true]:bg-surface-action-tint-hover data-[active=true]:data-[hover=true]:bg-surface-action-subtle-active', }), ], }, { variant: 'ghost', color: 'danger', className: [ Platform.select({ default: 'data-[active=true]:bg-surface-danger-subtle-active', web: 'data-[hover=true]:bg-surface-danger-tint-hover data-[active=true]:data-[hover=true]:bg-surface-danger-subtle-active', }), ], }, { variant: 'ghost', color: 'warning', className: [ Platform.select({ default: 'data-[active=true]:bg-surface-warning-subtle', web: 'data-[hover=true]:bg-surface-warning-tint data-[active=true]:data-[hover=true]:bg-surface-warning-subtle', }), ], }, { variant: 'ghost', color: 'success', className: [ Platform.select({ default: 'data-[active=true]:bg-surface-success-subtle', web: 'data-[hover=true]:bg-surface-success-tint data-[active=true]:data-[hover=true]:bg-surface-success-subtle', }), ], }, { variant: 'ghost', color: 'info', className: [ Platform.select({ default: 'data-[active=true]:bg-surface-info-subtle', web: 'data-[hover=true]:bg-surface-info-tint data-[active=true]:data-[hover=true]:bg-surface-info-subtle', }), ], }, ], defaultVariants: { variant: 'solid', color: 'action', size: 'default', fullWidth: false, }, }, ); export const buttonTextVariants = cva(['font-medium', 'text-center'], { variants: { variant: { solid: [], outline: [], ghost: [], }, color: { action: [], danger: [], warning: [], success: [], info: [], }, size: { default: 'text-base', small: 'text-sm', }, }, compoundVariants: [ // ── solid × color (filled foreground text) ────────────────────── { variant: 'solid', color: 'action', className: 'text-content-action-on-strong' }, { variant: 'solid', color: 'danger', className: 'text-content-danger-on-strong' }, { variant: 'solid', color: 'warning', className: 'text-content-warning-on-strong' }, { variant: 'solid', color: 'success', className: 'text-content-success-on-strong' }, { variant: 'solid', color: 'info', className: 'text-content-info-on-strong' }, // ── outline/ghost × color (transparent foreground text) ────────── { variant: ['outline', 'ghost'], color: 'action', className: 'text-content-action' }, { variant: ['outline', 'ghost'], color: 'danger', className: 'text-content-danger' }, { variant: ['outline', 'ghost'], color: 'warning', className: 'text-content-warning' }, { variant: ['outline', 'ghost'], color: 'success', className: 'text-content-success' }, { variant: ['outline', 'ghost'], color: 'info', className: 'text-content-info' }, ], defaultVariants: { variant: 'solid', color: 'action', size: 'default', }, }); export const buttonSpinnerVariants = cva([ 'data-[icon=inline-start]:me-1.5', 'data-[icon=inline-end]:ms-1.5', ]); // Spinner color is set via Uniwind's `colorClassName` prop (maps to the native // `color` prop on `ActivityIndicator`). `accent-*` utilities ONLY take effect // when passed through `colorClassName` — putting them on `className` is a no-op // because the underlying `color` prop is not part of the `style` object. export const buttonSpinnerColorVariants = cva([], { variants: { variant: { solid: [], outline: [], ghost: [], }, color: { action: [], danger: [], warning: [], success: [], info: [], }, }, compoundVariants: [ // ── solid × color ─────────────────────────────────────────────── { variant: 'solid', color: 'action', className: 'accent-[var(--color-content-action-on-strong)]', }, { variant: 'solid', color: 'danger', className: 'accent-[var(--color-content-danger-on-strong)]', }, { variant: 'solid', color: 'warning', className: 'accent-[var(--color-content-warning-on-strong)]', }, { variant: 'solid', color: 'success', className: 'accent-[var(--color-content-success-on-strong)]', }, { variant: 'solid', color: 'info', className: 'accent-[var(--color-content-info-on-strong)]', }, // ── outline/ghost × color ──────────────────────────────────────── { variant: ['outline', 'ghost'], color: 'action', className: 'accent-[var(--color-content-action)]', }, { variant: ['outline', 'ghost'], color: 'danger', className: 'accent-[var(--color-content-danger)]', }, { variant: ['outline', 'ghost'], color: 'warning', className: 'accent-[var(--color-content-warning)]', }, { variant: ['outline', 'ghost'], color: 'success', className: 'accent-[var(--color-content-success)]', }, { variant: ['outline', 'ghost'], color: 'info', className: 'accent-[var(--color-content-info)]', }, ], defaultVariants: { variant: 'solid', color: 'action', }, }); export const buttonGroupVariants = cva([], { variants: { flexDirection: { row: Platform.select({ web: 'flex-row', default: '' }), column: Platform.select({ web: 'flex-col', default: '' }), 'row-reverse': Platform.select({ web: 'flex-row-reverse', default: '' }), 'column-reverse': Platform.select({ web: 'flex-col-reverse', default: '' }), }, isAttached: { true: 'gap-0', false: 'gap-2', }, }, defaultVariants: { flexDirection: 'row', isAttached: false, }, }); export const buttonIconVariants = cva( ['data-[icon=inline-start]:me-1.5', 'data-[icon=inline-end]:ms-1.5'], { variants: { variant: { solid: [], outline: [], ghost: [], }, color: { action: [], danger: [], warning: [], success: [], info: [], }, size: { default: 'size-5', small: 'size-4', }, }, compoundVariants: [ // ── solid × color (filled foreground icon) ────────────────────── { variant: 'solid', color: 'action', className: 'text-content-action-on-strong' }, { variant: 'solid', color: 'danger', className: 'text-content-danger-on-strong' }, { variant: 'solid', color: 'warning', className: 'text-content-warning-on-strong' }, { variant: 'solid', color: 'success', className: 'text-content-success-on-strong' }, { variant: 'solid', color: 'info', className: 'text-content-info-on-strong' }, // ── outline/ghost × color (transparent foreground icon) ────────── { variant: ['outline', 'ghost'], color: 'action', className: 'text-content-action' }, { variant: ['outline', 'ghost'], color: 'danger', className: 'text-content-danger' }, { variant: ['outline', 'ghost'], color: 'warning', className: 'text-content-warning' }, { variant: ['outline', 'ghost'], color: 'success', className: 'text-content-success' }, { variant: ['outline', 'ghost'], color: 'info', className: 'text-content-info' }, ], defaultVariants: { variant: 'solid', color: 'action', size: 'default', }, }, ); export type ButtonVariantProps = VariantProps; export type ButtonGroupVariantProps = VariantProps;