ref,
render,
renderSlot,
+ useShadowRoot,
} from '../src'
describe('defineCustomElement', () => {
)
})
})
+
+ describe('useCustomElementRoot', () => {
+ test('should work for style injection', () => {
+ const Foo = defineCustomElement({
+ setup() {
+ const root = useShadowRoot()!
+ const style = document.createElement('style')
+ style.innerHTML = `div { color: red; }`
+ root.appendChild(style)
+ return () => h('div', 'hello')
+ },
+ })
+ customElements.define('my-el', Foo)
+ container.innerHTML = `<my-el></my-el>`
+ const el = container.childNodes[0] as VueElement
+ const style = el.shadowRoot?.querySelector('style')!
+ expect(style.textContent).toBe(`div { color: red; }`)
+ })
+ })
})
type VNodeProps,
createVNode,
defineComponent,
+ getCurrentInstance,
nextTick,
warn,
} from '@vue/runtime-core'
private _numberProps: Record<string, true> | null = null
private _styles?: HTMLStyleElement[]
private _ob?: MutationObserver | null = null
- private _root: Element | ShadowRoot
+ /**
+ * @internal
+ */
+ public _root: Element | ShadowRoot
private _slots?: Record<string, Node[]>
constructor(
this._ob = null
}
render(null, this._root)
+ this._instance!.isCE = undefined
this._instance = null
}
})
if (!this._instance) {
vnode.ce = instance => {
this._instance = instance
- instance.isCE = true
+ instance.isCE = this
// HMR
if (__DEV__) {
instance.ceReload = newStyles => {
}
}
}
+
+/**
+ * Retrieve the shadowRoot of the current custom element. Only usable in setup()
+ * of a `defineCustomElement` component.
+ */
+export function useShadowRoot(): ShadowRoot | null {
+ const instance = getCurrentInstance()
+ const el = instance && instance.isCE
+ if (el) {
+ return el.shadowRoot
+ } else if (__DEV__) {
+ if (!instance) {
+ warn(`useCustomElementRoot called without an active component instance.`)
+ } else {
+ warn(
+ `useCustomElementRoot can only be used in components defined via ` +
+ `defineCustomElement.`,
+ )
+ }
+ }
+ return null
+}