Skip to content

Commit cbfd888

Browse files
committed
feat(custom-element): Allow overriding properties
1 parent a53f01e commit cbfd888

File tree

1 file changed

+37
-15
lines changed

1 file changed

+37
-15
lines changed

packages/runtime-dom/src/apiCustomElement.ts

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,13 @@ export function defineCustomElement(
176176
if (isPlainObject(Comp)) extend(Comp, extraOptions)
177177
class VueCustomElement extends VueElement {
178178
static def = Comp
179+
static asyncDef: any | null = null
179180
constructor(initialProps?: Record<string, any>) {
180-
super(Comp, initialProps, _createApp)
181+
super(VueCustomElement.def, initialProps, _createApp)
181182
}
182183
}
183184

185+
_defineProps(VueCustomElement.prototype, Comp)
184186
return VueCustomElement
185187
}
186188

@@ -406,7 +408,16 @@ export class VueElement
406408
if (asyncDef) {
407409
this._pendingResolve = asyncDef().then((def: InnerComponentDef) => {
408410
def.configureApp = this._def.configureApp
409-
resolve((this._def = def), true)
411+
this._def = def
412+
const ctor = this.constructor as any
413+
if (!ctor.asyncDef) {
414+
const proto = Object.getPrototypeOf(this)
415+
_defineProps(proto, def)
416+
ctor.asyncDef = def
417+
} else if (ctor.asyncDef !== def) {
418+
warn('async loader returned inconsistent value')
419+
}
420+
resolve(def, true)
410421
})
411422
} else {
412423
resolve(this._def)
@@ -431,7 +442,7 @@ export class VueElement
431442
const exposed = this._instance && this._instance.exposed
432443
if (!exposed) return
433444
for (const key in exposed) {
434-
if (!hasOwn(this, key)) {
445+
if (!hasOwn(this, key) && !hasOwn(Object.getPrototypeOf(this), key)) {
435446
// exposed properties are readonly
436447
Object.defineProperty(this, key, {
437448
// unwrap ref to be consistent with public instance behavior
@@ -451,20 +462,9 @@ export class VueElement
451462
for (const key of Object.keys(this)) {
452463
if (key[0] !== '_' && declaredPropKeys.includes(key)) {
453464
this._setProp(key, this[key as keyof this])
465+
delete this[key as keyof this]
454466
}
455467
}
456-
457-
// defining getter/setters on prototype
458-
for (const key of declaredPropKeys.map(camelize)) {
459-
Object.defineProperty(this, key, {
460-
get() {
461-
return this._getProp(key)
462-
},
463-
set(val) {
464-
this._setProp(key, val, true, true)
465-
},
466-
})
467-
}
468468
}
469469

470470
protected _setAttr(key: string): void {
@@ -688,6 +688,28 @@ export class VueElement
688688
}
689689
}
690690

691+
function _defineProps(proto: object, def: InnerComponentDef) {
692+
const { props } = def
693+
const declaredPropKeys = isArray(props) ? props : Object.keys(props || {})
694+
// defining getter/setters on prototype
695+
for (const key of declaredPropKeys.map(camelize)) {
696+
Object.defineProperty(proto, key, {
697+
get() {
698+
return this._getProp(key)
699+
},
700+
set(val) {
701+
if (this._resolved) {
702+
this._setProp(key, val, true, true)
703+
} else {
704+
// when pre-upgrade or connect, set values directly on the instance
705+
Reflect.set({}, key, val, this)
706+
}
707+
},
708+
enumerable: true,
709+
})
710+
}
711+
}
712+
691713
export function useHost(caller?: string): VueElement | null {
692714
const instance = getCurrentInstance()
693715
const el = instance && (instance.ce as VueElement)

0 commit comments

Comments
 (0)