Files
landing-builder/lib/state/formStore.ts
T
2025-11-14 16:40:45 +09:00

70 lines
2.3 KiB
TypeScript

import { createStore } from 'zustand/vanilla'
export type BaseField = {
name: string
label: string
required?: boolean
pattern?: string
maxLength?: number
}
export type TextField = BaseField & { type: 'text' | 'email' | 'tel' | 'date' | 'textarea' }
export type CheckboxField = BaseField & { type: 'checkbox' }
export type RadioField = BaseField & { type: 'radio'; options: string[] }
export type SelectField = BaseField & { type: 'select'; options: string[] }
export type FormField = TextField | CheckboxField | RadioField | SelectField
export type FormFieldInput = FormField
export type FormState = {
fields: FormField[]
actionUrl: string
spam: { honeypotFieldName: string; minSubmitSeconds: number }
addField: (f: FormFieldInput) => void
moveField: (from: number, to: number) => void
removeField: (index: number) => void
updateField: (index: number, patch: Partial<FormField>) => void
setActionUrl: (url: string) => void
setSpam: (s: { honeypotFieldName?: string; minSubmitSeconds?: number }) => void
}
export function createFormStore() {
return createStore<FormState>((set) => ({
fields: [],
actionUrl: '',
spam: { honeypotFieldName: '_hp', minSubmitSeconds: 2 },
addField: (f) => set((st) => ({ fields: [...st.fields, f] })),
moveField: (from, to) =>
set((st) => {
const arr = [...st.fields]
if (from < 0 || from >= arr.length || to < 0 || to >= arr.length) return st
const [spliced] = arr.splice(from, 1)
arr.splice(to, 0, spliced)
return { fields: arr }
}),
removeField: (index) =>
set((st) => {
if (index < 0 || index >= st.fields.length) return st
const arr = st.fields.slice()
arr.splice(index, 1)
return { fields: arr }
}),
updateField: (index, patch) =>
set((st) => {
if (index < 0 || index >= st.fields.length) return st
const next = st.fields.slice()
next[index] = { ...next[index], ...patch } as FormField
return { fields: next }
}),
setActionUrl: (url) => set({ actionUrl: url }),
setSpam: (s) =>
set((st) => ({
spam: {
honeypotFieldName: s.honeypotFieldName ?? st.spam.honeypotFieldName,
minSubmitSeconds: s.minSubmitSeconds ?? st.spam.minSubmitSeconds,
},
})),
}))
}