From 8543baa2d866e5aa2fceda56c5fde162aeb6b9f9 Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Tue, 18 Nov 2025 23:20:29 +0800 Subject: [PATCH 1/4] feat(vModel): support `HTMLDetailsElement` --- .../__tests__/directives/vModel.spec.ts | 31 +++++++++++++++++++ packages/runtime-dom/src/directives/vModel.ts | 19 ++++++++++++ 2 files changed, 50 insertions(+) diff --git a/packages/runtime-dom/__tests__/directives/vModel.spec.ts b/packages/runtime-dom/__tests__/directives/vModel.spec.ts index c3c420f407a..8cacc8f520d 100644 --- a/packages/runtime-dom/__tests__/directives/vModel.spec.ts +++ b/packages/runtime-dom/__tests__/directives/vModel.spec.ts @@ -1496,4 +1496,35 @@ describe('vModel', () => { await nextTick() expect(foo.checked).toEqual(false) }) + + it('should work with details', async () => { + const component = defineComponent({ + data() { + return { value: null } + }, + render() { + return [ + withVModel( + h('details', { + 'onUpdate:modelValue': setValue.bind(this), + }), + this.value, + ), + ] + }, + }) + render(h(component), root) + + const details: HTMLDetailsElement = root.querySelector('details') + const data = root._vnode.component.data + + details.open = true + triggerEvent('toggle', details) + await nextTick() + expect(data.value).toEqual(true) + + data.value = false + await nextTick() + expect(details.open).toEqual(false) + }) }) diff --git a/packages/runtime-dom/src/directives/vModel.ts b/packages/runtime-dom/src/directives/vModel.ts index 07b23d20ac6..2a3bc6f211a 100644 --- a/packages/runtime-dom/src/directives/vModel.ts +++ b/packages/runtime-dom/src/directives/vModel.ts @@ -370,6 +370,22 @@ function getCheckboxValue( return checked } +export const vModelDetails: ModelDirective = { + created(el, { value }, vnode) { + el.open = looseEqual(value, vnode.props!.value) + el[assignKey] = getModelAssigner(vnode) + addEventListener(el, 'toggle', () => { + el[assignKey](el.open) + }) + }, + beforeUpdate(el, { value, oldValue }, vnode) { + el[assignKey] = getModelAssigner(vnode) + if (value !== oldValue) { + el.open = looseEqual(value, vnode.props!.value) + } + }, +} + export const vModelDynamic: ObjectDirective< HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement > = { @@ -393,6 +409,8 @@ function resolveDynamicModel(tagName: string, type: string | undefined) { return vModelSelect case 'TEXTAREA': return vModelText + case 'DETAILS': + return vModelDetails default: switch (type) { case 'checkbox': @@ -465,4 +483,5 @@ export type VModelDirective = | typeof vModelCheckbox | typeof vModelSelect | typeof vModelRadio + | typeof vModelDetails | typeof vModelDynamic From 628b2b8ee92716f3261172ae3429b394caeeb369 Mon Sep 17 00:00:00 2001 From: Vida Xie Date: Tue, 18 Nov 2025 23:42:39 +0800 Subject: [PATCH 2/4] wip: update --- packages/compiler-dom/__tests__/transforms/vModel.spec.ts | 7 +++++++ packages/compiler-dom/src/errors.ts | 2 +- packages/compiler-dom/src/runtimeHelpers.ts | 3 +++ packages/compiler-dom/src/transforms/vModel.ts | 1 + packages/compiler-ssr/src/transforms/ssrVModel.ts | 2 ++ .../compiler-vapor/__tests__/transforms/vModel.spec.ts | 6 ++++++ 6 files changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/compiler-dom/__tests__/transforms/vModel.spec.ts b/packages/compiler-dom/__tests__/transforms/vModel.spec.ts index 6fe39900ca8..3a466e3f7f7 100644 --- a/packages/compiler-dom/__tests__/transforms/vModel.spec.ts +++ b/packages/compiler-dom/__tests__/transforms/vModel.spec.ts @@ -10,6 +10,7 @@ import { transformElement } from '../../../compiler-core/src/transforms/transfor import { DOMErrorCodes } from '../../src/errors' import { V_MODEL_CHECKBOX, + V_MODEL_DETAILS, V_MODEL_DYNAMIC, V_MODEL_RADIO, V_MODEL_SELECT, @@ -99,6 +100,12 @@ describe('compiler: transform v-model', () => { expect(generate(root).code).toMatchSnapshot() }) + test('simple expression for details', () => { + const root = transformWithModel('
') + expect(root.helpers).toContain(V_MODEL_DETAILS) + expect(generate(root).code).toMatchSnapshot() + }) + describe('errors', () => { test('plain elements with argument', () => { const onError = vi.fn() diff --git a/packages/compiler-dom/src/errors.ts b/packages/compiler-dom/src/errors.ts index 788de930699..99afd0756da 100644 --- a/packages/compiler-dom/src/errors.ts +++ b/packages/compiler-dom/src/errors.ts @@ -53,7 +53,7 @@ export const DOMErrorMessages: Record = { [DOMErrorCodes.X_V_HTML_WITH_CHILDREN]: `v-html will override element children.`, [DOMErrorCodes.X_V_TEXT_NO_EXPRESSION]: `v-text is missing expression.`, [DOMErrorCodes.X_V_TEXT_WITH_CHILDREN]: `v-text will override element children.`, - [DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT]: `v-model can only be used on ,