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

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.
@@ -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 {