fix(gui-v2): :key on RightDrawer dynamic body to remount on switch

Adds :key="component" to <component :is="Body"> so opening drawer B
while A is open fully remounts (A's instance/state can't leak into B) —
a real defect for a primary shell overlay. Same-name reopen still
relies on the body reacting to prop changes (documented inline).
Companion test asserts the cross-component switch swaps the body
cleanly (A unmounts, B mounts). Addresses the Task 5 code-review
Important finding.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-16 21:30:43 +02:00
parent 2d7d4b49d8
commit ca0332d17a
2 changed files with 39 additions and 0 deletions

View File

@@ -141,9 +141,17 @@ const Body = computed(() => resolveDrawerComponent(component.value))
a minimal empty state this must NOT crash on null (resolveDrawerComponent
guarantees null for unknown names).
-->
<!--
:key on the drawer-body name forces a full remount when the open
drawer switches from one component to another (open A open B),
so component A's internal state never leaks into component B.
Same-name reopen relies on the body reacting to prop changes
(normal Vue); revisit if a real body ever needs a hard reset there.
-->
<component
:is="Body"
v-if="Body !== null"
:key="component ?? ''"
v-bind="bodyProps"
/>

View File

@@ -226,4 +226,35 @@ describe('RightDrawer', () => {
// Graceful-empty-state text must NOT appear when a component is rendered
expect(wrapper.text()).not.toContain('Geen inhoud')
})
// -------------------------------------------------------------------------
// 7. Switching the open drawer component swaps the body cleanly
// (the :key="component" remount guard — opening B while A is open
// unmounts A and mounts B; A's DOM/state must not linger).
// -------------------------------------------------------------------------
it('remounts the body when the open drawer switches to another component', async () => {
const BodyA = defineComponent({ template: '<div class="body-a">A</div>' })
const BodyB = defineComponent({ template: '<div class="body-b">B</div>' })
const nameA = `${PREFIX}BodyA`
const nameB = `${PREFIX}BodyB`
registerDrawerComponent(nameA, BodyA)
registerDrawerComponent(nameB, BodyB)
const wrapper = mountDrawer()
const shell = useShellUiStore()
shell.openDrawer(nameA, { title: 'A' })
await wrapper.vm.$nextTick()
expect(wrapper.find('.body-a').exists()).toBe(true)
expect(wrapper.find('.body-b').exists()).toBe(false)
// Switch to B while the drawer is still open — :key change forces a
// full remount so A is gone and B is mounted (no stale A instance).
shell.openDrawer(nameB, { title: 'B' })
await wrapper.vm.$nextTick()
expect(wrapper.find('.body-b').exists()).toBe(true)
expect(wrapper.find('.body-a').exists()).toBe(false)
})
})