{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "regex-input", "type": "registry:component", "registryDependencies": [ "input" ], "files": [ { "path": "components/domain-ui/regex-input.tsx", "content": "\"use client\";\n\nimport type * as React from \"react\";\nimport { Input } from \"@/components/ui/input\";\nimport {\n useSimpleRegex,\n type ValidationStatusType,\n} from \"@/hooks/use-simple-regex\";\n\nexport interface RegexInputProps extends React.ComponentProps<\"input\"> {\n regex: RegExp;\n onValidation?: (status: ValidationStatusType) => void;\n transformToUppercase?: boolean;\n}\n\nexport function RegexInput({\n regex,\n value,\n onChange,\n onValidation,\n defaultValue,\n transformToUppercase,\n ...props\n}: RegexInputProps) {\n const { value: displayValue, onChange: handleChange } = useSimpleRegex({\n regex,\n value: value as string | undefined,\n onChange: onChange\n ? (newValue: string) => {\n const syntheticEvent = {\n target: { value: newValue },\n currentTarget: { value: newValue },\n } as React.ChangeEvent;\n onChange(syntheticEvent);\n }\n : undefined,\n onValidation,\n defaultValue: defaultValue as string | undefined,\n transformToUppercase,\n });\n\n return ;\n}\n", "type": "registry:component" }, { "path": "hooks/use-simple-regex.ts", "content": "\"use client\";\n\nimport { useState, useCallback, useMemo, useEffect } from \"react\";\n\n/**\n * Simple Regex Validation Hook\n *\n * Provides basic regex validation without incremental matching.\n * Just validates if the full input matches the pattern.\n *\n * No NFA dependencies - uses native RegExp.test() only.\n */\n\nexport const ValidationStatus = {\n Valid: \"valid\",\n Invalid: \"invalid\",\n} as const;\n\nexport type ValidationStatusType =\n (typeof ValidationStatus)[keyof typeof ValidationStatus];\n\nexport interface UseSimpleRegexProps {\n regex: RegExp;\n value?: string;\n onChange?: (value: string) => void;\n onValidation?: (status: ValidationStatusType) => void;\n defaultValue?: string;\n transformToUppercase?: boolean;\n}\n\nexport interface UseSimpleRegexReturn {\n value: string;\n onChange: (e: React.ChangeEvent) => void;\n isValid: boolean;\n validationStatus: ValidationStatusType;\n}\n\nexport const useSimpleRegex = ({\n regex,\n value: controlledValue,\n onChange,\n onValidation,\n defaultValue,\n transformToUppercase,\n}: UseSimpleRegexProps): UseSimpleRegexReturn => {\n const [uncontrolledValue, setUncontrolledValue] = useState(\n defaultValue || \"\"\n );\n\n // Use controlled value if provided, otherwise use internal state\n const value =\n controlledValue !== undefined ? controlledValue : uncontrolledValue;\n\n // Simple validation - just test if it matches\n const { isValid, validationStatus } = useMemo(() => {\n const matches = regex.test(value);\n const status: ValidationStatusType = matches\n ? ValidationStatus.Valid\n : ValidationStatus.Invalid;\n\n return {\n isValid: matches,\n validationStatus: status,\n };\n }, [value, regex]);\n\n // Notify validation changes\n useEffect(() => {\n if (onValidation) {\n onValidation(validationStatus);\n }\n }, [validationStatus, onValidation]);\n\n // Handle input changes\n const handleChange = useCallback(\n (e: React.ChangeEvent) => {\n let newValue = e.target.value;\n \n // Transform to uppercase if requested\n if (transformToUppercase) {\n newValue = newValue.toUpperCase();\n }\n\n // Update state if uncontrolled\n if (controlledValue === undefined) {\n setUncontrolledValue(newValue);\n }\n\n // Call onChange callback\n if (onChange) {\n onChange(newValue);\n }\n },\n [controlledValue, onChange, transformToUppercase]\n );\n\n return {\n value,\n onChange: handleChange,\n isValid,\n validationStatus,\n };\n};\n", "type": "registry:hook" } ], "meta": { "tags": [ "input", "regex", "validation", "form", "simple" ] } }