@saas-ui/forms 3.0.0-alpha.1 → 3.0.0-alpha.10
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.
- package/CHANGELOG.md +80 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -29
- package/dist/ajv/index.d.mts +0 -35
- package/dist/ajv/index.d.ts +0 -35
- package/dist/ajv/index.js +0 -57
- package/dist/ajv/index.js.map +0 -1
- package/dist/ajv/index.mjs +0 -30
- package/dist/ajv/index.mjs.map +0 -1
- package/src/array-field.tsx +0 -266
- package/src/auto-form.tsx +0 -71
- package/src/base-field.tsx +0 -69
- package/src/create-field.tsx +0 -171
- package/src/create-form.tsx +0 -100
- package/src/create-step-form.tsx +0 -118
- package/src/default-fields.tsx +0 -233
- package/src/display-field.tsx +0 -46
- package/src/display-if.tsx +0 -69
- package/src/field-resolver.ts +0 -66
- package/src/field.tsx +0 -44
- package/src/fields-context.tsx +0 -33
- package/src/fields.tsx +0 -93
- package/src/form-context.tsx +0 -80
- package/src/form-layout.tsx +0 -59
- package/src/form.tsx +0 -252
- package/src/index.ts +0 -310
- package/src/object-field.tsx +0 -58
- package/src/step-form.tsx +0 -191
- package/src/submit-button.tsx +0 -71
- package/src/types.ts +0 -242
- package/src/use-array-field.tsx +0 -158
- package/src/use-form.tsx +0 -24
- package/src/use-step-form.tsx +0 -201
- package/src/utils.ts +0 -35
- package/src/watch-field.tsx +0 -37
package/src/fields.tsx
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
import * as React from 'react'
|
2
|
-
|
3
|
-
import { ArrayField } from './array-field'
|
4
|
-
import { Field } from './field'
|
5
|
-
import { FieldResolver } from './field-resolver'
|
6
|
-
import { useFormContext } from './form-context'
|
7
|
-
import { FormLayout } from './form-layout'
|
8
|
-
import { ObjectField } from './object-field'
|
9
|
-
import { BaseFieldProps } from './types'
|
10
|
-
|
11
|
-
export interface FieldsProps<TSchema = any> {
|
12
|
-
schema?: TSchema
|
13
|
-
fieldResolver?: FieldResolver
|
14
|
-
focusFirstField?: boolean
|
15
|
-
}
|
16
|
-
|
17
|
-
const mapNestedFields = (resolver: FieldResolver, name: string) => {
|
18
|
-
return resolver
|
19
|
-
.getNestedFields(name)
|
20
|
-
?.map(
|
21
|
-
(
|
22
|
-
{ name, type, ...nestedFieldProps }: BaseFieldProps,
|
23
|
-
i,
|
24
|
-
): React.ReactNode => (
|
25
|
-
<Field
|
26
|
-
key={name || i}
|
27
|
-
name={name}
|
28
|
-
type={type as any}
|
29
|
-
{...nestedFieldProps}
|
30
|
-
/>
|
31
|
-
),
|
32
|
-
)
|
33
|
-
}
|
34
|
-
|
35
|
-
export const AutoFields: React.FC<FieldsProps> = ({
|
36
|
-
schema: schemaProp,
|
37
|
-
fieldResolver: fieldResolverProp,
|
38
|
-
focusFirstField,
|
39
|
-
...props
|
40
|
-
}) => {
|
41
|
-
const context = useFormContext()
|
42
|
-
const schema = schemaProp || context.schema
|
43
|
-
const fieldResolver = fieldResolverProp || context.fieldResolver
|
44
|
-
const resolver = React.useMemo(() => fieldResolver, [schema, fieldResolver])
|
45
|
-
|
46
|
-
const fields = React.useMemo(() => resolver?.getFields(), [resolver])
|
47
|
-
|
48
|
-
const form = useFormContext()
|
49
|
-
|
50
|
-
React.useEffect(() => {
|
51
|
-
if (focusFirstField && fields?.[0]?.name) {
|
52
|
-
form.setFocus(fields[0].name)
|
53
|
-
}
|
54
|
-
}, [schema, fieldResolver, focusFirstField])
|
55
|
-
|
56
|
-
if (!resolver) {
|
57
|
-
return null
|
58
|
-
}
|
59
|
-
|
60
|
-
return (
|
61
|
-
<FormLayout {...props}>
|
62
|
-
{fields?.map(
|
63
|
-
({ name, type, ...fieldProps }: BaseFieldProps): React.ReactNode => {
|
64
|
-
if (type === 'array') {
|
65
|
-
return (
|
66
|
-
<ArrayField key={name} name={name} {...fieldProps}>
|
67
|
-
{mapNestedFields(resolver, name)}
|
68
|
-
</ArrayField>
|
69
|
-
)
|
70
|
-
} else if (type === 'object') {
|
71
|
-
return (
|
72
|
-
<ObjectField key={name} name={name} {...fieldProps}>
|
73
|
-
{mapNestedFields(resolver, name)}
|
74
|
-
</ObjectField>
|
75
|
-
)
|
76
|
-
}
|
77
|
-
|
78
|
-
return (
|
79
|
-
<Field
|
80
|
-
key={name}
|
81
|
-
name={name}
|
82
|
-
type={type as any}
|
83
|
-
// defaultValue={defaultValue}
|
84
|
-
{...fieldProps}
|
85
|
-
/>
|
86
|
-
)
|
87
|
-
},
|
88
|
-
)}
|
89
|
-
</FormLayout>
|
90
|
-
)
|
91
|
-
}
|
92
|
-
|
93
|
-
AutoFields.displayName = 'Fields'
|
package/src/form-context.tsx
DELETED
@@ -1,80 +0,0 @@
|
|
1
|
-
import * as React from 'react'
|
2
|
-
import {
|
3
|
-
FormProvider as HookFormProvider,
|
4
|
-
FormProviderProps as HookFormProviderProps,
|
5
|
-
useFormContext as useHookFormContext,
|
6
|
-
FieldValues,
|
7
|
-
} from 'react-hook-form'
|
8
|
-
import { FieldResolver } from './field-resolver'
|
9
|
-
import type { BaseFieldProps } from './types'
|
10
|
-
|
11
|
-
export type FormContextValue<
|
12
|
-
TFieldValues extends FieldValues = FieldValues,
|
13
|
-
TContext = any,
|
14
|
-
TSchema = any,
|
15
|
-
> = {
|
16
|
-
fieldResolver?: FieldResolver
|
17
|
-
schema?: TSchema
|
18
|
-
fields?: {
|
19
|
-
[key: string]: unknown
|
20
|
-
}
|
21
|
-
}
|
22
|
-
|
23
|
-
export type FormProviderProps<
|
24
|
-
TFieldValues extends FieldValues = FieldValues,
|
25
|
-
TContext = any,
|
26
|
-
TSchema = any,
|
27
|
-
> = HookFormProviderProps<TFieldValues, TContext> & {
|
28
|
-
fieldResolver?: FieldResolver
|
29
|
-
schema?: TSchema
|
30
|
-
fields?: {
|
31
|
-
[key: string]: unknown
|
32
|
-
}
|
33
|
-
}
|
34
|
-
|
35
|
-
const FormContext = React.createContext<FormContextValue | null>(null)
|
36
|
-
|
37
|
-
export const useFormContext = <
|
38
|
-
TFieldValues extends FieldValues = FieldValues,
|
39
|
-
TContext = any,
|
40
|
-
TSchema = any,
|
41
|
-
>() => {
|
42
|
-
const context = React.useContext(FormContext)
|
43
|
-
const hookContext = useHookFormContext<TFieldValues, TContext>()
|
44
|
-
|
45
|
-
return {
|
46
|
-
...hookContext,
|
47
|
-
...context,
|
48
|
-
}
|
49
|
-
}
|
50
|
-
|
51
|
-
export const useFieldProps = <TFieldValues extends FieldValues = FieldValues>(
|
52
|
-
name: string
|
53
|
-
): BaseFieldProps<TFieldValues> | undefined => {
|
54
|
-
const parsedName = name?.replace(/\.[0-9]/g, '.$')
|
55
|
-
const context = useFormContext()
|
56
|
-
return (context?.fields?.[parsedName] as any) || {}
|
57
|
-
}
|
58
|
-
|
59
|
-
export type UseFormReturn<
|
60
|
-
TFieldValues extends FieldValues = FieldValues,
|
61
|
-
TContext = any,
|
62
|
-
TSchema = any,
|
63
|
-
> = ReturnType<typeof useFormContext<TFieldValues, TContext, TSchema>>
|
64
|
-
|
65
|
-
export const FormProvider = <
|
66
|
-
TFieldValues extends FieldValues = FieldValues,
|
67
|
-
TContext = any,
|
68
|
-
TSchema = any,
|
69
|
-
>(
|
70
|
-
props: FormProviderProps<TFieldValues, TContext, TSchema>
|
71
|
-
) => {
|
72
|
-
const { children, fieldResolver, schema, fields, ...rest } = props
|
73
|
-
return (
|
74
|
-
<HookFormProvider {...rest}>
|
75
|
-
<FormContext.Provider value={{ fieldResolver, schema, fields }}>
|
76
|
-
{children}
|
77
|
-
</FormContext.Provider>
|
78
|
-
</HookFormProvider>
|
79
|
-
)
|
80
|
-
}
|
package/src/form-layout.tsx
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
import { forwardRef } from 'react'
|
2
|
-
|
3
|
-
import {
|
4
|
-
type HTMLChakraProps,
|
5
|
-
type RecipeProps,
|
6
|
-
SimpleGrid,
|
7
|
-
SimpleGridProps,
|
8
|
-
useRecipe,
|
9
|
-
} from '@chakra-ui/react'
|
10
|
-
import { cx } from '@saas-ui/core/utils'
|
11
|
-
|
12
|
-
export interface FormLayoutOptions {
|
13
|
-
columns?: SimpleGridProps['columns']
|
14
|
-
gap?: SimpleGridProps['gap']
|
15
|
-
}
|
16
|
-
|
17
|
-
export interface FormLayoutProps
|
18
|
-
extends RecipeProps<'formLayout'>,
|
19
|
-
FormLayoutOptions,
|
20
|
-
Omit<HTMLChakraProps<'div'>, 'columns'> {}
|
21
|
-
|
22
|
-
/**
|
23
|
-
* Create consistent field spacing and positioning.
|
24
|
-
*
|
25
|
-
* Renders form items in a `SimpleGrid`
|
26
|
-
* @see https://chakra-ui.com/docs/layout/simple-grid
|
27
|
-
*
|
28
|
-
* @see https://saas-ui.dev/docs/components/forms/form
|
29
|
-
*/
|
30
|
-
export const FormLayout = forwardRef<HTMLDivElement, FormLayoutProps>(
|
31
|
-
({ children, rowGap = 4, ...props }, ref) => {
|
32
|
-
const recipe = useRecipe({
|
33
|
-
key: 'formLayout',
|
34
|
-
})
|
35
|
-
|
36
|
-
const [variantProps, gridProps] = recipe.splitVariantProps(props)
|
37
|
-
|
38
|
-
const styles = recipe(variantProps)
|
39
|
-
|
40
|
-
return (
|
41
|
-
<SimpleGrid
|
42
|
-
ref={ref}
|
43
|
-
{...gridProps}
|
44
|
-
className={cx('sui-form-layout', props.className)}
|
45
|
-
css={[
|
46
|
-
{
|
47
|
-
rowGap,
|
48
|
-
},
|
49
|
-
styles,
|
50
|
-
props.css,
|
51
|
-
]}
|
52
|
-
>
|
53
|
-
{children}
|
54
|
-
</SimpleGrid>
|
55
|
-
)
|
56
|
-
},
|
57
|
-
)
|
58
|
-
|
59
|
-
FormLayout.displayName = 'FormLayout'
|
package/src/form.tsx
DELETED
@@ -1,252 +0,0 @@
|
|
1
|
-
import React, { forwardRef } from 'react'
|
2
|
-
|
3
|
-
import { HTMLChakraProps, chakra } from '@chakra-ui/react'
|
4
|
-
import { type MaybeRenderProp, cx, runIfFn } from '@saas-ui/core/utils'
|
5
|
-
import {
|
6
|
-
FieldValues,
|
7
|
-
ResolverOptions,
|
8
|
-
ResolverResult,
|
9
|
-
SubmitErrorHandler,
|
10
|
-
SubmitHandler,
|
11
|
-
UseFormProps,
|
12
|
-
UseFormReturn,
|
13
|
-
WatchObserver,
|
14
|
-
useForm,
|
15
|
-
} from 'react-hook-form'
|
16
|
-
|
17
|
-
import { ArrayField, ArrayFieldProps } from './array-field.tsx'
|
18
|
-
import { DisplayIf, DisplayIfProps } from './display-if.tsx'
|
19
|
-
import { FieldResolver } from './field-resolver.tsx'
|
20
|
-
import { Field as DefaultField } from './field.tsx'
|
21
|
-
import { AutoFields } from './fields.tsx'
|
22
|
-
import { FormProvider } from './form-context.tsx'
|
23
|
-
import { FormLayout } from './form-layout.tsx'
|
24
|
-
import { ObjectField, ObjectFieldProps } from './object-field.tsx'
|
25
|
-
import { SubmitButton } from './submit-button.tsx'
|
26
|
-
import {
|
27
|
-
DefaultFieldOverrides,
|
28
|
-
FieldProps,
|
29
|
-
type FocusableElement,
|
30
|
-
} from './types.ts'
|
31
|
-
import { UseArrayFieldReturn } from './use-array-field.tsx'
|
32
|
-
|
33
|
-
export type { UseFormReturn, FieldValues, SubmitHandler }
|
34
|
-
|
35
|
-
export interface FormRenderContext<
|
36
|
-
TFieldValues extends FieldValues = FieldValues,
|
37
|
-
TContext extends object = object,
|
38
|
-
TFieldTypes = FieldProps<TFieldValues>,
|
39
|
-
> extends UseFormReturn<TFieldValues, TContext> {
|
40
|
-
Field: React.FC<TFieldTypes & React.RefAttributes<FocusableElement>>
|
41
|
-
DisplayIf: React.FC<DisplayIfProps<TFieldValues>>
|
42
|
-
ArrayField: React.FC<
|
43
|
-
ArrayFieldProps<TFieldValues> & React.RefAttributes<UseArrayFieldReturn>
|
44
|
-
>
|
45
|
-
ObjectField: React.FC<ObjectFieldProps<TFieldValues>>
|
46
|
-
}
|
47
|
-
|
48
|
-
interface FormOptions<
|
49
|
-
TSchema = unknown,
|
50
|
-
TFieldValues extends FieldValues = FieldValues,
|
51
|
-
TContext extends object = object,
|
52
|
-
TExtraFieldProps extends object = object,
|
53
|
-
TFieldTypes = FieldProps<TFieldValues, TExtraFieldProps>,
|
54
|
-
> {
|
55
|
-
/**
|
56
|
-
* The form schema.
|
57
|
-
*/
|
58
|
-
schema?: TSchema
|
59
|
-
/**
|
60
|
-
* Triggers when any of the field change.
|
61
|
-
*/
|
62
|
-
onChange?: WatchObserver<TFieldValues>
|
63
|
-
/**
|
64
|
-
* The submit handler.
|
65
|
-
*/
|
66
|
-
onSubmit: SubmitHandler<TFieldValues>
|
67
|
-
/**
|
68
|
-
* Triggers when there are validation errors.
|
69
|
-
*/
|
70
|
-
onError?: SubmitErrorHandler<TFieldValues>
|
71
|
-
/**
|
72
|
-
* The Hook Form state ref.
|
73
|
-
*/
|
74
|
-
formRef?: React.Ref<UseFormReturn<TFieldValues, TContext>>
|
75
|
-
/**
|
76
|
-
* The form children, can be a render prop or a ReactNode.
|
77
|
-
*/
|
78
|
-
children?: MaybeRenderProp<
|
79
|
-
FormRenderContext<TFieldValues, TContext, TFieldTypes>
|
80
|
-
>
|
81
|
-
/**
|
82
|
-
* The field resolver, used to resolve the fields from schemas.
|
83
|
-
*/
|
84
|
-
fieldResolver?: FieldResolver
|
85
|
-
/**
|
86
|
-
* Field overrides
|
87
|
-
*/
|
88
|
-
fields?: DefaultFieldOverrides
|
89
|
-
}
|
90
|
-
|
91
|
-
export interface FormProps<
|
92
|
-
TSchema = unknown,
|
93
|
-
TFieldValues extends FieldValues = FieldValues,
|
94
|
-
TContext extends object = object,
|
95
|
-
TExtraFieldProps extends object = object,
|
96
|
-
TFieldTypes = FieldProps<TFieldValues, TExtraFieldProps>,
|
97
|
-
> extends UseFormProps<TFieldValues, TContext>,
|
98
|
-
Omit<
|
99
|
-
HTMLChakraProps<'form'>,
|
100
|
-
'children' | 'onChange' | 'onSubmit' | 'onError'
|
101
|
-
>,
|
102
|
-
FormOptions<
|
103
|
-
TSchema,
|
104
|
-
TFieldValues,
|
105
|
-
TContext,
|
106
|
-
TExtraFieldProps,
|
107
|
-
TFieldTypes
|
108
|
-
> {}
|
109
|
-
|
110
|
-
/**
|
111
|
-
* The wrapper component provides context, state, and focus management.
|
112
|
-
*
|
113
|
-
* @see Docs https://saas-ui.dev/docs/components/forms/form
|
114
|
-
*/
|
115
|
-
export const Form = forwardRef(
|
116
|
-
<
|
117
|
-
TSchema = any,
|
118
|
-
TFieldValues extends FieldValues = FieldValues,
|
119
|
-
TContext extends object = object,
|
120
|
-
TExtraFieldProps extends object = object,
|
121
|
-
TFieldTypes = FieldProps<TFieldValues>,
|
122
|
-
>(
|
123
|
-
props: FormProps<
|
124
|
-
TSchema,
|
125
|
-
TFieldValues,
|
126
|
-
TContext,
|
127
|
-
TExtraFieldProps,
|
128
|
-
TFieldTypes
|
129
|
-
>,
|
130
|
-
ref: React.ForwardedRef<HTMLFormElement>,
|
131
|
-
) => {
|
132
|
-
const {
|
133
|
-
mode = 'all',
|
134
|
-
resolver,
|
135
|
-
fieldResolver,
|
136
|
-
fields,
|
137
|
-
reValidateMode,
|
138
|
-
shouldFocusError,
|
139
|
-
shouldUnregister,
|
140
|
-
shouldUseNativeValidation,
|
141
|
-
criteriaMode,
|
142
|
-
delayError,
|
143
|
-
schema,
|
144
|
-
defaultValues,
|
145
|
-
values,
|
146
|
-
context,
|
147
|
-
resetOptions,
|
148
|
-
onChange,
|
149
|
-
onSubmit,
|
150
|
-
onError,
|
151
|
-
formRef,
|
152
|
-
children,
|
153
|
-
...rest
|
154
|
-
} = props
|
155
|
-
|
156
|
-
const form = {
|
157
|
-
mode,
|
158
|
-
resolver,
|
159
|
-
defaultValues,
|
160
|
-
values,
|
161
|
-
reValidateMode,
|
162
|
-
shouldFocusError,
|
163
|
-
shouldUnregister,
|
164
|
-
shouldUseNativeValidation,
|
165
|
-
criteriaMode,
|
166
|
-
delayError,
|
167
|
-
context,
|
168
|
-
resetOptions,
|
169
|
-
}
|
170
|
-
|
171
|
-
const methods = useForm<TFieldValues, TContext>(form)
|
172
|
-
const { handleSubmit } = methods
|
173
|
-
|
174
|
-
// This exposes the useForm api through the forwarded ref
|
175
|
-
React.useImperativeHandle(formRef, () => methods, [formRef, methods])
|
176
|
-
|
177
|
-
React.useEffect(() => {
|
178
|
-
let subscription: any
|
179
|
-
if (onChange) {
|
180
|
-
subscription = methods.watch(onChange)
|
181
|
-
}
|
182
|
-
return () => subscription?.unsubscribe()
|
183
|
-
}, [methods, onChange])
|
184
|
-
|
185
|
-
let _children = children
|
186
|
-
if (!_children && fieldResolver) {
|
187
|
-
_children = (
|
188
|
-
<FormLayout>
|
189
|
-
<AutoFields />
|
190
|
-
<SubmitButton {...fields?.submit} />
|
191
|
-
</FormLayout>
|
192
|
-
)
|
193
|
-
}
|
194
|
-
|
195
|
-
return (
|
196
|
-
<FormProvider
|
197
|
-
{...methods}
|
198
|
-
schema={schema}
|
199
|
-
fieldResolver={fieldResolver}
|
200
|
-
fields={fields}
|
201
|
-
>
|
202
|
-
<chakra.form
|
203
|
-
ref={ref}
|
204
|
-
onSubmit={handleSubmit(onSubmit, onError)}
|
205
|
-
{...rest}
|
206
|
-
className={cx('sui-form', props.className)}
|
207
|
-
>
|
208
|
-
{runIfFn(_children, {
|
209
|
-
Field: DefaultField as any,
|
210
|
-
DisplayIf: DisplayIf as any,
|
211
|
-
ArrayField: ArrayField as any,
|
212
|
-
ObjectField: ObjectField as any,
|
213
|
-
...methods,
|
214
|
-
})}
|
215
|
-
</chakra.form>
|
216
|
-
</FormProvider>
|
217
|
-
)
|
218
|
-
},
|
219
|
-
) as FormComponent
|
220
|
-
|
221
|
-
export type FormComponent = (<
|
222
|
-
TSchema = unknown,
|
223
|
-
TFieldValues extends FieldValues = FieldValues,
|
224
|
-
TContext extends object = object,
|
225
|
-
TExtraFieldProps extends object = object,
|
226
|
-
TFieldTypes = FieldProps<TFieldValues>,
|
227
|
-
>(
|
228
|
-
props: FormProps<
|
229
|
-
TSchema,
|
230
|
-
TFieldValues,
|
231
|
-
TContext,
|
232
|
-
TExtraFieldProps,
|
233
|
-
TFieldTypes
|
234
|
-
> & {
|
235
|
-
ref?: React.ForwardedRef<HTMLFormElement>
|
236
|
-
},
|
237
|
-
) => React.ReactElement) & {
|
238
|
-
displayName?: string
|
239
|
-
}
|
240
|
-
|
241
|
-
Form.displayName = 'Form'
|
242
|
-
|
243
|
-
export type GetResolver = <
|
244
|
-
TFieldValues extends FieldValues,
|
245
|
-
TContext extends object,
|
246
|
-
>(
|
247
|
-
schema: unknown,
|
248
|
-
) => (
|
249
|
-
values: TFieldValues,
|
250
|
-
context: TContext | undefined,
|
251
|
-
options: ResolverOptions<TFieldValues>,
|
252
|
-
) => Promise<ResolverResult<TFieldValues>>
|