"dev-prepare-cjs": "node scripts/prepare-cjs.js || npm run build-all-cjs",
"dev-compiler": "run-p \"dev template-explorer\" serve open",
"dev-sfc": "run-s dev-prepare-cjs dev-sfc-run",
- "dev-sfc-serve": "vite packages-private/sfc-playground --host",
+ "dev-sfc-serve": "vite packages-private/sfc-playground",
"dev-sfc-run": "run-p \"dev compiler-sfc -f esm-browser\" \"dev vue -if esm-bundler-runtime\" \"dev vue -ipf esm-browser-runtime\" \"dev server-renderer -if esm-bundler\" dev-sfc-serve",
"dev-vapor": "pnpm -C playground run dev",
"serve": "serve",
`;
exports[`compile > directives > v-pre > basic 1`] = `
-"import { template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, template as _template } from 'vue/vapor';
const t0 = _template("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}</div>")
export function render(_ctx, $props) {
const n0 = t0()
+ _setInheritAttrs(false)
return n0
}"
`;
`;
exports[`compile > dynamic root nodes and interpolation 1`] = `
-"import { delegate as _delegate, renderEffect as _renderEffect, setText as _setText, setDynamicProp as _setDynamicProp, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
+"import { delegate as _delegate, setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setText as _setText, setDynamicProp as _setDynamicProp, delegateEvents as _delegateEvents, template as _template } from 'vue/vapor';
const t0 = _template("<button></button>")
_delegateEvents("click")
export function render(_ctx) {
const n0 = t0()
_delegate(n0, "click", () => _ctx.handleClick)
+ _setInheritAttrs(["id"])
_renderEffect(() => _setText(n0, _ctx.count, "foo", _ctx.count, "foo", _ctx.count))
- _renderEffect(() => _setDynamicProp(n0, "id", _ctx.count))
+ _renderEffect(() => _setDynamicProp(n0, "id", _ctx.count, true))
return n0
}"
`;
exports[`compile > expression parsing > v-bind 1`] = `
"((_ctx) => {
const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, { [key.value+1]: _unref(foo)[key.value+1]() }))
+ _setInheritAttrs(true)
+ _renderEffect(() => _setDynamicProps(n0, [{ [key.value+1]: _unref(foo)[key.value+1]() }], true))
return n0
})()"
`;
`;
exports[`compiler: element transform > props + children 1`] = `
-"import { template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, template as _template } from 'vue/vapor';
const t0 = _template("<div id=\\"foo\\"><span></span></div>")
export function render(_ctx) {
const n0 = t0()
+ _setInheritAttrs(false)
return n0
}"
`;
exports[`compiler: element transform > props merging: class 1`] = `
-"import { renderEffect as _renderEffect, setClass as _setClass, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setClass as _setClass, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setClass(n0, ["foo", { bar: _ctx.isBar }]))
+ _setInheritAttrs(["class"])
+ _renderEffect(() => _setClass(n0, ["foo", { bar: _ctx.isBar }], true))
return n0
}"
`;
`;
exports[`compiler: element transform > props merging: style 1`] = `
-"import { renderEffect as _renderEffect, setStyle as _setStyle, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setStyle as _setStyle, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setStyle(n0, ["color: green", { color: 'red' }]))
+ _setInheritAttrs(["style"])
+ _renderEffect(() => _setStyle(n0, ["color: green", { color: 'red' }], true))
return n0
}"
`;
exports[`compiler: element transform > static props 1`] = `
-"import { template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, template as _template } from 'vue/vapor';
const t0 = _template("<div id=\\"foo\\" class=\\"bar\\"></div>")
export function render(_ctx) {
const n0 = t0()
+ _setInheritAttrs(false)
return n0
}"
`;
exports[`compiler: element transform > v-bind="obj" 1`] = `
-"import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, _ctx.obj))
+ _setInheritAttrs(true)
+ _renderEffect(() => _setDynamicProps(n0, [_ctx.obj], true))
return n0
}"
`;
exports[`compiler: element transform > v-bind="obj" after static prop 1`] = `
-"import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, { id: "foo" }, _ctx.obj))
+ _setInheritAttrs(true)
+ _renderEffect(() => _setDynamicProps(n0, [{ id: "foo" }, _ctx.obj], true))
return n0
}"
`;
exports[`compiler: element transform > v-bind="obj" before static prop 1`] = `
-"import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, _ctx.obj, { id: "foo" }))
+ _setInheritAttrs(true)
+ _renderEffect(() => _setDynamicProps(n0, [_ctx.obj, { id: "foo" }], true))
return n0
}"
`;
exports[`compiler: element transform > v-bind="obj" between static props 1`] = `
-"import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, { id: "foo" }, _ctx.obj, { class: "bar" }))
+ _setInheritAttrs(true)
+ _renderEffect(() => _setDynamicProps(n0, [{ id: "foo" }, _ctx.obj, { class: "bar" }], true))
return n0
}"
`;
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`compiler v-bind > .attr modifier 1`] = `
-"import { renderEffect as _renderEffect, setAttr as _setAttr, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setAttr as _setAttr, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setAttr(n0, "foo-bar", _ctx.id))
+ _setInheritAttrs(["foo-bar"])
+ _renderEffect(() => _setAttr(n0, "foo-bar", _ctx.id, true))
return n0
}"
`;
exports[`compiler v-bind > .attr modifier w/ no expression 1`] = `
-"import { renderEffect as _renderEffect, setAttr as _setAttr, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setAttr as _setAttr, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setAttr(n0, "foo-bar", _ctx.fooBar))
+ _setInheritAttrs(["foo-bar"])
+ _renderEffect(() => _setAttr(n0, "foo-bar", _ctx.fooBar, true))
return n0
}"
`;
exports[`compiler v-bind > .camel modifier 1`] = `
-"import { renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDynamicProp(n0, "fooBar", _ctx.id))
+ _setInheritAttrs(["fooBar"])
+ _renderEffect(() => _setDynamicProp(n0, "fooBar", _ctx.id, true))
return n0
}"
`;
exports[`compiler v-bind > .camel modifier w/ dynamic arg 1`] = `
"import { camelize as _camelize } from 'vue';
-import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
+import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, { [_camelize(_ctx.foo)]: _ctx.id }))
+ _setInheritAttrs(true)
+ _renderEffect(() => _setDynamicProps(n0, [{ [_camelize(_ctx.foo)]: _ctx.id }], true))
return n0
}"
`;
exports[`compiler v-bind > .camel modifier w/ no expression 1`] = `
-"import { renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDynamicProp(n0, "fooBar", _ctx.fooBar))
+ _setInheritAttrs(["fooBar"])
+ _renderEffect(() => _setDynamicProp(n0, "fooBar", _ctx.fooBar, true))
return n0
}"
`;
exports[`compiler v-bind > .prop modifier (shortband) w/ no expression 1`] = `
-"import { renderEffect as _renderEffect, setDOMProp as _setDOMProp, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDOMProp as _setDOMProp, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDOMProp(n0, "fooBar", _ctx.fooBar))
+ _setInheritAttrs(["fooBar"])
+ _renderEffect(() => _setDOMProp(n0, "fooBar", _ctx.fooBar, true))
return n0
}"
`;
exports[`compiler v-bind > .prop modifier (shorthand) 1`] = `
-"import { renderEffect as _renderEffect, setDOMProp as _setDOMProp, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDOMProp as _setDOMProp, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDOMProp(n0, "fooBar", _ctx.id))
+ _setInheritAttrs(["fooBar"])
+ _renderEffect(() => _setDOMProp(n0, "fooBar", _ctx.id, true))
return n0
}"
`;
exports[`compiler v-bind > .prop modifier 1`] = `
-"import { renderEffect as _renderEffect, setDOMProp as _setDOMProp, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDOMProp as _setDOMProp, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDOMProp(n0, "fooBar", _ctx.id))
+ _setInheritAttrs(["fooBar"])
+ _renderEffect(() => _setDOMProp(n0, "fooBar", _ctx.id, true))
return n0
}"
`;
exports[`compiler v-bind > .prop modifier w/ dynamic arg 1`] = `
-"import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, { ["." + _ctx.fooBar]: _ctx.id }))
+ _setInheritAttrs(true)
+ _renderEffect(() => _setDynamicProps(n0, [{ ["." + _ctx.fooBar]: _ctx.id }], true))
return n0
}"
`;
exports[`compiler v-bind > .prop modifier w/ no expression 1`] = `
-"import { renderEffect as _renderEffect, setDOMProp as _setDOMProp, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDOMProp as _setDOMProp, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDOMProp(n0, "fooBar", _ctx.fooBar))
+ _setInheritAttrs(["fooBar"])
+ _renderEffect(() => _setDOMProp(n0, "fooBar", _ctx.fooBar, true))
return n0
}"
`;
exports[`compiler v-bind > basic 1`] = `
-"import { renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDynamicProp(n0, "id", _ctx.id))
+ _setInheritAttrs(["id"])
+ _renderEffect(() => _setDynamicProp(n0, "id", _ctx.id, true))
return n0
}"
`;
exports[`compiler v-bind > dynamic arg 1`] = `
-"import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, { [_ctx.id]: _ctx.id, [_ctx.title]: _ctx.title }))
+ _setInheritAttrs(true)
+ _renderEffect(() => _setDynamicProps(n0, [{ [_ctx.id]: _ctx.id, [_ctx.title]: _ctx.title }], true))
return n0
}"
`;
exports[`compiler v-bind > dynamic arg w/ static attribute 1`] = `
-"import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDynamicProps(n0, { [_ctx.id]: _ctx.id, foo: "bar", checked: "" }))
+ _setInheritAttrs(true)
+ _renderEffect(() => _setDynamicProps(n0, [{ [_ctx.id]: _ctx.id, foo: "bar", checked: "" }], true))
return n0
}"
`;
exports[`compiler v-bind > no expression (shorthand) 1`] = `
-"import { renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDynamicProp(n0, "camel-case", _ctx.camelCase))
+ _setInheritAttrs(["camel-case"])
+ _renderEffect(() => _setDynamicProp(n0, "camel-case", _ctx.camelCase, true))
return n0
}"
`;
exports[`compiler v-bind > no expression 1`] = `
-"import { renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _renderEffect(() => _setDynamicProp(n0, "id", _ctx.id))
+ _setInheritAttrs(["id"])
+ _renderEffect(() => _setDynamicProp(n0, "id", _ctx.id, true))
return n0
}"
`;
exports[`compiler v-bind > should error if empty expression 1`] = `
-"import { template as _template } from 'vue/vapor';
+"import { setInheritAttrs as _setInheritAttrs, template as _template } from 'vue/vapor';
const t0 = _template("<div arg></div>")
export function render(_ctx) {
const n0 = t0()
+ _setInheritAttrs(false)
return n0
}"
`;
`;
exports[`compiler: vModel transform > should support input (checkbox) 1`] = `
-"import { vModelCheckbox as _vModelCheckbox, withDirectives as _withDirectives, delegate as _delegate, template as _template } from 'vue/vapor';
+"import { vModelCheckbox as _vModelCheckbox, withDirectives as _withDirectives, delegate as _delegate, setInheritAttrs as _setInheritAttrs, template as _template } from 'vue/vapor';
const t0 = _template("<input type=\\"checkbox\\">")
export function render(_ctx) {
const n0 = t0()
_withDirectives(n0, [[_vModelCheckbox, () => _ctx.model]])
_delegate(n0, "update:modelValue", () => $event => (_ctx.model = $event))
+ _setInheritAttrs(false)
return n0
}"
`;
`;
exports[`compiler: vModel transform > should support input (radio) 1`] = `
-"import { vModelRadio as _vModelRadio, withDirectives as _withDirectives, delegate as _delegate, template as _template } from 'vue/vapor';
+"import { vModelRadio as _vModelRadio, withDirectives as _withDirectives, delegate as _delegate, setInheritAttrs as _setInheritAttrs, template as _template } from 'vue/vapor';
const t0 = _template("<input type=\\"radio\\">")
export function render(_ctx) {
const n0 = t0()
_withDirectives(n0, [[_vModelRadio, () => _ctx.model]])
_delegate(n0, "update:modelValue", () => $event => (_ctx.model = $event))
+ _setInheritAttrs(false)
return n0
}"
`;
exports[`compiler: vModel transform > should support input (text) 1`] = `
-"import { vModelText as _vModelText, withDirectives as _withDirectives, delegate as _delegate, template as _template } from 'vue/vapor';
+"import { vModelText as _vModelText, withDirectives as _withDirectives, delegate as _delegate, setInheritAttrs as _setInheritAttrs, template as _template } from 'vue/vapor';
const t0 = _template("<input type=\\"text\\">")
export function render(_ctx) {
const n0 = t0()
_withDirectives(n0, [[_vModelText, () => _ctx.model]])
_delegate(n0, "update:modelValue", () => $event => (_ctx.model = $event))
+ _setInheritAttrs(false)
return n0
}"
`;
`;
exports[`compiler: vModel transform > should support w/ dynamic v-bind 1`] = `
-"import { vModelDynamic as _vModelDynamic, withDirectives as _withDirectives, delegate as _delegate, renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
+"import { vModelDynamic as _vModelDynamic, withDirectives as _withDirectives, delegate as _delegate, setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
const t0 = _template("<input>")
export function render(_ctx) {
const n0 = t0()
_withDirectives(n0, [[_vModelDynamic, () => _ctx.model]])
_delegate(n0, "update:modelValue", () => $event => (_ctx.model = $event))
- _renderEffect(() => _setDynamicProps(n0, _ctx.obj))
+ _setInheritAttrs(true)
+ _renderEffect(() => _setDynamicProps(n0, [_ctx.obj], true))
return n0
}"
`;
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`compiler: v-once > as root node 1`] = `
-"import { setDynamicProp as _setDynamicProp, template as _template } from 'vue/vapor';
+"import { setDynamicProp as _setDynamicProp, setInheritAttrs as _setInheritAttrs, template as _template } from 'vue/vapor';
const t0 = _template("<div></div>")
export function render(_ctx) {
const n0 = t0()
- _setDynamicProp(n0, "id", _ctx.foo)
+ _setDynamicProp(n0, "id", _ctx.foo, true)
+ _setInheritAttrs(["id"])
return n0
}"
`;
],
},
])
- expect(code).contains('_setDynamicProps(n0, _ctx.obj)')
+ expect(code).contains('_setDynamicProps(n0, [_ctx.obj], true)')
})
test('v-bind="obj" after static prop', () => {
],
},
])
- expect(code).contains('_setDynamicProps(n0, { id: "foo" }, _ctx.obj)')
+ expect(code).contains(
+ '_setDynamicProps(n0, [{ id: "foo" }, _ctx.obj], true)',
+ )
})
test('v-bind="obj" before static prop', () => {
],
},
])
- expect(code).contains('_setDynamicProps(n0, _ctx.obj, { id: "foo" })')
+ expect(code).contains(
+ '_setDynamicProps(n0, [_ctx.obj, { id: "foo" }], true)',
+ )
})
test('v-bind="obj" between static props', () => {
},
])
expect(code).contains(
- '_setDynamicProps(n0, { id: "foo" }, _ctx.obj, { class: "bar" })',
+ '_setDynamicProps(n0, [{ id: "foo" }, _ctx.obj, { class: "bar" }], true)',
)
})
delegate: true,
effect: false,
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
})
flags: DynamicFlag.REFERENCED,
})
expect(ir.template).toEqual(['<div></div>'])
- expect(ir.block.operation).lengthOf(1)
- expect(ir.block.operation[0]).toMatchObject({
+ expect(ir.block.operation).lengthOf(2)
+ expect(ir.block.operation[1]).toMatchObject({
type: IRNodeTypes.SET_TEMPLATE_REF,
element: 0,
value: {
})
expect(ir.template).toEqual(['<div></div>'])
expect(ir.block.operation).toMatchObject([
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
{
type: IRNodeTypes.DECLARE_OLD_REF,
id: 0,
})
expect(code).matchSnapshot()
- expect(code).contains('_setDynamicProp(n0, "id", _ctx.id)')
+ expect(code).contains('_setDynamicProp(n0, "id", _ctx.id, true)')
})
test('no expression', () => {
],
},
})
- expect(code).contains('_setDynamicProp(n0, "id", _ctx.id)')
+ expect(code).contains('_setDynamicProp(n0, "id", _ctx.id, true)')
})
test('no expression (shorthand)', () => {
],
},
})
- expect(code).contains('_setDynamicProp(n0, "camel-case", _ctx.camelCase)')
+ expect(code).contains(
+ '_setDynamicProp(n0, "camel-case", _ctx.camelCase, true)',
+ )
})
test('dynamic arg', () => {
],
})
expect(code).contains(
- '_setDynamicProps(n0, { [_ctx.id]: _ctx.id, [_ctx.title]: _ctx.title })',
+ '_setDynamicProps(n0, [{ [_ctx.id]: _ctx.id, [_ctx.title]: _ctx.title }], true)',
)
})
],
})
expect(code).contains(
- '_setDynamicProps(n0, { [_ctx.id]: _ctx.id, foo: "bar", checked: "" })',
+ '_setDynamicProps(n0, [{ [_ctx.id]: _ctx.id, foo: "bar", checked: "" }], true)',
)
})
})
expect(code).matchSnapshot()
- expect(code).contains('_setDynamicProp(n0, "fooBar", _ctx.id)')
+ expect(code).contains('_setDynamicProp(n0, "fooBar", _ctx.id, true)')
})
test('.camel modifier w/ no expression', () => {
},
})
expect(code).contains('renderEffect')
- expect(code).contains('_setDynamicProp(n0, "fooBar", _ctx.fooBar)')
+ expect(code).contains('_setDynamicProp(n0, "fooBar", _ctx.fooBar, true)')
})
test('.camel modifier w/ dynamic arg', () => {
expect(code).matchSnapshot()
expect(code).contains('renderEffect')
expect(code).contains(
- `_setDynamicProps(n0, { [_camelize(_ctx.foo)]: _ctx.id })`,
+ `_setDynamicProps(n0, [{ [_camelize(_ctx.foo)]: _ctx.id }], true)`,
)
})
},
})
expect(code).contains('renderEffect')
- expect(code).contains('_setDOMProp(n0, "fooBar", _ctx.id)')
+ expect(code).contains('_setDOMProp(n0, "fooBar", _ctx.id, true)')
})
test('.prop modifier w/ no expression', () => {
},
})
expect(code).contains('renderEffect')
- expect(code).contains('_setDOMProp(n0, "fooBar", _ctx.fooBar)')
+ expect(code).contains('_setDOMProp(n0, "fooBar", _ctx.fooBar, true)')
})
test('.prop modifier w/ dynamic arg', () => {
})
expect(code).contains('renderEffect')
expect(code).contains(
- `_setDynamicProps(n0, { ["." + _ctx.fooBar]: _ctx.id })`,
+ `_setDynamicProps(n0, [{ ["." + _ctx.fooBar]: _ctx.id }], true)`,
)
})
},
})
expect(code).contains('renderEffect')
- expect(code).contains('_setDOMProp(n0, "fooBar", _ctx.id)')
+ expect(code).contains('_setDOMProp(n0, "fooBar", _ctx.id, true)')
})
test('.prop modifier (shortband) w/ no expression', () => {
},
})
expect(code).contains('renderEffect')
- expect(code).contains('_setDOMProp(n0, "fooBar", _ctx.fooBar)')
+ expect(code).contains('_setDOMProp(n0, "fooBar", _ctx.fooBar, true)')
})
test('.attr modifier', () => {
},
})
expect(code).contains('renderEffect')
- expect(code).contains('_setAttr(n0, "foo-bar", _ctx.id)')
+ expect(code).contains('_setAttr(n0, "foo-bar", _ctx.id, true)')
})
test('.attr modifier w/ no expression', () => {
})
expect(code).contains('renderEffect')
- expect(code).contains('_setAttr(n0, "foo-bar", _ctx.fooBar)')
+ expect(code).contains('_setAttr(n0, "foo-bar", _ctx.fooBar, true)')
})
})
expect(vaporHelpers).contains('setHtml')
expect(helpers.size).toBe(0)
- expect(ir.block.operation).toEqual([])
+ expect(ir.block.operation).toMatchObject([
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
+ ])
expect(ir.block.effect).toMatchObject([
{
expressions: [
// children should have been removed
expect(ir.template).toEqual(['<div></div>'])
- expect(ir.block.operation).toEqual([])
+ expect(ir.block.operation).toMatchObject([
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
+ ])
expect(ir.block.effect).toMatchObject([
{
expressions: [
keyOverride: undefined,
delegate: true,
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
})
expect(vaporHelpers).contains('on')
expect(vaporHelpers).contains('renderEffect')
expect(helpers.size).toBe(0)
- expect(ir.block.operation).toEqual([])
+ expect(ir.block.operation).toMatchObject([
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
+ ])
expect(ir.block.effect[0].operations[0]).toMatchObject({
type: IRNodeTypes.SET_EVENT,
expect(vaporHelpers).contains('on')
expect(vaporHelpers).contains('renderEffect')
expect(helpers.size).toBe(0)
- expect(ir.block.operation).toEqual([])
+ expect(ir.block.operation).toMatchObject([
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
+ ])
expect(ir.block.effect[0].operations[0]).toMatchObject({
type: IRNodeTypes.SET_EVENT,
},
delegate: true,
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
expect(code).contains(`_delegate(n0, "click", () => $event => (_ctx.i++))`)
})
type: IRNodeTypes.SET_EVENT,
value: { content: 'foo();bar()' },
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
// should wrap with `{` for multiple statements
// in this case the return value is discarded and the behavior is
type: IRNodeTypes.SET_EVENT,
value: { content: '\nfoo();\nbar()\n' },
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
// should wrap with `{` for multiple statements
// in this case the return value is discarded and the behavior is
type: IRNodeTypes.SET_EVENT,
value: { content: 'foo($event)' },
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
// should NOT prefix $event
expect(code).contains(
type: IRNodeTypes.SET_EVENT,
value: { content: 'foo($event);bar()' },
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
// should NOT prefix $event
expect(code).contains(
type: IRNodeTypes.SET_EVENT,
value: { content: '$event => foo($event)' },
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
expect(code).contains(
`_delegate(n0, "click", () => $event => _ctx.foo($event))`,
type: IRNodeTypes.SET_EVENT,
value: { content: '(e: any): any => foo(e)' },
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
expect(code).contains(
`_delegate(n0, "click", () => (e: any): any => _ctx.foo(e))`,
`,
},
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
})
type: IRNodeTypes.SET_EVENT,
value: { content: `a['b' + c]` },
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
expect(code).matchSnapshot()
type: IRNodeTypes.SET_EVENT,
value: { content: `a['b' + c]` },
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
expect(code).matchSnapshot()
type: IRNodeTypes.SET_EVENT,
value: { content: `e => foo(e)` },
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
expect(code).contains(`_delegate(n0, "click", () => e => _ctx.foo(e))`)
})
keyOverride: undefined,
delegate: false,
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
expect(code).contains(
`_on(n0, "click", () => _ctx.test, {
options: [],
},
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
expect(code).matchSnapshot()
options: ['capture'],
},
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
expect(code).matchSnapshot()
type: IRNodeTypes.SET_EVENT,
modifiers: { nonKeys: ['exact'] },
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
expect(code).matchSnapshot()
options: [],
},
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
expect(code).matchSnapshot()
modifiers: { nonKeys: ['right'] },
keyOverride: undefined,
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
expect(code).matchSnapshot()
modifiers: { nonKeys: ['middle'] },
keyOverride: undefined,
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
expect(code).matchSnapshot()
type: IRNodeTypes.SET_EVENT,
delegate: true,
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
})
})
elements: [0],
parent: 2,
},
+ { type: IRNodeTypes.SET_INHERIT_ATTRS },
])
})
],
},
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
expect(code).not.contains('effect')
})
],
},
},
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
])
})
elements: [0],
parent: 1,
},
+ { type: IRNodeTypes.SET_INHERIT_ATTRS },
])
})
expect(code).toMatchSnapshot()
expect(helpers).lengthOf(0)
expect(ir.block.effect).lengthOf(0)
- expect(ir.block.operation).lengthOf(0)
+ expect(ir.block.operation).lengthOf(1)
})
test.todo('with hoistStatic: true')
expect(vaporHelpers).contains('setText')
expect(helpers.size).toBe(0)
- expect(ir.block.operation).toEqual([])
+ expect(ir.block.operation).toMatchObject([
+ {
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ },
+ ])
expect(ir.block.effect).toMatchObject([
{
genMulti,
} from './utils'
import { genExpression } from './expression'
-import { genPropKey } from './prop'
+import { genPropKey, genPropValue } from './prop'
import {
createSimpleExpression,
toValidAssetId,
}
function genProp(prop: IRProp, context: CodegenContext, isStatic?: boolean) {
+ const values = genPropValue(prop.values, context)
return [
...genPropKey(prop, context),
': ',
...(prop.handler
? genEventHandler(context, prop.values[0])
: isStatic
- ? ['() => (', ...genExpression(prop.values[0], context), ')']
- : genExpression(prop.values[0], context)),
+ ? ['() => (', ...values, ')']
+ : values),
...(prop.model
? [...genModelEvent(prop, context), ...genModelModifiers(prop, context)]
: []),
prefix = `${raw}: `
}
- const type = bindingMetadata[raw]
+ const type = bindingMetadata && bindingMetadata[raw]
if (inline) {
switch (type) {
case BindingTypes.SETUP_LET:
import { genSetHtml } from './html'
import { genIf } from './if'
import { genSetModelValue } from './modelValue'
-import { genDynamicProps, genSetProp } from './prop'
+import { genDynamicProps, genSetInheritAttrs, genSetProp } from './prop'
import { genDeclareOldRef, genSetTemplateRef } from './templateRef'
import { genCreateTextNode, genSetText } from './text'
import {
return genDeclareOldRef(oper)
case IRNodeTypes.SLOT_OUTLET_NODE:
return genSlotOutlet(oper, context)
+ case IRNodeTypes.SET_INHERIT_ATTRS:
+ return genSetInheritAttrs(oper, context)
}
return []
IRDynamicPropsKind,
type IRProp,
type SetDynamicPropsIRNode,
+ type SetInheritAttrsIRNode,
type SetPropIRNode,
type VaporHelper,
} from '../ir'
`n${oper.element}`,
omitKey ? false : genExpression(key, context),
genPropValue(values, context),
+ oper.root && 'true',
),
]
}
...genCall(
vaporHelper('setDynamicProps'),
`n${oper.element}`,
- ...oper.props.map(
- props =>
- Array.isArray(props)
- ? genLiteralObjectProps(props, context) // static and dynamic arg props
- : props.kind === IRDynamicPropsKind.ATTRIBUTE
- ? genLiteralObjectProps([props], context) // dynamic arg props
- : genExpression(props.value, context), // v-bind=""
+ genMulti(
+ DELIMITERS_ARRAY,
+ ...oper.props.map(
+ props =>
+ Array.isArray(props)
+ ? genLiteralObjectProps(props, context) // static and dynamic arg props
+ : props.kind === IRDynamicPropsKind.ATTRIBUTE
+ ? genLiteralObjectProps([props], context) // dynamic arg props
+ : genExpression(props.value, context), // v-bind=""
+ ),
),
+ oper.root && 'true',
),
]
}
return ['[', modifier && `${JSON.stringify(modifier)} + `, ...key, ']']
}
-function genPropValue(values: SimpleExpressionNode[], context: CodegenContext) {
+export function genPropValue(
+ values: SimpleExpressionNode[],
+ context: CodegenContext,
+): CodeFragment[] {
if (values.length === 1) {
return genExpression(values[0], context)
}
...values.map(expr => genExpression(expr, context)),
)
}
+
+export function genSetInheritAttrs(
+ { staticProps, dynamicProps }: SetInheritAttrsIRNode,
+ context: CodegenContext,
+): CodeFragment[] {
+ const { vaporHelper } = context
+
+ // - `undefined` : no props
+ // - `false` : all props are static
+ // - `string[]` : list of props are dynamic
+ // - `true` : all props as dynamic
+ const value =
+ dynamicProps === true
+ ? 'true'
+ : dynamicProps.length
+ ? genMulti(
+ DELIMITERS_ARRAY,
+ ...dynamicProps.map(p => JSON.stringify(p)),
+ )
+ : staticProps
+ ? 'false'
+ : null
+ if (value == null) return []
+ return [NEWLINE, ...genCall(vaporHelper('setInheritAttrs'), value)]
+}
...frags: CodeFragments[]
): CodeFragment[] {
if (placeholder) {
- while (!frags[frags.length - 1]) {
+ while (frags.length > 0 && !frags[frags.length - 1]) {
frags.pop()
}
frags = frags.map(frag => frag || placeholder)
SET_HTML,
SET_TEMPLATE_REF,
SET_MODEL_VALUE,
+ SET_INHERIT_ATTRS,
INSERT_NODE,
PREPEND_NODE,
type: IRNodeTypes.SET_PROP
element: number
prop: IRProp
+ root: boolean
}
export interface SetDynamicPropsIRNode extends BaseIRNode {
type: IRNodeTypes.SET_DYNAMIC_PROPS
element: number
props: IRProps[]
+ root: boolean
}
export interface SetDynamicEventsIRNode extends BaseIRNode {
isComponent: boolean
}
+export interface SetInheritAttrsIRNode extends BaseIRNode {
+ type: IRNodeTypes.SET_INHERIT_ATTRS
+ staticProps: boolean
+ dynamicProps: true | string[]
+}
+
export interface CreateTextNodeIRNode extends BaseIRNode {
type: IRNodeTypes.CREATE_TEXT_NODE
id: number
| SetHtmlIRNode
| SetTemplateRefIRNode
| SetModelValueIRNode
+ | SetInheritAttrsIRNode
| CreateTextNodeIRNode
| InsertNodeIRNode
| PrependNodeIRNode
isDynamicComponent,
)
+ const singleRoot =
+ context.root === context.parent &&
+ context.parent.node.children.filter(
+ child => child.type !== NodeTypes.COMMENT,
+ ).length === 1
;(isComponent ? transformComponentElement : transformNativeElement)(
node as any,
propsResult,
+ singleRoot,
context as TransformContext<ElementNode>,
isDynamicComponent,
)
function transformComponentElement(
node: ComponentNode,
propsResult: PropsResult,
+ singleRoot: boolean,
context: TransformContext,
isDynamicComponent: boolean,
) {
}
context.dynamic.flags |= DynamicFlag.NON_TEMPLATE | DynamicFlag.INSERT
- const root =
- context.root === context.parent && context.parent.node.children.length === 1
-
context.registerOperation({
type: IRNodeTypes.CREATE_COMPONENT_NODE,
id: context.reference(),
tag,
props: propsResult[0] ? propsResult[1] : [propsResult[1]],
asset,
- root,
+ root: singleRoot,
slots: [...context.slots],
once: context.inVOnce,
dynamic: dynamicComponent,
function transformNativeElement(
node: PlainElementNode,
propsResult: PropsResult,
+ singleRoot: boolean,
context: TransformContext<ElementNode>,
) {
const { tag } = node
template += `<${tag}`
if (scopeId) template += ` ${scopeId}`
+ let staticProps = false
+ const dynamicProps: string[] = []
if (propsResult[0] /* dynamic props */) {
const [, dynamicArgs, expressions] = propsResult
context.registerEffect(expressions, {
type: IRNodeTypes.SET_DYNAMIC_PROPS,
element: context.reference(),
props: dynamicArgs,
+ root: singleRoot,
})
} else {
for (const prop of propsResult[1]) {
const { key, values } = prop
if (key.isStatic && values.length === 1 && values[0].isStatic) {
+ staticProps = true
template += ` ${key.content}`
if (values[0].content) template += `="${values[0].content}"`
} else {
+ dynamicProps.push(key.content)
context.registerEffect(values, {
type: IRNodeTypes.SET_PROP,
element: context.reference(),
prop,
+ root: singleRoot,
})
}
}
}
+ if (singleRoot) {
+ context.registerOperation({
+ type: IRNodeTypes.SET_INHERIT_ATTRS,
+ staticProps: staticProps,
+ dynamicProps: propsResult[0] ? true : dynamicProps,
+ })
+ }
+
template += `>` + context.childrenTemplate.join('')
// TODO remove unnecessary close tag, e.g. if it's the last element of the template
if (!isVoidTag(tag)) {
ref,
renderEffect,
setDynamicProps,
+ setInheritAttrs,
template,
watchEffect,
} from '../src'
inheritAttrs: false,
setup(props, { attrs }) {
const el = document.createElement('div')
- renderEffect(() => {
- setDynamicProps(el, attrs)
- })
+ renderEffect(() => setDynamicProps(el, [attrs]))
return el
},
})
const toggle = ref(true)
const Wrapper = defineComponent({
- setup(_, { slots }) {
- return slots.default!()
+ setup(_) {
+ const n0 = createSlot('default')
+ setInheritAttrs(false, true)
+ return n0
},
})
const Child = defineComponent({
inheritAttrs: false,
setup(_: any, { attrs }: any) {
- return createComponent(Wrapper, null, {
+ const n0 = createComponent(Wrapper, null, {
default: () => {
const n0 = template('<div>')() as HTMLDivElement
- renderEffect(() => {
- setDynamicProps(n0, attrs)
- })
+ renderEffect(() => setDynamicProps(n0, [attrs], true))
return n0
},
})
+ return n0
},
})
getCurrentInstance,
nextTick,
ref,
+ setInheritAttrs,
setText,
template,
watchEffect,
props: ['foo'],
render() {
const instance = getCurrentInstance()!
- const n0 = t0()
+ const n0 = t0() as Element
+ setInheritAttrs()
watchEffect(() => setText(n0, instance.props.foo))
return n0
},
inheritAttrs: false,
render() {
const instance = getCurrentInstance()!
- const n0 = t0()
+ const n0 = t0() as Element
+ setInheritAttrs()
watchEffect(() => setText(n0, instance.props.foo))
return n0
},
props: ['custom-attr'],
render() {
const instance = getCurrentInstance()!
- const n0 = t0()
+ const n0 = t0() as Element
+ setInheritAttrs()
watchEffect(() => setText(n0, instance.attrs.foo))
return n0
},
describe('setDynamicProps', () => {
test('basic set dynamic props', () => {
const el = document.createElement('div')
- setDynamicProps(el, { foo: 'val' }, { bar: 'val' })
+ setDynamicProps(el, [{ foo: 'val' }, { bar: 'val' }])
expect(el.getAttribute('foo')).toBe('val')
expect(el.getAttribute('bar')).toBe('val')
})
test('should merge props', () => {
const el = document.createElement('div')
- setDynamicProps(el, { foo: 'val' }, { foo: 'newVal' })
+ setDynamicProps(el, [{ foo: 'val' }, { foo: 'newVal' }])
expect(el.getAttribute('foo')).toBe('newVal')
})
test('should reset old props', () => {
const el = document.createElement('div')
- setDynamicProps(el, { foo: 'val' })
+ setDynamicProps(el, [{ foo: 'val' }])
expect(el.attributes.length).toBe(1)
expect(el.getAttribute('foo')).toBe('val')
- setDynamicProps(el, { bar: 'val' })
+ setDynamicProps(el, [{ bar: 'val' }])
expect(el.attributes.length).toBe(1)
expect(el.getAttribute('bar')).toBe('val')
expect(el.getAttribute('foo')).toBeNull()
test('should reset old modifier props', () => {
const el = document.createElement('div')
- setDynamicProps(el, { ['.foo']: 'val' })
+ setDynamicProps(el, [{ ['.foo']: 'val' }])
expect((el as any).foo).toBe('val')
- setDynamicProps(el, { ['.bar']: 'val' })
+ setDynamicProps(el, [{ ['.bar']: 'val' }])
expect((el as any).bar).toBe('val')
expect((el as any).foo).toBe('')
- setDynamicProps(el, { ['^foo']: 'val' })
+ setDynamicProps(el, [{ ['^foo']: 'val' }])
expect(el.attributes.length).toBe(1)
expect(el.getAttribute('foo')).toBe('val')
- setDynamicProps(el, { ['^bar']: 'val' })
+ setDynamicProps(el, [{ ['^bar']: 'val' }])
expect(el.attributes.length).toBe(1)
expect(el.getAttribute('bar')).toBe('val')
expect(el.getAttribute('foo')).toBeNull()
walkRawProps,
} from './componentProps'
import { type RawSlots, isDynamicSlotFn } from './componentSlots'
-import { withAttrs } from './componentAttrs'
+import { setInheritAttrs, withAttrs } from './componentAttrs'
import { isString } from '@vue/shared'
import { renderEffect } from './renderEffect'
import { normalizeBlock } from './dom/element'
-import { setDynamicProp } from './dom/prop'
+import { setClass, setDynamicProp } from './dom/prop'
+import { setStyle } from './dom/style'
export function createComponent(
comp: Component | string,
singleRoot: boolean = false,
once: boolean = false,
): ComponentInternalInstance | HTMLElement {
+ const current = currentInstance!
+
if (isString(comp)) {
- return fallbackComponent(comp, rawProps, slots)
+ return fallbackComponent(comp, rawProps, slots, current, singleRoot)
}
- const current = currentInstance!
const instance = createComponentInstance(
comp,
singleRoot ? withAttrs(rawProps) : rawProps,
comp: string,
rawProps: RawProps | null,
slots: RawSlots | null,
+ instance: ComponentInternalInstance,
+ singleRoot: boolean = false,
): HTMLElement {
// eslint-disable-next-line no-restricted-globals
const el = document.createElement(comp)
- if (rawProps) {
- rawProps = normalizeRawProps(rawProps)
+ if (rawProps || Object.keys(instance.attrs).length) {
+ rawProps = [() => instance.attrs, ...normalizeRawProps(rawProps)]
+
renderEffect(() => {
- walkRawProps(rawProps as NormalizedRawProps, (key, value, getter) => {
- setDynamicProp(el, key, getter ? value() : value)
- })
+ let classes: unknown[] | undefined
+ let styles: unknown[] | undefined
+
+ walkRawProps(
+ rawProps as NormalizedRawProps,
+ (key, valueOrGetter, getter) => {
+ const value = getter ? valueOrGetter() : valueOrGetter
+ if (key === 'class') (classes ||= []).push(value)
+ else if (key === 'style') (styles ||= []).push(value)
+ else setDynamicProp(el, key, value)
+ },
+ )
+
+ if (classes) setClass(el, classes)
+ if (styles) setStyle(el, styles)
})
}
}
}
+ if (singleRoot) {
+ setInheritAttrs(true)
+ }
+
return el
}
shallowReadonly,
} from '@vue/reactivity'
import { isArray, isFunction, isObject } from '@vue/shared'
-import { fallThroughAttrs } from './componentAttrs'
import { VaporErrorCodes, callWithErrorHandling } from './errorHandling'
import { endMeasure, startMeasure } from './profiling'
import { devtoolsComponentAdded } from './devtools'
+import { fallThroughAttrs } from './componentAttrs'
export const fragmentKey: unique symbol = Symbol(__DEV__ ? `fragmentKey` : ``)
resetTracking()
}
- if (block instanceof DocumentFragment) {
- block = Array.from(block.childNodes)
- }
if (!block) {
// TODO: warn no template
block = []
emit: EmitFn
emitted: Record<string, boolean> | null
attrs: Data
+ /**
+ * - `undefined` : no props
+ * - `false` : all props are static
+ * - `string[]` : list of props are dynamic
+ * - `true` : all props as dynamic
+ */
+ dynamicAttrs?: string[] | boolean
slots: StaticSlots
refs: Data
// exposed properties via expose()
-import { camelize, isArray } from '@vue/shared'
+import { camelize, isArray, normalizeClass, normalizeStyle } from '@vue/shared'
import { type ComponentInternalInstance, currentInstance } from './component'
import { isEmitListener } from './componentEmits'
-import { setDynamicProps } from './dom/prop'
import { type RawProps, walkRawProps } from './componentProps'
import { renderEffect } from './renderEffect'
+import { mergeProp, setDynamicProp } from './dom/prop'
-export function patchAttrs(instance: ComponentInternalInstance): void {
+export function patchAttrs(
+ instance: ComponentInternalInstance,
+ hasDynamicProps?: boolean,
+): void {
const {
attrs,
rawProps,
if (!rawProps.length) return
const keys = new Set<string>()
+ const classes: any[] = []
+ const styles: any[] = []
walkRawProps(rawProps, registerAttr)
for (const key in attrs) {
}
}
+ setClassOrStyle(classes, 'class', normalizeClass)
+ setClassOrStyle(styles, 'style', normalizeStyle)
+
+ function setClassOrStyle(
+ values: any[],
+ field: 'class' | 'style',
+ normalize: (value: any) => any,
+ ) {
+ if (values.length) {
+ if (hasDynamicProps) {
+ Object.defineProperty(attrs, field, {
+ get() {
+ return normalize(values.map(value => value()))
+ },
+ enumerable: true,
+ configurable: true,
+ })
+ } else {
+ attrs[field] = normalizeClass(values)
+ }
+ }
+ }
+
function registerAttr(key: string, value: any, getter?: boolean) {
if (
(!options || !(camelize(key) in options)) &&
!isEmitListener(instance.emitsOptions, key) &&
- !keys.has(key)
+ (key === 'class' || key === 'style' || !keys.has(key))
) {
keys.add(key)
- if (getter) {
+
+ if (key === 'class' || key === 'style') {
+ ;(key === 'class' ? classes : styles).push(
+ hasDynamicProps ? (getter ? value : () => value) : value,
+ )
+ } else if (getter) {
Object.defineProperty(attrs, key, {
get: value,
enumerable: true,
const {
block,
type: { inheritAttrs },
+ dynamicAttrs,
} = instance
- if (inheritAttrs === false) return
+ if (
+ inheritAttrs === false ||
+ !(block instanceof Element) ||
+ // all props as dynamic
+ dynamicAttrs === true
+ )
+ return
- if (block instanceof Element) {
+ const hasStaticAttrs = dynamicAttrs || dynamicAttrs === false
+
+ let initial: Record<string, string> | undefined
+ if (hasStaticAttrs) {
// attrs in static template
- const initial: Record<string, string> = {}
+ initial = {}
for (let i = 0; i < block.attributes.length; i++) {
const attr = block.attributes[i]
+ if (dynamicAttrs && dynamicAttrs.includes(attr.name)) continue
initial[attr.name] = attr.value
}
- renderEffect(() => setDynamicProps(block, instance.attrs, initial))
}
+
+ renderEffect(() => {
+ for (const key in instance.attrs) {
+ if (dynamicAttrs && dynamicAttrs.includes(key)) continue
+
+ let value: unknown
+ if (hasStaticAttrs) {
+ value = mergeProp(key, instance.attrs[key], initial![key])
+ } else {
+ value = instance.attrs[key]
+ }
+
+ setDynamicProp(block, key, value)
+ }
+ })
+}
+
+export function setInheritAttrs(dynamicAttrs?: string[] | boolean): void {
+ const instance = currentInstance!
+ if (instance.type.inheritAttrs === false) return
+ instance.dynamicAttrs = dynamicAttrs
}
}
if (hasDynamicProps) {
- firstEffect(instance, () => patchAttrs(instance))
+ firstEffect(instance, () => patchAttrs(instance, true))
} else {
patchAttrs(instance)
}
} from '../componentMetadata'
import { on } from './event'
import type { Data } from '@vue/runtime-shared'
+import { currentInstance } from '../component'
+
+export function mergeInheritAttr(key: string, value: any): unknown {
+ const instance = currentInstance!
+ return mergeProp(key, instance.attrs[key], value)
+}
+
+export function setClass(el: Element, value: any, root?: boolean): void {
+ const prev = recordPropMetadata(
+ el,
+ 'class',
+ (value = normalizeClass(root ? mergeInheritAttr('class', value) : value)),
+ )
-export function setClass(el: Element, value: any): void {
- const prev = recordPropMetadata(el, 'class', (value = normalizeClass(value)))
if (value !== prev && (value || prev)) {
el.className = value
}
}
}
-export function setDynamicProps(el: Element, ...args: any): void {
+export function setDynamicProps(
+ el: Element,
+ args: any[],
+ root?: boolean,
+): void {
const oldProps = getMetadata(el)[MetadataKind.prop]
+ if (root) {
+ args.unshift(currentInstance!.attrs)
+ }
const props = args.length > 1 ? mergeProps(...args) : args[0]
for (const key in oldProps) {
}
}
-// TODO copied from runtime-core
+export function mergeProp(
+ key: string,
+ existing: unknown,
+ incoming: unknown,
+): unknown {
+ if (key === 'class') {
+ if (existing !== incoming) {
+ return normalizeClass([existing, incoming])
+ }
+ } else if (key === 'style') {
+ return normalizeStyle([existing, incoming])
+ } else if (isOn(key)) {
+ if (
+ incoming &&
+ existing !== incoming &&
+ !(isArray(existing) && existing.includes(incoming))
+ ) {
+ return existing ? [].concat(existing as any, incoming as any) : incoming
+ }
+ }
+ return incoming
+}
+
export function mergeProps(...args: Data[]): Data {
const ret: Data = {}
for (let i = 0; i < args.length; i++) {
const toMerge = args[i]
for (const key in toMerge) {
- if (key === 'class') {
- if (ret.class !== toMerge.class) {
- ret.class = normalizeClass([ret.class, toMerge.class])
- }
- } else if (key === 'style') {
- ret.style = normalizeStyle([ret.style, toMerge.style])
- } else if (isOn(key)) {
- const existing = ret[key]
- const incoming = toMerge[key]
- if (
- incoming &&
- existing !== incoming &&
- !(isArray(existing) && existing.includes(incoming))
- ) {
- ret[key] = existing
- ? [].concat(existing as any, incoming as any)
- : incoming
- }
- } else if (key !== '') {
- ret[key] = toMerge[key]
+ if (key !== '') {
+ ret[key] = mergeProp(key, ret[key], toMerge[key])
}
}
}
} from '@vue/shared'
import { warn } from '../warning'
import { recordPropMetadata } from '../componentMetadata'
+import { mergeInheritAttr } from './prop'
-export function setStyle(el: HTMLElement, value: any): void {
- const prev = recordPropMetadata(el, 'style', (value = normalizeStyle(value)))
+export function setStyle(el: HTMLElement, value: any, root?: boolean): void {
+ const prev = recordPropMetadata(
+ el,
+ 'style',
+ (value = normalizeStyle(root ? mergeInheritAttr('style', value) : value)),
+ )
patchStyle(el, prev, value)
}
export { createFor, createForSlots } from './apiCreateFor'
export { createComponent } from './apiCreateComponent'
export { createSelector } from './apiCreateSelector'
+export { setInheritAttrs } from './componentAttrs'
export {
resolveComponent,
"vue": "workspace:*"
},
"devDependencies": {
- "@vitejs/plugin-vue": "https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5",
+ "@vitejs/plugin-vue": "https://pkg.pr.new/@vitejs/plugin-vue@481bcd4",
"vite": "catalog:",
"vite-hyper-config": "^0.4.0",
"vite-plugin-inspect": "^0.8.7"
version: link:../packages/vue
devDependencies:
'@vitejs/plugin-vue':
- specifier: https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5
- version: https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5(vite@5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0))(vue@packages+vue)
+ specifier: https://pkg.pr.new/@vitejs/plugin-vue@481bcd4
+ version: https://pkg.pr.new/@vitejs/plugin-vue@481bcd4(vite@5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0))(vue@packages+vue)
vite:
specifier: 'catalog:'
version: 5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0)
vite: ^5.0.0
vue: ^3.2.25
+ '@vitejs/plugin-vue@https://pkg.pr.new/@vitejs/plugin-vue@481bcd4':
+ resolution: {tarball: https://pkg.pr.new/@vitejs/plugin-vue@481bcd4}
+ version: 5.1.5
+ engines: {node: ^18.0.0 || >=20.0.0}
+ peerDependencies:
+ vite: ^5.0.0
+ vue: ^3.2.25
+
'@vitejs/plugin-vue@https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5':
resolution: {tarball: https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5}
version: 5.1.4
vite: 5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0)
vue: link:packages/vue
- '@vitejs/plugin-vue@https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5(vite@5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))':
+ '@vitejs/plugin-vue@https://pkg.pr.new/@vitejs/plugin-vue@481bcd4(vite@5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0))(vue@packages+vue)':
dependencies:
vite: 5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0)
- vue: 3.5.12(typescript@5.6.2)
+ vue: link:packages/vue
- '@vitejs/plugin-vue@https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5(vite@5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0))(vue@packages+vue)':
+ '@vitejs/plugin-vue@https://pkg.pr.new/@vitejs/plugin-vue@e3c5ce5(vite@5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))':
dependencies:
vite: 5.4.8(@types/node@22.8.7)(sass@1.80.6)(terser@5.33.0)
- vue: link:packages/vue
+ vue: 3.5.12(typescript@5.6.2)
'@vitest/coverage-v8@2.1.1(vitest@2.1.1)':
dependencies: