Skip to content

Commit 6080cf1

Browse files
committed
feat: support v-model for <details> and <dialog>
1 parent 681ac7c commit 6080cf1

File tree

8 files changed

+121
-1
lines changed

8 files changed

+121
-1
lines changed

packages/compiler-dom/__tests__/transforms/__snapshots__/vModel.spec.ts.snap

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,38 @@ return function render(_ctx, _cache) {
127127
}"
128128
`;
129129

130+
exports[`compiler: transform v-model > simple expression for details 1`] = `
131+
"const _Vue = Vue
132+
133+
return function render(_ctx, _cache) {
134+
with (_ctx) {
135+
const { vModelDetails: _vModelDetails, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
136+
137+
return _withDirectives((_openBlock(), _createElementBlock(\\"details\\", {
138+
\\"onUpdate:modelValue\\": $event => ((model) = $event)
139+
}, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [
140+
[_vModelDetails, model]
141+
])
142+
}
143+
}"
144+
`;
145+
146+
exports[`compiler: transform v-model > simple expression for dialog 1`] = `
147+
"const _Vue = Vue
148+
149+
return function render(_ctx, _cache) {
150+
with (_ctx) {
151+
const { vModelDialog: _vModelDialog, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
152+
153+
return _withDirectives((_openBlock(), _createElementBlock(\\"dialog\\", {
154+
\\"onUpdate:modelValue\\": $event => ((model) = $event)
155+
}, null, 8 /* PROPS */, [\\"onUpdate:modelValue\\"])), [
156+
[_vModelDialog, model]
157+
])
158+
}
159+
}"
160+
`;
161+
130162
exports[`compiler: transform v-model > simple expression for input (checkbox) 1`] = `
131163
"const _Vue = Vue
132164

packages/compiler-dom/__tests__/transforms/vModel.spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { transformElement } from '../../../compiler-core/src/transforms/transfor
1010
import { DOMErrorCodes } from '../../src/errors'
1111
import {
1212
V_MODEL_CHECKBOX,
13+
V_MODEL_DETAILS,
14+
V_MODEL_DIALOG,
1315
V_MODEL_DYNAMIC,
1416
V_MODEL_RADIO,
1517
V_MODEL_SELECT,
@@ -84,6 +86,20 @@ describe('compiler: transform v-model', () => {
8486
expect(generate(root).code).toMatchSnapshot()
8587
})
8688

89+
test('simple expression for details', () => {
90+
const root = transformWithModel('<details v-model="model" />')
91+
92+
expect(root.helpers).toContain(V_MODEL_DETAILS)
93+
expect(generate(root).code).toMatchSnapshot()
94+
})
95+
96+
test('simple expression for dialog', () => {
97+
const root = transformWithModel('<dialog v-model="model" />')
98+
99+
expect(root.helpers).toContain(V_MODEL_DIALOG)
100+
expect(generate(root).code).toMatchSnapshot()
101+
})
102+
87103
test('simple expression for textarea', () => {
88104
const root = transformWithModel('<textarea v-model="model" />')
89105

packages/compiler-dom/src/runtimeHelpers.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ export const V_MODEL_RADIO = Symbol(__DEV__ ? `vModelRadio` : ``)
44
export const V_MODEL_CHECKBOX = Symbol(__DEV__ ? `vModelCheckbox` : ``)
55
export const V_MODEL_TEXT = Symbol(__DEV__ ? `vModelText` : ``)
66
export const V_MODEL_SELECT = Symbol(__DEV__ ? `vModelSelect` : ``)
7+
export const V_MODEL_DIALOG = Symbol(__DEV__ ? `vModelDialog` : ``)
8+
export const V_MODEL_DETAILS = Symbol(__DEV__ ? `vModelDetails` : ``)
79
export const V_MODEL_DYNAMIC = Symbol(__DEV__ ? `vModelDynamic` : ``)
810

911
export const V_ON_WITH_MODIFIERS = Symbol(__DEV__ ? `vOnModifiersGuard` : ``)
@@ -19,6 +21,8 @@ registerRuntimeHelpers({
1921
[V_MODEL_CHECKBOX]: `vModelCheckbox`,
2022
[V_MODEL_TEXT]: `vModelText`,
2123
[V_MODEL_SELECT]: `vModelSelect`,
24+
[V_MODEL_DETAILS]: `vModelDetails`,
25+
[V_MODEL_DIALOG]: `vModelDialog`,
2226
[V_MODEL_DYNAMIC]: `vModelDynamic`,
2327
[V_ON_WITH_MODIFIERS]: `withModifiers`,
2428
[V_ON_WITH_KEYS]: `withKeys`,

packages/compiler-dom/src/transforms/vModel.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import {
1212
V_MODEL_RADIO,
1313
V_MODEL_SELECT,
1414
V_MODEL_TEXT,
15-
V_MODEL_DYNAMIC
15+
V_MODEL_DYNAMIC,
16+
V_MODEL_DETAILS,
17+
V_MODEL_DIALOG
1618
} from '../runtimeHelpers'
1719

1820
export const transformModel: DirectiveTransform = (dir, node, context) => {
@@ -49,6 +51,8 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
4951
tag === 'input' ||
5052
tag === 'textarea' ||
5153
tag === 'select' ||
54+
tag === 'details' ||
55+
tag === 'dialog' ||
5256
isCustomElement
5357
) {
5458
let directiveToUse = V_MODEL_TEXT
@@ -92,6 +96,10 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
9296
}
9397
} else if (tag === 'select') {
9498
directiveToUse = V_MODEL_SELECT
99+
} else if (tag === 'dialog') {
100+
directiveToUse = V_MODEL_DIALOG
101+
} else if (tag === 'details') {
102+
directiveToUse = V_MODEL_DETAILS
95103
} else {
96104
// textarea
97105
__DEV__ && checkDuplicatedValue()

packages/compiler-ssr/__tests__/ssrElement.spec.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,4 +340,24 @@ describe('ssr: element', () => {
340340
`)
341341
})
342342
})
343+
344+
describe('v-model', () => {
345+
test('with details', () => {
346+
expect(getCompiledString(`<details v-model="x">Foo</details>`))
347+
.toMatchInlineSnapshot(`
348+
"\`<details\${
349+
(_ssrIncludeBooleanAttr(_ctx.x)) ? \\" open\\" : \\"\\"
350+
}>Foo</details>\`"
351+
`)
352+
})
353+
354+
test('with dialog', () => {
355+
expect(getCompiledString(`<dialog v-model="x">Foo</dialog>`))
356+
.toMatchInlineSnapshot(`
357+
"\`<dialog\${
358+
(_ssrIncludeBooleanAttr(_ctx.x)) ? \\" open\\" : \\"\\"
359+
}>Foo</dialog>\`"
360+
`)
361+
})
362+
})
343363
})

packages/compiler-ssr/src/transforms/ssrVModel.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
128128
} else if (node.tag === 'textarea') {
129129
checkDuplicatedValue()
130130
node.children = [createInterpolation(model, model.loc)]
131+
} else if (node.tag === 'dialog' || node.tag === 'details') {
132+
res.props = [createObjectProperty(`open`, model)]
131133
} else if (node.tag === 'select') {
132134
// NOOP
133135
// select relies on client-side directive to set initial selected state.

packages/runtime-dom/src/directives/vModel.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,42 @@ export const vModelSelect: ModelDirective<HTMLSelectElement> = {
210210
}
211211
}
212212

213+
export const vModelDetails: ModelDirective<HTMLDetailsElement> = {
214+
created(el, _, vnode) {
215+
addEventListener(el, 'toggle', () => {
216+
el._assign(el.open)
217+
})
218+
el._assign = getModelAssigner(vnode)
219+
},
220+
mounted(el, { value }) {
221+
el.open = value
222+
},
223+
beforeUpdate(el, _binding, vnode) {
224+
el._assign = getModelAssigner(vnode)
225+
},
226+
updated(el, { value }) {
227+
el.open = value
228+
}
229+
}
230+
231+
export const vModelDialog: ModelDirective<HTMLDialogElement> = {
232+
created(el, _, vnode) {
233+
addEventListener(el, 'close', () => {
234+
el._assign(false)
235+
})
236+
el._assign = getModelAssigner(vnode)
237+
},
238+
mounted(el, { value }) {
239+
el.open = value
240+
},
241+
beforeUpdate(el, _binding, vnode) {
242+
el._assign = getModelAssigner(vnode)
243+
},
244+
updated(el, { value }) {
245+
el.open = value
246+
}
247+
}
248+
213249
function setSelected(el: HTMLSelectElement, value: any) {
214250
const isMultiple = el.multiple
215251
if (isMultiple && !isArray(value) && !isSet(value)) {

packages/runtime-dom/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ export {
226226
vModelCheckbox,
227227
vModelRadio,
228228
vModelSelect,
229+
vModelDetails,
230+
vModelDialog,
229231
vModelDynamic
230232
} from './directives/vModel'
231233
export { withModifiers, withKeys } from './directives/vOn'

0 commit comments

Comments
 (0)