import * as React from 'react' import * as Switch from '@radix-ui/react-switch' import { Info } from 'lucide-react' import { FieldWrapper } from '../shared/FieldWrapper' import type { SAILMarginSize } from '../../types/sail' /** * Displays a toggle (switch) for boolean input * Maps to SAIL's a!toggleField() */ export interface ToggleFieldProps { /** Text to display as the label next to the toggle */ choiceLabel?: string /** Determines if a value is required to submit the form */ required?: boolean /** Determines if the field should display as grayed out */ disabled?: boolean /** Current checked state (true = on, false = off) */ value?: boolean /** Validation errors to display below the field */ validations?: string[] /** Callback when the user toggles the switch */ saveInto?: (value: boolean) => void /** Callback when the user toggles the switch (React-style alias for saveInto) */ onChange?: (value: boolean) => void /** Validation group name (no spaces) */ validationGroup?: string /** Custom message when field is required and not provided */ requiredMessage?: string /** Displays a help icon next to the choice label with tooltip text */ helpTooltip?: string /** Additional text for screen readers */ accessibilityText?: string /** Determines whether component is displayed */ showWhen?: boolean /** Space added above component */ marginAbove?: SAILMarginSize /** Space added below component */ marginBelow?: SAILMarginSize /** Determines whether the toggle appears on the left or right of the choice label. Valid values: "START" (default), "END" */ choicePosition?: "START" | "END" /** Additional Tailwind classes for prototype-specific styling (not part of SAIL API) */ className?: string } export const ToggleField: React.FC = ({ choiceLabel, required = false, disabled = false, value = false, validations = [], saveInto, onChange, validationGroup: _validationGroup, requiredMessage, helpTooltip, accessibilityText, showWhen = true, marginAbove = "NONE", marginBelow = "STANDARD", choicePosition = "START", className }) => { // Visibility control if (!showWhen) return null const inputId = `togglefield-${Math.random().toString(36).substring(2, 11)}` const handleChange = (checked: boolean) => { const handler = onChange || saveInto if (handler && !disabled) { handler(checked) } } // Show validation errors const showValidations = validations.length > 0 // Show required message (default per SAIL docs: "Enable the toggle to continue") const resolvedRequiredMessage = requiredMessage || "Enable the toggle to continue" const showRequiredMessage = required && !value // The Radix switch control (fixed STANDARD size, ACCENT color) const switchControl = ( {value && ( )} ) // Inline label element (rendered next to the switch control) const inlineLabel = choiceLabel ? ( ) : null // The switch + inline label row // choicePosition="START" means toggle appears on the left of the label // choicePosition="END" means toggle appears on the right of the label const switchElement = (
{choicePosition === "END" ? ( <> {inlineLabel} {switchControl} ) : ( <> {switchControl} {inlineLabel} )}
) // Footer content (validations and required message) const footerContent = ( <> {showValidations && ( )} {showRequiredMessage && (

{resolvedRequiredMessage}

)} ) // Use FieldWrapper without a label — we handle the label inline return ( {switchElement} ) }