@sanity/form-toolkit 2.2.3 → 3.0.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.
- package/LICENSE +2 -1
- package/dist/_chunks-es/{create-handler.mjs → create-handler.js} +45 -17
- package/dist/_chunks-es/create-handler.js.map +1 -0
- package/dist/form-renderer/index.d.ts +53 -64
- package/dist/form-renderer/index.d.ts.map +1 -0
- package/dist/form-renderer/index.js +123 -108
- package/dist/form-renderer/index.js.map +1 -1
- package/dist/form-schema/index.d.ts +7 -11
- package/dist/form-schema/index.d.ts.map +1 -0
- package/dist/form-schema/index.js +181 -181
- package/dist/form-schema/index.js.map +1 -1
- package/dist/formium/index.d.ts +4 -7
- package/dist/formium/index.d.ts.map +1 -0
- package/dist/formium/index.js +35 -25
- package/dist/formium/index.js.map +1 -1
- package/dist/hubspot/index.d.ts +52 -48
- package/dist/hubspot/index.d.ts.map +1 -0
- package/dist/hubspot/index.js +52 -26
- package/dist/hubspot/index.js.map +1 -1
- package/dist/mailchimp/index.d.ts +56 -42
- package/dist/mailchimp/index.d.ts.map +1 -0
- package/dist/mailchimp/index.js +55 -37
- package/dist/mailchimp/index.js.map +1 -1
- package/package.json +36 -107
- package/dist/_chunks-cjs/create-handler.js +0 -68
- package/dist/_chunks-cjs/create-handler.js.map +0 -1
- package/dist/_chunks-es/create-handler.mjs.map +0 -1
- package/dist/form-renderer/index.d.mts +0 -66
- package/dist/form-renderer/index.mjs +0 -128
- package/dist/form-renderer/index.mjs.map +0 -1
- package/dist/form-schema/index.d.mts +0 -28
- package/dist/form-schema/index.mjs +0 -230
- package/dist/form-schema/index.mjs.map +0 -1
- package/dist/formium/index.d.mts +0 -20
- package/dist/formium/index.mjs +0 -30
- package/dist/formium/index.mjs.map +0 -1
- package/dist/hubspot/index.d.mts +0 -49
- package/dist/hubspot/index.mjs +0 -48
- package/dist/hubspot/index.mjs.map +0 -1
- package/dist/mailchimp/index.d.mts +0 -45
- package/dist/mailchimp/index.mjs +0 -49
- package/dist/mailchimp/index.mjs.map +0 -1
- package/sanity.json +0 -8
- package/src/form-renderer/components/default-field.tsx +0 -123
- package/src/form-renderer/components/form-renderer.tsx +0 -62
- package/src/form-renderer/components/types.ts +0 -51
- package/src/form-renderer/index.ts +0 -4
- package/src/form-schema/components/validation-type.tsx +0 -14
- package/src/form-schema/index.ts +0 -35
- package/src/form-schema/schema-types/form-field.ts +0 -224
- package/src/form-schema/schema-types/form.ts +0 -52
- package/src/form-schema/schema-types/index.ts +0 -9
- package/src/formium/index.ts +0 -52
- package/src/hubspot/components/option.tsx +0 -17
- package/src/hubspot/create-handler.ts +0 -6
- package/src/hubspot/fetch-hubspot-data.ts +0 -33
- package/src/hubspot/index.ts +0 -52
- package/src/index.ts +0 -19
- package/src/mailchimp/components/option.tsx +0 -30
- package/src/mailchimp/create-handler.ts +0 -39
- package/src/mailchimp/index.ts +0 -43
- package/src/shared/create-handler.ts +0 -109
- package/v2-incompatible.js +0 -11
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import type {ChangeEvent, FC, LegacyRef} from 'react'
|
|
2
|
-
|
|
3
|
-
import type {FieldComponentProps} from './types'
|
|
4
|
-
|
|
5
|
-
export const DefaultField: FC<FieldComponentProps> = ({field, fieldState, error}) => {
|
|
6
|
-
const {type, label, name, options = {}, choices = [], validation = []} = field
|
|
7
|
-
if (!type || !name) return null
|
|
8
|
-
const validationRules = validation.reduce((acc: Record<string, string>, v) => {
|
|
9
|
-
acc[v.type] = v.value
|
|
10
|
-
return acc
|
|
11
|
-
}, {})
|
|
12
|
-
const {value, onChange, onBlur, ref} = fieldState
|
|
13
|
-
|
|
14
|
-
const handleChange = (
|
|
15
|
-
e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>,
|
|
16
|
-
) => {
|
|
17
|
-
onChange(e.target.value)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const handleCheckboxChange = (e: ChangeEvent<HTMLInputElement>, choiceValue: string) => {
|
|
21
|
-
if (Array.isArray(value)) {
|
|
22
|
-
const newValue = e.target.checked
|
|
23
|
-
? [...value, choiceValue]
|
|
24
|
-
: value.filter((v: string) => v !== choiceValue)
|
|
25
|
-
onChange(newValue)
|
|
26
|
-
} else {
|
|
27
|
-
onChange(e.target.checked ? choiceValue : '')
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const renderInput = () => {
|
|
32
|
-
switch (type) {
|
|
33
|
-
case 'submit':
|
|
34
|
-
return <button type="submit">{label || 'Submit'}</button>
|
|
35
|
-
case 'textarea':
|
|
36
|
-
return (
|
|
37
|
-
<textarea
|
|
38
|
-
ref={ref as LegacyRef<HTMLTextAreaElement>}
|
|
39
|
-
name={name}
|
|
40
|
-
onChange={handleChange}
|
|
41
|
-
onBlur={onBlur}
|
|
42
|
-
placeholder={options.placeholder}
|
|
43
|
-
{...validationRules}
|
|
44
|
-
value={value ?? ''}
|
|
45
|
-
/>
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
case 'select':
|
|
49
|
-
return (
|
|
50
|
-
<select
|
|
51
|
-
ref={ref as LegacyRef<HTMLSelectElement>}
|
|
52
|
-
name={name}
|
|
53
|
-
value={value ?? ''}
|
|
54
|
-
onChange={handleChange}
|
|
55
|
-
{...validationRules}
|
|
56
|
-
onBlur={onBlur}
|
|
57
|
-
>
|
|
58
|
-
{choices?.map((choice, i) => (
|
|
59
|
-
<option key={i} value={choice.value}>
|
|
60
|
-
{choice.label}
|
|
61
|
-
</option>
|
|
62
|
-
))}
|
|
63
|
-
</select>
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
case 'radio':
|
|
67
|
-
return choices?.map((choice, i) => (
|
|
68
|
-
<label key={i}>
|
|
69
|
-
<input
|
|
70
|
-
type="radio"
|
|
71
|
-
name={name}
|
|
72
|
-
ref={ref as LegacyRef<HTMLInputElement>}
|
|
73
|
-
value={choice.value}
|
|
74
|
-
checked={value === choice.value}
|
|
75
|
-
onChange={handleChange}
|
|
76
|
-
onBlur={onBlur}
|
|
77
|
-
{...validationRules}
|
|
78
|
-
/>
|
|
79
|
-
{choice.label}
|
|
80
|
-
</label>
|
|
81
|
-
))
|
|
82
|
-
|
|
83
|
-
case 'checkbox':
|
|
84
|
-
return choices?.map((choice, i) => (
|
|
85
|
-
<label key={i}>
|
|
86
|
-
<input
|
|
87
|
-
type="checkbox"
|
|
88
|
-
name={name}
|
|
89
|
-
ref={ref as LegacyRef<HTMLInputElement>}
|
|
90
|
-
value={choice.value}
|
|
91
|
-
checked={Array.isArray(value) ? value.includes(choice.value) : value === choice.value}
|
|
92
|
-
onChange={(e) => handleCheckboxChange(e, choice.value)}
|
|
93
|
-
onBlur={onBlur}
|
|
94
|
-
{...validationRules}
|
|
95
|
-
/>
|
|
96
|
-
{choice.label}
|
|
97
|
-
</label>
|
|
98
|
-
))
|
|
99
|
-
|
|
100
|
-
default:
|
|
101
|
-
return (
|
|
102
|
-
<input
|
|
103
|
-
type={type}
|
|
104
|
-
ref={ref as LegacyRef<HTMLInputElement>}
|
|
105
|
-
name={name}
|
|
106
|
-
value={value ?? options.defaultValue ?? ''}
|
|
107
|
-
onChange={handleChange}
|
|
108
|
-
{...validationRules}
|
|
109
|
-
onBlur={onBlur}
|
|
110
|
-
placeholder={options.placeholder}
|
|
111
|
-
/>
|
|
112
|
-
)
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return (
|
|
117
|
-
<>
|
|
118
|
-
{label && !['hidden', 'submit'].includes(type) && <label htmlFor={name}>{label}</label>}
|
|
119
|
-
{renderInput()}
|
|
120
|
-
{error && <span className="error">{error}</span>}
|
|
121
|
-
</>
|
|
122
|
-
)
|
|
123
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type {ComponentType, FC, HTMLProps} from 'react'
|
|
2
|
-
|
|
3
|
-
import {DefaultField} from './default-field'
|
|
4
|
-
import type {FieldComponentProps, FieldState, FormDataProps, FormField} from './types'
|
|
5
|
-
|
|
6
|
-
interface FormRendererProps extends HTMLProps<HTMLFormElement> {
|
|
7
|
-
formData?: FormDataProps
|
|
8
|
-
// Function to get field state for a given field name
|
|
9
|
-
getFieldState?: (fieldName: string) => FieldState
|
|
10
|
-
// Function to get field error for a given field name
|
|
11
|
-
getFieldError?: (fieldName: string) => string | undefined
|
|
12
|
-
// Override default field components
|
|
13
|
-
fieldComponents?: Record<string, ComponentType<FieldComponentProps>>
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const FormRenderer: FC<FormRendererProps> = (props) => {
|
|
17
|
-
const {
|
|
18
|
-
formData,
|
|
19
|
-
getFieldState = (name) => ({
|
|
20
|
-
value: undefined,
|
|
21
|
-
onChange: () => {},
|
|
22
|
-
name, // Pass name to field for native form handling
|
|
23
|
-
}),
|
|
24
|
-
getFieldError,
|
|
25
|
-
fieldComponents = {},
|
|
26
|
-
children,
|
|
27
|
-
} = props
|
|
28
|
-
const renderField = (field: FormField) => {
|
|
29
|
-
const CustomComponent = fieldComponents[field.type]
|
|
30
|
-
const fieldState = getFieldState(field.name)
|
|
31
|
-
const error = getFieldError?.(field.name)
|
|
32
|
-
|
|
33
|
-
if (CustomComponent) {
|
|
34
|
-
return <CustomComponent field={field} fieldState={fieldState} error={error} />
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return <DefaultField field={field} fieldState={fieldState} error={error} />
|
|
38
|
-
}
|
|
39
|
-
const elProps = Object.assign({}, props)
|
|
40
|
-
delete elProps.formData
|
|
41
|
-
delete elProps.getFieldState
|
|
42
|
-
delete elProps.getFieldError
|
|
43
|
-
delete elProps.fieldComponents
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<form {...elProps} id={elProps.id ?? formData?.id?.current}>
|
|
47
|
-
{formData?.fields?.map((field) => (
|
|
48
|
-
<div key={field._key} className="form-field">
|
|
49
|
-
{renderField(field)}
|
|
50
|
-
</div>
|
|
51
|
-
))}
|
|
52
|
-
|
|
53
|
-
{children}
|
|
54
|
-
|
|
55
|
-
{renderField({
|
|
56
|
-
type: 'submit',
|
|
57
|
-
name: 'submit',
|
|
58
|
-
label: formData?.submitButton?.text || 'Submit',
|
|
59
|
-
})}
|
|
60
|
-
</form>
|
|
61
|
-
)
|
|
62
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
export type ValidationRule = {
|
|
2
|
-
type: string
|
|
3
|
-
value: string
|
|
4
|
-
message: string
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export type FieldChoice = {
|
|
8
|
-
label: string
|
|
9
|
-
value: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export type FieldOptions = {
|
|
13
|
-
placeholder?: string
|
|
14
|
-
defaultValue?: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export type FormField = {
|
|
18
|
-
type: string
|
|
19
|
-
label?: string
|
|
20
|
-
name: string
|
|
21
|
-
required?: boolean
|
|
22
|
-
validation?: ValidationRule[]
|
|
23
|
-
options?: FieldOptions
|
|
24
|
-
choices?: FieldChoice[]
|
|
25
|
-
_key?: string
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export type FormDataProps = {
|
|
29
|
-
title: string
|
|
30
|
-
id: {
|
|
31
|
-
current: string
|
|
32
|
-
}
|
|
33
|
-
fields?: FormField[]
|
|
34
|
-
submitButton?: {
|
|
35
|
-
text: string
|
|
36
|
-
position: 'left' | 'center' | 'right'
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface FieldState {
|
|
41
|
-
value?: string | number | readonly string[]
|
|
42
|
-
onChange: (value: unknown) => void
|
|
43
|
-
onBlur?: () => void
|
|
44
|
-
ref?: unknown
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface FieldComponentProps {
|
|
48
|
-
field: FormField
|
|
49
|
-
fieldState: FieldState
|
|
50
|
-
error?: string
|
|
51
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type {StringInputProps} from 'sanity'
|
|
2
|
-
import {useFormValue} from 'sanity'
|
|
3
|
-
|
|
4
|
-
import type {FormField} from '../../form-renderer/components/types'
|
|
5
|
-
import {validationTypesByFieldType} from '../schema-types/form-field'
|
|
6
|
-
|
|
7
|
-
export const ValidationType = (props: StringInputProps) => {
|
|
8
|
-
const {type} = useFormValue([...props.path.slice(0, 2)]) as FormField
|
|
9
|
-
if (!type) return props.renderDefault(props)
|
|
10
|
-
if (props.schemaType?.options) {
|
|
11
|
-
props.schemaType.options.list = validationTypesByFieldType[type]
|
|
12
|
-
}
|
|
13
|
-
return props.renderDefault(props)
|
|
14
|
-
}
|
package/src/form-schema/index.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import {definePlugin, type FieldDefinition} from 'sanity'
|
|
2
|
-
|
|
3
|
-
// import {structureTool} from 'sanity/structure'
|
|
4
|
-
// import {FormRenderer} from './components/form-renderer'
|
|
5
|
-
import {schema} from './schema-types'
|
|
6
|
-
// import {defaultDocumentNode} from './structure'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Usage in `sanity.config.ts` (or .js)
|
|
10
|
-
*
|
|
11
|
-
* ```ts
|
|
12
|
-
* import {defineConfig} from 'sanity'
|
|
13
|
-
* import {formSchema} from '@sanity/form-toolkit'
|
|
14
|
-
*
|
|
15
|
-
* export default defineConfig({
|
|
16
|
-
* // ...
|
|
17
|
-
* plugins: [formSchema()],
|
|
18
|
-
* })
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
export type FieldsOption = Array<FieldDefinition>
|
|
22
|
-
interface FormSchemaPluginOptions {
|
|
23
|
-
/**
|
|
24
|
-
* Array of field definitions to be used in the form schema.
|
|
25
|
-
*/
|
|
26
|
-
fields?: FieldsOption
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export const formSchema = definePlugin((options: FormSchemaPluginOptions | undefined) => {
|
|
30
|
-
return {
|
|
31
|
-
name: 'form-toolkit_form-schema',
|
|
32
|
-
schema: schema(options?.fields ?? []),
|
|
33
|
-
// plugins: [structureTool({defaultDocumentNode})],
|
|
34
|
-
}
|
|
35
|
-
})
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
import {LuTextCursorInput} from 'react-icons/lu'
|
|
2
|
-
import {defineField, defineType} from 'sanity'
|
|
3
|
-
|
|
4
|
-
import {ValidationType} from '../components/validation-type'
|
|
5
|
-
interface ValidationContextDocument {
|
|
6
|
-
fields?: Array<{
|
|
7
|
-
name: string
|
|
8
|
-
type?: string
|
|
9
|
-
}>
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// Validation options by field type
|
|
13
|
-
export const validationTypesByFieldType: Record<string, string[]> = {
|
|
14
|
-
checkbox: ['minSelectedCount', 'maxSelectedCount'],
|
|
15
|
-
color: [],
|
|
16
|
-
date: ['minDate', 'maxDate'],
|
|
17
|
-
'datetime-local': ['minDate', 'maxDate'],
|
|
18
|
-
email: ['pattern'],
|
|
19
|
-
file: ['maxSize', 'fileType'],
|
|
20
|
-
hidden: [],
|
|
21
|
-
number: ['min', 'max'],
|
|
22
|
-
// password: ['minLength', 'pattern'],
|
|
23
|
-
radio: [],
|
|
24
|
-
range: ['min', 'max', 'step'],
|
|
25
|
-
select: [],
|
|
26
|
-
tel: ['pattern'],
|
|
27
|
-
text: ['minLength', 'maxLength', 'pattern'],
|
|
28
|
-
textarea: ['minLength', 'maxLength'],
|
|
29
|
-
time: [],
|
|
30
|
-
url: ['pattern'],
|
|
31
|
-
}
|
|
32
|
-
export const formFieldType = defineType({
|
|
33
|
-
name: 'formField',
|
|
34
|
-
title: 'Form Field',
|
|
35
|
-
type: 'object',
|
|
36
|
-
icon: LuTextCursorInput,
|
|
37
|
-
fields: [
|
|
38
|
-
defineField({
|
|
39
|
-
name: 'type',
|
|
40
|
-
title: 'Field Type',
|
|
41
|
-
type: 'string',
|
|
42
|
-
options: {
|
|
43
|
-
list: Object.keys(validationTypesByFieldType).map((type) => {
|
|
44
|
-
const title = (fieldType: string) => {
|
|
45
|
-
switch (fieldType) {
|
|
46
|
-
case 'datetime-local':
|
|
47
|
-
return 'Date & Time'
|
|
48
|
-
case 'textarea':
|
|
49
|
-
return 'Text Area'
|
|
50
|
-
case 'tel':
|
|
51
|
-
return 'Phone Number'
|
|
52
|
-
default:
|
|
53
|
-
return fieldType.charAt(0).toUpperCase() + fieldType.slice(1)
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return {title: title(type), value: type}
|
|
57
|
-
}),
|
|
58
|
-
},
|
|
59
|
-
}),
|
|
60
|
-
defineField({
|
|
61
|
-
name: 'label',
|
|
62
|
-
title: 'Field Label',
|
|
63
|
-
type: 'string',
|
|
64
|
-
}),
|
|
65
|
-
defineField({
|
|
66
|
-
name: 'name',
|
|
67
|
-
title: 'Field Name',
|
|
68
|
-
type: 'string',
|
|
69
|
-
description:
|
|
70
|
-
'Must start with a letter and contain only letters, numbers, underscores, or hyphens. Must be unique within the form.',
|
|
71
|
-
validation: (Rule) =>
|
|
72
|
-
Rule.required().custom((name, context) => {
|
|
73
|
-
if (!name) {
|
|
74
|
-
return 'Required'
|
|
75
|
-
}
|
|
76
|
-
// Check format (HTML ID/name rules)
|
|
77
|
-
if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)) {
|
|
78
|
-
return 'Field name must start with a letter and contain only letters, numbers, underscores, or hyphens'
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Check uniqueness across all fields
|
|
82
|
-
const doc = context.document as ValidationContextDocument
|
|
83
|
-
const allFieldNames = doc?.fields?.map((field) => field.name) || []
|
|
84
|
-
|
|
85
|
-
// Count occurrences of this name
|
|
86
|
-
const nameCount = allFieldNames.filter((n) => n === name).length
|
|
87
|
-
|
|
88
|
-
// If we find more than one occurrence (including current field), it's not unique
|
|
89
|
-
if (nameCount > 1) {
|
|
90
|
-
return 'Field name must be unique across all form fields'
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Check for reserved HTML form attributes
|
|
94
|
-
const reservedNames = [
|
|
95
|
-
'action',
|
|
96
|
-
'method',
|
|
97
|
-
'target',
|
|
98
|
-
'enctype',
|
|
99
|
-
'accept-charset',
|
|
100
|
-
'autocomplete',
|
|
101
|
-
'novalidate',
|
|
102
|
-
'rel',
|
|
103
|
-
'submit',
|
|
104
|
-
'reset',
|
|
105
|
-
]
|
|
106
|
-
if (reservedNames.includes(name.toLowerCase())) {
|
|
107
|
-
return 'This name is reserved for HTML form attributes. Please choose a different name.'
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return true
|
|
111
|
-
}),
|
|
112
|
-
}),
|
|
113
|
-
defineField({
|
|
114
|
-
name: 'required',
|
|
115
|
-
title: 'Required',
|
|
116
|
-
type: 'boolean',
|
|
117
|
-
initialValue: false,
|
|
118
|
-
}),
|
|
119
|
-
defineField({
|
|
120
|
-
name: 'validation',
|
|
121
|
-
title: 'Validation Rules',
|
|
122
|
-
type: 'array',
|
|
123
|
-
hidden: ({parent}) => {
|
|
124
|
-
if (!parent?.type) return true
|
|
125
|
-
const validationTypes = validationTypesByFieldType[parent.type]
|
|
126
|
-
return !validationTypes || validationTypes.length === 0
|
|
127
|
-
},
|
|
128
|
-
of: [
|
|
129
|
-
{
|
|
130
|
-
type: 'object',
|
|
131
|
-
fields: [
|
|
132
|
-
defineField({
|
|
133
|
-
name: 'type',
|
|
134
|
-
title: 'Validation Type',
|
|
135
|
-
type: 'string',
|
|
136
|
-
options: {
|
|
137
|
-
// TODO: I think this needs to be a custom input component?
|
|
138
|
-
// list: ({parent}) => (parent?.type ? validationTypesByFieldType[parent.type] : []),
|
|
139
|
-
list: [],
|
|
140
|
-
},
|
|
141
|
-
components: {
|
|
142
|
-
input: ValidationType,
|
|
143
|
-
},
|
|
144
|
-
}),
|
|
145
|
-
defineField({
|
|
146
|
-
name: 'value',
|
|
147
|
-
title: 'Value',
|
|
148
|
-
type: 'string',
|
|
149
|
-
}),
|
|
150
|
-
defineField({
|
|
151
|
-
name: 'message',
|
|
152
|
-
title: 'Error Message',
|
|
153
|
-
type: 'string',
|
|
154
|
-
}),
|
|
155
|
-
],
|
|
156
|
-
preview: {
|
|
157
|
-
select: {
|
|
158
|
-
title: 'type',
|
|
159
|
-
subtitle: 'value',
|
|
160
|
-
},
|
|
161
|
-
},
|
|
162
|
-
},
|
|
163
|
-
],
|
|
164
|
-
}),
|
|
165
|
-
defineField({
|
|
166
|
-
name: 'choices',
|
|
167
|
-
title: 'Choices',
|
|
168
|
-
type: 'array',
|
|
169
|
-
hidden: ({parent}) => {
|
|
170
|
-
return !['select', 'radio', 'checkbox'].includes(parent?.type)
|
|
171
|
-
},
|
|
172
|
-
of: [
|
|
173
|
-
{
|
|
174
|
-
type: 'object',
|
|
175
|
-
fields: [
|
|
176
|
-
defineField({
|
|
177
|
-
name: 'label',
|
|
178
|
-
title: 'Label',
|
|
179
|
-
type: 'string',
|
|
180
|
-
}),
|
|
181
|
-
defineField({
|
|
182
|
-
name: 'value',
|
|
183
|
-
title: 'Value',
|
|
184
|
-
type: 'string',
|
|
185
|
-
}),
|
|
186
|
-
],
|
|
187
|
-
},
|
|
188
|
-
],
|
|
189
|
-
}),
|
|
190
|
-
defineField({
|
|
191
|
-
name: 'options',
|
|
192
|
-
title: 'Field Options',
|
|
193
|
-
type: 'object',
|
|
194
|
-
hidden: ({parent}) => {
|
|
195
|
-
return ['select', 'radio', 'checkbox', 'file'].includes(parent?.type)
|
|
196
|
-
},
|
|
197
|
-
fields: [
|
|
198
|
-
defineField({
|
|
199
|
-
name: 'placeholder',
|
|
200
|
-
title: 'Placeholder',
|
|
201
|
-
type: 'string',
|
|
202
|
-
}),
|
|
203
|
-
defineField({
|
|
204
|
-
name: 'defaultValue',
|
|
205
|
-
title: 'Default Value',
|
|
206
|
-
type: 'string',
|
|
207
|
-
}),
|
|
208
|
-
],
|
|
209
|
-
}),
|
|
210
|
-
],
|
|
211
|
-
preview: {
|
|
212
|
-
select: {
|
|
213
|
-
label: 'label',
|
|
214
|
-
name: 'name',
|
|
215
|
-
type: 'type',
|
|
216
|
-
},
|
|
217
|
-
prepare({label, name, type}) {
|
|
218
|
-
return {
|
|
219
|
-
title: label || name,
|
|
220
|
-
subtitle: type,
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
},
|
|
224
|
-
})
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import {FaWpforms} from 'react-icons/fa'
|
|
2
|
-
import {defineField, defineType, type SchemaTypeDefinition} from 'sanity'
|
|
3
|
-
|
|
4
|
-
import type {FieldsOption} from '..'
|
|
5
|
-
|
|
6
|
-
export const formType = (fields: FieldsOption): SchemaTypeDefinition => {
|
|
7
|
-
// const fieldsOf =
|
|
8
|
-
// fields && fields.length ? [{type: 'formField'}, ...fields] : [{type: 'formField'}]
|
|
9
|
-
return defineType({
|
|
10
|
-
name: 'form',
|
|
11
|
-
title: 'Form',
|
|
12
|
-
type: 'document',
|
|
13
|
-
icon: FaWpforms,
|
|
14
|
-
fields: [
|
|
15
|
-
defineField({
|
|
16
|
-
name: 'title',
|
|
17
|
-
title: 'Form Title',
|
|
18
|
-
type: 'string',
|
|
19
|
-
description: 'Internal title for the form',
|
|
20
|
-
validation: (Rule) => Rule.required(),
|
|
21
|
-
}),
|
|
22
|
-
defineField({
|
|
23
|
-
name: 'id',
|
|
24
|
-
title: 'Form ID',
|
|
25
|
-
type: 'slug',
|
|
26
|
-
options: {
|
|
27
|
-
source: 'title',
|
|
28
|
-
},
|
|
29
|
-
// validation: (Rule) => Rule.required(),
|
|
30
|
-
}),
|
|
31
|
-
defineField({
|
|
32
|
-
name: 'fields',
|
|
33
|
-
title: 'Form Fields',
|
|
34
|
-
type: 'array',
|
|
35
|
-
of: [{type: 'formField'}, ...fields],
|
|
36
|
-
}),
|
|
37
|
-
defineField({
|
|
38
|
-
name: 'submitButton',
|
|
39
|
-
title: 'Submit Button',
|
|
40
|
-
type: 'object',
|
|
41
|
-
fields: [
|
|
42
|
-
defineField({
|
|
43
|
-
name: 'text',
|
|
44
|
-
title: 'Button Text',
|
|
45
|
-
type: 'string',
|
|
46
|
-
initialValue: 'Submit',
|
|
47
|
-
}),
|
|
48
|
-
],
|
|
49
|
-
}),
|
|
50
|
-
],
|
|
51
|
-
})
|
|
52
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type {SchemaTypeDefinition} from 'sanity'
|
|
2
|
-
|
|
3
|
-
import type {FieldsOption} from '..'
|
|
4
|
-
import {formType} from './form'
|
|
5
|
-
import {formFieldType} from './form-field'
|
|
6
|
-
|
|
7
|
-
export const schema = (fields: FieldsOption): {types: SchemaTypeDefinition[]} => {
|
|
8
|
-
return {types: [formType(fields), formFieldType]}
|
|
9
|
-
}
|
package/src/formium/index.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import {createClient, type Form} from '@formium/client'
|
|
2
|
-
import {asyncList} from '@sanity/sanity-plugin-async-list'
|
|
3
|
-
import {definePlugin} from 'sanity'
|
|
4
|
-
|
|
5
|
-
interface FormiumInputConfig {
|
|
6
|
-
/* nothing here yet */
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Usage in `sanity.config.ts` (or .js)
|
|
11
|
-
*
|
|
12
|
-
* ```ts
|
|
13
|
-
* import {defineConfig} from 'sanity'
|
|
14
|
-
* import {formiumInput} from 'sanity-plugin-form-toolkit'
|
|
15
|
-
*
|
|
16
|
-
* export default defineConfig({
|
|
17
|
-
* // ...
|
|
18
|
-
* plugins: [formiumInput()],
|
|
19
|
-
* })
|
|
20
|
-
* ```
|
|
21
|
-
*/
|
|
22
|
-
// Is Formium dead? All attempts to use the API come back with an expired cert https://github.com/formium/formium/issues/77
|
|
23
|
-
export const formiumInput = definePlugin<FormiumInputConfig | void>(() => {
|
|
24
|
-
return {
|
|
25
|
-
name: 'sanity-plugin-form-toolkit_formium-input',
|
|
26
|
-
plugins: [
|
|
27
|
-
asyncList({
|
|
28
|
-
schemaType: 'formiumInput',
|
|
29
|
-
secrets: {
|
|
30
|
-
keys: [
|
|
31
|
-
{key: 'projectId', title: 'Project ID'},
|
|
32
|
-
{key: 'token', title: 'Token'},
|
|
33
|
-
],
|
|
34
|
-
},
|
|
35
|
-
loader: async ({secrets}) => {
|
|
36
|
-
const formium = createClient(secrets?.projectId || '', {
|
|
37
|
-
apiToken: secrets?.token,
|
|
38
|
-
})
|
|
39
|
-
const {data}: {data: Form[]} = await formium.findForms()
|
|
40
|
-
return data && data.length
|
|
41
|
-
? data.map(({name, id}) => {
|
|
42
|
-
return {
|
|
43
|
-
title: name,
|
|
44
|
-
value: id,
|
|
45
|
-
}
|
|
46
|
-
})
|
|
47
|
-
: []
|
|
48
|
-
},
|
|
49
|
-
}),
|
|
50
|
-
],
|
|
51
|
-
}
|
|
52
|
-
})
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import {Card, Text} from '@sanity/ui'
|
|
2
|
-
import type {ReactElement} from 'react'
|
|
3
|
-
|
|
4
|
-
export const Option = (option: {value: string; name: string}): ReactElement => {
|
|
5
|
-
return (
|
|
6
|
-
<Card data-as="button" padding={3} radius={2} tone="inherit">
|
|
7
|
-
<Text size={2} textOverflow="ellipsis">
|
|
8
|
-
{option.name}
|
|
9
|
-
</Text>
|
|
10
|
-
<Card paddingTop={2} tone="inherit" style={{background: 'inherit'}}>
|
|
11
|
-
<Text size={1} textOverflow="ellipsis">
|
|
12
|
-
{`ID: ${option.value}`}
|
|
13
|
-
</Text>
|
|
14
|
-
</Card>
|
|
15
|
-
</Card>
|
|
16
|
-
)
|
|
17
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
type HubSpotForm = {
|
|
2
|
-
id: string
|
|
3
|
-
name: string
|
|
4
|
-
[key: string]: unknown // Additional properties from the API response
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
type MappedResult = HubSpotForm & {
|
|
8
|
-
value: string
|
|
9
|
-
}
|
|
10
|
-
export async function fetchHubSpotData({token}: {token: string}): Promise<MappedResult[] | null> {
|
|
11
|
-
try {
|
|
12
|
-
const apiResponse = await fetch('https://api.hubapi.com/marketing/v3/forms/?limit=9999', {
|
|
13
|
-
headers: {
|
|
14
|
-
Authorization: `Bearer ${token}`,
|
|
15
|
-
},
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
if (!apiResponse.ok) {
|
|
19
|
-
console.error(`Failed to fetch data: ${apiResponse.statusText}`)
|
|
20
|
-
return null
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const {results}: {results: HubSpotForm[]} = await apiResponse.json()
|
|
24
|
-
|
|
25
|
-
return results.map((result) => ({
|
|
26
|
-
...result,
|
|
27
|
-
value: result.id,
|
|
28
|
-
}))
|
|
29
|
-
} catch (e: unknown) {
|
|
30
|
-
console.error(e)
|
|
31
|
-
return null // Explicitly return null on error
|
|
32
|
-
}
|
|
33
|
-
}
|