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

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,7 @@ import { FieldValues, UseFormReturn } from 'react-hook-form';
3
3
  import { HTMLChakraProps } from '@chakra-ui/system';
4
4
  import { StepperStepsProps } from '@saas-ui/stepper';
5
5
  import { ButtonProps } from '@saas-ui/button';
6
- import { FormProps } from '.';
6
+ import { FormProps } from './form';
7
7
  import { UseStepFormProps } from './use-step-form';
8
8
  export interface StepFormProps<TFieldValues extends FieldValues = FieldValues> extends UseStepFormProps<TFieldValues>, FormProps<TFieldValues> {
9
9
  }
@@ -19,6 +19,10 @@ export interface FormStepOptions {
19
19
  * Schema
20
20
  */
21
21
  schema?: any;
22
+ /**
23
+ * Hook Form Resolver
24
+ */
25
+ resolver?: any;
22
26
  }
23
27
  export declare const FormStepper: React.FC<StepperStepsProps>;
24
28
  export interface FormStepProps extends FormStepOptions, HTMLChakraProps<'div'> {
@@ -1 +1 @@
1
- {"version":3,"file":"step-form.d.ts","sourceRoot":"","sources":["../src/step-form.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE5D,OAAO,EAEL,eAAe,EAGhB,MAAM,mBAAmB,CAAA;AAI1B,OAAO,EAGL,iBAAiB,EAGlB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAU,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAErD,OAAO,EAAQ,SAAS,EAAgB,MAAM,GAAG,CAAA;AAEjD,OAAO,EAIL,gBAAgB,EACjB,MAAM,iBAAiB,CAAA;AAExB,MAAM,WAAW,aAAa,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,CAC3E,SAAQ,gBAAgB,CAAC,YAAY,CAAC,EACpC,SAAS,CAAC,YAAY,CAAC;CAAG;AAE9B,eAAO,MAAM,QAAQ;;MA2BhB,MAAM,YAAY,CAAA;AAEvB,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,MAAM,CAAC,EAAE,GAAG,CAAA;CACb;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA4BnD,CAAA;AAED,MAAM,WAAW,aACf,SAAQ,eAAe,EACrB,eAAe,CAAC,KAAK,CAAC;CAAG;AAE7B,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAW5C,CAAA;AAMD,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAY5C,CAAA;AAMD,MAAM,WAAW,eAAgB,SAAQ,WAAW;IAClD,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAYhD,CAAA"}
1
+ {"version":3,"file":"step-form.d.ts","sourceRoot":"","sources":["../src/step-form.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE5D,OAAO,EAEL,eAAe,EAGhB,MAAM,mBAAmB,CAAA;AAI1B,OAAO,EAGL,iBAAiB,EAGlB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAU,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAErD,OAAO,EAAQ,SAAS,EAAE,MAAM,QAAQ,CAAA;AAGxC,OAAO,EAIL,gBAAgB,EACjB,MAAM,iBAAiB,CAAA;AAExB,MAAM,WAAW,aAAa,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,CAC3E,SAAQ,gBAAgB,CAAC,YAAY,CAAC,EACpC,SAAS,CAAC,YAAY,CAAC;CAAG;AAE9B,eAAO,MAAM,QAAQ;;MA2BhB,MAAM,YAAY,CAAA;AAEvB,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ;;OAEG;IACH,QAAQ,CAAC,EAAE,GAAG,CAAA;CACf;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA4BnD,CAAA;AAED,MAAM,WAAW,aACf,SAAQ,eAAe,EACrB,eAAe,CAAC,KAAK,CAAC;CAAG;AAE7B,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAW5C,CAAA;AAMD,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAY5C,CAAA;AAMD,MAAM,WAAW,eAAgB,SAAQ,WAAW;IAClD,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAYhD,CAAA"}
@@ -52,7 +52,7 @@ export interface ArrayFieldOptions {
52
52
  */
53
53
  defaultValue?: Record<string, any>;
54
54
  /**
55
- * Default key name for rows, change this if your data uses 'id'
55
+ * Default key name for rows, change this if your data uses a different 'id' field
56
56
  * @default "id"
57
57
  */
58
58
  keyName?: string;
@@ -4,6 +4,7 @@ import { UseStepperProps, UseStepperReturn } from '@saas-ui/stepper';
4
4
  export interface StepState {
5
5
  name: string;
6
6
  schema?: any;
7
+ resolver?: any;
7
8
  isActive?: boolean;
8
9
  isCompleted?: boolean;
9
10
  }
@@ -31,6 +32,7 @@ export declare function useStepForm<TFieldValues extends FieldValues = FieldValu
31
32
  getFormProps: (props: any) => {
32
33
  onSubmit: SubmitHandler<TFieldValues>;
33
34
  schema: any;
35
+ resolver: any;
34
36
  };
35
37
  updateStep: (step: any) => void;
36
38
  steps: {};
@@ -39,6 +41,7 @@ export declare type UseStepFormReturn = ReturnType<typeof useStepForm>;
39
41
  export interface UseFormStepProps {
40
42
  name: string;
41
43
  schema?: any;
44
+ resolver?: any;
42
45
  }
43
46
  export declare function useFormStep(props: UseFormStepProps): StepState;
44
47
  //# sourceMappingURL=use-step-form.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-step-form.d.ts","sourceRoot":"","sources":["../src/use-step-form.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE5D,OAAO,EAGL,eAAe,EACf,gBAAgB,EACjB,MAAM,kBAAkB,CAAA;AAEzB,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAA;IAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;CACjC;AAED,eAAO,MAAO,gBAAgB,mCAAE,kBAAkB,uBAK9C,CAAA;AAEJ,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAElC,MAAM,WAAW,gBAAgB,CAC/B,YAAY,SAAS,WAAW,GAAG,WAAW,CAC9C,SAAQ,eAAe,EACrB,SAAS,CAAC,YAAY,CAAC;CAAG;AAE9B,wBAAgB,WAAW,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,EACxE,KAAK,EAAE,gBAAgB,CAAC,YAAY,CAAC;;;;;;;;;;;;;;;;;;;EAyDtC;AAED,oBAAY,iBAAiB,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAA;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,GAAG,CAAA;CACb;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,SAAS,CAc9D"}
1
+ {"version":3,"file":"use-step-form.d.ts","sourceRoot":"","sources":["../src/use-step-form.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE5D,OAAO,EAGL,eAAe,EACf,gBAAgB,EACjB,MAAM,kBAAkB,CAAA;AAEzB,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,QAAQ,CAAC,EAAE,GAAG,CAAA;IACd,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAA;IAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;CACjC;AAED,eAAO,MAAO,gBAAgB,mCAAE,kBAAkB,uBAK9C,CAAA;AAEJ,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAElC,MAAM,WAAW,gBAAgB,CAC/B,YAAY,SAAS,WAAW,GAAG,WAAW,CAC9C,SAAQ,eAAe,EACrB,SAAS,CAAC,YAAY,CAAC;CAAG;AAE9B,wBAAgB,WAAW,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,EACxE,KAAK,EAAE,gBAAgB,CAAC,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;EA0DtC;AAED,oBAAY,iBAAiB,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAA;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,QAAQ,CAAC,EAAE,GAAG,CAAA;CACf;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,SAAS,CAc9D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saas-ui/forms",
3
- "version": "0.5.0",
3
+ "version": "0.6.0-next.0",
4
4
  "description": "Theme and components agnostic SaasProvider",
5
5
  "source": "src/index.ts",
6
6
  "exports": {
@@ -8,12 +8,15 @@
8
8
  "require": "./dist/index.js",
9
9
  "default": "./dist/index.modern.js"
10
10
  },
11
- "./resolvers/yup": {
12
- "require": "./dist/resolvers/yup.js",
13
- "default": "./dist/resolvers/yup.modern.js"
14
- },
15
11
  "./src": {
16
12
  "default": "./src/index.ts"
13
+ },
14
+ "./yup": {
15
+ "require": "./yup/dist/index.js",
16
+ "default": "./yup/dist/index.modern.js"
17
+ },
18
+ "./yup/src": {
19
+ "default": "./yup/src/index.ts"
17
20
  }
18
21
  },
19
22
  "main": "./dist/index.js",
@@ -21,14 +24,19 @@
21
24
  "types": "./dist/index.d.ts",
22
25
  "scripts": {
23
26
  "clean": "rimraf --no-glob ./dist",
24
- "build": "yarn clean && cross-env NODE_ENV=production microbundle --tsconfig ./tsconfig.json --jsx React.createElement --jsxFragment React.Fragment -f cjs,modern --compress",
27
+ "build": "yarn build:package && yarn build:yup",
28
+ "build:package": "yarn clean && cross-env NODE_ENV=production microbundle --tsconfig ./tsconfig.json --jsx React.createElement --jsxFragment React.Fragment -f cjs,modern --compress",
29
+ "build:yup": "cross-env NODE_ENV=production microbundle --cwd yup --tsconfig ./yup/tsconfig.json -f cjs,modern --compress",
25
30
  "lint": "eslint src --ext .ts,.tsx,.js,.jsx --config ../../.eslintrc.js",
26
31
  "lint:staged": "lint-staged --allow-empty --config ../../lint-staged.config.js",
27
32
  "typecheck": "tsc --noEmit"
28
33
  },
29
34
  "files": [
30
35
  "dist",
31
- "src"
36
+ "src",
37
+ "yup/package.json",
38
+ "yup/src",
39
+ "yup/dist"
32
40
  ],
33
41
  "sideEffects": false,
34
42
  "publishConfig": {
@@ -64,21 +72,21 @@
64
72
  "dependencies": {
65
73
  "@chakra-ui/icons": "^1.1.1",
66
74
  "@chakra-ui/react-utils": "^1.2.1",
75
+ "@chakra-ui/utils": "^1.10.4",
67
76
  "@hookform/resolvers": "^2.8.3",
68
- "@saas-ui/button": "0.3.0",
69
- "@saas-ui/input-right-button": "0.3.0",
77
+ "@saas-ui/button": "0.4.0-next.0",
78
+ "@saas-ui/input-right-button": "0.3.1-next.0",
70
79
  "@saas-ui/number-input": "0.3.0",
71
- "@saas-ui/password-input": "0.3.0",
80
+ "@saas-ui/password-input": "0.3.1-next.0",
72
81
  "@saas-ui/pin-input": "0.3.0",
73
82
  "@saas-ui/radio": "0.3.0",
74
83
  "@saas-ui/react-utils": "0.1.0",
75
- "@saas-ui/select": "0.3.0",
84
+ "@saas-ui/select": "0.4.0-next.0",
76
85
  "react-hook-form": "^7.22.0"
77
86
  },
78
87
  "peerDependencies": {
79
88
  "@chakra-ui/react": ">=1.8.0",
80
89
  "@chakra-ui/system": ">=1.0.0",
81
- "react": ">=16.8.6",
82
- "yup": "^0.32.11"
90
+ "react": ">=16.8.6"
83
91
  }
84
92
  }
@@ -20,6 +20,7 @@ import {
20
20
  useArrayFieldRowContext,
21
21
  useArrayFieldRemoveButton,
22
22
  useArrayFieldAddButton,
23
+ UseArrayFieldReturn,
23
24
  } from './use-array-field'
24
25
 
25
26
  interface ArrayField {
@@ -137,26 +138,28 @@ export interface ArrayFieldProps
137
138
  extends ArrayFieldOptions,
138
139
  Omit<FieldProps, 'defaultValue'> {}
139
140
 
140
- export const ArrayField: React.FC<ArrayFieldProps> = (props) => {
141
- const { children, ...containerProps } = props
142
-
143
- return (
144
- <ArrayFieldContainer {...containerProps}>
145
- <ArrayFieldRows>
146
- {(fields: ArrayField[]) => (
147
- <>
148
- {fields.map(({ id }, index: number) => (
149
- <ArrayFieldRow key={id} index={index}>
150
- {children}
151
- </ArrayFieldRow>
152
- ))}
153
- </>
154
- )}
155
- </ArrayFieldRows>
156
- <ArrayFieldAddButton />
157
- </ArrayFieldContainer>
158
- )
159
- }
141
+ export const ArrayField = React.forwardRef(
142
+ (props: ArrayFieldProps, ref: React.ForwardedRef<UseArrayFieldReturn>) => {
143
+ const { children, ...containerProps } = props
144
+
145
+ return (
146
+ <ArrayFieldContainer ref={ref} {...containerProps}>
147
+ <ArrayFieldRows>
148
+ {(fields: ArrayField[]) => (
149
+ <>
150
+ {fields.map(({ id }, index: number) => (
151
+ <ArrayFieldRow key={id} index={index}>
152
+ {children}
153
+ </ArrayFieldRow>
154
+ ))}
155
+ </>
156
+ )}
157
+ </ArrayFieldRows>
158
+ <ArrayFieldAddButton />
159
+ </ArrayFieldContainer>
160
+ )
161
+ }
162
+ )
160
163
 
161
164
  export interface ArrayFieldRowsProps {
162
165
  children: (fields: ArrayField[]) => React.ReactElement | null
@@ -169,28 +172,36 @@ export const ArrayFieldRows = ({
169
172
  return children(fields)
170
173
  }
171
174
 
172
- export const ArrayFieldContainer: React.FC<ArrayFieldProps> = ({
173
- name,
174
- defaultValue,
175
- keyName,
176
- min,
177
- max,
178
- children,
179
- ...fieldProps
180
- }) => {
181
- const context = useArrayField({
182
- name,
183
- defaultValue,
184
- keyName,
185
- min,
186
- max,
187
- })
188
-
189
- return (
190
- <ArrayFieldProvider value={context}>
191
- <BaseField name={name} {...fieldProps}>
192
- {children}
193
- </BaseField>
194
- </ArrayFieldProvider>
195
- )
196
- }
175
+ export const ArrayFieldContainer = React.forwardRef(
176
+ (
177
+ {
178
+ name,
179
+ defaultValue,
180
+ keyName,
181
+ min,
182
+ max,
183
+ children,
184
+ ...fieldProps
185
+ }: ArrayFieldProps,
186
+ ref: React.ForwardedRef<UseArrayFieldReturn>
187
+ ) => {
188
+ const context = useArrayField({
189
+ name,
190
+ defaultValue,
191
+ keyName,
192
+ min,
193
+ max,
194
+ })
195
+
196
+ // This exposes the useArrayField api through the forwarded ref
197
+ React.useImperativeHandle(ref, () => context, [ref, context])
198
+
199
+ return (
200
+ <ArrayFieldProvider value={context}>
201
+ <BaseField name={name} {...fieldProps}>
202
+ {children}
203
+ </BaseField>
204
+ </ArrayFieldProvider>
205
+ )
206
+ }
207
+ )
package/src/auto-form.tsx CHANGED
@@ -3,14 +3,14 @@ import { FieldValues, UseFormReturn } from 'react-hook-form'
3
3
  import { forwardRef } from '@chakra-ui/react'
4
4
 
5
5
  import { Form, FormProps } from './form'
6
-
7
6
  import { FormLayout } from './layout'
8
7
  import { Fields } from './fields'
9
8
  import { SubmitButton } from './submit-button'
10
9
 
11
10
  interface AutoFormOptions {
12
- schema: any
13
11
  submitLabel?: false | string
12
+ schema: any
13
+ fieldResolver?: any
14
14
  }
15
15
 
16
16
  export interface AutoFormProps<TFieldValues extends FieldValues>
@@ -22,11 +22,12 @@ export const AutoForm = forwardRef(
22
22
  props: AutoFormProps<TFieldValues>,
23
23
  ref: React.ForwardedRef<UseFormReturn<TFieldValues>>
24
24
  ) => {
25
- const { schema, submitLabel = 'Submit', ...rest } = props
25
+ const { schema, submitLabel = 'Submit', fieldResolver, ...rest } = props
26
+
26
27
  return (
27
- <Form {...rest} schema={schema} ref={ref}>
28
+ <Form {...rest} ref={ref}>
28
29
  <FormLayout>
29
- {<Fields schema={schema} />}
30
+ {<Fields schema={schema} fieldResolver={fieldResolver} />}
30
31
  {submitLabel && <SubmitButton label={submitLabel} />}
31
32
  </FormLayout>
32
33
  </Form>
@@ -0,0 +1,39 @@
1
+ import { FieldProps } from './field'
2
+
3
+ import { get } from '@chakra-ui/utils'
4
+
5
+ export type FieldResolver = {
6
+ getFields(): FieldProps[]
7
+ getNestedFields(name: string): FieldProps[]
8
+ }
9
+
10
+ // @todo finalize this
11
+ export type FormSchema = Record<string, any>
12
+
13
+ const mapFields = (schema: FormSchema) =>
14
+ Object.entries(schema).map(([name, field]) => {
15
+ return {
16
+ name,
17
+ ...field,
18
+ }
19
+ })
20
+
21
+ export const defaultFieldResolver = (schema: FormSchema): FieldResolver => {
22
+ const getFields = () => {
23
+ return mapFields(schema)
24
+ }
25
+ const getNestedFields = (name: string) => {
26
+ const field = get(schema, name)
27
+
28
+ if (!field) return []
29
+
30
+ if (field.items?.type === 'object') {
31
+ return mapFields(field.items.properties)
32
+ } else if (field.type === 'object') {
33
+ return mapFields(field.properties)
34
+ }
35
+ return [field.items]
36
+ }
37
+
38
+ return { getFields, getNestedFields }
39
+ }
package/src/field.tsx CHANGED
@@ -29,6 +29,7 @@ import { PasswordInput } from '@saas-ui/password-input'
29
29
  import { RadioInput } from '@saas-ui/radio'
30
30
  import { PinInput } from '@saas-ui/pin-input'
31
31
  import { Select, NativeSelect } from '@saas-ui/select'
32
+ import { FocusableElement } from '@chakra-ui/utils'
32
33
 
33
34
  export interface Option {
34
35
  value: string
@@ -158,7 +159,7 @@ export const Field = forwardRef(
158
159
  props: FieldProps<TFieldValues> & {
159
160
  [key: string]: unknown // Make sure attributes of custom components work. Need to change this to a global typedef at some point.
160
161
  },
161
- ref: React.ForwardedRef<typeof FormControl>
162
+ ref: React.ForwardedRef<FocusableElement>
162
163
  ) => {
163
164
  const { type = defaultInputType } = props
164
165
  const InputComponent = getInput(type)
@@ -169,7 +170,7 @@ export const Field = forwardRef(
169
170
  props: FieldProps<TFieldValues> & {
170
171
  [key: string]: unknown
171
172
  } & {
172
- ref?: React.ForwardedRef<typeof FormControl>
173
+ ref?: React.ForwardedRef<FocusableElement>
173
174
  }
174
175
  ) => React.ReactElement
175
176
 
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 }
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,15 +77,10 @@ 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
 
90
- // This exposes the useForm api through the forwareded ref
83
+ // This exposes the useForm api through the forwarded ref
91
84
  React.useImperativeHandle(ref, () => methods, [ref, methods])
92
85
 
93
86
  return (
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
@@ -20,7 +20,8 @@ import {
20
20
  } from '@saas-ui/stepper'
21
21
  import { Button, ButtonProps } from '@saas-ui/button'
22
22
 
23
- import { Form, FormProps, SubmitButton } from '.'
23
+ import { Form, FormProps } from './form'
24
+ import { SubmitButton } from './submit-button'
24
25
 
25
26
  import {
26
27
  useStepForm,
@@ -71,6 +72,10 @@ export interface FormStepOptions {
71
72
  * Schema
72
73
  */
73
74
  schema?: any
75
+ /**
76
+ * Hook Form Resolver
77
+ */
78
+ resolver?: any
74
79
  }
75
80
 
76
81
  export const FormStepper: React.FC<StepperStepsProps> = (props) => {
@@ -108,8 +113,8 @@ export interface FormStepProps
108
113
  HTMLChakraProps<'div'> {}
109
114
 
110
115
  export const FormStep: React.FC<FormStepProps> = (props) => {
111
- const { name, schema, children, className, ...rest } = props
112
- const step = useFormStep({ name, schema })
116
+ const { name, schema, resolver, children, className, ...rest } = props
117
+ const step = useFormStep({ name, schema, resolver })
113
118
 
114
119
  const { isActive } = step
115
120
 
@@ -69,7 +69,7 @@ export interface ArrayFieldOptions {
69
69
  */
70
70
  defaultValue?: Record<string, any>
71
71
  /**
72
- * Default key name for rows, change this if your data uses 'id'
72
+ * Default key name for rows, change this if your data uses a different 'id' field
73
73
  * @default "id"
74
74
  */
75
75
  keyName?: string
@@ -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,20 +101,21 @@ 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 {
115
118
  ...step,
116
- ...(steps[name] || {}),
119
+ ...(steps[name] || { name, schema }),
117
120
  }
118
121
  }
@@ -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"}