Teleport,
type VueElement,
createApp,
+ createBlock,
+ createCommentVNode,
+ createElementBlock,
+ createElementVNode,
defineAsyncComponent,
defineComponent,
defineCustomElement,
inject,
nextTick,
onMounted,
+ openBlock,
provide,
ref,
render,
renderSlot,
useHost,
useShadowRoot,
+ withCtx,
} from '../src'
declare var __VUE_HMR_RUNTIME__: HMRRuntime
expect(target.innerHTML).toBe(`<span>default</span>`)
app.unmount()
})
+
+ //#13206
+ test('should update slotted children correctly w/ shadowRoot false', async () => {
+ const E = defineCustomElement(
+ defineComponent({
+ props: {
+ isShown: { type: Boolean, required: true },
+ },
+ render() {
+ return this.isShown
+ ? h('div', { key: 0 }, [renderSlot(this.$slots, 'default')])
+ : null
+ },
+ }),
+ { shadowRoot: false },
+ )
+ customElements.define('ce-shadow-root-false', E)
+
+ const Comp = defineComponent({
+ props: {
+ isShown: { type: Boolean, required: true },
+ },
+ render() {
+ return h('ce-shadow-root-false', { 'is-shown': this.isShown }, [
+ renderSlot(this.$slots, 'default'),
+ ])
+ },
+ })
+
+ const isShown = ref(false)
+ const count = ref(0)
+
+ function click() {
+ isShown.value = !isShown.value
+ count.value++
+ }
+
+ const App = {
+ render() {
+ return (
+ openBlock(),
+ createBlock(
+ Comp,
+ { isShown: isShown.value },
+ {
+ default: withCtx(() => [
+ createElementVNode('div', null, isShown.value, 1 /* TEXT */),
+ count.value > 1
+ ? (openBlock(), createElementBlock('div', { key: 0 }, 'hi'))
+ : createCommentVNode('v-if', true),
+ ]),
+ _: 1 /* STABLE */,
+ },
+ 8 /* PROPS */,
+ ['isShown'],
+ )
+ )
+ },
+ }
+ const container = document.createElement('div')
+ document.body.appendChild(container)
+
+ const app = createApp(App)
+ app.mount(container)
+ expect(container.innerHTML).toBe(
+ `<ce-shadow-root-false data-v-app=""><!----></ce-shadow-root-false>`,
+ )
+
+ click()
+ await nextTick()
+ expect(container.innerHTML).toBe(
+ `<ce-shadow-root-false data-v-app="" is-shown=""><div><div>true</div><!--v-if--></div></ce-shadow-root-false>`,
+ )
+
+ click()
+ await nextTick()
+ expect(container.innerHTML).toBe(
+ `<ce-shadow-root-false data-v-app=""><!----></ce-shadow-root-false>`,
+ )
+
+ click()
+ await nextTick()
+ expect(container.innerHTML).toBe(
+ `<ce-shadow-root-false data-v-app="" is-shown=""><div><div>true</div><div>hi</div></div></ce-shadow-root-false>`,
+ )
+ })
})
describe('helpers', () => {
*/
_updateSlots(children: VNode[]): void {
children.forEach(child => {
- this._slots![child.slotName!] = collectElements(
- child.children as VNodeArrayChildren,
- )
+ // slot children are always Fragments
+ this._slots![child.slotName!] = collectFragmentElements(child)
})
}
return el && el.shadowRoot
}
+function collectFragmentElements(child: VNode): Node[] {
+ return [
+ child.el as Node,
+ ...collectElements(child.children as VNodeArrayChildren),
+ child.anchor as Node,
+ ]
+}
+
function collectElements(children: VNodeArrayChildren): Node[] {
const nodes: Node[] = []
- for (const vnode of children) {
- if (isArray(vnode)) {
- nodes.push(...collectElements(vnode))
- } else if (isVNode(vnode)) {
- if (vnode.type === Fragment) {
- nodes.push(...collectElements(vnode.children as VNodeArrayChildren))
- } else if (vnode.el) {
- nodes.push(vnode.el as Node)
+ for (const child of children) {
+ if (isArray(child)) {
+ nodes.push(...collectElements(child))
+ } else if (isVNode(child)) {
+ if (child.type === Fragment) {
+ nodes.push(...collectFragmentElements(child))
+ } else if (child.el) {
+ nodes.push(child.el as Node)
}
}
}