@saas-ui/forms 2.0.0-next.2 → 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.
Files changed (62) hide show
  1. package/CHANGELOG.md +188 -0
  2. package/README.md +53 -6
  3. package/dist/ajv/index.d.ts +24 -11
  4. package/dist/ajv/index.js +7 -9
  5. package/dist/ajv/index.js.map +1 -1
  6. package/dist/ajv/index.mjs +7 -10
  7. package/dist/ajv/index.mjs.map +1 -1
  8. package/dist/index.d.ts +519 -280
  9. package/dist/index.js +777 -696
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.mjs +756 -676
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/yup/index.d.ts +525 -21
  14. package/dist/yup/index.js +21 -9
  15. package/dist/yup/index.js.map +1 -1
  16. package/dist/yup/index.mjs +21 -10
  17. package/dist/yup/index.mjs.map +1 -1
  18. package/dist/zod/index.d.ts +525 -12
  19. package/dist/zod/index.js +21 -1
  20. package/dist/zod/index.js.map +1 -1
  21. package/dist/zod/index.mjs +21 -3
  22. package/dist/zod/index.mjs.map +1 -1
  23. package/package.json +33 -10
  24. package/src/array-field.tsx +88 -48
  25. package/src/auto-form.tsx +7 -3
  26. package/src/base-field.tsx +54 -0
  27. package/src/create-field.tsx +144 -0
  28. package/src/create-form.tsx +68 -0
  29. package/src/create-step-form.tsx +100 -0
  30. package/src/default-fields.tsx +163 -0
  31. package/src/display-field.tsx +9 -11
  32. package/src/display-if.tsx +20 -13
  33. package/src/field-resolver.ts +10 -8
  34. package/src/field.tsx +18 -445
  35. package/src/fields-context.tsx +23 -0
  36. package/src/fields.tsx +34 -21
  37. package/src/form-context.tsx +84 -0
  38. package/src/form.tsx +77 -55
  39. package/src/index.ts +58 -4
  40. package/src/input-right-button/input-right-button.stories.tsx +1 -1
  41. package/src/input-right-button/input-right-button.tsx +0 -2
  42. package/src/layout.tsx +16 -11
  43. package/src/number-input/number-input.tsx +9 -5
  44. package/src/object-field.tsx +35 -13
  45. package/src/password-input/password-input.stories.tsx +23 -2
  46. package/src/password-input/password-input.tsx +6 -6
  47. package/src/pin-input/pin-input.tsx +1 -5
  48. package/src/radio/radio-input.stories.tsx +1 -1
  49. package/src/radio/radio-input.tsx +12 -10
  50. package/src/select/native-select.tsx +1 -4
  51. package/src/select/select-context.tsx +130 -0
  52. package/src/select/select.stories.tsx +116 -85
  53. package/src/select/select.test.tsx +1 -1
  54. package/src/select/select.tsx +162 -146
  55. package/src/step-form.tsx +76 -76
  56. package/src/submit-button.tsx +5 -1
  57. package/src/types.ts +149 -0
  58. package/src/use-array-field.tsx +9 -3
  59. package/src/use-step-form.tsx +54 -9
  60. package/src/utils.ts +23 -1
  61. package/src/watch-field.tsx +2 -6
  62. /package/src/radio/{radio.test.tsx → radio-input.test.tsx} +0 -0
package/dist/zod/index.js CHANGED
@@ -75,16 +75,36 @@ var zodParseMeta = (meta) => {
75
75
  }
76
76
  };
77
77
  var createZodForm = (options) => {
78
- return forms.createForm({
78
+ const ZodForm = forms.createForm({
79
79
  resolver: (schema) => zod.zodResolver(schema, options == null ? void 0 : options.schemaOptions, options == null ? void 0 : options.resolverOptions),
80
+ fieldResolver: zodFieldResolver,
80
81
  ...options
81
82
  });
83
+ ZodForm.displayName = "ZodForm";
84
+ ZodForm.id = "ZodForm";
85
+ return ZodForm;
82
86
  };
87
+ var createZodStepForm = (options) => {
88
+ const ZodStepForm = forms.createStepForm({
89
+ resolver: (schema) => zod.zodResolver(schema, options == null ? void 0 : options.schemaOptions, options == null ? void 0 : options.resolverOptions),
90
+ fieldResolver: zodFieldResolver,
91
+ ...options
92
+ });
93
+ ZodStepForm.displayName = "ZodStepForm";
94
+ ZodStepForm.id = "ZodStepForm";
95
+ return ZodStepForm;
96
+ };
97
+
98
+ // zod/src/index.ts
99
+ var Form = createZodForm();
100
+ var StepForm = createZodStepForm();
83
101
 
84
102
  Object.defineProperty(exports, 'zodResolver', {
85
103
  enumerable: true,
86
104
  get: function () { return zod.zodResolver; }
87
105
  });
106
+ exports.Form = Form;
107
+ exports.StepForm = StepForm;
88
108
  exports.createZodForm = createZodForm;
89
109
  exports.getFieldsFromSchema = getFieldsFromSchema;
90
110
  exports.getNestedSchema = getNestedSchema;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../zod/src/zod-resolver.ts","../../zod/src/create-zod-form.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,UAAX,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;AAE3B,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,SAAS,kBAA8C;AAWhD,IAAM,gBAAgB,CAAC,YAAiC;AAC7D,SAAO,WAA2B;AAAA,IAChC,UAAU,CAAC,WACT,YAAY,QAAQ,mCAAS,eAAe,mCAAS,eAAe;AAAA,IACtE,GAAG;AAAA,EACL,CAAC;AAMH","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 { createForm, CreateFormProps, FormProps } from '@saas-ui/forms'\nimport { zodResolver } from './zod-resolver'\nimport { z } from 'zod'\n\ntype ResolverArgs = Parameters<typeof zodResolver>\n\nexport interface CreateZodFormProps extends CreateFormProps {\n schemaOptions?: ResolverArgs[1]\n resolverOptions?: ResolverArgs[2]\n}\n\nexport const createZodForm = (options?: CreateZodFormProps) => {\n return createForm<z.AnyZodObject>({\n resolver: (schema) =>\n zodResolver(schema, options?.schemaOptions, options?.resolverOptions),\n ...options,\n }) as <\n TSchema extends z.AnyZodObject = z.AnyZodObject,\n TContext extends object = object\n >(\n props: FormProps<z.infer<TSchema>, TContext, TSchema>\n ) => React.ReactElement\n}\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"]}
@@ -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) => {
@@ -74,12 +74,30 @@ var zodParseMeta = (meta) => {
74
74
  }
75
75
  };
76
76
  var createZodForm = (options) => {
77
- return createForm({
77
+ const ZodForm = createForm({
78
78
  resolver: (schema) => zodResolver(schema, options == null ? void 0 : options.schemaOptions, options == null ? void 0 : options.resolverOptions),
79
+ fieldResolver: zodFieldResolver,
79
80
  ...options
80
81
  });
82
+ ZodForm.displayName = "ZodForm";
83
+ ZodForm.id = "ZodForm";
84
+ return ZodForm;
81
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
+ };
96
+
97
+ // zod/src/index.ts
98
+ var Form = createZodForm();
99
+ var StepForm = createZodStepForm();
82
100
 
83
- export { createZodForm, getFieldsFromSchema, getNestedSchema, zodFieldResolver, zodMeta, zodParseMeta };
101
+ export { Form, StepForm, createZodForm, getFieldsFromSchema, getNestedSchema, zodFieldResolver, zodMeta, zodParseMeta };
84
102
  //# sourceMappingURL=out.js.map
85
103
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../zod/src/zod-resolver.ts","../../zod/src/create-zod-form.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,UAAX,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;AAE3B,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,SAAS,kBAA8C;AAWhD,IAAM,gBAAgB,CAAC,YAAiC;AAC7D,SAAO,WAA2B;AAAA,IAChC,UAAU,CAAC,WACT,YAAY,QAAQ,mCAAS,eAAe,mCAAS,eAAe;AAAA,IACtE,GAAG;AAAA,EACL,CAAC;AAMH","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 { createForm, CreateFormProps, FormProps } from '@saas-ui/forms'\nimport { zodResolver } from './zod-resolver'\nimport { z } from 'zod'\n\ntype ResolverArgs = Parameters<typeof zodResolver>\n\nexport interface CreateZodFormProps extends CreateFormProps {\n schemaOptions?: ResolverArgs[1]\n resolverOptions?: ResolverArgs[2]\n}\n\nexport const createZodForm = (options?: CreateZodFormProps) => {\n return createForm<z.AnyZodObject>({\n resolver: (schema) =>\n zodResolver(schema, options?.schemaOptions, options?.resolverOptions),\n ...options,\n }) as <\n TSchema extends z.AnyZodObject = z.AnyZodObject,\n TContext extends object = object\n >(\n props: FormProps<z.infer<TSchema>, TContext, TSchema>\n ) => React.ReactElement\n}\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,11 +1,12 @@
1
1
  {
2
2
  "name": "@saas-ui/forms",
3
- "version": "2.0.0-next.2",
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": {
7
7
  ".": {
8
8
  "require": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
9
10
  "import": "./dist/index.mjs"
10
11
  },
11
12
  "./src": {
@@ -13,6 +14,7 @@
13
14
  },
14
15
  "./yup": {
15
16
  "require": "./dist/yup/index.js",
17
+ "types": "./dist/yup/index.d.ts",
16
18
  "import": "./dist/yup/index.mjs"
17
19
  },
18
20
  "./yup/src": {
@@ -20,6 +22,7 @@
20
22
  },
21
23
  "./zod": {
22
24
  "require": "./dist/zod/index.js",
25
+ "types": "./dist/zod/index.d.ts",
23
26
  "import": "./dist/zod/index.mjs"
24
27
  },
25
28
  "./zod/src": {
@@ -27,12 +30,26 @@
27
30
  },
28
31
  "./ajv": {
29
32
  "require": "./dist/ajv/index.js",
33
+ "types": "./dist/ajv/index.d.ts",
30
34
  "import": "./dist/ajv/index.mjs"
31
35
  },
32
36
  "./ajv/src": {
33
37
  "default": "./ajv/src/index.ts"
34
38
  }
35
39
  },
40
+ "typesVersions": {
41
+ "*": {
42
+ "ajv": [
43
+ "./dist/ajv/index.d.ts"
44
+ ],
45
+ "yup": [
46
+ "./dist/yup/index.d.ts"
47
+ ],
48
+ "zod": [
49
+ "./dist/zod/index.d.ts"
50
+ ]
51
+ }
52
+ },
36
53
  "main": "./dist/index.js",
37
54
  "module": "./dist/index.mjs",
38
55
  "types": "./dist/index.d.ts",
@@ -45,7 +62,8 @@
45
62
  "build:ajv": "tsup ajv/src/index.ts --config ajv/tsup.config.ts",
46
63
  "lint": "eslint src --ext .ts,.tsx,.js,.jsx --config ../../.eslintrc.js",
47
64
  "lint:staged": "lint-staged --allow-empty --config ../../lint-staged.config.js",
48
- "typecheck": "tsc --noEmit"
65
+ "typecheck": "tsc --noEmit",
66
+ "tsd": "tsd"
49
67
  },
50
68
  "files": [
51
69
  "dist",
@@ -83,11 +101,11 @@
83
101
  "url": "https://storybook.saas-ui.dev"
84
102
  },
85
103
  "dependencies": {
86
- "@chakra-ui/icons": "^2.0.16",
87
- "@chakra-ui/react-utils": "^2.0.11",
88
- "@chakra-ui/utils": "^2.0.14",
89
- "@saas-ui/core": "2.0.0-next.2",
90
- "react-hook-form": "^7.43.0"
104
+ "@chakra-ui/react-utils": "^2.0.12",
105
+ "@chakra-ui/utils": "^2.0.15",
106
+ "@hookform/resolvers": "^3.1.0",
107
+ "@saas-ui/core": "2.0.0-next.17",
108
+ "react-hook-form": "^7.43.9"
91
109
  },
92
110
  "peerDependencies": {
93
111
  "@chakra-ui/react": ">=2.4.9",
@@ -98,10 +116,15 @@
98
116
  "react-dom": ">=18.0.0"
99
117
  },
100
118
  "devDependencies": {
101
- "@hookform/resolvers": "^2.9.3",
102
119
  "@types/json-schema": "^7.0.11",
103
120
  "ajv": "^8.12.0",
104
- "yup": "^0.32.11",
105
- "zod": "^3.20.2"
121
+ "ajv-errors": "^3.0.0",
122
+ "json-schema-to-ts": "^2.8.2",
123
+ "tsd": "^0.28.1",
124
+ "yup": "^1.1.1",
125
+ "zod": "^3.21.4"
126
+ },
127
+ "tsd": {
128
+ "directory": "tests"
106
129
  }
107
130
  }
@@ -7,11 +7,11 @@ import {
7
7
  Button,
8
8
  ButtonProps,
9
9
  } from '@chakra-ui/react'
10
- import { __DEV__ } from '@chakra-ui/utils'
11
- import { AddIcon, MinusIcon } from '@chakra-ui/icons'
10
+ import { PlusIcon, MinusIcon } from '@saas-ui/core/icons'
12
11
 
13
12
  import { FormLayout, FormLayoutProps } from './layout'
14
- import { BaseField, FieldProps } from './field'
13
+ import { BaseField } from './base-field'
14
+ import { BaseFieldProps } from './types'
15
15
 
16
16
  import { mapNestedFields } from './utils'
17
17
 
@@ -27,6 +27,10 @@ import {
27
27
  useArrayFieldAddButton,
28
28
  UseArrayFieldReturn,
29
29
  } from './use-array-field'
30
+ import { FieldPath, FieldValues } from 'react-hook-form'
31
+ import { isFunction } from '@chakra-ui/utils'
32
+ import { MaybeRenderProp } from '@chakra-ui/react-utils'
33
+ import { useFieldProps } from './form-context'
30
34
 
31
35
  export interface ArrayFieldButtonProps extends ButtonProps {}
32
36
 
@@ -53,7 +57,11 @@ interface ArrayFieldRowProps extends FormLayoutProps {
53
57
  */
54
58
  children: React.ReactNode
55
59
  }
56
-
60
+ /**
61
+ * Render prop component, to get access to the internal fields state. Must be a child of ArrayFieldContainer.
62
+ *
63
+ * @see Docs https://saas-ui.dev/docs/components/forms/array-field
64
+ */
57
65
  export const ArrayFieldRow: React.FC<ArrayFieldRowProps> = ({
58
66
  children,
59
67
  index,
@@ -67,9 +75,7 @@ export const ArrayFieldRow: React.FC<ArrayFieldRowProps> = ({
67
75
  )
68
76
  }
69
77
 
70
- if (__DEV__) {
71
- ArrayFieldRow.displayName = 'ArrayFieldRow'
72
- }
78
+ ArrayFieldRow.displayName = 'ArrayFieldRow'
73
79
 
74
80
  export interface ArrayFieldRowFieldsProps extends FormLayoutProps {
75
81
  /**
@@ -85,7 +91,11 @@ export interface ArrayFieldRowFieldsProps extends FormLayoutProps {
85
91
  */
86
92
  children: React.ReactNode
87
93
  }
88
-
94
+ /**
95
+ * Add the name prefix to the fields and acts as a horizontal form layout by default.
96
+ *
97
+ * @see Docs https://saas-ui.dev/docs/components/forms/array-field
98
+ */
89
99
  export const ArrayFieldRowFields: React.FC<ArrayFieldRowFieldsProps> = ({
90
100
  children,
91
101
  ...layoutProps
@@ -98,13 +108,17 @@ export const ArrayFieldRowFields: React.FC<ArrayFieldRowFieldsProps> = ({
98
108
  )
99
109
  }
100
110
 
101
- if (__DEV__) {
102
- ArrayFieldRowFields.displayName = 'ArrayFieldRowFields'
103
- }
111
+ ArrayFieldRowFields.displayName = 'ArrayFieldRowFields'
104
112
 
113
+ /**
114
+ * The row container component providers row context.
115
+ *
116
+ * @see Docs https://saas-ui.dev/docs/components/forms/array-field
117
+ */
105
118
  export const ArrayFieldRowContainer: React.FC<ArrayFieldRowProps> = ({
106
119
  children,
107
120
  index,
121
+ ...rest
108
122
  }) => {
109
123
  const context = useArrayFieldRow({ index })
110
124
 
@@ -118,15 +132,20 @@ export const ArrayFieldRowContainer: React.FC<ArrayFieldRowProps> = ({
118
132
 
119
133
  return (
120
134
  <ArrayFieldRowProvider value={context}>
121
- <chakra.div __css={styles}>{children}</chakra.div>
135
+ <chakra.div {...rest} __css={styles}>
136
+ {children}
137
+ </chakra.div>
122
138
  </ArrayFieldRowProvider>
123
139
  )
124
140
  }
125
141
 
126
- if (__DEV__) {
127
- ArrayFieldRowContainer.displayName = 'ArrayFieldRowContainer'
128
- }
142
+ ArrayFieldRowContainer.displayName = 'ArrayFieldRowContainer'
129
143
 
144
+ /**
145
+ * The default remove button.
146
+ *
147
+ * @see Docs https://saas-ui.dev/docs/components/forms/array-field
148
+ */
130
149
  export const ArrayFieldRemoveButton: React.FC<ArrayFieldButtonProps> = (
131
150
  props
132
151
  ) => {
@@ -137,10 +156,13 @@ export const ArrayFieldRemoveButton: React.FC<ArrayFieldButtonProps> = (
137
156
  )
138
157
  }
139
158
 
140
- if (__DEV__) {
141
- ArrayFieldRemoveButton.displayName = 'ArrayFieldRemoveButton'
142
- }
159
+ ArrayFieldRemoveButton.displayName = 'ArrayFieldRemoveButton'
143
160
 
161
+ /**
162
+ * The default add button.
163
+ *
164
+ * @see Docs https://saas-ui.dev/docs/components/forms/array-field
165
+ */
144
166
  export const ArrayFieldAddButton: React.FC<ArrayFieldButtonProps> = (props) => {
145
167
  return (
146
168
  <Button
@@ -149,36 +171,48 @@ export const ArrayFieldAddButton: React.FC<ArrayFieldButtonProps> = (props) => {
149
171
  {...useArrayFieldAddButton()}
150
172
  {...props}
151
173
  >
152
- {props.children || <AddIcon />}
174
+ {props.children || <PlusIcon />}
153
175
  </Button>
154
176
  )
155
177
  }
156
178
 
157
- if (__DEV__) {
158
- ArrayFieldAddButton.displayName = 'ArrayFieldAddButton'
159
- }
179
+ ArrayFieldAddButton.displayName = 'ArrayFieldAddButton'
160
180
 
161
- export interface ArrayFieldProps
162
- extends ArrayFieldOptions,
163
- Omit<FieldProps, 'defaultValue'> {}
181
+ export interface ArrayFieldProps<
182
+ TFieldValues extends FieldValues = FieldValues,
183
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
184
+ > extends ArrayFieldOptions<TFieldValues, TName>,
185
+ Omit<
186
+ BaseFieldProps<TFieldValues, TName>,
187
+ 'name' | 'defaultValue' | 'children'
188
+ > {
189
+ children: MaybeRenderProp<ArrayField[]>
190
+ }
164
191
 
192
+ /**
193
+ * The wrapper component that composes the default ArrayField functionality.
194
+ *
195
+ * @see Docs https://saas-ui.dev/docs/components/forms/array-field
196
+ */
165
197
  export const ArrayField = forwardRef(
166
198
  (props: ArrayFieldProps, ref: React.ForwardedRef<UseArrayFieldReturn>) => {
167
199
  const { children, ...containerProps } = props
168
200
 
201
+ const rowFn = isFunction(children)
202
+ ? children
203
+ : (fields: ArrayField[]) => (
204
+ <>
205
+ {fields.map(({ id }, index: number) => (
206
+ <ArrayFieldRow key={id} index={index}>
207
+ {children}
208
+ </ArrayFieldRow>
209
+ )) || null}
210
+ </>
211
+ )
212
+
169
213
  return (
170
214
  <ArrayFieldContainer ref={ref} {...containerProps}>
171
- <ArrayFieldRows>
172
- {(fields: ArrayField[]) => (
173
- <>
174
- {fields.map(({ id }, index: number) => (
175
- <ArrayFieldRow key={id} index={index}>
176
- {children}
177
- </ArrayFieldRow>
178
- ))}
179
- </>
180
- )}
181
- </ArrayFieldRows>
215
+ <ArrayFieldRows>{rowFn as any}</ArrayFieldRows>
182
216
  <ArrayFieldAddButton />
183
217
  </ArrayFieldContainer>
184
218
  )
@@ -191,9 +225,7 @@ export const ArrayField = forwardRef(
191
225
  displayName: string
192
226
  }
193
227
 
194
- if (__DEV__) {
195
- ArrayField.displayName = 'ArrayField'
196
- }
228
+ ArrayField.displayName = 'ArrayField'
197
229
 
198
230
  export interface ArrayFieldRowsProps {
199
231
  children: (fields: ArrayField[]) => React.ReactElement | null
@@ -206,10 +238,18 @@ export const ArrayFieldRows = ({
206
238
  return children(fields)
207
239
  }
208
240
 
209
- if (__DEV__) {
210
- ArrayFieldRows.displayName = 'ArrayFieldRows'
241
+ ArrayFieldRows.displayName = 'ArrayFieldRows'
242
+
243
+ export interface ArrayFieldContainerProps
244
+ extends Omit<ArrayFieldProps, 'children'> {
245
+ children: React.ReactNode
211
246
  }
212
247
 
248
+ /**
249
+ * The container component provides context and state management.
250
+ *
251
+ * @see Docs https://saas-ui.dev/docs/components/forms/array-field
252
+ */
213
253
  export const ArrayFieldContainer = React.forwardRef(
214
254
  (
215
255
  {
@@ -220,15 +260,17 @@ export const ArrayFieldContainer = React.forwardRef(
220
260
  max,
221
261
  children,
222
262
  ...fieldProps
223
- }: ArrayFieldProps,
263
+ }: ArrayFieldContainerProps,
224
264
  ref: React.ForwardedRef<UseArrayFieldReturn>
225
265
  ) => {
266
+ const overrides = useFieldProps(name)
267
+
226
268
  const context = useArrayField({
227
269
  name,
228
270
  defaultValue,
229
271
  keyName,
230
- min,
231
- max,
272
+ min: min || (overrides as any)?.min,
273
+ max: max || (overrides as any)?.max,
232
274
  })
233
275
 
234
276
  // This exposes the useArrayField api through the forwarded ref
@@ -236,7 +278,7 @@ export const ArrayFieldContainer = React.forwardRef(
236
278
 
237
279
  return (
238
280
  <ArrayFieldProvider value={context}>
239
- <BaseField name={name} {...fieldProps}>
281
+ <BaseField name={name} {...fieldProps} {...overrides}>
240
282
  {children}
241
283
  </BaseField>
242
284
  </ArrayFieldProvider>
@@ -244,6 +286,4 @@ export const ArrayFieldContainer = React.forwardRef(
244
286
  }
245
287
  )
246
288
 
247
- if (__DEV__) {
248
- ArrayFieldContainer.displayName = 'ArrayFieldContainer'
249
- }
289
+ ArrayFieldContainer.displayName = 'ArrayFieldContainer'
package/src/auto-form.tsx CHANGED
@@ -4,7 +4,7 @@ import { forwardRef } from '@chakra-ui/react'
4
4
 
5
5
  import { Form, FormProps } from './form'
6
6
  import { FormLayout } from './layout'
7
- import { Fields } from './fields'
7
+ import { AutoFields } from './fields'
8
8
  import { SubmitButton } from './submit-button'
9
9
 
10
10
  interface AutoFormOptions {
@@ -32,7 +32,11 @@ export interface AutoFormProps<
32
32
  AutoFormOptions {
33
33
  children?: React.ReactNode
34
34
  }
35
-
35
+ /**
36
+ * The wrapper component that manages context and state.
37
+ *
38
+ * @see Docs https://saas-ui.dev/docs/components/forms/auto-form
39
+ */
36
40
  export const AutoForm = forwardRef(
37
41
  <
38
42
  TFieldValues extends FieldValues = FieldValues,
@@ -52,7 +56,7 @@ export const AutoForm = forwardRef(
52
56
  return (
53
57
  <Form {...rest} schema={schema} ref={ref}>
54
58
  <FormLayout>
55
- {<Fields schema={schema} fieldResolver={fieldResolver} />}
59
+ {<AutoFields schema={schema} fieldResolver={fieldResolver} />}
56
60
  {submitLabel && <SubmitButton>{submitLabel}</SubmitButton>}
57
61
  {children}
58
62
  </FormLayout>
@@ -0,0 +1,54 @@
1
+ import * as React from 'react'
2
+ import { FormState, get } from 'react-hook-form'
3
+
4
+ import {
5
+ Box,
6
+ FormControl,
7
+ FormLabel,
8
+ FormHelperText,
9
+ FormErrorMessage,
10
+ } from '@chakra-ui/react'
11
+
12
+ import { useFormContext } from './form-context'
13
+
14
+ import { BaseFieldProps, FieldProps } from './types'
15
+
16
+ const getError = (name: string, formState: FormState<{ [x: string]: any }>) => {
17
+ return get(formState.errors, name)
18
+ }
19
+
20
+ const isTouched = (
21
+ name: string,
22
+ formState: FormState<{ [x: string]: any }>
23
+ ) => {
24
+ return get(formState.touchedFields, name)
25
+ }
26
+
27
+ /**
28
+ * The default BaseField component
29
+ * Composes the Chakra UI FormControl component, with FormLabel, FormHelperText and FormErrorMessage.
30
+ */
31
+ export const BaseField: React.FC<BaseFieldProps> = (props) => {
32
+ const { name, label, help, hideLabel, children, ...controlProps } = props
33
+
34
+ const { formState } = useFormContext()
35
+
36
+ const error = getError(name, formState)
37
+
38
+ return (
39
+ <FormControl {...controlProps} isInvalid={!!error}>
40
+ {label && !hideLabel ? <FormLabel>{label}</FormLabel> : null}
41
+ <Box>
42
+ {children}
43
+ {help && !error?.message ? (
44
+ <FormHelperText>{help}</FormHelperText>
45
+ ) : null}
46
+ {error?.message && (
47
+ <FormErrorMessage>{error?.message}</FormErrorMessage>
48
+ )}
49
+ </Box>
50
+ </FormControl>
51
+ )
52
+ }
53
+
54
+ BaseField.displayName = 'BaseField'