Boolean props auto-enable when another prop is changed in the Canvas form
## Summary In Canvas, when editing a component that has boolean props (e.g. `card-program`), changing any non-boolean prop causes all boolean props to appear enabled (toggle switches flip to ON) even though the user never toggled them. ## Root causes Two bugs were identified: ### 1. `|| []` coerces boolean `false` to `[]` in `layoutModelSlice.ts` In `_addNewComponentToLayout` → `buildInitialData()`, when building the initial model for a newly dropped component: ```typescript // BEFORE (buggy): initialData.resolved[propName] = prop.default_values?.resolved || []; // For boolean false: false || [] = [] (truthy empty array!) // AFTER (fixed): initialData.resolved[propName] = prop.default_values?.resolved ?? []; // For boolean false: false ?? [] = false (correct) ``` The same issue applied to `source` on line 566. ### 2. Twig renders `element[#value]` as `0` for unchecked checkboxes during AJAX rebuilds When a Drupal AJAX form rebuild fires (POST request, e.g. triggered by a media library field or any other AJAX-enabled widget), `Checkbox::valueCallback()` returns integer `0` (not PHP boolean `false`) for an unchecked, unsubmitted checkbox: ```php // Checkbox::valueCallback — when $input is NULL (unchecked, submitted form) return isset($input) ? $element[#return_value] : 0; // returns integer 0 ``` The template `input--checkbox--inwidget-boolean-checkbox.html.twig` then passes this to the React `DrupalToggle` component: ```twig current_value="{{ element[#value] }}" ``` Twig renders integer `0` as the string `0`. In JavaScript, `!!0 === true`, so `DrupalToggle` initializes `isChecked = true` — the toggle appears ON. ## Fixes ### Fix 1 — `layoutModelSlice.ts` Change `|| []` to `?? []` at lines 559 and 566 so boolean `false` is preserved. ### Fix 2 — `input--checkbox--inwidget-boolean-checkbox.html.twig` Use `element[#checked]` (a proper boolean set by `processCheckbox`) instead of `element[#value]`: ```twig {# BEFORE #} default_value="{{ element[#default_value] }}" current_value="{{ element[#value] }}" {# AFTER #} default_value="{{ element[#default_value] ? 1 : }}" current_value="{{ element[#checked] ? 1 : }}" ``` This guarantees the template only ever passes `1` or `` — never the ambiguous `0`. ### Fix 3 — `DrupalToggle.tsx` Add a defensive `parseChecked()` helper so that `0` and `0` are treated as falsy: ```typescript const parseChecked = (v?: string | number): boolean => v !== undefined && v !== null && v !== && v !== 0 && v !== 0; const [isChecked, setIsChecked] = useState( parseChecked(defaultValue) || parseChecked(currentValue), ); ``` ## Steps to reproduce 1. Open a Canvas layout editor. 2. Drop a component that has boolean props (e.g. `card-program` from Vartheme BS5). 3. Verify all boolean toggles are OFF. 4. Change any non-boolean prop (e.g. a text field). 5. Observe: boolean toggles flip to ON automatically. ## Affected versions Canvas `1.x` branch.
issue