import { Platform } from 'react-native'; import { cva } from 'class-variance-authority'; import { DISABLED_CURSOR, DISABLED_OPACITY, TRANSITION_COLORS } from '../../styles/constants'; // TODO: Handle text wrapping in the label export const checkboxRootVariants = cva([ 'flex-row items-center gap-2.5', DISABLED_OPACITY, DISABLED_CURSOR, // Suppress stray outline on the Pressable/label wrapper; focus ring is drawn on Checkbox.Indicator (Radio pattern). 'web:outline-none web:focus:outline-none web:focus-visible:outline-none', ]); export const checkboxIndicatorVariants = cva([ 'items-center justify-center', 'h-5 w-5', 'rounded', 'border-2 border-solid', 'data-[disabled=true]:opacity-50', // Background — layered by specificity. checked=false acts as an explicit reset so the base bg // reasserts when transitioning from checked/indeterminate on native (where absent attributes // break data-[attr=false] selectors). // IMPORTANT: On native (Uniwind), only the LAST data-[] condition in a compound chain is // effectively evaluated. Place the most discriminating condition last to avoid false matches. 'data-[checked=false]:bg-surface-primary', 'data-[checked=true]:bg-surface-action-strong', 'data-[indeterminate=true]:bg-surface-action-strong', // Border — invalid (later) beats checked/indeterminate. 'data-[checked=false]:border-content-secondary', 'data-[checked=true]:border-stroke-action', 'data-[indeterminate=true]:border-stroke-action', 'data-[invalid=true]:border-stroke-danger', Platform.select({ web: [ // Invalid bg — compound selectors evaluate correctly on web. 'data-[invalid=true]:data-[checked=true]:bg-surface-danger-strong', 'data-[invalid=true]:data-[indeterminate=true]:bg-surface-danger-strong', TRANSITION_COLORS, // Hover — unchecked (Figma: border unchanged, bg overlay at opacity/hover) 'data-[hover=true]:data-[checked=false]:data-[indeterminate=false]:bg-content-secondary/[0.08]', // Hover — unchecked + invalid (overlay uses danger token) 'data-[hover=true]:data-[invalid=true]:data-[checked=false]:data-[indeterminate=false]:bg-surface-danger-strong/[0.08]', // Hover — checked / indeterminate (bg + border darken together) 'data-[hover=true]:data-[checked=true]:bg-surface-action-strong-hover', 'data-[hover=true]:data-[checked=true]:border-surface-action-strong-hover', 'data-[hover=true]:data-[indeterminate=true]:bg-surface-action-strong-hover', 'data-[hover=true]:data-[indeterminate=true]:border-surface-action-strong-hover', 'data-[hover=true]:data-[checked=true]:data-[invalid=true]:bg-surface-danger-strong-hover', 'data-[hover=true]:data-[checked=true]:data-[invalid=true]:border-surface-danger-strong-hover', 'data-[hover=true]:data-[indeterminate=true]:data-[invalid=true]:bg-surface-danger-strong-hover', 'data-[hover=true]:data-[indeterminate=true]:data-[invalid=true]:border-surface-danger-strong-hover', // Active — CSS :active pseudo-class (web root does not track press via data-active). // data-[hover=true] guard ensures active beats hover by specificity (0,3,0 > 0,2,0). // Unchecked — border only (Radio pattern) 'web:active:data-[hover=true]:data-[checked=false]:data-[indeterminate=false]:border-stroke-hover', 'web:active:data-[hover=true]:data-[invalid=true]:data-[checked=false]:data-[indeterminate=false]:border-surface-danger-strong-active', 'web:active:data-[hover=true]:data-[checked=true]:bg-surface-action-strong-active', 'web:active:data-[hover=true]:data-[checked=true]:border-surface-action-strong-active', 'web:active:data-[hover=true]:data-[indeterminate=true]:bg-surface-action-strong-active', 'web:active:data-[hover=true]:data-[indeterminate=true]:border-surface-action-strong-active', 'web:active:data-[hover=true]:data-[checked=true]:data-[invalid=true]:bg-surface-danger-strong-active', 'web:active:data-[hover=true]:data-[checked=true]:data-[invalid=true]:border-surface-danger-strong-active', 'web:active:data-[hover=true]:data-[indeterminate=true]:data-[invalid=true]:bg-surface-danger-strong-active', 'web:active:data-[hover=true]:data-[indeterminate=true]:data-[invalid=true]:border-surface-danger-strong-active', // Focus ring 'web:data-[focus-visible=true]:outline-none', 'web:data-[focus-visible=true]:ring-2 web:data-[focus-visible=true]:ring-stroke-focus web:data-[focus-visible=true]:ring-offset-2', ].join(' '), default: [ // Native: Uniwind only evaluates the last data-[] condition in a compound chain. // Use single-condition data-[field-state=...] selectors (emitted by CheckboxIndicator). // checked/indeterminate + invalid → danger bg 'data-[field-state=checked-invalid]:bg-surface-danger-strong', 'data-[field-state=indeterminate-invalid]:bg-surface-danger-strong', // unchecked + active → border only (Radio pattern) 'data-[field-state=active]:border-stroke-hover', 'data-[field-state=invalid-active]:border-surface-danger-strong-active', // checked/indeterminate + active → action active bg + matching border 'data-[field-state=checked-active]:bg-surface-action-strong-active', 'data-[field-state=checked-active]:border-surface-action-strong-active', 'data-[field-state=indeterminate-active]:bg-surface-action-strong-active', 'data-[field-state=indeterminate-active]:border-surface-action-strong-active', // checked/indeterminate + invalid + active → danger active bg + matching border 'data-[field-state=checked-invalid-active]:bg-surface-danger-strong-active', 'data-[field-state=checked-invalid-active]:border-surface-danger-strong-active', 'data-[field-state=indeterminate-invalid-active]:bg-surface-danger-strong-active', 'data-[field-state=indeterminate-invalid-active]:border-surface-danger-strong-active', ].join(' '), }), ]); export const checkboxIconVariants = cva(['text-white', 'h-5 w-5']); export const checkboxLabelVariants = cva([ 'text-content-primary text-base', 'data-[disabled=true]:text-content-tertiary', ]); export const checkboxGroupVariants = cva([], { variants: { direction: { column: 'gap-2', row: 'flex-row gap-4', }, }, defaultVariants: { direction: 'column', }, });