diff --git a/apps/web/app/(builder)/lib/core/sync.ts b/apps/web/app/(builder)/lib/core/sync.ts index 5e162b6..cd3befb 100644 --- a/apps/web/app/(builder)/lib/core/sync.ts +++ b/apps/web/app/(builder)/lib/core/sync.ts @@ -140,9 +140,9 @@ function syncFieldValues( // Array: always preserve rows if (field.type === "array") { - if (currentVal !== undefined) { + if (Array.isArray(currentVal)) { result[name] = currentVal; - } else if (defaultVal !== undefined) { + } else if (Array.isArray(defaultVal)) { result[name] = defaultVal; } else { result[name] = []; diff --git a/apps/web/app/(builder)/lib/properties.ts b/apps/web/app/(builder)/lib/properties.ts index 885074b..2b5eb7a 100644 --- a/apps/web/app/(builder)/lib/properties.ts +++ b/apps/web/app/(builder)/lib/properties.ts @@ -23,6 +23,16 @@ export function extractDefaults(fields: Field[]): Record { const defaults: Record = {}; for (const field of fields) { if ("name" in field && field.name) { + // Array values must always be arrays at runtime. + if (field.type === "array") { + const explicitDefault = (field as unknown as Record) + .defaultValue; + defaults[field.name] = Array.isArray(explicitDefault) + ? deepClone(explicitDefault) + : []; + continue; + } + if ("defaultValue" in field) { // Deep clone to avoid frozen object references from Zustand/immer defaults[field.name] = deepClone( diff --git a/apps/web/app/(builder)/lib/registry.ts b/apps/web/app/(builder)/lib/registry.ts index 902b8da..2b2a533 100644 --- a/apps/web/app/(builder)/lib/registry.ts +++ b/apps/web/app/(builder)/lib/registry.ts @@ -141,7 +141,7 @@ export const builderFieldRegistry: BuilderFieldRegistry = { icon: CheckmarkSquare02Icon, category: "selection", }, - defaultProps: { type: "checkbox", label: "Checkbox" }, + defaultProps: { type: "checkbox", label: "Checkbox", defaultValue: false }, properties: checkboxFieldProperties, }, "checkbox-group": {