Generated by Spark: Load more of UI from JSON declarations and break up large components into atomic and create hooks as needed

This commit is contained in:
2026-01-17 11:38:28 +00:00
committed by GitHub
parent 19a44c4010
commit 3ae07db657
28 changed files with 2227 additions and 465 deletions

View File

@@ -1,2 +1,2 @@
export * from './use-form'
export * from './use-form-field'
export { useFormField, useForm } from './use-form-field'
export type { ValidationRule, FieldConfig, FormConfig } from './use-form-field'

View File

@@ -1,33 +1,40 @@
import { useState, useCallback } from 'react'
export type ValidationRule<T> = {
export interface ValidationRule<T = any> {
validate: (value: T) => boolean
message: string
}
export function useFormField<T>(
initialValue: T,
rules: ValidationRule<T>[] = []
) {
const [value, setValue] = useState<T>(initialValue)
export interface FieldConfig<T = any> {
name: string
defaultValue?: T
rules?: ValidationRule<T>[]
}
export function useFormField<T = any>(config: FieldConfig<T>) {
const [value, setValue] = useState<T | undefined>(config.defaultValue)
const [error, setError] = useState<string | null>(null)
const [touched, setTouched] = useState(false)
const validate = useCallback(() => {
for (const rule of rules) {
if (!rule.validate(value)) {
if (!config.rules || !touched) return true
for (const rule of config.rules) {
if (!rule.validate(value as T)) {
setError(rule.message)
return false
}
}
setError(null)
return true
}, [value, rules])
}, [value, config.rules, touched])
const onChange = useCallback((newValue: T) => {
setValue(newValue)
setTouched(true)
}, [])
if (touched) {
setError(null)
}
}, [touched])
const onBlur = useCallback(() => {
setTouched(true)
@@ -35,20 +42,43 @@ export function useFormField<T>(
}, [validate])
const reset = useCallback(() => {
setValue(initialValue)
setValue(config.defaultValue)
setError(null)
setTouched(false)
}, [initialValue])
}, [config.defaultValue])
return {
value,
setValue,
onChange,
onBlur,
error,
touched,
isValid: error === null && touched,
validate,
onChange,
onBlur,
reset,
validate,
isValid: error === null,
isDirty: value !== config.defaultValue,
}
}
export interface FormConfig {
fields: Record<string, FieldConfig>
onSubmit?: (values: Record<string, any>) => void | Promise<void>
}
export function useForm(config: FormConfig) {
const [isSubmitting, setIsSubmitting] = useState(false)
const submit = useCallback(async (values: Record<string, any>) => {
setIsSubmitting(true)
try {
await config.onSubmit?.(values)
} finally {
setIsSubmitting(false)
}
}, [config])
return {
submit,
isSubmitting,
}
}