{
  "name": "mask-input-validation-modes-demo",
  "type": "registry:example",
  "registryDependencies": [
    "badge",
    "card",
    "label",
    "mask-input"
  ],
  "files": [
    {
      "path": "examples/mask-input-validation-modes-demo.tsx",
      "type": "registry:example",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { Badge } from \"@/registry/bases/radix/ui/badge\";\nimport { Button } from \"@/registry/bases/radix/ui/button\";\nimport { Label } from \"@/registry/bases/radix/ui/label\";\nimport { MaskInput } from \"@/registry/bases/radix/ui/mask-input\";\n\nconst modes = [\n  {\n    label: \"onChange\",\n    description: \"Validates on every keystroke\",\n    value: \"onChange\" as const,\n  },\n  {\n    label: \"onBlur\",\n    description: \"Validates when field loses focus\",\n    value: \"onBlur\" as const,\n  },\n  {\n    label: \"onTouched\",\n    description: \"Validates after first blur, then on change\",\n    value: \"onTouched\" as const,\n  },\n  {\n    label: \"onSubmit\",\n    description: \"Validates only on form submission\",\n    value: \"onSubmit\" as const,\n  },\n];\n\nexport default function MaskInputValidationModesDemo() {\n  const [validationStates, setValidationStates] = React.useState({\n    onChange: { isValid: true, message: \"\" },\n    onBlur: { isValid: true, message: \"\" },\n    onTouched: { isValid: true, message: \"\" },\n    onSubmit: { isValid: true, message: \"\" },\n  });\n\n  const [values, setValues] = React.useState({\n    onChange: \"\",\n    onBlur: \"\",\n    onTouched: \"\",\n    onSubmit: \"\",\n  });\n\n  const [submitAttempted, setSubmitAttempted] = React.useState(false);\n\n  const onValidate = React.useCallback(\n    (mode: keyof typeof validationStates) =>\n      (isValid: boolean, unmaskedValue: string) => {\n        const message = isValid\n          ? `✓ Valid (${unmaskedValue.length}/10)`\n          : `✗ Invalid (${unmaskedValue.length}/10)`;\n\n        setValidationStates((prev) => ({\n          ...prev,\n          [mode]: { isValid, message },\n        }));\n      },\n    [],\n  );\n\n  const onValueChange = React.useCallback(\n    (mode: keyof typeof values) =>\n      (_maskedValue: string, unmaskedValue: string) => {\n        setValues((prev) => ({\n          ...prev,\n          [mode]: unmaskedValue,\n        }));\n      },\n    [],\n  );\n\n  const onSubmit = React.useCallback(\n    (event: React.FormEvent) => {\n      event.preventDefault();\n      setSubmitAttempted(true);\n\n      const unmaskedValue = values.onSubmit;\n      const isValid = unmaskedValue.length === 10;\n      const message = isValid\n        ? `✓ Valid (${unmaskedValue.length}/10)`\n        : `✗ Invalid (${unmaskedValue.length}/10)`;\n\n      setValidationStates((prev) => ({\n        ...prev,\n        onSubmit: { isValid, message },\n      }));\n    },\n    [values.onSubmit],\n  );\n\n  return (\n    <div className=\"grid w-full gap-4 sm:grid-cols-2\">\n      {modes.map((mode) => (\n        <ValidationModeCard\n          key={mode.value}\n          mode={mode}\n          value={values[mode.value]}\n          validationState={validationStates[mode.value]}\n          onValueChange={onValueChange(mode.value)}\n          onValidate={onValidate(mode.value)}\n          onSubmit={mode.value === \"onSubmit\" ? onSubmit : undefined}\n          submitAttempted={submitAttempted}\n        />\n      ))}\n    </div>\n  );\n}\n\ninterface ValidationModeCardProps {\n  mode: (typeof modes)[number];\n  value: string;\n  validationState: { isValid: boolean; message: string };\n  onValueChange: (maskedValue: string, unmaskedValue: string) => void;\n  onValidate: (isValid: boolean, unmaskedValue: string) => void;\n  onSubmit?: (event: React.FormEvent) => void;\n  submitAttempted: boolean;\n}\n\nfunction ValidationModeCard({\n  mode,\n  value,\n  validationState,\n  onValueChange,\n  onValidate,\n  onSubmit,\n  submitAttempted,\n}: ValidationModeCardProps) {\n  const inputContent = (\n    <div className=\"flex flex-col gap-1\">\n      <Label htmlFor={`phone-${mode.value}`} className=\"sr-only\">\n        Phone Number\n      </Label>\n      <MaskInput\n        id={`phone-${mode.value}`}\n        mask=\"phone\"\n        validationMode={mode.value}\n        placeholder=\"Enter phone number\"\n        value={value}\n        onValueChange={onValueChange}\n        onValidate={onValidate}\n        invalid={!validationState.isValid}\n        className=\"h-8 text-sm\"\n      />\n    </div>\n  );\n\n  return (\n    <div className=\"flex flex-col gap-3 rounded-md border bg-card p-4 text-card-foreground shadow-sm\">\n      <div className=\"flex flex-col gap-1\">\n        <h4 className=\"text-xs font-medium\">{mode.label}</h4>\n        <p className=\"text-xs leading-tight text-muted-foreground\">\n          {mode.description}\n        </p>\n      </div>\n      {onSubmit ? (\n        <form onSubmit={onSubmit} className=\"flex flex-col gap-2\">\n          {inputContent}\n          <Button type=\"submit\" size=\"sm\" className=\"h-7 text-xs\">\n            Submit\n          </Button>\n        </form>\n      ) : (\n        inputContent\n      )}\n      <div className=\"flex items-center gap-1\">\n        <Badge\n          variant={validationState.isValid ? \"default\" : \"destructive\"}\n          className=\"h-5 px-1.5 text-xs\"\n        >\n          {validationState.isValid ? \"Valid\" : \"Invalid\"}\n        </Badge>\n        <span className=\"text-xs text-muted-foreground\">\n          {validationState.message ||\n            (mode.value === \"onSubmit\" && !submitAttempted\n              ? \"Click 'Submit' to check...\"\n              : \"Start typing to see validation...\")}\n        </span>\n      </div>\n    </div>\n  );\n}\n",
      "target": ""
    }
  ]
}