@sanity/form-toolkit 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -42,11 +42,11 @@ declare type FormField = {
42
42
  type: string
43
43
  label?: string
44
44
  name: string
45
- required: boolean
45
+ required?: boolean
46
46
  validation?: ValidationRule[]
47
47
  options?: FieldOptions
48
48
  choices?: FieldChoice[]
49
- _key: string
49
+ _key?: string
50
50
  }
51
51
 
52
52
  export declare const FormRenderer: FC<FormRendererProps>
@@ -42,11 +42,11 @@ declare type FormField = {
42
42
  type: string
43
43
  label?: string
44
44
  name: string
45
- required: boolean
45
+ required?: boolean
46
46
  validation?: ValidationRule[]
47
47
  options?: FieldOptions
48
48
  choices?: FieldChoice[]
49
- _key: string
49
+ _key?: string
50
50
  }
51
51
 
52
52
  export declare const FormRenderer: FC<FormRendererProps>
@@ -14,6 +14,8 @@ const DefaultField = ({ field, fieldState, error }) => {
14
14
  onChange(e.target.checked ? choiceValue : "");
15
15
  }, renderInput = () => {
16
16
  switch (type) {
17
+ case "submit":
18
+ return /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", children: label || "Submit" });
17
19
  case "textarea":
18
20
  return /* @__PURE__ */ jsxRuntime.jsx(
19
21
  "textarea",
@@ -86,7 +88,7 @@ const DefaultField = ({ field, fieldState, error }) => {
86
88
  }
87
89
  };
88
90
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
89
- label && type != "hidden" && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: name, children: label }),
91
+ label && !["hidden", "submit"].includes(type) && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: name, children: label }),
90
92
  renderInput(),
91
93
  error && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "error", children: error })
92
94
  ] });
@@ -110,7 +112,11 @@ const DefaultField = ({ field, fieldState, error }) => {
110
112
  return delete elProps.formData, delete elProps.getFieldState, delete elProps.getFieldError, delete elProps.fieldComponents, /* @__PURE__ */ jsxRuntime.jsxs("form", { ...elProps, id: elProps.id ?? formData?.id?.current, children: [
111
113
  formData?.fields?.map((field) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "form-field", children: renderField(field) }, field._key)),
112
114
  children,
113
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", children: formData?.submitButton?.text || "Submit" })
115
+ renderField({
116
+ type: "submit",
117
+ name: "submit",
118
+ label: formData?.submitButton?.text || "Submit"
119
+ })
114
120
  ] });
115
121
  }, formType = sanity.defineType({
116
122
  name: "form",
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/form-schema/components/default-field.tsx","../../src/form-schema/components/form-renderer.tsx","../../src/form-schema/schema-types/form.ts","../../src/form-schema/schema-types/form-field.ts","../../src/form-schema/schema-types/index.ts","../../src/form-schema/index.ts"],"sourcesContent":["import type {ChangeEvent, FC, LegacyRef} from 'react'\n\nimport type {FieldComponentProps} from './types'\n\nexport const DefaultField: FC<FieldComponentProps> = ({field, fieldState, error}) => {\n const {type, label, name, options = {}, choices = []} = field\n if (!type || !name) return null\n\n const {value, onChange, onBlur, ref} = fieldState\n\n const handleChange = (\n e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>,\n ) => {\n onChange(e.target.value)\n }\n\n const handleCheckboxChange = (e: ChangeEvent<HTMLInputElement>, choiceValue: string) => {\n if (Array.isArray(value)) {\n const newValue = e.target.checked\n ? [...value, choiceValue]\n : value.filter((v: string) => v !== choiceValue)\n onChange(newValue)\n } else {\n onChange(e.target.checked ? choiceValue : '')\n }\n }\n\n const renderInput = () => {\n switch (type) {\n case 'textarea':\n return (\n <textarea\n ref={ref as LegacyRef<HTMLTextAreaElement>}\n name={name}\n value={value ?? ''}\n onChange={handleChange}\n onBlur={onBlur}\n placeholder={options.placeholder}\n />\n )\n\n case 'select':\n return (\n <select\n ref={ref as LegacyRef<HTMLSelectElement>}\n name={name}\n value={value ?? ''}\n onChange={handleChange}\n onBlur={onBlur}\n >\n {choices?.map((choice, i) => (\n <option key={i} value={choice.value}>\n {choice.label}\n </option>\n ))}\n </select>\n )\n\n case 'radio':\n return choices?.map((choice, i) => (\n <label key={i}>\n <input\n type=\"radio\"\n name={name}\n ref={ref as LegacyRef<HTMLInputElement>}\n value={choice.value}\n checked={value === choice.value}\n onChange={handleChange}\n onBlur={onBlur}\n />\n {choice.label}\n </label>\n ))\n\n case 'checkbox':\n return choices?.map((choice, i) => (\n <label key={i}>\n <input\n type=\"checkbox\"\n name={name}\n ref={ref as LegacyRef<HTMLInputElement>}\n value={choice.value}\n checked={Array.isArray(value) ? value.includes(choice.value) : value === choice.value}\n onChange={(e) => handleCheckboxChange(e, choice.value)}\n onBlur={onBlur}\n />\n {choice.label}\n </label>\n ))\n\n default:\n return (\n <input\n type={type}\n ref={ref as LegacyRef<HTMLInputElement>}\n name={name}\n value={value ?? options.defaultValue ?? ''}\n onChange={handleChange}\n onBlur={onBlur}\n placeholder={options.placeholder}\n />\n )\n }\n }\n\n return (\n <>\n {label && type != 'hidden' && <label htmlFor={name}>{label}</label>}\n {renderInput()}\n {error && <span className=\"error\">{error}</span>}\n </>\n )\n}\n","import type {ComponentType, FC, HTMLProps} from 'react'\n\nimport {DefaultField} from './default-field'\nimport type {FieldComponentProps, FieldState, FormDataProps, FormField} from './types'\n\ninterface FormRendererProps extends HTMLProps<HTMLFormElement> {\n formData?: FormDataProps\n // Function to get field state for a given field name\n getFieldState?: (fieldName: string) => FieldState\n // Function to get field error for a given field name\n getFieldError?: (fieldName: string) => string | undefined\n // Override default field components\n fieldComponents?: Record<string, ComponentType<FieldComponentProps>>\n}\n\nexport const FormRenderer: FC<FormRendererProps> = (props) => {\n const {\n formData,\n getFieldState = (name) => ({\n value: undefined,\n onChange: () => {},\n name, // Pass name to field for native form handling\n }),\n getFieldError,\n fieldComponents = {},\n children,\n } = props\n const renderField = (field: FormField) => {\n const CustomComponent = fieldComponents[field.type]\n const fieldState = getFieldState(field.name)\n const error = getFieldError?.(field.name)\n\n if (CustomComponent) {\n return <CustomComponent field={field} fieldState={fieldState} error={error} />\n }\n\n return <DefaultField field={field} fieldState={fieldState} error={error} />\n }\n const elProps = Object.assign({}, props)\n delete elProps.formData\n delete elProps.getFieldState\n delete elProps.getFieldError\n delete elProps.fieldComponents\n\n return (\n <form {...elProps} id={elProps.id ?? formData?.id?.current}>\n {formData?.fields?.map((field) => (\n <div key={field._key} className=\"form-field\">\n {renderField(field)}\n </div>\n ))}\n\n {children}\n\n <button type=\"submit\">{formData?.submitButton?.text || 'Submit'}</button>\n </form>\n )\n}\n","import {FaWpforms} from 'react-icons/fa'\nimport {defineField, defineType} from 'sanity'\n\nexport const formType = defineType({\n name: 'form',\n title: 'Form',\n type: 'document',\n icon: FaWpforms,\n fields: [\n defineField({\n name: 'title',\n title: 'Form Title',\n type: 'string',\n description: 'Internal title for the form',\n validation: (Rule) => Rule.required(),\n }),\n defineField({\n name: 'id',\n title: 'Form ID',\n type: 'slug',\n options: {\n source: 'title',\n },\n // validation: (Rule) => Rule.required(),\n }),\n defineField({\n name: 'fields',\n title: 'Form Fields',\n type: 'array',\n of: [{type: 'formField'}],\n }),\n defineField({\n name: 'submitButton',\n title: 'Submit Button',\n type: 'object',\n fields: [\n defineField({\n name: 'text',\n title: 'Button Text',\n type: 'string',\n initialValue: 'Submit',\n }),\n // defineField({\n // name: 'position',\n // title: 'Button Position',\n // type: 'string',\n // options: {\n // list: ['left', 'center', 'right'],\n // },\n // initialValue: 'center',\n // }),\n ],\n }),\n ],\n})\n","import {LuTextCursorInput} from 'react-icons/lu'\nimport {defineField, defineType} from 'sanity'\n\ninterface ValidationContextDocument {\n fields?: Array<{\n name: string\n type?: string\n }>\n}\n// Validation options by field type\nexport const validationTypesByFieldType = {\n checkbox: ['minSelectedCount', 'maxSelectedCount', 'custom'],\n color: ['custom'],\n date: ['minDate', 'maxDate', 'custom'],\n 'datetime-local': ['minDate', 'maxDate', 'custom'],\n email: ['pattern', 'custom'],\n file: ['maxSize', 'fileType', 'custom'],\n hidden: ['custom'],\n number: ['min', 'max', 'custom'],\n // password: ['minLength', 'pattern', 'custom'],\n radio: ['custom'],\n range: ['min', 'max', 'step', 'custom'],\n select: ['custom'],\n tel: ['pattern', 'custom'],\n text: ['minLength', 'maxLength', 'pattern', 'custom'],\n textarea: ['minLength', 'maxLength', 'custom'],\n time: ['custom'],\n url: ['pattern', 'custom'],\n}\nexport const formFieldType = defineType({\n name: 'formField',\n title: 'Form Field',\n type: 'object',\n icon: LuTextCursorInput,\n fields: [\n defineField({\n name: 'type',\n title: 'Field Type',\n type: 'string',\n options: {\n list: Object.keys(validationTypesByFieldType).map((type) => {\n const title = (fieldType: string) => {\n switch (fieldType) {\n case 'datetime-local':\n return 'Date & Time'\n case 'textarea':\n return 'Text Area'\n case 'tel':\n return 'Phone Number'\n default:\n return fieldType.charAt(0).toUpperCase() + fieldType.slice(1)\n }\n }\n return {title: title(type), value: type}\n }),\n },\n }),\n defineField({\n name: 'label',\n title: 'Field Label',\n type: 'string',\n }),\n defineField({\n name: 'name',\n title: 'Field Name',\n type: 'string',\n description:\n 'Must start with a letter and contain only letters, numbers, underscores, or hyphens. Must be unique within the form.',\n validation: (Rule) =>\n Rule.required().custom((name, context) => {\n if (!name) {\n return 'Required'\n }\n // Check format (HTML ID/name rules)\n if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)) {\n return 'Field name must start with a letter and contain only letters, numbers, underscores, or hyphens'\n }\n\n // Check uniqueness across all fields\n const doc = context.document as ValidationContextDocument\n const allFieldNames = doc?.fields?.map((field) => field.name) || []\n\n // Count occurrences of this name\n const nameCount = allFieldNames.filter((n) => n === name).length\n\n // If we find more than one occurrence (including current field), it's not unique\n if (nameCount > 1) {\n return 'Field name must be unique across all form fields'\n }\n\n // Check for reserved HTML form attributes\n const reservedNames = [\n 'action',\n 'method',\n 'target',\n 'enctype',\n 'accept-charset',\n 'autocomplete',\n 'novalidate',\n 'rel',\n 'submit',\n 'reset',\n ]\n if (reservedNames.includes(name.toLowerCase())) {\n return 'This name is reserved for HTML form attributes. Please choose a different name.'\n }\n\n return true\n }),\n }),\n defineField({\n name: 'required',\n title: 'Required',\n type: 'boolean',\n initialValue: false,\n }),\n // defineField({\n // name: 'validation',\n // title: 'Validation Rules',\n // type: 'array',\n // of: [\n // {\n // type: 'object',\n // fields: [\n // defineField({\n // name: 'type',\n // title: 'Validation Type',\n // type: 'string',\n\n // hidden: ({parent}) => !parent?.type,\n // options: {\n // // TODO: I think this needs to be a custom input component?\n // // list: ({parent}) => (parent?.type ? validationTypesByFieldType[parent.type] : []),\n // list: [],\n // },\n // }),\n // defineField({\n // name: 'value',\n // title: 'Value',\n // type: 'string',\n // }),\n // defineField({\n // name: 'message',\n // title: 'Error Message',\n // type: 'string',\n // }),\n // ],\n // },\n // ],\n // }),\n defineField({\n name: 'choices',\n title: 'Choices',\n type: 'array',\n hidden: ({parent}) => {\n return !['select', 'radio', 'checkbox'].includes(parent?.type)\n },\n of: [\n {\n type: 'object',\n fields: [\n defineField({\n name: 'label',\n title: 'Label',\n type: 'string',\n }),\n defineField({\n name: 'value',\n title: 'Value',\n type: 'string',\n }),\n ],\n },\n ],\n }),\n defineField({\n name: 'options',\n title: 'Field Options',\n type: 'object',\n hidden: ({parent}) => {\n return ['select', 'radio', 'checkbox', 'file'].includes(parent?.type)\n },\n fields: [\n defineField({\n name: 'placeholder',\n title: 'Placeholder',\n type: 'string',\n }),\n defineField({\n name: 'defaultValue',\n title: 'Default Value',\n type: 'string',\n }),\n ],\n }),\n ],\n preview: {\n select: {\n label: 'label',\n name: 'name',\n type: 'type',\n },\n prepare({label, name, type}) {\n return {\n title: label || name,\n subtitle: type,\n }\n },\n },\n})\n","import type {SchemaTypeDefinition} from 'sanity'\n\nimport {formType} from './form'\nimport {formFieldType} from './form-field'\n\nexport const schema: {types: SchemaTypeDefinition[]} = {\n types: [formType, formFieldType],\n}\n","import {definePlugin} from 'sanity'\n\n// import {structureTool} from 'sanity/structure'\nimport {FormRenderer} from './components/form-renderer'\nimport {schema} from './schema-types'\n// import {defaultDocumentNode} from './structure'\n\n/**\n * Usage in `sanity.config.ts` (or .js)\n *\n * ```ts\n * import {defineConfig} from 'sanity'\n * import {formSchema} from '@sanity/form-toolkit'\n *\n * export default defineConfig({\n * // ...\n * plugins: [formSchema()],\n * })\n * ```\n */\nexport type {FormDataProps} from './components/types'\nexport {FormRenderer}\nexport const formSchema = definePlugin(() => {\n return {\n name: 'form-toolkit_form-schema',\n schema,\n // plugins: [structureTool({defaultDocumentNode})],\n }\n})\n"],"names":["jsx","jsxs","Fragment","defineType","FaWpforms","defineField","LuTextCursorInput","definePlugin"],"mappings":";;;AAIO,MAAM,eAAwC,CAAC,EAAC,OAAO,YAAY,YAAW;AAC7E,QAAA,EAAC,MAAM,OAAO,MAAM,UAAU,IAAI,UAAU,CAAC,EAAA,IAAK;AACxD,MAAI,CAAC,QAAQ,CAAC,KAAa,QAAA;AAErB,QAAA,EAAC,OAAO,UAAU,QAAQ,QAAO,YAEjC,eAAe,CACnB,MACG;AACM,aAAA,EAAE,OAAO,KAAK;AAAA,EAAA,GAGnB,uBAAuB,CAAC,GAAkC,gBAAwB;AAClF,QAAA,MAAM,QAAQ,KAAK,GAAG;AACxB,YAAM,WAAW,EAAE,OAAO,UACtB,CAAC,GAAG,OAAO,WAAW,IACtB,MAAM,OAAO,CAAC,MAAc,MAAM,WAAW;AACjD,eAAS,QAAQ;AAAA,IACnB;AACE,eAAS,EAAE,OAAO,UAAU,cAAc,EAAE;AAAA,EAEhD,GAEM,cAAc,MAAM;AACxB,YAAQ,MAAM;AAAA,MACZ,KAAK;AAED,eAAAA,2BAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA,OAAO,SAAS;AAAA,YAChB,UAAU;AAAA,YACV;AAAA,YACA,aAAa,QAAQ;AAAA,UAAA;AAAA,QACvB;AAAA,MAGJ,KAAK;AAED,eAAAA,2BAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA,OAAO,SAAS;AAAA,YAChB,UAAU;AAAA,YACV;AAAA,YAEC,UAAS,SAAA,IAAI,CAAC,QAAQ,MACrBA,2BAAAA,IAAC,UAAe,EAAA,OAAO,OAAO,OAC3B,UAAO,OAAA,MAAA,GADG,CAEb,CACD;AAAA,UAAA;AAAA,QACH;AAAA,MAGJ,KAAK;AACH,eAAO,SAAS,IAAI,CAAC,QAAQ,sCAC1B,SACC,EAAA,UAAA;AAAA,UAAAA,2BAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL;AAAA,cACA;AAAA,cACA,OAAO,OAAO;AAAA,cACd,SAAS,UAAU,OAAO;AAAA,cAC1B,UAAU;AAAA,cACV;AAAA,YAAA;AAAA,UACF;AAAA,UACC,OAAO;AAAA,QAAA,EAAA,GAVE,CAWZ,CACD;AAAA,MAEH,KAAK;AACH,eAAO,SAAS,IAAI,CAAC,QAAQ,sCAC1B,SACC,EAAA,UAAA;AAAA,UAAAA,2BAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL;AAAA,cACA;AAAA,cACA,OAAO,OAAO;AAAA,cACd,SAAS,MAAM,QAAQ,KAAK,IAAI,MAAM,SAAS,OAAO,KAAK,IAAI,UAAU,OAAO;AAAA,cAChF,UAAU,CAAC,MAAM,qBAAqB,GAAG,OAAO,KAAK;AAAA,cACrD;AAAA,YAAA;AAAA,UACF;AAAA,UACC,OAAO;AAAA,QAAA,EAAA,GAVE,CAWZ,CACD;AAAA,MAEH;AAEI,eAAAA,2BAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA,YACA,OAAO,SAAS,QAAQ,gBAAgB;AAAA,YACxC,UAAU;AAAA,YACV;AAAA,YACA,aAAa,QAAQ;AAAA,UAAA;AAAA,QACvB;AAAA,IAAA;AAAA,EAGR;AAEA,SAEKC,2BAAA,KAAAC,qBAAA,EAAA,UAAA;AAAA,IAAA,SAAS,QAAQ,YAAYF,+BAAC,SAAM,EAAA,SAAS,MAAO,UAAM,OAAA;AAAA,IAC1D,YAAY;AAAA,IACZ,SAASA,2BAAA,IAAC,QAAK,EAAA,WAAU,SAAS,UAAM,MAAA,CAAA;AAAA,EAAA,GAC3C;AAEJ,GCjGa,eAAsC,CAAC,UAAU;AACtD,QAAA;AAAA,IACJ;AAAA,IACA,gBAAgB,CAAC,UAAU;AAAA,MACzB,OAAO;AAAA,MACP,UAAU,MAAM;AAAA,MAAC;AAAA,MACjB;AAAA;AAAA,IAAA;AAAA,IAEF;AAAA,IACA,kBAAkB,CAAC;AAAA,IACnB;AAAA,EAAA,IACE,OACE,cAAc,CAAC,UAAqB;AACxC,UAAM,kBAAkB,gBAAgB,MAAM,IAAI,GAC5C,aAAa,cAAc,MAAM,IAAI,GACrC,QAAQ,gBAAgB,MAAM,IAAI;AAEpC,WAAA,kBACMA,2BAAA,IAAA,iBAAA,EAAgB,OAAc,YAAwB,MAAc,CAAA,IAGtEA,2BAAAA,IAAA,cAAA,EAAa,OAAc,YAAwB,MAAc,CAAA;AAAA,KAErE,UAAU,OAAO,OAAO,CAAA,GAAI,KAAK;AAChC,SAAA,OAAA,QAAQ,UACf,OAAO,QAAQ,eACf,OAAO,QAAQ,eACf,OAAO,QAAQ,iBAGZC,2BAAA,KAAA,QAAA,EAAM,GAAG,SAAS,IAAI,QAAQ,MAAM,UAAU,IAAI,SAChD,UAAA;AAAA,IAAA,UAAU,QAAQ,IAAI,CAAC,UACrBD,2BAAAA,IAAA,OAAA,EAAqB,WAAU,cAC7B,UAAY,YAAA,KAAK,EADV,GAAA,MAAM,IAEhB,CACD;AAAA,IAEA;AAAA,mCAEA,UAAO,EAAA,MAAK,UAAU,UAAU,UAAA,cAAc,QAAQ,SAAS,CAAA;AAAA,EAAA,GAClE;AAEJ,GCtDa,WAAWG,OAAAA,WAAW;AAAA,EACjC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAMC,GAAA;AAAA,EACN,QAAQ;AAAA,IACNC,mBAAY;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,MACb,YAAY,CAAC,SAAS,KAAK,SAAS;AAAA,IAAA,CACrC;AAAA,IACDA,mBAAY;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,SAAS;AAAA,QACP,QAAQ;AAAA,MAAA;AAAA;AAAA,IACV,CAED;AAAA,IACDA,mBAAY;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,IAAI,CAAC,EAAC,MAAM,YAAY,CAAA;AAAA,IAAA,CACzB;AAAA,IACDA,mBAAY;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,QAAQ;AAAA,QACNA,mBAAY;AAAA,UACV,MAAM;AAAA,UACN,OAAO;AAAA,UACP,MAAM;AAAA,UACN,cAAc;AAAA,QACf,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAAA;AAAA,IAWJ,CAAA;AAAA,EAAA;AAEL,CAAC,GC5CY,6BAA6B;AAAA,EACxC,UAAU,CAAC,oBAAoB,oBAAoB,QAAQ;AAAA,EAC3D,OAAO,CAAC,QAAQ;AAAA,EAChB,MAAM,CAAC,WAAW,WAAW,QAAQ;AAAA,EACrC,kBAAkB,CAAC,WAAW,WAAW,QAAQ;AAAA,EACjD,OAAO,CAAC,WAAW,QAAQ;AAAA,EAC3B,MAAM,CAAC,WAAW,YAAY,QAAQ;AAAA,EACtC,QAAQ,CAAC,QAAQ;AAAA,EACjB,QAAQ,CAAC,OAAO,OAAO,QAAQ;AAAA;AAAA,EAE/B,OAAO,CAAC,QAAQ;AAAA,EAChB,OAAO,CAAC,OAAO,OAAO,QAAQ,QAAQ;AAAA,EACtC,QAAQ,CAAC,QAAQ;AAAA,EACjB,KAAK,CAAC,WAAW,QAAQ;AAAA,EACzB,MAAM,CAAC,aAAa,aAAa,WAAW,QAAQ;AAAA,EACpD,UAAU,CAAC,aAAa,aAAa,QAAQ;AAAA,EAC7C,MAAM,CAAC,QAAQ;AAAA,EACf,KAAK,CAAC,WAAW,QAAQ;AAC3B,GACa,gBAAgBF,OAAAA,WAAW;AAAA,EACtC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAMG,GAAA;AAAA,EACN,QAAQ;AAAA,IACND,mBAAY;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,SAAS;AAAA,QACP,MAAM,OAAO,KAAK,0BAA0B,EAAE,IAAI,CAAC,UAa1C,EAAC,QAZM,CAAC,cAAsB;AACnC,kBAAQ,WAAW;AAAA,YACjB,KAAK;AACI,qBAAA;AAAA,YACT,KAAK;AACI,qBAAA;AAAA,YACT,KAAK;AACI,qBAAA;AAAA,YACT;AACS,qBAAA,UAAU,OAAO,CAAC,EAAE,gBAAgB,UAAU,MAAM,CAAC;AAAA,UAAA;AAAA,QAG7C,GAAA,IAAI,GAAG,OAAO,OACpC;AAAA,MAAA;AAAA,IACH,CACD;AAAA,IACDA,mBAAY;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,IAAA,CACP;AAAA,IACDA,mBAAY;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,aACE;AAAA,MACF,YAAY,CAAC,SACX,KAAK,SAAW,EAAA,OAAO,CAAC,MAAM,YACvB,OAIA,2BAA2B,KAAK,IAAI,KAK7B,QAAQ,UACO,QAAQ,IAAI,CAAC,UAAU,MAAM,IAAI,KAAK,CAAA,GAGjC,OAAO,CAAC,MAAM,MAAM,IAAI,EAAE,SAG1C,IACP,qDAIa;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA,EAEgB,SAAS,KAAK,YAAA,CAAa,IACpC,oFAGF,KAhCE,mGAJA,UAqCV;AAAA,IAAA,CACJ;AAAA,IACDA,mBAAY;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,cAAc;AAAA,IAAA,CACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAmCDA,mBAAY;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,QAAQ,CAAC,EAAC,OACD,MAAA,CAAC,CAAC,UAAU,SAAS,UAAU,EAAE,SAAS,QAAQ,IAAI;AAAA,MAE/D,IAAI;AAAA,QACF;AAAA,UACE,MAAM;AAAA,UACN,QAAQ;AAAA,YACNA,mBAAY;AAAA,cACV,MAAM;AAAA,cACN,OAAO;AAAA,cACP,MAAM;AAAA,YAAA,CACP;AAAA,YACDA,mBAAY;AAAA,cACV,MAAM;AAAA,cACN,OAAO;AAAA,cACP,MAAM;AAAA,YACP,CAAA;AAAA,UAAA;AAAA,QACH;AAAA,MACF;AAAA,IACF,CACD;AAAA,IACDA,mBAAY;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,QAAQ,CAAC,EAAC,OACD,MAAA,CAAC,UAAU,SAAS,YAAY,MAAM,EAAE,SAAS,QAAQ,IAAI;AAAA,MAEtE,QAAQ;AAAA,QACNA,mBAAY;AAAA,UACV,MAAM;AAAA,UACN,OAAO;AAAA,UACP,MAAM;AAAA,QAAA,CACP;AAAA,QACDA,mBAAY;AAAA,UACV,MAAM;AAAA,UACN,OAAO;AAAA,UACP,MAAM;AAAA,QACP,CAAA;AAAA,MAAA;AAAA,IAEJ,CAAA;AAAA,EACH;AAAA,EACA,SAAS;AAAA,IACP,QAAQ;AAAA,MACN,OAAO;AAAA,MACP,MAAM;AAAA,MACN,MAAM;AAAA,IACR;AAAA,IACA,QAAQ,EAAC,OAAO,MAAM,QAAO;AACpB,aAAA;AAAA,QACL,OAAO,SAAS;AAAA,QAChB,UAAU;AAAA,MACZ;AAAA,IAAA;AAAA,EACF;AAEJ,CAAC,GC5MY,SAA0C;AAAA,EACrD,OAAO,CAAC,UAAU,aAAa;AACjC,GCea,aAAaE,oBAAa,OAC9B;AAAA,EACL,MAAM;AAAA,EACN;AAAA;AAEF,EACD;;;"}
1
+ {"version":3,"file":"index.js","sources":["../../src/form-schema/components/default-field.tsx","../../src/form-schema/components/form-renderer.tsx","../../src/form-schema/schema-types/form.ts","../../src/form-schema/schema-types/form-field.ts","../../src/form-schema/schema-types/index.ts","../../src/form-schema/index.ts"],"sourcesContent":["import type {ChangeEvent, FC, LegacyRef} from 'react'\n\nimport type {FieldComponentProps} from './types'\n\nexport const DefaultField: FC<FieldComponentProps> = ({field, fieldState, error}) => {\n const {type, label, name, options = {}, choices = []} = field\n if (!type || !name) return null\n\n const {value, onChange, onBlur, ref} = fieldState\n\n const handleChange = (\n e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>,\n ) => {\n onChange(e.target.value)\n }\n\n const handleCheckboxChange = (e: ChangeEvent<HTMLInputElement>, choiceValue: string) => {\n if (Array.isArray(value)) {\n const newValue = e.target.checked\n ? [...value, choiceValue]\n : value.filter((v: string) => v !== choiceValue)\n onChange(newValue)\n } else {\n onChange(e.target.checked ? choiceValue : '')\n }\n }\n\n const renderInput = () => {\n switch (type) {\n case 'submit':\n return <button type=\"submit\">{label || 'Submit'}</button>\n case 'textarea':\n return (\n <textarea\n ref={ref as LegacyRef<HTMLTextAreaElement>}\n name={name}\n value={value ?? ''}\n onChange={handleChange}\n onBlur={onBlur}\n placeholder={options.placeholder}\n />\n )\n\n case 'select':\n return (\n <select\n ref={ref as LegacyRef<HTMLSelectElement>}\n name={name}\n value={value ?? ''}\n onChange={handleChange}\n onBlur={onBlur}\n >\n {choices?.map((choice, i) => (\n <option key={i} value={choice.value}>\n {choice.label}\n </option>\n ))}\n </select>\n )\n\n case 'radio':\n return choices?.map((choice, i) => (\n <label key={i}>\n <input\n type=\"radio\"\n name={name}\n ref={ref as LegacyRef<HTMLInputElement>}\n value={choice.value}\n checked={value === choice.value}\n onChange={handleChange}\n onBlur={onBlur}\n />\n {choice.label}\n </label>\n ))\n\n case 'checkbox':\n return choices?.map((choice, i) => (\n <label key={i}>\n <input\n type=\"checkbox\"\n name={name}\n ref={ref as LegacyRef<HTMLInputElement>}\n value={choice.value}\n checked={Array.isArray(value) ? value.includes(choice.value) : value === choice.value}\n onChange={(e) => handleCheckboxChange(e, choice.value)}\n onBlur={onBlur}\n />\n {choice.label}\n </label>\n ))\n\n default:\n return (\n <input\n type={type}\n ref={ref as LegacyRef<HTMLInputElement>}\n name={name}\n value={value ?? options.defaultValue ?? ''}\n onChange={handleChange}\n onBlur={onBlur}\n placeholder={options.placeholder}\n />\n )\n }\n }\n\n return (\n <>\n {label && !['hidden', 'submit'].includes(type) && <label htmlFor={name}>{label}</label>}\n {renderInput()}\n {error && <span className=\"error\">{error}</span>}\n </>\n )\n}\n","import type {ComponentType, FC, HTMLProps} from 'react'\n\nimport {DefaultField} from './default-field'\nimport type {FieldComponentProps, FieldState, FormDataProps, FormField} from './types'\n\ninterface FormRendererProps extends HTMLProps<HTMLFormElement> {\n formData?: FormDataProps\n // Function to get field state for a given field name\n getFieldState?: (fieldName: string) => FieldState\n // Function to get field error for a given field name\n getFieldError?: (fieldName: string) => string | undefined\n // Override default field components\n fieldComponents?: Record<string, ComponentType<FieldComponentProps>>\n}\n\nexport const FormRenderer: FC<FormRendererProps> = (props) => {\n const {\n formData,\n getFieldState = (name) => ({\n value: undefined,\n onChange: () => {},\n name, // Pass name to field for native form handling\n }),\n getFieldError,\n fieldComponents = {},\n children,\n } = props\n const renderField = (field: FormField) => {\n const CustomComponent = fieldComponents[field.type]\n const fieldState = getFieldState(field.name)\n const error = getFieldError?.(field.name)\n\n if (CustomComponent) {\n return <CustomComponent field={field} fieldState={fieldState} error={error} />\n }\n\n return <DefaultField field={field} fieldState={fieldState} error={error} />\n }\n const elProps = Object.assign({}, props)\n delete elProps.formData\n delete elProps.getFieldState\n delete elProps.getFieldError\n delete elProps.fieldComponents\n\n return (\n <form {...elProps} id={elProps.id ?? formData?.id?.current}>\n {formData?.fields?.map((field) => (\n <div key={field._key} className=\"form-field\">\n {renderField(field)}\n </div>\n ))}\n\n {children}\n\n {renderField({\n type: 'submit',\n name: 'submit',\n label: formData?.submitButton?.text || 'Submit',\n })}\n </form>\n )\n}\n","import {FaWpforms} from 'react-icons/fa'\nimport {defineField, defineType} from 'sanity'\n\nexport const formType = defineType({\n name: 'form',\n title: 'Form',\n type: 'document',\n icon: FaWpforms,\n fields: [\n defineField({\n name: 'title',\n title: 'Form Title',\n type: 'string',\n description: 'Internal title for the form',\n validation: (Rule) => Rule.required(),\n }),\n defineField({\n name: 'id',\n title: 'Form ID',\n type: 'slug',\n options: {\n source: 'title',\n },\n // validation: (Rule) => Rule.required(),\n }),\n defineField({\n name: 'fields',\n title: 'Form Fields',\n type: 'array',\n of: [{type: 'formField'}],\n }),\n defineField({\n name: 'submitButton',\n title: 'Submit Button',\n type: 'object',\n fields: [\n defineField({\n name: 'text',\n title: 'Button Text',\n type: 'string',\n initialValue: 'Submit',\n }),\n // defineField({\n // name: 'position',\n // title: 'Button Position',\n // type: 'string',\n // options: {\n // list: ['left', 'center', 'right'],\n // },\n // initialValue: 'center',\n // }),\n ],\n }),\n ],\n})\n","import {LuTextCursorInput} from 'react-icons/lu'\nimport {defineField, defineType} from 'sanity'\n\ninterface ValidationContextDocument {\n fields?: Array<{\n name: string\n type?: string\n }>\n}\n// Validation options by field type\nexport const validationTypesByFieldType = {\n checkbox: ['minSelectedCount', 'maxSelectedCount', 'custom'],\n color: ['custom'],\n date: ['minDate', 'maxDate', 'custom'],\n 'datetime-local': ['minDate', 'maxDate', 'custom'],\n email: ['pattern', 'custom'],\n file: ['maxSize', 'fileType', 'custom'],\n hidden: ['custom'],\n number: ['min', 'max', 'custom'],\n // password: ['minLength', 'pattern', 'custom'],\n radio: ['custom'],\n range: ['min', 'max', 'step', 'custom'],\n select: ['custom'],\n tel: ['pattern', 'custom'],\n text: ['minLength', 'maxLength', 'pattern', 'custom'],\n textarea: ['minLength', 'maxLength', 'custom'],\n time: ['custom'],\n url: ['pattern', 'custom'],\n}\nexport const formFieldType = defineType({\n name: 'formField',\n title: 'Form Field',\n type: 'object',\n icon: LuTextCursorInput,\n fields: [\n defineField({\n name: 'type',\n title: 'Field Type',\n type: 'string',\n options: {\n list: Object.keys(validationTypesByFieldType).map((type) => {\n const title = (fieldType: string) => {\n switch (fieldType) {\n case 'datetime-local':\n return 'Date & Time'\n case 'textarea':\n return 'Text Area'\n case 'tel':\n return 'Phone Number'\n default:\n return fieldType.charAt(0).toUpperCase() + fieldType.slice(1)\n }\n }\n return {title: title(type), value: type}\n }),\n },\n }),\n defineField({\n name: 'label',\n title: 'Field Label',\n type: 'string',\n }),\n defineField({\n name: 'name',\n title: 'Field Name',\n type: 'string',\n description:\n 'Must start with a letter and contain only letters, numbers, underscores, or hyphens. Must be unique within the form.',\n validation: (Rule) =>\n Rule.required().custom((name, context) => {\n if (!name) {\n return 'Required'\n }\n // Check format (HTML ID/name rules)\n if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)) {\n return 'Field name must start with a letter and contain only letters, numbers, underscores, or hyphens'\n }\n\n // Check uniqueness across all fields\n const doc = context.document as ValidationContextDocument\n const allFieldNames = doc?.fields?.map((field) => field.name) || []\n\n // Count occurrences of this name\n const nameCount = allFieldNames.filter((n) => n === name).length\n\n // If we find more than one occurrence (including current field), it's not unique\n if (nameCount > 1) {\n return 'Field name must be unique across all form fields'\n }\n\n // Check for reserved HTML form attributes\n const reservedNames = [\n 'action',\n 'method',\n 'target',\n 'enctype',\n 'accept-charset',\n 'autocomplete',\n 'novalidate',\n 'rel',\n 'submit',\n 'reset',\n ]\n if (reservedNames.includes(name.toLowerCase())) {\n return 'This name is reserved for HTML form attributes. Please choose a different name.'\n }\n\n return true\n }),\n }),\n defineField({\n name: 'required',\n title: 'Required',\n type: 'boolean',\n initialValue: false,\n }),\n // defineField({\n // name: 'validation',\n // title: 'Validation Rules',\n // type: 'array',\n // of: [\n // {\n // type: 'object',\n // fields: [\n // defineField({\n // name: 'type',\n // title: 'Validation Type',\n // type: 'string',\n\n // hidden: ({parent}) => !parent?.type,\n // options: {\n // // TODO: I think this needs to be a custom input component?\n // // list: ({parent}) => (parent?.type ? validationTypesByFieldType[parent.type] : []),\n // list: [],\n // },\n // }),\n // defineField({\n // name: 'value',\n // title: 'Value',\n // type: 'string',\n // }),\n // defineField({\n // name: 'message',\n // title: 'Error Message',\n // type: 'string',\n // }),\n // ],\n // },\n // ],\n // }),\n defineField({\n name: 'choices',\n title: 'Choices',\n type: 'array',\n hidden: ({parent}) => {\n return !['select', 'radio', 'checkbox'].includes(parent?.type)\n },\n of: [\n {\n type: 'object',\n fields: [\n defineField({\n name: 'label',\n title: 'Label',\n type: 'string',\n }),\n defineField({\n name: 'value',\n title: 'Value',\n type: 'string',\n }),\n ],\n },\n ],\n }),\n defineField({\n name: 'options',\n title: 'Field Options',\n type: 'object',\n hidden: ({parent}) => {\n return ['select', 'radio', 'checkbox', 'file'].includes(parent?.type)\n },\n fields: [\n defineField({\n name: 'placeholder',\n title: 'Placeholder',\n type: 'string',\n }),\n defineField({\n name: 'defaultValue',\n title: 'Default Value',\n type: 'string',\n }),\n ],\n }),\n ],\n preview: {\n select: {\n label: 'label',\n name: 'name',\n type: 'type',\n },\n prepare({label, name, type}) {\n return {\n title: label || name,\n subtitle: type,\n }\n },\n },\n})\n","import type {SchemaTypeDefinition} from 'sanity'\n\nimport {formType} from './form'\nimport {formFieldType} from './form-field'\n\nexport const schema: {types: SchemaTypeDefinition[]} = {\n types: [formType, formFieldType],\n}\n","import {definePlugin} from 'sanity'\n\n// import {structureTool} from 'sanity/structure'\nimport {FormRenderer} from './components/form-renderer'\nimport {schema} from './schema-types'\n// import {defaultDocumentNode} from './structure'\n\n/**\n * Usage in `sanity.config.ts` (or .js)\n *\n * ```ts\n * import {defineConfig} from 'sanity'\n * import {formSchema} from '@sanity/form-toolkit'\n *\n * export default defineConfig({\n * // ...\n * plugins: [formSchema()],\n * })\n * ```\n */\nexport type {FormDataProps} from './components/types'\nexport {FormRenderer}\nexport const formSchema = definePlugin(() => {\n return {\n name: 'form-toolkit_form-schema',\n schema,\n // plugins: [structureTool({defaultDocumentNode})],\n }\n})\n"],"names":["jsx","jsxs","Fragment","defineType","FaWpforms","defineField","LuTextCursorInput","definePlugin"],"mappings":"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"}
@@ -15,6 +15,8 @@ const DefaultField = ({ field, fieldState, error }) => {
15
15
  onChange(e.target.checked ? choiceValue : "");
16
16
  }, renderInput = () => {
17
17
  switch (type) {
18
+ case "submit":
19
+ return /* @__PURE__ */ jsx("button", { type: "submit", children: label || "Submit" });
18
20
  case "textarea":
19
21
  return /* @__PURE__ */ jsx(
20
22
  "textarea",
@@ -87,7 +89,7 @@ const DefaultField = ({ field, fieldState, error }) => {
87
89
  }
88
90
  };
89
91
  return /* @__PURE__ */ jsxs(Fragment, { children: [
90
- label && type != "hidden" && /* @__PURE__ */ jsx("label", { htmlFor: name, children: label }),
92
+ label && !["hidden", "submit"].includes(type) && /* @__PURE__ */ jsx("label", { htmlFor: name, children: label }),
91
93
  renderInput(),
92
94
  error && /* @__PURE__ */ jsx("span", { className: "error", children: error })
93
95
  ] });
@@ -111,7 +113,11 @@ const DefaultField = ({ field, fieldState, error }) => {
111
113
  return delete elProps.formData, delete elProps.getFieldState, delete elProps.getFieldError, delete elProps.fieldComponents, /* @__PURE__ */ jsxs("form", { ...elProps, id: elProps.id ?? formData?.id?.current, children: [
112
114
  formData?.fields?.map((field) => /* @__PURE__ */ jsx("div", { className: "form-field", children: renderField(field) }, field._key)),
113
115
  children,
114
- /* @__PURE__ */ jsx("button", { type: "submit", children: formData?.submitButton?.text || "Submit" })
116
+ renderField({
117
+ type: "submit",
118
+ name: "submit",
119
+ label: formData?.submitButton?.text || "Submit"
120
+ })
115
121
  ] });
116
122
  }, formType = defineType({
117
123
  name: "form",
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../../src/form-schema/components/default-field.tsx","../../src/form-schema/components/form-renderer.tsx","../../src/form-schema/schema-types/form.ts","../../src/form-schema/schema-types/form-field.ts","../../src/form-schema/schema-types/index.ts","../../src/form-schema/index.ts"],"sourcesContent":["import type {ChangeEvent, FC, LegacyRef} from 'react'\n\nimport type {FieldComponentProps} from './types'\n\nexport const DefaultField: FC<FieldComponentProps> = ({field, fieldState, error}) => {\n const {type, label, name, options = {}, choices = []} = field\n if (!type || !name) return null\n\n const {value, onChange, onBlur, ref} = fieldState\n\n const handleChange = (\n e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>,\n ) => {\n onChange(e.target.value)\n }\n\n const handleCheckboxChange = (e: ChangeEvent<HTMLInputElement>, choiceValue: string) => {\n if (Array.isArray(value)) {\n const newValue = e.target.checked\n ? [...value, choiceValue]\n : value.filter((v: string) => v !== choiceValue)\n onChange(newValue)\n } else {\n onChange(e.target.checked ? choiceValue : '')\n }\n }\n\n const renderInput = () => {\n switch (type) {\n case 'textarea':\n return (\n <textarea\n ref={ref as LegacyRef<HTMLTextAreaElement>}\n name={name}\n value={value ?? ''}\n onChange={handleChange}\n onBlur={onBlur}\n placeholder={options.placeholder}\n />\n )\n\n case 'select':\n return (\n <select\n ref={ref as LegacyRef<HTMLSelectElement>}\n name={name}\n value={value ?? ''}\n onChange={handleChange}\n onBlur={onBlur}\n >\n {choices?.map((choice, i) => (\n <option key={i} value={choice.value}>\n {choice.label}\n </option>\n ))}\n </select>\n )\n\n case 'radio':\n return choices?.map((choice, i) => (\n <label key={i}>\n <input\n type=\"radio\"\n name={name}\n ref={ref as LegacyRef<HTMLInputElement>}\n value={choice.value}\n checked={value === choice.value}\n onChange={handleChange}\n onBlur={onBlur}\n />\n {choice.label}\n </label>\n ))\n\n case 'checkbox':\n return choices?.map((choice, i) => (\n <label key={i}>\n <input\n type=\"checkbox\"\n name={name}\n ref={ref as LegacyRef<HTMLInputElement>}\n value={choice.value}\n checked={Array.isArray(value) ? value.includes(choice.value) : value === choice.value}\n onChange={(e) => handleCheckboxChange(e, choice.value)}\n onBlur={onBlur}\n />\n {choice.label}\n </label>\n ))\n\n default:\n return (\n <input\n type={type}\n ref={ref as LegacyRef<HTMLInputElement>}\n name={name}\n value={value ?? options.defaultValue ?? ''}\n onChange={handleChange}\n onBlur={onBlur}\n placeholder={options.placeholder}\n />\n )\n }\n }\n\n return (\n <>\n {label && type != 'hidden' && <label htmlFor={name}>{label}</label>}\n {renderInput()}\n {error && <span className=\"error\">{error}</span>}\n </>\n )\n}\n","import type {ComponentType, FC, HTMLProps} from 'react'\n\nimport {DefaultField} from './default-field'\nimport type {FieldComponentProps, FieldState, FormDataProps, FormField} from './types'\n\ninterface FormRendererProps extends HTMLProps<HTMLFormElement> {\n formData?: FormDataProps\n // Function to get field state for a given field name\n getFieldState?: (fieldName: string) => FieldState\n // Function to get field error for a given field name\n getFieldError?: (fieldName: string) => string | undefined\n // Override default field components\n fieldComponents?: Record<string, ComponentType<FieldComponentProps>>\n}\n\nexport const FormRenderer: FC<FormRendererProps> = (props) => {\n const {\n formData,\n getFieldState = (name) => ({\n value: undefined,\n onChange: () => {},\n name, // Pass name to field for native form handling\n }),\n getFieldError,\n fieldComponents = {},\n children,\n } = props\n const renderField = (field: FormField) => {\n const CustomComponent = fieldComponents[field.type]\n const fieldState = getFieldState(field.name)\n const error = getFieldError?.(field.name)\n\n if (CustomComponent) {\n return <CustomComponent field={field} fieldState={fieldState} error={error} />\n }\n\n return <DefaultField field={field} fieldState={fieldState} error={error} />\n }\n const elProps = Object.assign({}, props)\n delete elProps.formData\n delete elProps.getFieldState\n delete elProps.getFieldError\n delete elProps.fieldComponents\n\n return (\n <form {...elProps} id={elProps.id ?? formData?.id?.current}>\n {formData?.fields?.map((field) => (\n <div key={field._key} className=\"form-field\">\n {renderField(field)}\n </div>\n ))}\n\n {children}\n\n <button type=\"submit\">{formData?.submitButton?.text || 'Submit'}</button>\n </form>\n )\n}\n","import {FaWpforms} from 'react-icons/fa'\nimport {defineField, defineType} from 'sanity'\n\nexport const formType = defineType({\n name: 'form',\n title: 'Form',\n type: 'document',\n icon: FaWpforms,\n fields: [\n defineField({\n name: 'title',\n title: 'Form Title',\n type: 'string',\n description: 'Internal title for the form',\n validation: (Rule) => Rule.required(),\n }),\n defineField({\n name: 'id',\n title: 'Form ID',\n type: 'slug',\n options: {\n source: 'title',\n },\n // validation: (Rule) => Rule.required(),\n }),\n defineField({\n name: 'fields',\n title: 'Form Fields',\n type: 'array',\n of: [{type: 'formField'}],\n }),\n defineField({\n name: 'submitButton',\n title: 'Submit Button',\n type: 'object',\n fields: [\n defineField({\n name: 'text',\n title: 'Button Text',\n type: 'string',\n initialValue: 'Submit',\n }),\n // defineField({\n // name: 'position',\n // title: 'Button Position',\n // type: 'string',\n // options: {\n // list: ['left', 'center', 'right'],\n // },\n // initialValue: 'center',\n // }),\n ],\n }),\n ],\n})\n","import {LuTextCursorInput} from 'react-icons/lu'\nimport {defineField, defineType} from 'sanity'\n\ninterface ValidationContextDocument {\n fields?: Array<{\n name: string\n type?: string\n }>\n}\n// Validation options by field type\nexport const validationTypesByFieldType = {\n checkbox: ['minSelectedCount', 'maxSelectedCount', 'custom'],\n color: ['custom'],\n date: ['minDate', 'maxDate', 'custom'],\n 'datetime-local': ['minDate', 'maxDate', 'custom'],\n email: ['pattern', 'custom'],\n file: ['maxSize', 'fileType', 'custom'],\n hidden: ['custom'],\n number: ['min', 'max', 'custom'],\n // password: ['minLength', 'pattern', 'custom'],\n radio: ['custom'],\n range: ['min', 'max', 'step', 'custom'],\n select: ['custom'],\n tel: ['pattern', 'custom'],\n text: ['minLength', 'maxLength', 'pattern', 'custom'],\n textarea: ['minLength', 'maxLength', 'custom'],\n time: ['custom'],\n url: ['pattern', 'custom'],\n}\nexport const formFieldType = defineType({\n name: 'formField',\n title: 'Form Field',\n type: 'object',\n icon: LuTextCursorInput,\n fields: [\n defineField({\n name: 'type',\n title: 'Field Type',\n type: 'string',\n options: {\n list: Object.keys(validationTypesByFieldType).map((type) => {\n const title = (fieldType: string) => {\n switch (fieldType) {\n case 'datetime-local':\n return 'Date & Time'\n case 'textarea':\n return 'Text Area'\n case 'tel':\n return 'Phone Number'\n default:\n return fieldType.charAt(0).toUpperCase() + fieldType.slice(1)\n }\n }\n return {title: title(type), value: type}\n }),\n },\n }),\n defineField({\n name: 'label',\n title: 'Field Label',\n type: 'string',\n }),\n defineField({\n name: 'name',\n title: 'Field Name',\n type: 'string',\n description:\n 'Must start with a letter and contain only letters, numbers, underscores, or hyphens. Must be unique within the form.',\n validation: (Rule) =>\n Rule.required().custom((name, context) => {\n if (!name) {\n return 'Required'\n }\n // Check format (HTML ID/name rules)\n if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)) {\n return 'Field name must start with a letter and contain only letters, numbers, underscores, or hyphens'\n }\n\n // Check uniqueness across all fields\n const doc = context.document as ValidationContextDocument\n const allFieldNames = doc?.fields?.map((field) => field.name) || []\n\n // Count occurrences of this name\n const nameCount = allFieldNames.filter((n) => n === name).length\n\n // If we find more than one occurrence (including current field), it's not unique\n if (nameCount > 1) {\n return 'Field name must be unique across all form fields'\n }\n\n // Check for reserved HTML form attributes\n const reservedNames = [\n 'action',\n 'method',\n 'target',\n 'enctype',\n 'accept-charset',\n 'autocomplete',\n 'novalidate',\n 'rel',\n 'submit',\n 'reset',\n ]\n if (reservedNames.includes(name.toLowerCase())) {\n return 'This name is reserved for HTML form attributes. Please choose a different name.'\n }\n\n return true\n }),\n }),\n defineField({\n name: 'required',\n title: 'Required',\n type: 'boolean',\n initialValue: false,\n }),\n // defineField({\n // name: 'validation',\n // title: 'Validation Rules',\n // type: 'array',\n // of: [\n // {\n // type: 'object',\n // fields: [\n // defineField({\n // name: 'type',\n // title: 'Validation Type',\n // type: 'string',\n\n // hidden: ({parent}) => !parent?.type,\n // options: {\n // // TODO: I think this needs to be a custom input component?\n // // list: ({parent}) => (parent?.type ? validationTypesByFieldType[parent.type] : []),\n // list: [],\n // },\n // }),\n // defineField({\n // name: 'value',\n // title: 'Value',\n // type: 'string',\n // }),\n // defineField({\n // name: 'message',\n // title: 'Error Message',\n // type: 'string',\n // }),\n // ],\n // },\n // ],\n // }),\n defineField({\n name: 'choices',\n title: 'Choices',\n type: 'array',\n hidden: ({parent}) => {\n return !['select', 'radio', 'checkbox'].includes(parent?.type)\n },\n of: [\n {\n type: 'object',\n fields: [\n defineField({\n name: 'label',\n title: 'Label',\n type: 'string',\n }),\n defineField({\n name: 'value',\n title: 'Value',\n type: 'string',\n }),\n ],\n },\n ],\n }),\n defineField({\n name: 'options',\n title: 'Field Options',\n type: 'object',\n hidden: ({parent}) => {\n return ['select', 'radio', 'checkbox', 'file'].includes(parent?.type)\n },\n fields: [\n defineField({\n name: 'placeholder',\n title: 'Placeholder',\n type: 'string',\n }),\n defineField({\n name: 'defaultValue',\n title: 'Default Value',\n type: 'string',\n }),\n ],\n }),\n ],\n preview: {\n select: {\n label: 'label',\n name: 'name',\n type: 'type',\n },\n prepare({label, name, type}) {\n return {\n title: label || name,\n subtitle: type,\n }\n },\n },\n})\n","import type {SchemaTypeDefinition} from 'sanity'\n\nimport {formType} from './form'\nimport {formFieldType} from './form-field'\n\nexport const schema: {types: SchemaTypeDefinition[]} = {\n types: [formType, formFieldType],\n}\n","import {definePlugin} from 'sanity'\n\n// import {structureTool} from 'sanity/structure'\nimport {FormRenderer} from './components/form-renderer'\nimport {schema} from './schema-types'\n// import {defaultDocumentNode} from './structure'\n\n/**\n * Usage in `sanity.config.ts` (or .js)\n *\n * ```ts\n * import {defineConfig} from 'sanity'\n * import {formSchema} from '@sanity/form-toolkit'\n *\n * export default defineConfig({\n * // ...\n * plugins: [formSchema()],\n * })\n * ```\n */\nexport type {FormDataProps} from './components/types'\nexport {FormRenderer}\nexport const formSchema = definePlugin(() => {\n return {\n name: 'form-toolkit_form-schema',\n schema,\n // plugins: [structureTool({defaultDocumentNode})],\n }\n})\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../../src/form-schema/components/default-field.tsx","../../src/form-schema/components/form-renderer.tsx","../../src/form-schema/schema-types/form.ts","../../src/form-schema/schema-types/form-field.ts","../../src/form-schema/schema-types/index.ts","../../src/form-schema/index.ts"],"sourcesContent":["import type {ChangeEvent, FC, LegacyRef} from 'react'\n\nimport type {FieldComponentProps} from './types'\n\nexport const DefaultField: FC<FieldComponentProps> = ({field, fieldState, error}) => {\n const {type, label, name, options = {}, choices = []} = field\n if (!type || !name) return null\n\n const {value, onChange, onBlur, ref} = fieldState\n\n const handleChange = (\n e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>,\n ) => {\n onChange(e.target.value)\n }\n\n const handleCheckboxChange = (e: ChangeEvent<HTMLInputElement>, choiceValue: string) => {\n if (Array.isArray(value)) {\n const newValue = e.target.checked\n ? [...value, choiceValue]\n : value.filter((v: string) => v !== choiceValue)\n onChange(newValue)\n } else {\n onChange(e.target.checked ? choiceValue : '')\n }\n }\n\n const renderInput = () => {\n switch (type) {\n case 'submit':\n return <button type=\"submit\">{label || 'Submit'}</button>\n case 'textarea':\n return (\n <textarea\n ref={ref as LegacyRef<HTMLTextAreaElement>}\n name={name}\n value={value ?? ''}\n onChange={handleChange}\n onBlur={onBlur}\n placeholder={options.placeholder}\n />\n )\n\n case 'select':\n return (\n <select\n ref={ref as LegacyRef<HTMLSelectElement>}\n name={name}\n value={value ?? ''}\n onChange={handleChange}\n onBlur={onBlur}\n >\n {choices?.map((choice, i) => (\n <option key={i} value={choice.value}>\n {choice.label}\n </option>\n ))}\n </select>\n )\n\n case 'radio':\n return choices?.map((choice, i) => (\n <label key={i}>\n <input\n type=\"radio\"\n name={name}\n ref={ref as LegacyRef<HTMLInputElement>}\n value={choice.value}\n checked={value === choice.value}\n onChange={handleChange}\n onBlur={onBlur}\n />\n {choice.label}\n </label>\n ))\n\n case 'checkbox':\n return choices?.map((choice, i) => (\n <label key={i}>\n <input\n type=\"checkbox\"\n name={name}\n ref={ref as LegacyRef<HTMLInputElement>}\n value={choice.value}\n checked={Array.isArray(value) ? value.includes(choice.value) : value === choice.value}\n onChange={(e) => handleCheckboxChange(e, choice.value)}\n onBlur={onBlur}\n />\n {choice.label}\n </label>\n ))\n\n default:\n return (\n <input\n type={type}\n ref={ref as LegacyRef<HTMLInputElement>}\n name={name}\n value={value ?? options.defaultValue ?? ''}\n onChange={handleChange}\n onBlur={onBlur}\n placeholder={options.placeholder}\n />\n )\n }\n }\n\n return (\n <>\n {label && !['hidden', 'submit'].includes(type) && <label htmlFor={name}>{label}</label>}\n {renderInput()}\n {error && <span className=\"error\">{error}</span>}\n </>\n )\n}\n","import type {ComponentType, FC, HTMLProps} from 'react'\n\nimport {DefaultField} from './default-field'\nimport type {FieldComponentProps, FieldState, FormDataProps, FormField} from './types'\n\ninterface FormRendererProps extends HTMLProps<HTMLFormElement> {\n formData?: FormDataProps\n // Function to get field state for a given field name\n getFieldState?: (fieldName: string) => FieldState\n // Function to get field error for a given field name\n getFieldError?: (fieldName: string) => string | undefined\n // Override default field components\n fieldComponents?: Record<string, ComponentType<FieldComponentProps>>\n}\n\nexport const FormRenderer: FC<FormRendererProps> = (props) => {\n const {\n formData,\n getFieldState = (name) => ({\n value: undefined,\n onChange: () => {},\n name, // Pass name to field for native form handling\n }),\n getFieldError,\n fieldComponents = {},\n children,\n } = props\n const renderField = (field: FormField) => {\n const CustomComponent = fieldComponents[field.type]\n const fieldState = getFieldState(field.name)\n const error = getFieldError?.(field.name)\n\n if (CustomComponent) {\n return <CustomComponent field={field} fieldState={fieldState} error={error} />\n }\n\n return <DefaultField field={field} fieldState={fieldState} error={error} />\n }\n const elProps = Object.assign({}, props)\n delete elProps.formData\n delete elProps.getFieldState\n delete elProps.getFieldError\n delete elProps.fieldComponents\n\n return (\n <form {...elProps} id={elProps.id ?? formData?.id?.current}>\n {formData?.fields?.map((field) => (\n <div key={field._key} className=\"form-field\">\n {renderField(field)}\n </div>\n ))}\n\n {children}\n\n {renderField({\n type: 'submit',\n name: 'submit',\n label: formData?.submitButton?.text || 'Submit',\n })}\n </form>\n )\n}\n","import {FaWpforms} from 'react-icons/fa'\nimport {defineField, defineType} from 'sanity'\n\nexport const formType = defineType({\n name: 'form',\n title: 'Form',\n type: 'document',\n icon: FaWpforms,\n fields: [\n defineField({\n name: 'title',\n title: 'Form Title',\n type: 'string',\n description: 'Internal title for the form',\n validation: (Rule) => Rule.required(),\n }),\n defineField({\n name: 'id',\n title: 'Form ID',\n type: 'slug',\n options: {\n source: 'title',\n },\n // validation: (Rule) => Rule.required(),\n }),\n defineField({\n name: 'fields',\n title: 'Form Fields',\n type: 'array',\n of: [{type: 'formField'}],\n }),\n defineField({\n name: 'submitButton',\n title: 'Submit Button',\n type: 'object',\n fields: [\n defineField({\n name: 'text',\n title: 'Button Text',\n type: 'string',\n initialValue: 'Submit',\n }),\n // defineField({\n // name: 'position',\n // title: 'Button Position',\n // type: 'string',\n // options: {\n // list: ['left', 'center', 'right'],\n // },\n // initialValue: 'center',\n // }),\n ],\n }),\n ],\n})\n","import {LuTextCursorInput} from 'react-icons/lu'\nimport {defineField, defineType} from 'sanity'\n\ninterface ValidationContextDocument {\n fields?: Array<{\n name: string\n type?: string\n }>\n}\n// Validation options by field type\nexport const validationTypesByFieldType = {\n checkbox: ['minSelectedCount', 'maxSelectedCount', 'custom'],\n color: ['custom'],\n date: ['minDate', 'maxDate', 'custom'],\n 'datetime-local': ['minDate', 'maxDate', 'custom'],\n email: ['pattern', 'custom'],\n file: ['maxSize', 'fileType', 'custom'],\n hidden: ['custom'],\n number: ['min', 'max', 'custom'],\n // password: ['minLength', 'pattern', 'custom'],\n radio: ['custom'],\n range: ['min', 'max', 'step', 'custom'],\n select: ['custom'],\n tel: ['pattern', 'custom'],\n text: ['minLength', 'maxLength', 'pattern', 'custom'],\n textarea: ['minLength', 'maxLength', 'custom'],\n time: ['custom'],\n url: ['pattern', 'custom'],\n}\nexport const formFieldType = defineType({\n name: 'formField',\n title: 'Form Field',\n type: 'object',\n icon: LuTextCursorInput,\n fields: [\n defineField({\n name: 'type',\n title: 'Field Type',\n type: 'string',\n options: {\n list: Object.keys(validationTypesByFieldType).map((type) => {\n const title = (fieldType: string) => {\n switch (fieldType) {\n case 'datetime-local':\n return 'Date & Time'\n case 'textarea':\n return 'Text Area'\n case 'tel':\n return 'Phone Number'\n default:\n return fieldType.charAt(0).toUpperCase() + fieldType.slice(1)\n }\n }\n return {title: title(type), value: type}\n }),\n },\n }),\n defineField({\n name: 'label',\n title: 'Field Label',\n type: 'string',\n }),\n defineField({\n name: 'name',\n title: 'Field Name',\n type: 'string',\n description:\n 'Must start with a letter and contain only letters, numbers, underscores, or hyphens. Must be unique within the form.',\n validation: (Rule) =>\n Rule.required().custom((name, context) => {\n if (!name) {\n return 'Required'\n }\n // Check format (HTML ID/name rules)\n if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)) {\n return 'Field name must start with a letter and contain only letters, numbers, underscores, or hyphens'\n }\n\n // Check uniqueness across all fields\n const doc = context.document as ValidationContextDocument\n const allFieldNames = doc?.fields?.map((field) => field.name) || []\n\n // Count occurrences of this name\n const nameCount = allFieldNames.filter((n) => n === name).length\n\n // If we find more than one occurrence (including current field), it's not unique\n if (nameCount > 1) {\n return 'Field name must be unique across all form fields'\n }\n\n // Check for reserved HTML form attributes\n const reservedNames = [\n 'action',\n 'method',\n 'target',\n 'enctype',\n 'accept-charset',\n 'autocomplete',\n 'novalidate',\n 'rel',\n 'submit',\n 'reset',\n ]\n if (reservedNames.includes(name.toLowerCase())) {\n return 'This name is reserved for HTML form attributes. Please choose a different name.'\n }\n\n return true\n }),\n }),\n defineField({\n name: 'required',\n title: 'Required',\n type: 'boolean',\n initialValue: false,\n }),\n // defineField({\n // name: 'validation',\n // title: 'Validation Rules',\n // type: 'array',\n // of: [\n // {\n // type: 'object',\n // fields: [\n // defineField({\n // name: 'type',\n // title: 'Validation Type',\n // type: 'string',\n\n // hidden: ({parent}) => !parent?.type,\n // options: {\n // // TODO: I think this needs to be a custom input component?\n // // list: ({parent}) => (parent?.type ? validationTypesByFieldType[parent.type] : []),\n // list: [],\n // },\n // }),\n // defineField({\n // name: 'value',\n // title: 'Value',\n // type: 'string',\n // }),\n // defineField({\n // name: 'message',\n // title: 'Error Message',\n // type: 'string',\n // }),\n // ],\n // },\n // ],\n // }),\n defineField({\n name: 'choices',\n title: 'Choices',\n type: 'array',\n hidden: ({parent}) => {\n return !['select', 'radio', 'checkbox'].includes(parent?.type)\n },\n of: [\n {\n type: 'object',\n fields: [\n defineField({\n name: 'label',\n title: 'Label',\n type: 'string',\n }),\n defineField({\n name: 'value',\n title: 'Value',\n type: 'string',\n }),\n ],\n },\n ],\n }),\n defineField({\n name: 'options',\n title: 'Field Options',\n type: 'object',\n hidden: ({parent}) => {\n return ['select', 'radio', 'checkbox', 'file'].includes(parent?.type)\n },\n fields: [\n defineField({\n name: 'placeholder',\n title: 'Placeholder',\n type: 'string',\n }),\n defineField({\n name: 'defaultValue',\n title: 'Default Value',\n type: 'string',\n }),\n ],\n }),\n ],\n preview: {\n select: {\n label: 'label',\n name: 'name',\n type: 'type',\n },\n prepare({label, name, type}) {\n return {\n title: label || name,\n subtitle: type,\n }\n },\n },\n})\n","import type {SchemaTypeDefinition} from 'sanity'\n\nimport {formType} from './form'\nimport {formFieldType} from './form-field'\n\nexport const schema: {types: SchemaTypeDefinition[]} = {\n types: [formType, formFieldType],\n}\n","import {definePlugin} from 'sanity'\n\n// import {structureTool} from 'sanity/structure'\nimport {FormRenderer} from './components/form-renderer'\nimport {schema} from './schema-types'\n// import {defaultDocumentNode} from './structure'\n\n/**\n * Usage in `sanity.config.ts` (or .js)\n *\n * ```ts\n * import {defineConfig} from 'sanity'\n * import {formSchema} from '@sanity/form-toolkit'\n *\n * export default defineConfig({\n * // ...\n * plugins: [formSchema()],\n * })\n * ```\n */\nexport type {FormDataProps} from './components/types'\nexport {FormRenderer}\nexport const formSchema = definePlugin(() => {\n return {\n name: 'form-toolkit_form-schema',\n schema,\n // plugins: [structureTool({defaultDocumentNode})],\n }\n})\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/form-toolkit",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Tool kit for integrating forms with a Sanity Studio",
5
5
  "keywords": [
6
6
  "sanity",
@@ -27,6 +27,8 @@ export const DefaultField: FC<FieldComponentProps> = ({field, fieldState, error}
27
27
 
28
28
  const renderInput = () => {
29
29
  switch (type) {
30
+ case 'submit':
31
+ return <button type="submit">{label || 'Submit'}</button>
30
32
  case 'textarea':
31
33
  return (
32
34
  <textarea
@@ -105,7 +107,7 @@ export const DefaultField: FC<FieldComponentProps> = ({field, fieldState, error}
105
107
 
106
108
  return (
107
109
  <>
108
- {label && type != 'hidden' && <label htmlFor={name}>{label}</label>}
110
+ {label && !['hidden', 'submit'].includes(type) && <label htmlFor={name}>{label}</label>}
109
111
  {renderInput()}
110
112
  {error && <span className="error">{error}</span>}
111
113
  </>
@@ -52,7 +52,11 @@ export const FormRenderer: FC<FormRendererProps> = (props) => {
52
52
 
53
53
  {children}
54
54
 
55
- <button type="submit">{formData?.submitButton?.text || 'Submit'}</button>
55
+ {renderField({
56
+ type: 'submit',
57
+ name: 'submit',
58
+ label: formData?.submitButton?.text || 'Submit',
59
+ })}
56
60
  </form>
57
61
  )
58
62
  }
@@ -19,11 +19,11 @@ export type FormField = {
19
19
  type: string
20
20
  label?: string
21
21
  name: string
22
- required: boolean
22
+ required?: boolean
23
23
  validation?: ValidationRule[]
24
24
  options?: FieldOptions
25
25
  choices?: FieldChoice[]
26
- _key: string
26
+ _key?: string
27
27
  }
28
28
 
29
29
  export type FormDataProps = {