assertStyles(el, [`div { color: blue; }`, `div { color: red; }`])
})
+ test('inject child component styles before parent styles', async () => {
+ const Baz = () => h(Bar)
+ const Bar = defineComponent({
+ styles: [`div { color: green; }`],
+ render() {
+ return 'bar'
+ },
+ })
+ const WrapperBar = defineComponent({
+ styles: [`div { color: blue; }`],
+ render() {
+ return h(Baz)
+ },
+ })
+ const WBaz = () => h(WrapperBar)
+ const Foo = defineCustomElement({
+ styles: [`div { color: red; }`],
+ render() {
+ return [h(Baz), h(WBaz)]
+ },
+ })
+ customElements.define('my-el-with-wrapper-child-styles', Foo)
+ container.innerHTML = `<my-el-with-wrapper-child-styles></my-el-with-wrapper-child-styles>`
+ const el = container.childNodes[0] as VueElement
+
+ // inject order should be child -> parent
+ assertStyles(el, [
+ `div { color: green; }`,
+ `div { color: blue; }`,
+ `div { color: red; }`,
+ ])
+ })
+
+ test('inject child component styles when parent has no styles', async () => {
+ const Baz = () => h(Bar)
+ const Bar = defineComponent({
+ styles: [`div { color: green; }`],
+ render() {
+ return 'bar'
+ },
+ })
+ const WrapperBar = defineComponent({
+ styles: [`div { color: blue; }`],
+ render() {
+ return h(Baz)
+ },
+ })
+ const WBaz = () => h(WrapperBar)
+ // without styles
+ const Foo = defineCustomElement({
+ render() {
+ return [h(Baz), h(WBaz)]
+ },
+ })
+ customElements.define('my-el-with-inject-child-styles', Foo)
+ container.innerHTML = `<my-el-with-inject-child-styles></my-el-with-inject-child-styles>`
+ const el = container.childNodes[0] as VueElement
+
+ assertStyles(el, [`div { color: green; }`, `div { color: blue; }`])
+ })
+
test('with nonce', () => {
const Foo = defineCustomElement(
{
private _styleChildren = new WeakSet()
private _pendingResolve: Promise<void> | undefined
private _parent: VueElement | undefined
+ private _styleAnchor?: HTMLStyleElement | Text
/**
* dev only
*/
private _applyStyles(
styles: string[] | undefined,
owner?: ConcreteComponent,
+ parentComp?: ConcreteComponent & CustomElementOptions,
) {
if (!styles) return
if (owner) {
}
this._styleChildren.add(owner)
}
+
+ // if parent has no styles but child does, create an anchor
+ // to inject child styles before it.
+ if (parentComp && !parentComp.styles) {
+ const anchor = document.createTextNode('')
+ if (this._styleAnchor) {
+ this.shadowRoot!.insertBefore(anchor, this._styleAnchor)
+ } else {
+ this.shadowRoot!.prepend(anchor)
+ }
+ this._styleAnchor = anchor
+ }
+
const nonce = this._nonce
+ let last = undefined
for (let i = styles.length - 1; i >= 0; i--) {
const s = document.createElement('style')
if (nonce) s.setAttribute('nonce', nonce)
s.textContent = styles[i]
- this.shadowRoot!.prepend(s)
+
+ // inject styles before parent styles
+ if (parentComp) {
+ this.shadowRoot!.insertBefore(s, last || this._styleAnchor!)
+ } else {
+ this.shadowRoot!.prepend(s)
+ this._styleAnchor = s
+ }
+ last = s
+
// record for HMR
if (__DEV__) {
if (owner) {
/**
* @internal
*/
- _injectChildStyle(comp: ConcreteComponent & CustomElementOptions): void {
- this._applyStyles(comp.styles, comp)
+ _injectChildStyle(
+ comp: ConcreteComponent & CustomElementOptions,
+ parentComp?: ConcreteComponent,
+ ): void {
+ this._applyStyles(comp.styles, comp, parentComp)
}
/**