@saas-ui/forms 0.5.3 → 0.6.0-next.0

Sign up to get free protection for your applications and to get access to all the features.
package/src/fields.tsx CHANGED
@@ -1,51 +1,66 @@
1
1
  import * as React from 'react'
2
- import { getFieldsFromSchema, getNestedSchema } from './resolvers/yup'
3
2
 
4
3
  import { FormLayout } from './layout'
5
4
  import { Field, FieldProps } from './field'
6
5
 
7
6
  import { ArrayField } from './array-field'
8
7
  import { ObjectField } from './object-field'
8
+ import { FieldResolver } from './field-resolver'
9
+ import { defaultFieldResolver } from './field-resolver'
9
10
 
10
11
  export interface FieldsProps {
11
12
  schema: any
13
+ fieldResolver?: FieldResolver
12
14
  }
13
15
 
14
- const getNestedFields = (schema: any, name: string) => {
15
- return getFieldsFromSchema(getNestedSchema(schema, name)).map(
16
- ({ name, type, ...nestedFieldProps }: FieldProps): React.ReactNode => (
17
- <Field key={name} name={name} type={type} {...nestedFieldProps} />
16
+ const mapNestedFields = (resolver: FieldResolver, name: string) => {
17
+ return resolver
18
+ .getNestedFields(name)
19
+ ?.map(
20
+ ({ name, type, ...nestedFieldProps }: FieldProps, i): React.ReactNode => (
21
+ <Field key={name || i} name={name} type={type} {...nestedFieldProps} />
22
+ )
18
23
  )
19
- )
20
24
  }
21
25
 
22
- export const Fields: React.FC<FieldsProps> = ({ schema, ...props }) => {
26
+ export const Fields: React.FC<FieldsProps> = ({
27
+ schema,
28
+ fieldResolver,
29
+ ...props
30
+ }) => {
31
+ const resolver = React.useMemo(
32
+ () => fieldResolver || defaultFieldResolver(schema),
33
+ [schema, fieldResolver]
34
+ )
35
+
23
36
  return (
24
37
  <FormLayout {...props}>
25
- {getFieldsFromSchema(schema).map(
26
- ({
27
- name,
28
- type,
29
- defaultValue,
30
- ...fieldProps
31
- }: FieldProps): React.ReactNode => {
32
- if (type === 'array') {
33
- return (
34
- <ArrayField name={name} {...fieldProps}>
35
- {getNestedFields(schema, name)}
36
- </ArrayField>
37
- )
38
- } else if (type === 'object') {
39
- return (
40
- <ObjectField name={name} {...fieldProps}>
41
- {getNestedFields(schema, name)}
42
- </ObjectField>
43
- )
44
- }
38
+ {resolver
39
+ .getFields()
40
+ .map(
41
+ ({
42
+ name,
43
+ type,
44
+ defaultValue,
45
+ ...fieldProps
46
+ }: FieldProps): React.ReactNode => {
47
+ if (type === 'array') {
48
+ return (
49
+ <ArrayField key={name} name={name} {...fieldProps}>
50
+ {mapNestedFields(resolver, name)}
51
+ </ArrayField>
52
+ )
53
+ } else if (type === 'object') {
54
+ return (
55
+ <ObjectField key={name} name={name} {...fieldProps}>
56
+ {mapNestedFields(resolver, name)}
57
+ </ObjectField>
58
+ )
59
+ }
45
60
 
46
- return <Field key={name} name={name} type={type} {...fieldProps} />
47
- }
48
- )}
61
+ return <Field key={name} name={name} type={type} {...fieldProps} />
62
+ }
63
+ )}
49
64
  </FormLayout>
50
65
  )
51
66
  }
package/src/form.tsx CHANGED
@@ -12,9 +12,7 @@ import {
12
12
  SubmitErrorHandler,
13
13
  } from 'react-hook-form'
14
14
 
15
- import { yupResolver } from './resolvers/yup'
16
-
17
- export type { UseFormReturn, FieldValues }
15
+ export type { UseFormReturn, FieldValues, SubmitHandler }
18
16
 
19
17
  interface FormOptions<TFieldValues extends FieldValues = FieldValues> {
20
18
  /**
@@ -35,15 +33,15 @@ interface FormOptions<TFieldValues extends FieldValues = FieldValues> {
35
33
  formRef?: React.MutableRefObject<HTMLFormElement>
36
34
  }
37
35
 
36
+ /**
37
+ * @todo Figure out how to pass down FieldValues to all Field components,
38
+ * if at all possible.
39
+ */
38
40
  export interface FormProps<TFieldValues extends FieldValues = FieldValues>
39
41
  extends UseFormProps<TFieldValues>,
40
42
  Omit<HTMLChakraProps<'form'>, 'onSubmit' | 'onError'>,
41
43
  FormOptions<TFieldValues> {}
42
44
 
43
- /**
44
- * @todo Figure out how to pass down FieldValues to all Field components,
45
- * if at all possible.
46
- */
47
45
  export const Form = forwardRef(
48
46
  <TFieldValues extends FieldValues = FieldValues>(
49
47
  props: FormProps<TFieldValues>,
@@ -79,11 +77,6 @@ export const Form = forwardRef(
79
77
  delayError,
80
78
  }
81
79
 
82
- // @todo remove yup dependency and just use resolver prop?
83
- if (schema) {
84
- form.resolver = yupResolver(schema)
85
- }
86
-
87
80
  const methods = useForm<TFieldValues>(form)
88
81
  const { handleSubmit } = methods
89
82
 
package/src/index.ts CHANGED
@@ -11,7 +11,7 @@ export * from './object-field'
11
11
  export * from './display-if'
12
12
  export * from './step-form'
13
13
  export * from './use-step-form'
14
-
14
+ export * from './field-resolver'
15
15
  export * from '@saas-ui/input-right-button'
16
16
 
17
17
  export type { FieldErrors } from 'react-hook-form'
package/src/step-form.tsx CHANGED
@@ -72,6 +72,10 @@ export interface FormStepOptions {
72
72
  * Schema
73
73
  */
74
74
  schema?: any
75
+ /**
76
+ * Hook Form Resolver
77
+ */
78
+ resolver?: any
75
79
  }
76
80
 
77
81
  export const FormStepper: React.FC<StepperStepsProps> = (props) => {
@@ -109,8 +113,8 @@ export interface FormStepProps
109
113
  HTMLChakraProps<'div'> {}
110
114
 
111
115
  export const FormStep: React.FC<FormStepProps> = (props) => {
112
- const { name, schema, children, className, ...rest } = props
113
- const step = useFormStep({ name, schema })
116
+ const { name, schema, resolver, children, className, ...rest } = props
117
+ const step = useFormStep({ name, schema, resolver })
114
118
 
115
119
  const { isActive } = step
116
120
 
@@ -11,6 +11,7 @@ import {
11
11
  export interface StepState {
12
12
  name: string
13
13
  schema?: any
14
+ resolver?: any
14
15
  isActive?: boolean
15
16
  isCompleted?: boolean
16
17
  }
@@ -69,6 +70,7 @@ export function useStepForm<TFieldValues extends FieldValues = FieldValues>(
69
70
  return {
70
71
  onSubmit: onSubmitStep,
71
72
  schema: step?.schema,
73
+ resolver: step?.resolver,
72
74
  }
73
75
  },
74
76
  [steps, onSubmitStep, activeStep]
@@ -99,16 +101,17 @@ export type UseStepFormReturn = ReturnType<typeof useStepForm>
99
101
  export interface UseFormStepProps {
100
102
  name: string
101
103
  schema?: any
104
+ resolver?: any
102
105
  }
103
106
 
104
107
  export function useFormStep(props: UseFormStepProps): StepState {
105
- const { name, schema } = props
108
+ const { name, schema, resolver } = props
106
109
  const step = useStep({ name })
107
110
 
108
111
  const { steps, updateStep } = useStepFormContext()
109
112
 
110
113
  React.useEffect(() => {
111
- updateStep({ name, schema })
114
+ updateStep({ name, schema, resolver })
112
115
  }, [name, schema])
113
116
 
114
117
  return {
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "yup",
3
+ "description": "Saas UI Forms field resolver: yup",
4
+ "version": "1.0.0",
5
+ "private": true,
6
+ "source": "src/index.ts",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.modern.js",
9
+ "types": "./dist/index.d.ts",
10
+ "author": "Eelco Wiersma <eelco@appulse.nl>",
11
+ "license": "MIT",
12
+ "peerDependencies": {
13
+ "@hookform/resolvers": "^2.8.3",
14
+ "react-hook-form": "^7.22.0",
15
+ "yup": "^0.32.11"
16
+ }
17
+ }
@@ -1,12 +0,0 @@
1
- import { SchemaOf, AnySchema } from 'yup';
2
- export { yupResolver } from '@hookform/resolvers/yup';
3
- import { FieldProps } from '../field';
4
- /**
5
- * A helper function to render forms automatically based on a Yup schema
6
- *
7
- * @param schema The Yup schema
8
- * @returns {FieldProps[]}
9
- */
10
- export declare const getFieldsFromSchema: (schema: SchemaOf<AnySchema>) => FieldProps[];
11
- export declare const getNestedSchema: (schema: SchemaOf<AnySchema>, path: string) => any;
12
- //# sourceMappingURL=yup.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"yup.d.ts","sourceRoot":"","sources":["../../src/resolvers/yup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAS,MAAM,KAAK,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAErD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAmCrC;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,WACtB,SAAS,SAAS,CAAC,KAC1B,UAAU,EA4BZ,CAAA;AAED,eAAO,MAAM,eAAe,WAAY,SAAS,SAAS,CAAC,QAAQ,MAAM,QAExE,CAAA"}
@@ -1,79 +0,0 @@
1
- import { SchemaOf, AnySchema, reach } from 'yup'
2
- export { yupResolver } from '@hookform/resolvers/yup'
3
-
4
- import { FieldProps } from '../field'
5
-
6
- // @TODO get proper typings for the schema fields
7
-
8
- const getType = (field: any) => {
9
- if (field.spec.meta?.type) {
10
- return field.spec.meta.type
11
- }
12
-
13
- switch (field.type) {
14
- case 'array':
15
- return 'array'
16
- case 'object':
17
- return 'object'
18
- case 'number':
19
- return 'number'
20
- case 'date':
21
- return 'date'
22
- case 'string':
23
- default:
24
- return 'text'
25
- }
26
- }
27
-
28
- type Options = {
29
- min?: number
30
- max?: number
31
- }
32
-
33
- const getArrayOption = (field: any, name: string) => {
34
- for (const test of field.tests) {
35
- if (test.OPTIONS?.params[name]) return test.OPTIONS.params[name]
36
- }
37
- }
38
-
39
- /**
40
- * A helper function to render forms automatically based on a Yup schema
41
- *
42
- * @param schema The Yup schema
43
- * @returns {FieldProps[]}
44
- */
45
- export const getFieldsFromSchema = (
46
- schema: SchemaOf<AnySchema>
47
- ): FieldProps[] => {
48
- const fields = []
49
-
50
- let schemaFields: Record<string, any> = {}
51
- if (schema.type === 'array') {
52
- /* @ts-ignore this is actually valid */
53
- schemaFields = schema.innerType.fields
54
- } else {
55
- schemaFields = schema.fields
56
- }
57
-
58
- for (const name in schemaFields) {
59
- const field = schemaFields[name]
60
-
61
- const options: Options = {}
62
- if (field.type === 'array') {
63
- options.min = getArrayOption(field, 'min')
64
- options.max = getArrayOption(field, 'max')
65
- }
66
-
67
- fields.push({
68
- name,
69
- label: field.spec.label || name,
70
- type: getType(field),
71
- ...options,
72
- })
73
- }
74
- return fields
75
- }
76
-
77
- export const getNestedSchema = (schema: SchemaOf<AnySchema>, path: string) => {
78
- return reach(schema, path)
79
- }