*/
_ceVNode?: VNode
+ /**
+ * @internal vapor custom element instance
+ */
+ _ceComponent?: GenericComponentInstance | null
+
/**
* v2 compat only
*/
protected _slots?: Record<string, Node[]>
protected abstract _hasPreRendered(): boolean | undefined
- protected abstract _mountComponent(def: Def): void
- protected abstract _updateComponent(): void
- protected abstract _unmountComponent(): void
+ protected abstract _mount(def: Def): void
+ protected abstract _update(): void
+ protected abstract _unmount(): void
constructor(
/**
this._ob.disconnect()
this._ob = null
}
- this._unmountComponent()
+ this._unmount()
if (this._teleportTargets) {
this._teleportTargets.clear()
this._teleportTargets = undefined
}
}
+ private _mountComponent(def: Def): void {
+ this._mount(def)
+ this._processExposed()
+ }
+
+ protected _processExposed(): void {
+ const exposed = this._instance && this._instance.exposed
+ if (!exposed) return
+ for (const key in exposed) {
+ if (!hasOwn(this, key)) {
+ Object.defineProperty(this, key, {
+ get: () => unref(exposed[key]),
+ })
+ } else if (__DEV__) {
+ warn(`Exposed property "${key}" already exists on custom element.`)
+ }
+ }
+ }
+
+ protected _processEmit(): void {
+ const dispatch = (event: string, args: any[]) => {
+ this.dispatchEvent(
+ new CustomEvent(
+ event,
+ isPlainObject(args[0])
+ ? extend({ detail: args }, args[0])
+ : { detail: args },
+ ),
+ )
+ }
+
+ this._instance!.emit = (event: string, ...args: any[]) => {
+ dispatch(event, args)
+ if (hyphenate(event) !== event) {
+ dispatch(hyphenate(event), args)
+ }
+ }
+ }
+
private _resolveProps(def: Def): void {
const { props } = def
const declaredPropKeys = isArray(props) ? props : Object.keys(props || {})
}
}
if (shouldUpdate && this._instance) {
- this._updateComponent()
+ this._update()
}
// reflect
if (shouldReflect) {
}
}
- protected _mountComponent(def: InnerComponentDef): void {
+ protected _mount(def: InnerComponentDef): void {
if ((__DEV__ || __FEATURE_PROD_DEVTOOLS__) && !def.name) {
// @ts-expect-error
def.name = 'VueElement'
}
this._app._ceVNode = this._createVNode()
this._app.mount(this._root)
-
- const exposed = this._instance && this._instance.exposed
- if (!exposed) return
- for (const key in exposed) {
- if (!hasOwn(this, key)) {
- Object.defineProperty(this, key, {
- get: () => unref(exposed[key]),
- })
- } else if (__DEV__) {
- warn(`Exposed property "${key}" already exists on custom element.`)
- }
- }
}
- protected _updateComponent(): void {
+ protected _update(): void {
if (!this._app) return
const vnode = this._createVNode()
vnode.appContext = this._app._context
render(vnode, this._root)
}
- protected _unmountComponent(): void {
+ protected _unmount(): void {
if (this._app) {
this._app.unmount()
}
}
this._applyStyles(newStyles)
this._instance = null
- this._updateComponent()
- }
- }
-
- const dispatch = (event: string, args: any[]) => {
- this.dispatchEvent(
- new CustomEvent(
- event,
- isPlainObject(args[0])
- ? extend({ detail: args }, args[0])
- : { detail: args },
- ),
- )
- }
-
- instance.emit = (event: string, ...args: any[]) => {
- dispatch(event, args)
- if (hyphenate(event) !== event) {
- dispatch(hyphenate(event), args)
+ this._update()
}
}
+ this._processEmit()
this._setParent()
}
}
container.textContent = ''
}
- const instance = createComponent(
- app._component,
- app._props as RawProps,
- null,
- false,
- false,
- app._context,
- )
+ const instance =
+ (app._ceComponent as VaporComponentInstance) ||
+ createComponent(
+ app._component,
+ app._props as RawProps,
+ null,
+ false,
+ false,
+ app._context,
+ )
mountComponent(instance, container)
flushOnAppMount()
let instance: VaporComponentInstance
withHydration(container, () => {
- instance = createComponent(
- app._component,
- app._props as RawProps,
- null,
- false,
- false,
- app._context,
- )
+ instance =
+ (app._ceComponent as VaporComponentInstance) ||
+ createComponent(
+ app._component,
+ app._props as RawProps,
+ null,
+ false,
+ false,
+ app._context,
+ )
mountComponent(instance, container)
flushOnAppMount()
})
import { extend, isPlainObject } from '@vue/shared'
-import { createVaporApp, defineVaporComponent } from '.'
+import { createComponent, createVaporApp, defineVaporComponent } from '.'
import {
type CreateAppFunction,
type CustomElementOptions,
VueElementBase,
warn,
} from '@vue/runtime-dom'
-import type { ObjectVaporComponent, VaporComponent } from './component'
+import {
+ type ObjectVaporComponent,
+ type VaporComponent,
+ type VaporComponentInstance,
+ mountComponent,
+ unmountComponent,
+} from './component'
export type VaporElementConstructor<P = {}> = {
new (initialProps?: Record<string, any>): VaporElement & P
return true
}
}
- protected _mountComponent(def: VaporInnerComponentDef): void {
- throw new Error('Method not implemented.')
+ protected _mount(def: VaporInnerComponentDef): void {
+ if ((__DEV__ || __FEATURE_PROD_DEVTOOLS__) && !def.name) {
+ def.name = 'VaporElement'
+ }
+
+ this._app = this._createApp(this._def)
+ this._inheritParentContext()
+ if (this._def.configureApp) {
+ this._def.configureApp(this._app)
+ }
+
+ this._app._ceComponent = this._createComponent()
+ this._app!.mount(this._root)
+ }
+
+ protected _update(): void {
+ if (!this._app) return
+ unmountComponent(this._instance! as VaporComponentInstance, this._root)
+ const instance = this._createComponent()
+ instance.appContext = this._app!._context
+ mountComponent(this._instance! as VaporComponentInstance, this._root)
}
- protected _updateComponent(): void {
- throw new Error('Method not implemented.')
+
+ protected _unmount(): void {
+ this._app!.unmount()
+ this._app = this._instance = null
}
- protected _unmountComponent(): void {
- throw new Error('Method not implemented.')
+
+ private _createComponent() {
+ this._instance = createComponent(this._def, this._props)
+ if (!this.shadowRoot) {
+ this._instance!.m = this._instance!.u = [this._renderSlots.bind(this)]
+ }
+
+ this._instance.ce = this
+ this._instance.isCE = true
+
+ if (__DEV__) {
+ this._instance.ceReload = newStyles => {
+ if (this._styles) {
+ this._styles.forEach(s => this._root.removeChild(s))
+ this._styles.length = 0
+ }
+ this._applyStyles(newStyles)
+ this._instance = null
+ this._update()
+ }
+ }
+
+ this._processEmit()
+ this._setParent()
+
+ return this._instance
}
}
export type { VaporDirective } from './directives/custom'
export { VaporTeleportImpl as VaporTeleport } from './components/Teleport'
export { VaporKeepAliveImpl as VaporKeepAlive } from './components/KeepAlive'
+export {
+ defineVaporCustomElement,
+ defineVaporSSRCustomElement,
+} from './apiDefineVaporCustomElement'
// compiler-use only
export { insert, prepend, remove } from './block'