]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(custom-element): support early-set domProps for async custom elements
authorEvan You <evan@vuejs.org>
Thu, 8 Aug 2024 08:26:48 +0000 (16:26 +0800)
committerEvan You <evan@vuejs.org>
Thu, 8 Aug 2024 08:26:48 +0000 (16:26 +0800)
close #11081
close #11082

packages/runtime-dom/__tests__/customElement.spec.ts
packages/runtime-dom/src/apiCustomElement.ts
packages/runtime-dom/src/patchProp.ts

index 38af0e2a63ef0e69d72759fc756c2aa7283e9a0e..da0d614f6574cd77369f5982de1f177499c97da6 100644 (file)
@@ -1206,4 +1206,39 @@ describe('defineCustomElement', () => {
       'hello',
     )
   })
+
+  // #11081
+  test('Props can be casted when mounting custom elements in component rendering functions', async () => {
+    const E = defineCustomElement(
+      defineAsyncComponent(() =>
+        Promise.resolve({
+          props: ['fooValue'],
+          setup(props) {
+            expect(props.fooValue).toBe('fooValue')
+            return () => h('div', props.fooValue)
+          },
+        }),
+      ),
+    )
+    customElements.define('my-el-async-4', E)
+    const R = defineComponent({
+      setup() {
+        const fooValue = ref('fooValue')
+        return () => {
+          return h('div', null, [
+            h('my-el-async-4', {
+              fooValue: fooValue.value,
+            }),
+          ])
+        }
+      },
+    })
+
+    const app = createApp(R)
+    app.mount(container)
+    await new Promise(r => setTimeout(r))
+    const e = container.querySelector('my-el-async-4') as VueElement
+    expect(e.shadowRoot!.innerHTML).toBe(`<div>fooValue</div>`)
+    app.unmount()
+  })
 })
index af6063cdb02262a831d50977d747cf64782aaa03..aa191ba6c7ced1965d5adc196cc1643e14af4420 100644 (file)
@@ -200,6 +200,7 @@ export class VueElement
   extends BaseClass
   implements ComponentCustomElementInterface
 {
+  _isVueCE = true
   /**
    * @internal
    */
@@ -208,6 +209,10 @@ export class VueElement
    * @internal
    */
   _app: App | null = null
+  /**
+   * @internal
+   */
+  _root: Element | ShadowRoot
   /**
    * @internal
    */
@@ -228,10 +233,6 @@ export class VueElement
    */
   private _childStyles?: Map<string, HTMLStyleElement[]>
   private _ob?: MutationObserver | null = null
-  /**
-   * @internal
-   */
-  public _root: Element | ShadowRoot
   private _slots?: Record<string, Node[]>
 
   constructor(
index f3ef14ee83c3313b85c2f43e62e6585132d4e9db..98b69967c71b7607187b7b2b44b19fc59aa7119f 100644 (file)
@@ -5,6 +5,7 @@ import { patchDOMProp } from './modules/props'
 import { patchEvent } from './modules/events'
 import { isFunction, isModelListener, isOn, isString } from '@vue/shared'
 import type { RendererOptions } from '@vue/runtime-core'
+import type { VueElement } from './apiCustomElement'
 
 const isNativeOn = (key: string) =>
   key.charCodeAt(0) === 111 /* o */ &&
@@ -127,5 +128,14 @@ function shouldSetAsProp(
     return false
   }
 
-  return key in el
+  if (key in el) {
+    return true
+  }
+
+  // #11081 force set props for possible async custom element
+  if ((el as VueElement)._isVueCE && (/[A-Z]/.test(key) || !isString(value))) {
+    return true
+  }
+
+  return false
 }