@saas-ui/forms 0.5.0 → 0.6.0-next.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.
@@ -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"}