@zeno-lib/forms 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/package.json +21 -11
  2. package/src/addons/validation-spinner.tsx +3 -4
  3. package/src/create-form.tsx +49 -0
  4. package/src/create-zeno-form.tsx +531 -0
  5. package/src/fields/checkbox-field.tsx +15 -12
  6. package/src/fields/combobox-field.tsx +13 -14
  7. package/src/fields/date-picker-field.tsx +18 -15
  8. package/src/fields/input-field.tsx +12 -13
  9. package/src/fields/number-field.tsx +1 -2
  10. package/src/fields/otp-field.tsx +15 -12
  11. package/src/fields/radio-group-field.tsx +12 -13
  12. package/src/fields/reset-button.tsx +2 -3
  13. package/src/fields/select-field.tsx +12 -13
  14. package/src/fields/slider-field.tsx +11 -12
  15. package/src/fields/submit-button.tsx +3 -4
  16. package/src/fields/switch-field.tsx +15 -12
  17. package/src/fields/textarea-field.tsx +12 -13
  18. package/src/form-element.tsx +51 -0
  19. package/src/index.ts +14 -0
  20. package/src/lib/apply-validation-error.test.ts +1 -2
  21. package/src/lib/required-indicator.tsx +1 -1
  22. package/src/lib/schema-defaults.test.ts +1 -2
  23. package/src/lib/schema-required.test.ts +98 -6
  24. package/src/lib/schema-required.ts +126 -22
  25. package/src/lib/use-is-invalid.ts +4 -4
  26. package/src/lib/use-rebased-default-values.ts +42 -0
  27. package/src/lib/use-unsaved-changes-warning.ts +3 -3
  28. package/src/lib/validation-error.test.ts +1 -1
  29. package/src/lib/validation-logic.test.ts +1 -1
  30. package/src/lib/validation-modes.test-d.ts +1 -1
  31. package/src/lib/validation-modes.test.ts +12 -2
  32. package/src/lib/validation-modes.ts +3 -1
  33. package/src/use-app-fields.test-d.ts +8 -25
  34. package/src/use-app-fields.test.tsx +8 -32
  35. package/src/use-form.cascade.test.tsx +4 -6
  36. package/src/use-form.focus-invalid.test.tsx +198 -0
  37. package/src/use-form.reset-defaults.test.tsx +125 -0
  38. package/src/use-form.test-d.ts +2 -3
  39. package/src/use-form.test.tsx +12 -14
  40. package/src/use-form.unsaved-warning.test.tsx +4 -13
  41. package/src/use-form.validation-modes.test.tsx +10 -8
  42. package/src/form.tsx +0 -105
  43. package/src/use-app-fields.tsx +0 -272
  44. package/src/use-form.tsx +0 -450
@@ -1,272 +0,0 @@
1
- "use client"
2
-
3
- import type { DeepKeys } from "@tanstack/react-form"
4
- import { type ComponentProps, useMemo } from "react"
5
-
6
- import { CheckboxField as CheckboxFieldImpl } from "./fields/checkbox-field"
7
- import { ComboboxField as ComboboxFieldImpl } from "./fields/combobox-field"
8
- import { DatePickerField as DatePickerFieldImpl } from "./fields/date-picker-field"
9
- import { EmailField as EmailFieldImpl } from "./fields/email-field"
10
- import { InputField as InputFieldImpl } from "./fields/input-field"
11
- import { NumberField as NumberFieldImpl } from "./fields/number-field"
12
- import { OtpField as OtpFieldImpl } from "./fields/otp-field"
13
- import { PasswordField as PasswordFieldImpl } from "./fields/password-field"
14
- import { RadioGroupField as RadioGroupFieldImpl } from "./fields/radio-group-field"
15
- import { SelectField as SelectFieldImpl } from "./fields/select-field"
16
- import { SliderField as SliderFieldImpl } from "./fields/slider-field"
17
- import { SwitchField as SwitchFieldImpl } from "./fields/switch-field"
18
- import { TextAreaField as TextAreaFieldImpl } from "./fields/textarea-field"
19
-
20
- type FormDataOf<F> = F extends { state: { values: infer V } } ? V : never
21
-
22
- type AnyAppForm = {
23
- AppField: unknown
24
- state: { values: unknown }
25
- }
26
-
27
- type WithDefaultName<T, D extends string> =
28
- D extends DeepKeys<T> ? { name?: DeepKeys<T> } : { name: DeepKeys<T> }
29
-
30
- // Loose validators type for the typed wrappers — name-aware validator typing
31
- // from TanStack Form would collide with our per-field generics. Callers pass
32
- // standard schemas (Zod) or functions; both flow through to `<Field>` at
33
- // runtime unchanged. The structural shape mirrors TanStack's `FieldValidators`
34
- // slots so prop-name autocomplete still works.
35
- type AnyFieldValidators = {
36
- onMount?: unknown
37
- onChange?: unknown
38
- onChangeAsync?: unknown
39
- onChangeAsyncDebounceMs?: number
40
- onBlur?: unknown
41
- onBlurAsync?: unknown
42
- onBlurAsyncDebounceMs?: number
43
- onSubmit?: unknown
44
- onSubmitAsync?: unknown
45
- onSubmitAsyncDebounceMs?: number
46
- onDynamic?: unknown
47
- onDynamicAsync?: unknown
48
- }
49
-
50
- // Mirrors TanStack's `FieldListeners`. Same loose-shape rationale as
51
- // `AnyFieldValidators`: prop-name autocomplete with no per-field generic
52
- // collisions. Use for cascade patterns where changing one field updates
53
- // another (`form.setFieldValue(...)` inside `onChange`).
54
- type AnyFieldListeners = {
55
- onChange?: unknown
56
- onChangeDebounceMs?: number
57
- onBlur?: unknown
58
- onBlurDebounceMs?: number
59
- onMount?: unknown
60
- onSubmit?: unknown
61
- }
62
-
63
- type WithValidators = {
64
- validators?: AnyFieldValidators
65
- listeners?: AnyFieldListeners
66
- }
67
-
68
- function useAppFields<TForm extends AnyAppForm>(form: TForm) {
69
- type T = FormDataOf<TForm>
70
-
71
- return useMemo(() => {
72
- const Field = form.AppField as React.ComponentType<{
73
- name: string
74
- validators?: AnyFieldValidators
75
- listeners?: AnyFieldListeners
76
- children: () => React.ReactNode
77
- }>
78
-
79
- return {
80
- CheckboxField<N extends DeepKeys<T>>({
81
- name,
82
- validators,
83
- listeners,
84
- ...props
85
- }: ComponentProps<typeof CheckboxFieldImpl> & {
86
- name: N
87
- } & WithValidators) {
88
- return (
89
- <Field listeners={listeners} name={name} validators={validators}>
90
- {() => <CheckboxFieldImpl {...props} />}
91
- </Field>
92
- )
93
- },
94
- ComboboxField<N extends DeepKeys<T>>({
95
- name,
96
- validators,
97
- listeners,
98
- ...props
99
- }: ComponentProps<typeof ComboboxFieldImpl> & {
100
- name: N
101
- } & WithValidators) {
102
- return (
103
- <Field listeners={listeners} name={name} validators={validators}>
104
- {() => <ComboboxFieldImpl {...props} />}
105
- </Field>
106
- )
107
- },
108
- DatePickerField<N extends DeepKeys<T>>({
109
- name,
110
- validators,
111
- listeners,
112
- ...props
113
- }: ComponentProps<typeof DatePickerFieldImpl> & {
114
- name: N
115
- } & WithValidators) {
116
- return (
117
- <Field listeners={listeners} name={name} validators={validators}>
118
- {() => <DatePickerFieldImpl {...props} />}
119
- </Field>
120
- )
121
- },
122
- EmailField({
123
- name,
124
- validators,
125
- listeners,
126
- ...props
127
- }: ComponentProps<typeof EmailFieldImpl> &
128
- WithDefaultName<T, "email"> &
129
- WithValidators) {
130
- return (
131
- <Field
132
- listeners={listeners}
133
- name={(name ?? "email") as string}
134
- validators={validators}
135
- >
136
- {() => <EmailFieldImpl {...props} />}
137
- </Field>
138
- )
139
- },
140
- InputField<N extends DeepKeys<T>>({
141
- name,
142
- validators,
143
- listeners,
144
- ...props
145
- }: ComponentProps<typeof InputFieldImpl> & { name: N } & WithValidators) {
146
- return (
147
- <Field listeners={listeners} name={name} validators={validators}>
148
- {() => <InputFieldImpl {...props} />}
149
- </Field>
150
- )
151
- },
152
- NumberField<N extends DeepKeys<T>>({
153
- name,
154
- validators,
155
- listeners,
156
- ...props
157
- }: ComponentProps<typeof NumberFieldImpl> & {
158
- name: N
159
- } & WithValidators) {
160
- return (
161
- <Field listeners={listeners} name={name} validators={validators}>
162
- {() => <NumberFieldImpl {...props} />}
163
- </Field>
164
- )
165
- },
166
- OtpField<N extends DeepKeys<T>>({
167
- name,
168
- validators,
169
- listeners,
170
- ...props
171
- }: ComponentProps<typeof OtpFieldImpl> & {
172
- name: N
173
- } & WithValidators) {
174
- return (
175
- <Field listeners={listeners} name={name} validators={validators}>
176
- {() => <OtpFieldImpl {...props} />}
177
- </Field>
178
- )
179
- },
180
- PasswordField({
181
- name,
182
- validators,
183
- listeners,
184
- ...props
185
- }: ComponentProps<typeof PasswordFieldImpl> &
186
- WithDefaultName<T, "password"> &
187
- WithValidators) {
188
- return (
189
- <Field
190
- listeners={listeners}
191
- name={(name ?? "password") as string}
192
- validators={validators}
193
- >
194
- {() => <PasswordFieldImpl {...props} />}
195
- </Field>
196
- )
197
- },
198
- RadioGroupField<N extends DeepKeys<T>>({
199
- name,
200
- validators,
201
- listeners,
202
- ...props
203
- }: ComponentProps<typeof RadioGroupFieldImpl> & {
204
- name: N
205
- } & WithValidators) {
206
- return (
207
- <Field listeners={listeners} name={name} validators={validators}>
208
- {() => <RadioGroupFieldImpl {...props} />}
209
- </Field>
210
- )
211
- },
212
- SelectField<N extends DeepKeys<T>>({
213
- name,
214
- validators,
215
- listeners,
216
- ...props
217
- }: ComponentProps<typeof SelectFieldImpl> & {
218
- name: N
219
- } & WithValidators) {
220
- return (
221
- <Field listeners={listeners} name={name} validators={validators}>
222
- {() => <SelectFieldImpl {...props} />}
223
- </Field>
224
- )
225
- },
226
- SliderField<N extends DeepKeys<T>>({
227
- name,
228
- validators,
229
- listeners,
230
- ...props
231
- }: ComponentProps<typeof SliderFieldImpl> & {
232
- name: N
233
- } & WithValidators) {
234
- return (
235
- <Field listeners={listeners} name={name} validators={validators}>
236
- {() => <SliderFieldImpl {...props} />}
237
- </Field>
238
- )
239
- },
240
- SwitchField<N extends DeepKeys<T>>({
241
- name,
242
- validators,
243
- listeners,
244
- ...props
245
- }: ComponentProps<typeof SwitchFieldImpl> & {
246
- name: N
247
- } & WithValidators) {
248
- return (
249
- <Field listeners={listeners} name={name} validators={validators}>
250
- {() => <SwitchFieldImpl {...props} />}
251
- </Field>
252
- )
253
- },
254
- TextAreaField<N extends DeepKeys<T>>({
255
- name,
256
- validators,
257
- listeners,
258
- ...props
259
- }: ComponentProps<typeof TextAreaFieldImpl> & {
260
- name: N
261
- } & WithValidators) {
262
- return (
263
- <Field listeners={listeners} name={name} validators={validators}>
264
- {() => <TextAreaFieldImpl {...props} />}
265
- </Field>
266
- )
267
- },
268
- }
269
- }, [form])
270
- }
271
-
272
- export { useAppFields }