@saas-ui/forms 2.0.0-next.19 → 2.0.0-next.20

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  import { zodResolver } from '@hookform/resolvers/zod';
2
2
  export { zodResolver } from '@hookform/resolvers/zod';
3
3
  import { get } from '@chakra-ui/utils';
4
- import { createForm } from '@saas-ui/forms';
4
+ import { createForm, createStepForm } from '@saas-ui/forms';
5
5
 
6
6
  // zod/src/zod-resolver.ts
7
7
  var getType = (field) => {
@@ -83,10 +83,21 @@ var createZodForm = (options) => {
83
83
  ZodForm.id = "ZodForm";
84
84
  return ZodForm;
85
85
  };
86
+ var createZodStepForm = (options) => {
87
+ const ZodStepForm = createStepForm({
88
+ resolver: (schema) => zodResolver(schema, options == null ? void 0 : options.schemaOptions, options == null ? void 0 : options.resolverOptions),
89
+ fieldResolver: zodFieldResolver,
90
+ ...options
91
+ });
92
+ ZodStepForm.displayName = "ZodStepForm";
93
+ ZodStepForm.id = "ZodStepForm";
94
+ return ZodStepForm;
95
+ };
86
96
 
87
97
  // zod/src/index.ts
88
98
  var Form = createZodForm();
99
+ var StepForm = createZodStepForm();
89
100
 
90
- export { Form, createZodForm, getFieldsFromSchema, getNestedSchema, zodFieldResolver, zodMeta, zodParseMeta };
101
+ export { Form, StepForm, createZodForm, getFieldsFromSchema, getNestedSchema, zodFieldResolver, zodMeta, zodParseMeta };
91
102
  //# sourceMappingURL=out.js.map
92
103
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../zod/src/zod-resolver.ts","../../zod/src/create-zod-form.ts","../../zod/src/index.ts"],"names":[],"mappings":";AACA,SAAS,mBAAmB;AAC5B,SAAS,WAAW;AAUpB,IAAM,UAAU,CAAC,UAAwB;AACvC,UAAQ,MAAM,KAAK,UAAU;AAAA,IAC3B,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL;AACE,aAAO;AAAA,EACX;AACF;AAEA,IAAM,iBAAiB,CAAC,OAAY,SAAiB;AA5BrD;AA6BE,UAAO,WAAM,KAAK,IAAI,MAAf,mBAAkB;AAC3B;AAQO,IAAM,sBAAsB,CAAC,WAAuC;AACzE,QAAM,SAAuB,CAAC;AAE9B,MAAI,eAAoC,CAAC;AACzC,MAAI,OAAO,KAAK,aAAa,YAAY;AACvC,mBAAe,OAAO,KAAK,KAAK;AAAA,EAClC,WAAW,OAAO,KAAK,aAAa,aAAa;AAC/C,mBAAe,OAAO,KAAK,MAAM;AAAA,EACnC,OAAO;AACL,WAAO;AAAA,EACT;AAEA,aAAW,QAAQ,cAAc;AAC/B,UAAM,QAAQ,aAAa,IAAI;AAE/B,UAAM,UAAmB,CAAC;AAC1B,QAAI,MAAM,KAAK,aAAa,YAAY;AACtC,cAAQ,MAAM,eAAe,OAAO,WAAW;AAC/C,cAAQ,MAAM,eAAe,OAAO,WAAW;AAAA,IACjD;AAEA,UAAM,OAAO,MAAM,eAAe,aAAa,MAAM,WAAW;AAEhE,WAAO,KAAK;AAAA,MACV;AAAA,MACA,QAAO,6BAAM,UAAS,MAAM,eAAe;AAAA,MAC3C,OAAM,6BAAM,SAAQ,QAAQ,KAAK;AAAA,MACjC,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEO,IAAM,kBAAkB,CAAC,QAAsB,SAAiB;AACrE,SAAO,IAAI,OAAO,KAAK,MAAM,GAAG,IAAI;AACtC;AAEO,IAAM,mBAAmB,CAAyB,WAAc;AACrE,SAAO;AAAA,IACL,YAAY;AACV,aAAO,oBAAoB,MAAM;AAAA,IACnC;AAAA,IACA,gBAAgB,MAAc;AAC5B,aAAO,oBAAoB,gBAAgB,QAAQ,IAAI,CAAC;AAAA,IAC1D;AAAA,EACF;AACF;AAOO,IAAM,UAAU,CAAC,SAAkB;AACxC,SAAO,KAAK,UAAU,IAAI;AAC5B;AAEO,IAAM,eAAe,CAAC,SAAiB;AAC5C,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,SAAS,GAAP;AACA,WAAO;AAAA,EACT;AACF;;;ACrGA;AAAA,EACE;AAAA,OAKK;AAkCA,IAAM,gBAAgB,CAC3B,YACG;AACH,QAAM,UAAU,WAAW;AAAA,IACzB,UAAU,CAAC,WACT,YAAY,QAAQ,mCAAS,eAAe,mCAAS,eAAe;AAAA,IACtE,eAAe;AAAA,IACf,GAAG;AAAA,EACL,CAAC;AAED,UAAQ,cAAc;AACtB,UAAQ,KAAK;AAEb,SAAO;AACT;;;ACzCO,IAAM,OAAO,cAAc","sourcesContent":["import * as z from 'zod'\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport { get } from '@chakra-ui/utils'\nimport { FieldProps } from '@saas-ui/forms'\n\nexport { zodResolver }\n\nexport type Options = {\n min?: number\n max?: number\n}\n\nconst getType = (field: z.ZodTypeAny) => {\n switch (field._def.typeName) {\n case 'ZodArray':\n return 'array'\n case 'ZodObject':\n return 'object'\n case 'ZodNumber':\n return 'number'\n case 'ZodDate':\n return 'date'\n case 'ZodString':\n default:\n return 'text'\n }\n}\n\nconst getArrayOption = (field: any, name: string) => {\n return field._def[name]?.value\n}\n\n/**\n * A helper function to render forms automatically based on a Yup schema\n *\n * @param schema The Yup schema\n * @returns {FieldProps[]}\n */\nexport const getFieldsFromSchema = (schema: z.ZodTypeAny): FieldProps[] => {\n const fields: FieldProps[] = []\n\n let schemaFields: Record<string, any> = {}\n if (schema._def.typeName === 'ZodArray') {\n schemaFields = schema._def.type.shape\n } else if (schema._def.typeName === 'ZodObject') {\n schemaFields = schema._def.shape()\n } else {\n return fields\n }\n\n for (const name in schemaFields) {\n const field = schemaFields[name]\n\n const options: Options = {}\n if (field._def.typeName === 'ZodArray') {\n options.min = getArrayOption(field, 'minLength')\n options.max = getArrayOption(field, 'maxLength')\n }\n\n const meta = field.description && zodParseMeta(field.description)\n\n fields.push({\n name,\n label: meta?.label || field.description || name,\n type: meta?.type || getType(field),\n ...options,\n })\n }\n return fields\n}\n\nexport const getNestedSchema = (schema: z.ZodTypeAny, path: string) => {\n return get(schema._def.shape(), path)\n}\n\nexport const zodFieldResolver = <T extends z.ZodTypeAny>(schema: T) => {\n return {\n getFields() {\n return getFieldsFromSchema(schema)\n },\n getNestedFields(name: string) {\n return getFieldsFromSchema(getNestedSchema(schema, name))\n },\n }\n}\n\nexport interface ZodMeta {\n label: string\n type?: string\n}\n\nexport const zodMeta = (meta: ZodMeta) => {\n return JSON.stringify(meta)\n}\n\nexport const zodParseMeta = (meta: string) => {\n try {\n return JSON.parse(meta)\n } catch (e) {\n return meta\n }\n}\n","import {\n createForm,\n CreateFormProps,\n WithFields,\n FormProps,\n FieldValues,\n} from '@saas-ui/forms'\nimport { zodFieldResolver, zodResolver } from './zod-resolver'\nimport { z } from 'zod'\n\ntype ResolverArgs = Parameters<typeof zodResolver>\n\nexport interface CreateZodFormProps<FieldDefs>\n extends CreateFormProps<FieldDefs> {\n schemaOptions?: ResolverArgs[1]\n resolverOptions?: ResolverArgs[2]\n}\n\nexport type ZodFormType<\n FieldDefs,\n ExtraProps = object,\n ExtraOverrides = object,\n Type extends 'zod' = 'zod'\n> = (<\n TSchema extends z.AnyZodObject = z.AnyZodObject,\n TFieldValues extends z.infer<TSchema> = z.infer<TSchema>,\n TContext extends object = object\n>(\n props: WithFields<\n FormProps<TSchema, TFieldValues, TContext>,\n FieldDefs,\n ExtraOverrides\n > & {\n ref?: React.ForwardedRef<HTMLFormElement>\n } & ExtraProps\n) => React.ReactElement) & {\n displayName?: string\n id?: string\n}\n\nexport const createZodForm = <FieldDefs>(\n options?: CreateZodFormProps<FieldDefs>\n) => {\n const ZodForm = createForm({\n resolver: (schema: any) =>\n zodResolver(schema, options?.schemaOptions, options?.resolverOptions),\n fieldResolver: zodFieldResolver,\n ...options,\n })\n\n ZodForm.displayName = 'ZodForm'\n ZodForm.id = 'ZodForm'\n\n return ZodForm as ZodFormType<FieldDefs>\n}\n","export {\n zodResolver,\n getFieldsFromSchema,\n getNestedSchema,\n zodFieldResolver,\n zodMeta,\n zodParseMeta,\n} from './zod-resolver'\nexport type { Options, ZodMeta } from './zod-resolver'\nexport { createZodForm, type ZodFormType } from './create-zod-form'\n\nimport { createZodForm } from './create-zod-form'\n\nexport const Form = createZodForm()\n"]}
1
+ {"version":3,"sources":["../../zod/src/zod-resolver.ts","../../zod/src/create-zod-form.ts","../../zod/src/create-zod-step-form.ts","../../zod/src/index.ts"],"names":[],"mappings":";AACA,SAAS,mBAAmB;AAC5B,SAAS,WAAW;AAUpB,IAAM,UAAU,CAAC,UAAwB;AACvC,UAAQ,MAAM,KAAK,UAAU;AAAA,IAC3B,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL;AACE,aAAO;AAAA,EACX;AACF;AAEA,IAAM,iBAAiB,CAAC,OAAY,SAAiB;AA5BrD;AA6BE,UAAO,WAAM,KAAK,IAAI,MAAf,mBAAkB;AAC3B;AAQO,IAAM,sBAAsB,CAAC,WAAuC;AACzE,QAAM,SAAuB,CAAC;AAE9B,MAAI,eAAoC,CAAC;AACzC,MAAI,OAAO,KAAK,aAAa,YAAY;AACvC,mBAAe,OAAO,KAAK,KAAK;AAAA,EAClC,WAAW,OAAO,KAAK,aAAa,aAAa;AAC/C,mBAAe,OAAO,KAAK,MAAM;AAAA,EACnC,OAAO;AACL,WAAO;AAAA,EACT;AAEA,aAAW,QAAQ,cAAc;AAC/B,UAAM,QAAQ,aAAa,IAAI;AAE/B,UAAM,UAAmB,CAAC;AAC1B,QAAI,MAAM,KAAK,aAAa,YAAY;AACtC,cAAQ,MAAM,eAAe,OAAO,WAAW;AAC/C,cAAQ,MAAM,eAAe,OAAO,WAAW;AAAA,IACjD;AAEA,UAAM,OAAO,MAAM,eAAe,aAAa,MAAM,WAAW;AAEhE,WAAO,KAAK;AAAA,MACV;AAAA,MACA,QAAO,6BAAM,UAAS,MAAM,eAAe;AAAA,MAC3C,OAAM,6BAAM,SAAQ,QAAQ,KAAK;AAAA,MACjC,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEO,IAAM,kBAAkB,CAAC,QAAsB,SAAiB;AACrE,SAAO,IAAI,OAAO,KAAK,MAAM,GAAG,IAAI;AACtC;AAEO,IAAM,mBAAmB,CAAyB,WAAc;AACrE,SAAO;AAAA,IACL,YAAY;AACV,aAAO,oBAAoB,MAAM;AAAA,IACnC;AAAA,IACA,gBAAgB,MAAc;AAC5B,aAAO,oBAAoB,gBAAgB,QAAQ,IAAI,CAAC;AAAA,IAC1D;AAAA,EACF;AACF;AAOO,IAAM,UAAU,CAAC,SAAkB;AACxC,SAAO,KAAK,UAAU,IAAI;AAC5B;AAEO,IAAM,eAAe,CAAC,SAAiB;AAC5C,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,SAAS,GAAP;AACA,WAAO;AAAA,EACT;AACF;;;ACrGA;AAAA,EACE;AAAA,OAKK;AAkCA,IAAM,gBAAgB,CAC3B,YACG;AACH,QAAM,UAAU,WAAW;AAAA,IACzB,UAAU,CAAC,WACT,YAAY,QAAQ,mCAAS,eAAe,mCAAS,eAAe;AAAA,IACtE,eAAe;AAAA,IACf,GAAG;AAAA,EACL,CAAC;AAED,UAAQ,cAAc;AACtB,UAAQ,KAAK;AAEb,SAAO;AACT;;;ACtDA;AAAA,EAEE;AAAA,OAGK;AA6CA,IAAM,oBAAoB,CAC/B,YACG;AACH,QAAM,cAAc,eAAmC;AAAA,IACrD,UAAU,CAAC,WACT,YAAY,QAAQ,mCAAS,eAAe,mCAAS,eAAe;AAAA,IACtE,eAAe;AAAA,IACf,GAAG;AAAA,EACL,CAAC;AAED,cAAY,cAAc;AAC1B,cAAY,KAAK;AAEjB,SAAO;AACT;;;AClDO,IAAM,OAAO,cAAc;AAE3B,IAAM,WAAW,kBAAkB","sourcesContent":["import * as z from 'zod'\nimport { zodResolver } from '@hookform/resolvers/zod'\nimport { get } from '@chakra-ui/utils'\nimport { FieldProps } from '@saas-ui/forms'\n\nexport { zodResolver }\n\nexport type Options = {\n min?: number\n max?: number\n}\n\nconst getType = (field: z.ZodTypeAny) => {\n switch (field._def.typeName) {\n case 'ZodArray':\n return 'array'\n case 'ZodObject':\n return 'object'\n case 'ZodNumber':\n return 'number'\n case 'ZodDate':\n return 'date'\n case 'ZodString':\n default:\n return 'text'\n }\n}\n\nconst getArrayOption = (field: any, name: string) => {\n return field._def[name]?.value\n}\n\n/**\n * A helper function to render forms automatically based on a Yup schema\n *\n * @param schema The Yup schema\n * @returns {FieldProps[]}\n */\nexport const getFieldsFromSchema = (schema: z.ZodTypeAny): FieldProps[] => {\n const fields: FieldProps[] = []\n\n let schemaFields: Record<string, any> = {}\n if (schema._def.typeName === 'ZodArray') {\n schemaFields = schema._def.type.shape\n } else if (schema._def.typeName === 'ZodObject') {\n schemaFields = schema._def.shape()\n } else {\n return fields\n }\n\n for (const name in schemaFields) {\n const field = schemaFields[name]\n\n const options: Options = {}\n if (field._def.typeName === 'ZodArray') {\n options.min = getArrayOption(field, 'minLength')\n options.max = getArrayOption(field, 'maxLength')\n }\n\n const meta = field.description && zodParseMeta(field.description)\n\n fields.push({\n name,\n label: meta?.label || field.description || name,\n type: meta?.type || getType(field),\n ...options,\n })\n }\n return fields\n}\n\nexport const getNestedSchema = (schema: z.ZodTypeAny, path: string) => {\n return get(schema._def.shape(), path)\n}\n\nexport const zodFieldResolver = <T extends z.ZodTypeAny>(schema: T) => {\n return {\n getFields() {\n return getFieldsFromSchema(schema)\n },\n getNestedFields(name: string) {\n return getFieldsFromSchema(getNestedSchema(schema, name))\n },\n }\n}\n\nexport interface ZodMeta {\n label: string\n type?: string\n}\n\nexport const zodMeta = (meta: ZodMeta) => {\n return JSON.stringify(meta)\n}\n\nexport const zodParseMeta = (meta: string) => {\n try {\n return JSON.parse(meta)\n } catch (e) {\n return meta\n }\n}\n","import {\n createForm,\n CreateFormProps,\n WithFields,\n FormProps,\n FieldValues,\n} from '@saas-ui/forms'\nimport { zodFieldResolver, zodResolver } from './zod-resolver'\nimport { z } from 'zod'\n\ntype ResolverArgs = Parameters<typeof zodResolver>\n\nexport interface CreateZodFormProps<FieldDefs>\n extends CreateFormProps<FieldDefs> {\n schemaOptions?: ResolverArgs[1]\n resolverOptions?: ResolverArgs[2]\n}\n\nexport type ZodFormType<\n FieldDefs,\n ExtraProps = object,\n ExtraOverrides = object,\n Type extends 'zod' = 'zod'\n> = (<\n TSchema extends z.AnyZodObject = z.AnyZodObject,\n TFieldValues extends z.infer<TSchema> = z.infer<TSchema>,\n TContext extends object = object\n>(\n props: WithFields<\n FormProps<TSchema, TFieldValues, TContext>,\n FieldDefs,\n ExtraOverrides\n > & {\n ref?: React.ForwardedRef<HTMLFormElement>\n } & ExtraProps\n) => React.ReactElement) & {\n displayName?: string\n id?: string\n}\n\nexport const createZodForm = <FieldDefs>(\n options?: CreateZodFormProps<FieldDefs>\n) => {\n const ZodForm = createForm({\n resolver: (schema: any) =>\n zodResolver(schema, options?.schemaOptions, options?.resolverOptions),\n fieldResolver: zodFieldResolver,\n ...options,\n })\n\n ZodForm.displayName = 'ZodForm'\n ZodForm.id = 'ZodForm'\n\n return ZodForm as ZodFormType<FieldDefs>\n}\n","import {\n CreateFormProps,\n createStepForm,\n StepsOptions,\n UseStepFormProps,\n} from '@saas-ui/forms'\nimport { zodFieldResolver, zodResolver } from './zod-resolver'\nimport { AnyZodObject, z } from 'zod'\nimport React from 'react'\n\ntype ResolverArgs = Parameters<typeof zodResolver>\n\nexport interface CreateZodFormProps<FieldDefs>\n extends CreateFormProps<FieldDefs> {\n schemaOptions?: ResolverArgs[1]\n resolverOptions?: ResolverArgs[2]\n}\n\ntype InferStepType<T extends Required<StepsOptions<AnyZodObject>>> = T extends [\n infer Step,\n ...infer Rest\n]\n ? Step extends { schema: AnyZodObject }\n ? z.infer<Step['schema']> &\n (Rest extends Required<StepsOptions<AnyZodObject>>\n ? InferStepType<Rest>\n : object)\n : object\n : object\n\ntype ZodStepFormType<\n FieldDefs,\n ExtraProps = object,\n ExtraOverrides = object\n> = (<\n TSteps extends Required<StepsOptions<AnyZodObject>> = Required<\n StepsOptions<AnyZodObject>\n >,\n TFieldValues extends InferStepType<TSteps> = InferStepType<TSteps>,\n TContext extends object = object\n>(\n props: UseStepFormProps<TSteps, TFieldValues, TContext> & {\n steps: TSteps\n ref?: React.ForwardedRef<HTMLFormElement>\n }\n) => React.ReactElement) & {\n displayName?: string\n id?: string\n}\n\nexport const createZodStepForm = <FieldDefs>(\n options?: CreateZodFormProps<FieldDefs>\n) => {\n const ZodStepForm = createStepForm<any, any, any, any>({\n resolver: (schema: any) =>\n zodResolver(schema, options?.schemaOptions, options?.resolverOptions),\n fieldResolver: zodFieldResolver,\n ...options,\n })\n\n ZodStepForm.displayName = 'ZodStepForm'\n ZodStepForm.id = 'ZodStepForm'\n\n return ZodStepForm as ZodStepFormType<FieldDefs>\n}\n","export {\n zodResolver,\n getFieldsFromSchema,\n getNestedSchema,\n zodFieldResolver,\n zodMeta,\n zodParseMeta,\n} from './zod-resolver'\nexport type { Options, ZodMeta } from './zod-resolver'\nexport { createZodForm, type ZodFormType } from './create-zod-form'\n\nimport { createZodForm } from './create-zod-form'\nimport { createZodStepForm } from './create-zod-step-form'\n\nexport const Form = createZodForm()\n\nexport const StepForm = createZodStepForm()\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saas-ui/forms",
3
- "version": "2.0.0-next.19",
3
+ "version": "2.0.0-next.20",
4
4
  "description": "Fully functional forms for Chakra UI.",
5
5
  "source": "src/index.ts",
6
6
  "exports": {
@@ -103,8 +103,8 @@
103
103
  "dependencies": {
104
104
  "@chakra-ui/react-utils": "^2.0.12",
105
105
  "@chakra-ui/utils": "^2.0.15",
106
- "@hookform/resolvers": "^3.0.1",
107
- "@saas-ui/core": "2.0.0-next.16",
106
+ "@hookform/resolvers": "^3.1.0",
107
+ "@saas-ui/core": "2.0.0-next.17",
108
108
  "react-hook-form": "^7.43.9"
109
109
  },
110
110
  "peerDependencies": {
@@ -119,9 +119,9 @@
119
119
  "@types/json-schema": "^7.0.11",
120
120
  "ajv": "^8.12.0",
121
121
  "ajv-errors": "^3.0.0",
122
- "json-schema-to-ts": "^2.7.2",
122
+ "json-schema-to-ts": "^2.8.2",
123
123
  "tsd": "^0.28.1",
124
- "yup": "^1.0.2",
124
+ "yup": "^1.1.1",
125
125
  "zod": "^3.21.4"
126
126
  },
127
127
  "tsd": {
@@ -1,58 +1,39 @@
1
- import { useMemo } from 'react'
1
+ import React, { useMemo } from 'react'
2
2
  import { forwardRef } from '@chakra-ui/react'
3
- import { FormType } from './create-form'
4
3
  import {
5
4
  ArrayField,
6
5
  DisplayIf,
7
6
  FieldProps,
8
7
  FieldValues,
8
+ FieldsProvider,
9
9
  Form,
10
+ GetFieldResolver,
10
11
  ObjectField,
11
12
  } from './'
12
13
  import { Field } from './field'
13
- import { StepFormProps, FormStep } from './step-form'
14
+ import { FormStep, StepsOptions } from './step-form'
14
15
  import {
15
16
  StepFormProvider,
16
17
  UseStepFormProps,
17
18
  useStepForm,
18
19
  } from './use-step-form'
19
- import { YupFormType } from '../yup/src/create-yup-form'
20
- import { ZodFormType } from '../zod/src/create-zod-form'
21
20
  import { StepperProvider } from '@saas-ui/core'
22
21
  import { runIfFn } from '@chakra-ui/utils'
22
+ import { GetResolver } from './form'
23
23
 
24
- // /**
25
- // * @todo make this dynamic to support other schema types
26
- // */
27
- type MergeStepFormProps<T> = T extends YupFormType<
28
- infer FieldDefs,
29
- infer ExtraProps,
30
- infer ExtraOverrides,
31
- 'yup'
32
- >
33
- ? YupFormType<
34
- FieldDefs,
35
- ExtraProps & Omit<StepFormProps, 'children'>,
36
- ExtraOverrides
37
- >
38
- : T extends ZodFormType<
39
- infer FieldDefs,
40
- infer ExtraProps,
41
- infer ExtraOverrides,
42
- 'zod'
43
- >
44
- ? ZodFormType<
45
- FieldDefs,
46
- ExtraProps & Omit<StepFormProps, 'children'>,
47
- ExtraOverrides
48
- >
49
- : T extends FormType<infer FieldDefs, infer ExtraProps, infer ExtraOverrides>
50
- ? FormType<
51
- FieldDefs,
52
- ExtraProps & Omit<StepFormProps, 'children'>,
53
- ExtraOverrides
54
- >
55
- : never
24
+ type StepFormType<FieldDefs, ExtraProps = object, ExtraOverrides = object> = (<
25
+ TSteps extends StepsOptions<any> = StepsOptions<any>,
26
+ TFieldValues extends FieldValues = FieldValues,
27
+ TContext extends object = object,
28
+ TFieldTypes = FieldProps<TFieldValues>
29
+ >(
30
+ props: UseStepFormProps<TSteps, TFieldValues, TContext, TFieldTypes> & {
31
+ ref?: React.ForwardedRef<HTMLFormElement>
32
+ }
33
+ ) => React.ReactElement) & {
34
+ displayName?: string
35
+ id?: string
36
+ }
56
37
 
57
38
  export type DefaultFormType<
58
39
  FieldDefs = any,
@@ -69,59 +50,25 @@ export type DefaultFormType<
69
50
  id?: string
70
51
  }
71
52
 
72
- // export function createStepForm<
73
- // FieldDefs = any,
74
- // ExtraProps = object,
75
- // ExtraOverrides = object,
76
- // TFormType extends DefaultFormType<
77
- // FieldDefs,
78
- // ExtraProps,
79
- // ExtraOverrides
80
- // > = DefaultFormType<FieldDefs, ExtraProps, ExtraOverrides>
81
- // >(Form: TFormType) {
82
- // const StepForm = forwardRef<any, 'div'>((props, ref) => {
83
- // const { children, ...rest } = props
84
-
85
- // const stepper = useStepForm(props)
86
-
87
- // const { getFormProps, ...ctx } = stepper
88
-
89
- // const context = useMemo(() => ctx, [ctx])
90
-
91
- // return (
92
- // <StepperProvider value={context}>
93
- // <StepFormProvider value={context}>
94
- // <Form ref={ref} {...rest} {...getFormProps()}>
95
- // {runIfFn(children, {
96
- // ...stepper,
97
- // FormStep,
98
- // Field,
99
- // })}
100
- // </Form>
101
- // </StepFormProvider>
102
- // </StepperProvider>
103
- // )
104
- // }) as MergeStepFormProps<TFormType>
105
-
106
- // StepForm.displayName = `Step${Form.displayName || Form.name}`
107
-
108
- // return StepForm
109
- // }
53
+ export interface CreateFormProps<FieldDefs> {
54
+ resolver?: GetResolver
55
+ fieldResolver?: GetFieldResolver
56
+ fields?: FieldDefs extends Record<string, React.FC<any>> ? FieldDefs : never
57
+ }
110
58
 
111
59
  export function createStepForm<
112
60
  FieldDefs = any,
113
61
  ExtraProps = object,
114
- ExtraOverrides = object,
115
- TFormType extends DefaultFormType<
116
- FieldDefs,
117
- ExtraProps,
118
- ExtraOverrides
119
- > = DefaultFormType<FieldDefs, ExtraProps, ExtraOverrides>
120
- >(Form: TFormType) {
62
+ ExtraOverrides = object
63
+ >({ fields, resolver, fieldResolver }: CreateFormProps<FieldDefs> = {}) {
121
64
  const StepForm = forwardRef<any, 'div'>((props, ref) => {
122
- const { children, ...rest } = props
65
+ const { children, steps, ...rest } = props
123
66
 
124
- const stepper = useStepForm(props)
67
+ const stepper = useStepForm({
68
+ resolver,
69
+ fieldResolver,
70
+ ...props,
71
+ })
125
72
 
126
73
  const { getFormProps, ...ctx } = stepper
127
74
 
@@ -130,30 +77,22 @@ export function createStepForm<
130
77
  return (
131
78
  <StepperProvider value={context}>
132
79
  <StepFormProvider value={context}>
133
- <Form ref={ref} {...rest} {...getFormProps()}>
134
- {runIfFn(children, {
135
- ...stepper,
136
- Field: Field as any,
137
- DisplayIf: DisplayIf as any,
138
- ArrayField: ArrayField as any,
139
- ObjectField: ObjectField as any,
140
- })}
141
- </Form>
80
+ <FieldsProvider value={fields || {}}>
81
+ <Form ref={ref} {...rest} {...getFormProps()}>
82
+ {runIfFn(children, {
83
+ ...stepper,
84
+ Field: Field as any,
85
+ FormStep: FormStep as any,
86
+ DisplayIf: DisplayIf as any,
87
+ ArrayField: ArrayField as any,
88
+ ObjectField: ObjectField as any,
89
+ })}
90
+ </Form>
91
+ </FieldsProvider>
142
92
  </StepFormProvider>
143
93
  </StepperProvider>
144
94
  )
145
- }) as (<
146
- TFieldValues extends FieldValues = FieldValues,
147
- TContext extends object = object,
148
- TFieldTypes = FieldProps<TFieldValues>
149
- >(
150
- props: UseStepFormProps<TFieldValues, TContext, TFieldTypes> & {
151
- ref?: React.ForwardedRef<HTMLFormElement>
152
- }
153
- ) => React.ReactElement) & {
154
- displayName?: string
155
- id?: string
156
- }
95
+ }) as StepFormType<FieldDefs, ExtraProps, ExtraOverrides>
157
96
 
158
97
  StepForm.displayName = `Step${Form.displayName || Form.name}`
159
98
 
package/src/index.ts CHANGED
@@ -57,14 +57,21 @@ export { FormProvider, useFormContext } from './form-context'
57
57
  import { createForm } from './create-form'
58
58
  import { createStepForm } from './create-step-form'
59
59
 
60
+ /**
61
+ * Form component.
62
+ *
63
+ * @see Docs https://saas-ui.dev/docs/components/forms/form
64
+ */
60
65
  export const Form = createForm()
61
66
 
67
+ export { createStepForm } from './create-step-form'
68
+
62
69
  /**
63
- * The wrapper component provides context, state, and focus management.
70
+ * Multi-step form component.
64
71
  *
65
72
  * @see Docs https://saas-ui.dev/docs/components/forms/step-form
66
73
  */
67
- export const StepForm = createStepForm(Form)
74
+ export const StepForm = createStepForm()
68
75
 
69
76
  export type {
70
77
  BatchFieldArrayUpdate,
package/src/step-form.tsx CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react'
2
2
 
3
- import { FieldValues, UseFormReturn } from 'react-hook-form'
3
+ import { FieldValues } from 'react-hook-form'
4
4
 
5
5
  import {
6
6
  chakra,
@@ -10,90 +10,48 @@ import {
10
10
  ThemingProps,
11
11
  } from '@chakra-ui/react'
12
12
 
13
- import { callAllHandlers, runIfFn, cx } from '@chakra-ui/utils'
13
+ import { callAllHandlers, cx } from '@chakra-ui/utils'
14
14
 
15
15
  import {
16
- StepperProvider,
17
- StepperSteps,
18
- StepperStepsProps,
19
- StepperStep,
16
+ Steps,
17
+ StepsItem,
18
+ StepsItemProps,
19
+ StepsProps,
20
20
  useStepperContext,
21
- StepperContainer,
22
- StepperProps,
23
21
  } from '@saas-ui/core'
24
22
 
25
- import { Form } from './'
26
- import { Field } from './field'
27
-
28
23
  import { SubmitButton } from './submit-button'
29
24
 
30
25
  import {
31
- useStepForm,
32
26
  useFormStep,
33
- StepFormProvider,
34
27
  UseStepFormProps,
35
28
  FormStepSubmitHandler,
36
29
  } from './use-step-form'
37
30
  import { FieldProps } from './types'
38
- import { DisplayIf } from './display-if'
39
- import { ArrayField } from './array-field'
40
- import { ObjectField } from './object-field'
41
- import { createStepForm } from './create-step-form'
31
+
32
+ export type StepsOptions<TSchema, TName extends string = string> = {
33
+ /**
34
+ * The step name
35
+ */
36
+ name: TName
37
+ /**
38
+ * Schema
39
+ */
40
+ schema?: TSchema
41
+ }[]
42
42
 
43
43
  export interface StepFormProps<
44
+ TSteps extends StepsOptions<any> = StepsOptions<any>,
44
45
  TFieldValues extends FieldValues = FieldValues,
45
46
  TContext extends object = object,
46
47
  TFieldTypes = FieldProps<TFieldValues>
47
- > extends UseStepFormProps<TFieldValues, TContext, TFieldTypes> {}
48
-
49
- // export const StepForm = React.forwardRef(
50
- // <
51
- // TFieldValues extends FieldValues = FieldValues,
52
- // TContext extends object = object,
53
- // TFieldTypes = FieldProps<TFieldValues>
54
- // >(
55
- // props: StepFormProps<TFieldValues, TContext, TFieldTypes>,
56
- // ref: React.ForwardedRef<HTMLFormElement>
57
- // ) => {
58
- // const { children, ...rest } = props
59
-
60
- // const stepper = useStepForm(props)
61
-
62
- // const { getFormProps, ...ctx } = stepper
63
-
64
- // const context = React.useMemo(() => ctx, [ctx])
65
-
66
- // return (
67
- // <StepperProvider value={context}>
68
- // <StepFormProvider value={context}>
69
- // <Form ref={ref} {...rest} {...getFormProps()}>
70
- // {runIfFn(children, {
71
- // ...stepper,
72
- // Field: Field as any,
73
- // DisplayIf: DisplayIf as any,
74
- // ArrayField: ArrayField as any,
75
- // ObjectField: ObjectField as any,
76
- // })}
77
- // </Form>
78
- // </StepFormProvider>
79
- // </StepperProvider>
80
- // )
81
- // }
82
- // ) as <
83
- // TFieldValues extends FieldValues = FieldValues,
84
- // TContext extends object = object,
85
- // TFieldTypes = FieldProps<TFieldValues>
86
- // >(
87
- // props: UseStepFormProps<TFieldValues, TContext, TFieldTypes> & {
88
- // ref?: React.ForwardedRef<HTMLFormElement>
89
- // }
90
- // ) => React.ReactElement
91
-
92
- export interface FormStepOptions {
48
+ > extends UseStepFormProps<TSteps, TFieldValues, TContext, TFieldTypes> {}
49
+
50
+ export interface FormStepOptions<TName extends string = string> {
93
51
  /**
94
52
  * The step name
95
53
  */
96
- name: string
54
+ name: TName
97
55
  /**
98
56
  * Schema
99
57
  */
@@ -104,9 +62,9 @@ export interface FormStepOptions {
104
62
  resolver?: any
105
63
  }
106
64
 
107
- export interface FormStepperProps
108
- extends StepperStepsProps,
109
- ThemingProps<'Stepper'> {}
65
+ export interface FormStepperProps extends StepsProps, ThemingProps<'Stepper'> {
66
+ render?: StepsItemProps['render']
67
+ }
110
68
 
111
69
  /**
112
70
  * Renders a stepper that displays progress above the form.
@@ -116,7 +74,16 @@ export interface FormStepperProps
116
74
  export const FormStepper: React.FC<FormStepperProps> = (props) => {
117
75
  const { activeIndex, setIndex } = useStepperContext()
118
76
 
119
- const { children, orientation, variant, colorScheme, size, ...rest } = props
77
+ const {
78
+ children,
79
+ orientation,
80
+ variant,
81
+ colorScheme,
82
+ size,
83
+ onChange: onChangeProp,
84
+ render,
85
+ ...rest
86
+ } = props
120
87
 
121
88
  const elements = React.Children.map(children, (child) => {
122
89
  if (
@@ -125,14 +92,15 @@ export const FormStepper: React.FC<FormStepperProps> = (props) => {
125
92
  ) {
126
93
  const { isCompleted } = useFormStep(child.props) // Register this step
127
94
  return (
128
- <StepperStep
95
+ <StepsItem
96
+ render={render}
129
97
  name={child.props.name}
130
98
  title={child.props.title}
131
99
  isCompleted={isCompleted}
132
100
  {...rest}
133
101
  >
134
102
  {child.props.children}
135
- </StepperStep>
103
+ </StepsItem>
136
104
  )
137
105
  }
138
106
  return child
@@ -140,10 +108,11 @@ export const FormStepper: React.FC<FormStepperProps> = (props) => {
140
108
 
141
109
  const onChange = React.useCallback((i: number) => {
142
110
  setIndex(i)
111
+ onChangeProp?.(i)
143
112
  }, [])
144
113
 
145
114
  return (
146
- <StepperContainer
115
+ <Steps
147
116
  orientation={orientation}
148
117
  step={activeIndex}
149
118
  variant={variant}
@@ -151,15 +120,13 @@ export const FormStepper: React.FC<FormStepperProps> = (props) => {
151
120
  size={size}
152
121
  onChange={onChange}
153
122
  >
154
- <StepperSteps mb="4" {...props}>
155
- {elements}
156
- </StepperSteps>
157
- </StepperContainer>
123
+ {elements}
124
+ </Steps>
158
125
  )
159
126
  }
160
127
 
161
- export interface FormStepProps
162
- extends FormStepOptions,
128
+ export interface FormStepProps<TName extends string = string>
129
+ extends FormStepOptions<TName>,
163
130
  Omit<HTMLChakraProps<'div'>, 'onSubmit'> {
164
131
  onSubmit?: FormStepSubmitHandler
165
132
  }
@@ -168,10 +135,11 @@ export interface FormStepProps
168
135
  *
169
136
  * @see Docs https://saas-ui.dev/docs/components/forms/step-form
170
137
  */
171
- export const FormStep: React.FC<FormStepProps> = (props) => {
172
- const { name, schema, resolver, children, className, onSubmit, ...rest } =
173
- props
174
- const step = useFormStep({ name, schema, resolver, onSubmit })
138
+ export const FormStep = <TName extends string = string>(
139
+ props: FormStepProps<TName>
140
+ ) => {
141
+ const { name, children, className, onSubmit, ...rest } = props
142
+ const step = useFormStep({ name, onSubmit })
175
143
 
176
144
  const { isActive } = step
177
145
 
@@ -34,7 +34,7 @@ export const [StepFormProvider, useStepFormContext] =
34
34
  })
35
35
 
36
36
  import { FormProps } from './form'
37
- import { FormStepProps } from './step-form'
37
+ import { FormStepProps, StepsOptions } from './step-form'
38
38
  import { FieldProps } from './types'
39
39
  import { FocusableElement } from '@chakra-ui/utils'
40
40
  import { DisplayIfProps } from './display-if'
@@ -42,12 +42,17 @@ import { ArrayFieldProps } from './array-field'
42
42
  import { UseArrayFieldReturn } from './use-array-field'
43
43
  import { ObjectFieldProps } from './object-field'
44
44
 
45
+ type StepName<T extends { [k: number]: { readonly name: string } }> =
46
+ T[number]['name']
47
+
45
48
  interface StepFormRenderContext<
49
+ TSteps extends StepsOptions<any> = StepsOptions<any>,
46
50
  TFieldValues extends FieldValues = FieldValues,
47
51
  TContext extends object = object,
48
52
  TFieldTypes = FieldProps<TFieldValues>
49
53
  > extends UseStepFormReturn<TFieldValues> {
50
54
  Field: React.FC<TFieldTypes & React.RefAttributes<FocusableElement>>
55
+ FormStep: React.FC<FormStepProps<StepName<TSteps>>>
51
56
  DisplayIf: React.FC<DisplayIfProps<TFieldValues>>
52
57
  ArrayField: React.FC<
53
58
  ArrayFieldProps<TFieldValues> & React.RefAttributes<UseArrayFieldReturn>
@@ -56,13 +61,15 @@ interface StepFormRenderContext<
56
61
  }
57
62
 
58
63
  export interface UseStepFormProps<
64
+ TSteps extends StepsOptions<any> = StepsOptions<any>,
59
65
  TFieldValues extends FieldValues = FieldValues,
60
66
  TContext extends object = object,
61
67
  TFieldTypes = FieldProps<TFieldValues>
62
68
  > extends Omit<UseStepperProps, 'onChange'>,
63
69
  Omit<FormProps<any, TFieldValues, TContext, TFieldTypes>, 'children'> {
70
+ steps?: TSteps
64
71
  children: MaybeRenderProp<
65
- StepFormRenderContext<TFieldValues, TContext, TFieldTypes>
72
+ StepFormRenderContext<TSteps, TFieldValues, TContext, TFieldTypes>
66
73
  >
67
74
  }
68
75
 
@@ -79,15 +86,18 @@ export interface UseStepFormReturn<
79
86
  }
80
87
 
81
88
  export function useStepForm<
89
+ TSteps extends StepsOptions<any> = StepsOptions<any>,
82
90
  TFieldValues extends FieldValues = FieldValues,
83
91
  TContext extends object = object,
84
92
  TFieldTypes = FieldProps<TFieldValues>
85
93
  >(
86
- props: UseStepFormProps<TFieldValues, TContext, TFieldTypes>
94
+ props: UseStepFormProps<TSteps, TFieldValues, TContext, TFieldTypes>
87
95
  ): UseStepFormReturn<TFieldValues> {
88
- const { onChange, ...rest } = props
96
+ const { onChange, steps: stepsOptions, resolver, ...rest } = props
89
97
  const stepper = useStepper(rest)
90
98
 
99
+ const [options, setOptions] = React.useState<TSteps | undefined>(stepsOptions)
100
+
91
101
  const { activeStep, isLastStep, nextStep } = stepper
92
102
 
93
103
  const [steps, updateSteps] = React.useState<Record<string, StepState>>({})
@@ -121,23 +131,30 @@ export function useStepForm<
121
131
 
122
132
  const getFormProps = React.useCallback(() => {
123
133
  const step = steps[activeStep]
134
+
124
135
  return {
125
136
  onSubmit: onSubmitStep,
126
137
  schema: step?.schema,
127
- resolver: step?.resolver,
138
+ resolver: step?.schema
139
+ ? /* @todo fix resolver type */ (resolver as any)?.(step.schema)
140
+ : undefined,
128
141
  }
129
142
  }, [steps, onSubmitStep, activeStep])
130
143
 
131
144
  const updateStep = React.useCallback(
132
145
  (step: StepState) => {
146
+ const stepOptions = options?.find((s) => s.name === step.name)
133
147
  updateSteps((steps) => {
134
148
  return {
135
149
  ...steps,
136
- [step.name]: step,
150
+ [step.name]: {
151
+ ...step,
152
+ schema: stepOptions?.schema,
153
+ },
137
154
  }
138
155
  })
139
156
  },
140
- [steps]
157
+ [steps, options]
141
158
  )
142
159
 
143
160
  return {