function createInnerComp(
comp: ConcreteComponent,
- {
- vnode: { ref, props, children, shapeFlag },
- parent
- }: ComponentInternalInstance
+ parent: ComponentInternalInstance
) {
+ const { ref, props, children, ce } = parent.vnode
const vnode = createVNode(comp, props, children)
// ensure inner component inherits the async wrapper's ref owner
vnode.ref = ref
+ // pass the custom element callback on to the inner comp
+ // and remove it from the async wrapper
+ vnode.ce = ce
+ delete parent.vnode.ce
+
return vnode
}
// components to be unmounted and re-mounted. Queue the update so that we
// don't end up forcing the same parent to re-render multiple times.
queueJob(instance.parent.update)
- // instance is the inner component of an async custom element
- // invoke to reset styles
- if (
- (instance.parent.type as ComponentOptions).__asyncLoader &&
- instance.parent.ceReload
- ) {
- instance.parent.ceReload((newComp as any).styles)
- }
} else if (instance.appContext.reload) {
// root instance mounted via createApp() has a reload method
instance.appContext.reload()
import {
defineAsyncComponent,
+ defineComponent,
defineCustomElement,
h,
inject,
})
describe('emits', () => {
- const E = defineCustomElement({
+ const CompDef = defineComponent({
setup(_, { emit }) {
emit('created')
return () =>
})
}
})
+ const E = defineCustomElement(CompDef)
customElements.define('my-el-emits', E)
test('emit on connect', () => {
expect(spy1).toHaveBeenCalledTimes(1)
expect(spy2).toHaveBeenCalledTimes(1)
})
+
+ test('emit from within async component wrapper', async () => {
+ const E = defineCustomElement(
+ defineAsyncComponent(
+ () => new Promise<typeof CompDef>(res => res(CompDef as any))
+ )
+ )
+ customElements.define('my-async-el-emits', E)
+ container.innerHTML = `<my-async-el-emits></my-async-el-emits>`
+ const e = container.childNodes[0] as VueElement
+ const spy = jest.fn()
+ e.addEventListener('my-click', spy)
+ // this feels brittle but seems necessary to reach the node in the DOM.
+ await customElements.whenDefined('my-async-el-emits')
+ e.shadowRoot!.childNodes[0].dispatchEvent(new CustomEvent('click'))
+ expect(spy).toHaveBeenCalled()
+ expect(spy.mock.calls[0][0]).toMatchObject({
+ detail: [1]
+ })
+ })
})
describe('slots', () => {
this._styles.length = 0
}
this._applyStyles(newStyles)
- // if this is an async component, ceReload is called from the inner
- // component so no need to reload the async wrapper
- if (!(this._def as ComponentOptions).__asyncLoader) {
- // reload
- this._instance = null
- this._update()
- }
+ this._instance = null
+ this._update()
}
}