Skip to content

Commit 61f90b0

Browse files
fix(runtime): merge styles within ShadowRoot into a single node (#6014)
* fix(runtime): merge shadow root styles into into a single node * fix build * change order how styles are applied * prettier
1 parent 1564b7a commit 61f90b0

9 files changed

+71
-5
lines changed

src/runtime/styles.ts

+14-3
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,21 @@ export const addStyle = (styleContainerNode: any, cmpMeta: d.ComponentRuntimeMet
108108
(styleContainerNode as HTMLElement).insertBefore(styleElm, referenceNode);
109109
} else if ('host' in styleContainerNode) {
110110
/**
111-
* if a scoped component is used within a shadow root, we want to insert the styles
112-
* at the beginning of the shadow root node
111+
* If a scoped component is used within a shadow root, we want to insert the styles
112+
* at the beginning of the shadow root node.
113+
*
114+
* However if there is already a style node in the ShadowRoot, we just append
115+
* the styles to the existing node.
116+
*
117+
* Note: order of how styles are applied is important. The new style node
118+
* should be inserted before the existing style node.
113119
*/
114-
(styleContainerNode as HTMLElement).prepend(styleElm);
120+
const existingStyleContainer = styleContainerNode.querySelector('style');
121+
if (existingStyleContainer) {
122+
existingStyleContainer.innerHTML = style + existingStyleContainer.innerHTML;
123+
} else {
124+
(styleContainerNode as HTMLElement).prepend(styleElm);
125+
}
115126
} else {
116127
styleContainerNode.append(styleElm);
117128
}

test/end-to-end/src/components.d.ts

+13
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ export namespace Components {
104104
}
105105
interface NestedCmpParent {
106106
}
107+
interface NestedScopeCmp {
108+
}
107109
interface PathAliasCmp {
108110
}
109111
interface PrerenderCmp {
@@ -350,6 +352,12 @@ declare global {
350352
prototype: HTMLNestedCmpParentElement;
351353
new (): HTMLNestedCmpParentElement;
352354
};
355+
interface HTMLNestedScopeCmpElement extends Components.NestedScopeCmp, HTMLStencilElement {
356+
}
357+
var HTMLNestedScopeCmpElement: {
358+
prototype: HTMLNestedScopeCmpElement;
359+
new (): HTMLNestedScopeCmpElement;
360+
};
353361
interface HTMLPathAliasCmpElement extends Components.PathAliasCmp, HTMLStencilElement {
354362
}
355363
var HTMLPathAliasCmpElement: {
@@ -445,6 +453,7 @@ declare global {
445453
"method-cmp": HTMLMethodCmpElement;
446454
"nested-cmp-child": HTMLNestedCmpChildElement;
447455
"nested-cmp-parent": HTMLNestedCmpParentElement;
456+
"nested-scope-cmp": HTMLNestedScopeCmpElement;
448457
"path-alias-cmp": HTMLPathAliasCmpElement;
449458
"prerender-cmp": HTMLPrerenderCmpElement;
450459
"prop-cmp": HTMLPropCmpElement;
@@ -529,6 +538,8 @@ declare namespace LocalJSX {
529538
}
530539
interface NestedCmpParent {
531540
}
541+
interface NestedScopeCmp {
542+
}
532543
interface PathAliasCmp {
533544
}
534545
interface PrerenderCmp {
@@ -588,6 +599,7 @@ declare namespace LocalJSX {
588599
"method-cmp": MethodCmp;
589600
"nested-cmp-child": NestedCmpChild;
590601
"nested-cmp-parent": NestedCmpParent;
602+
"nested-scope-cmp": NestedScopeCmp;
591603
"path-alias-cmp": PathAliasCmp;
592604
"prerender-cmp": PrerenderCmp;
593605
"prop-cmp": PropCmp;
@@ -635,6 +647,7 @@ declare module "@stencil/core" {
635647
"method-cmp": LocalJSX.MethodCmp & JSXBase.HTMLAttributes<HTMLMethodCmpElement>;
636648
"nested-cmp-child": LocalJSX.NestedCmpChild & JSXBase.HTMLAttributes<HTMLNestedCmpChildElement>;
637649
"nested-cmp-parent": LocalJSX.NestedCmpParent & JSXBase.HTMLAttributes<HTMLNestedCmpParentElement>;
650+
"nested-scope-cmp": LocalJSX.NestedScopeCmp & JSXBase.HTMLAttributes<HTMLNestedScopeCmpElement>;
638651
"path-alias-cmp": LocalJSX.PathAliasCmp & JSXBase.HTMLAttributes<HTMLPathAliasCmpElement>;
639652
"prerender-cmp": LocalJSX.PrerenderCmp & JSXBase.HTMLAttributes<HTMLPrerenderCmpElement>;
640653
"prop-cmp": LocalJSX.PropCmp & JSXBase.HTMLAttributes<HTMLPropCmpElement>;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:host {
2+
display: block;
3+
}

test/end-to-end/src/declarative-shadow-dom/nested-child-cmp.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Component, h } from '@stencil/core';
22

33
@Component({
44
tag: 'nested-cmp-child',
5+
styleUrl: `nested-child-cmp.css`,
56
shadow: true,
67
})
78
export class NestedCmpChild {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:host {
2+
color: green;
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Component, h } from '@stencil/core';
2+
3+
@Component({
4+
tag: 'nested-scope-cmp',
5+
styleUrl: 'nested-scope-cmp.css',
6+
scoped: true,
7+
})
8+
export class NestedScopeCmp {
9+
render() {
10+
return (
11+
<div class="some-scope-class">
12+
<slot></slot>
13+
</div>
14+
);
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:host {
2+
display: inline-block;
3+
}

test/end-to-end/src/declarative-shadow-dom/parent-cmp.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ import { Component, h } from '@stencil/core';
33
@Component({
44
tag: 'nested-cmp-parent',
55
shadow: true,
6+
styleUrl: 'parent-cmp.css',
67
})
78
export class NestedCmpParent {
89
render() {
910
return (
1011
<div class="some-class">
11-
<slot></slot>
12+
<nested-scope-cmp>
13+
<slot></slot>
14+
</nested-scope-cmp>
1215
</div>
1316
);
1417
}

test/end-to-end/src/declarative-shadow-dom/test.e2e.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -346,13 +346,26 @@ describe('renderToString', () => {
346346
);
347347
expect(html).toBe(`<nested-cmp-parent custom-hydrate-flag="" s-id="29">
348348
<template shadowrootmode="open">
349+
<style>
350+
.sc-nested-scope-cmp-h{color:green}:host{display:inline-block}
351+
</style>
349352
<div c-id="29.0.0.0" class="some-class">
350-
<slot c-id="29.1.1.0"></slot>
353+
<nested-scope-cmp c-id="29.1.1.0" class="sc-nested-scope-cmp-h sc-nested-scope-cmp-s" custom-hydrate-flag="" s-id="31">
354+
<!--r.31-->
355+
<!--o.29.2.c-->
356+
<div c-id="31.0.0.0" class="sc-nested-scope-cmp sc-nested-scope-cmp-s some-scope-class">
357+
<!--s.31.1.1.0.-->
358+
<slot c-id="29.2.2.0" class="sc-nested-scope-cmp"></slot>
359+
</div>
360+
</nested-scope-cmp>
351361
</div>
352362
</template>
353363
<!--r.29-->
354364
<nested-cmp-child custom-hydrate-flag="" s-id="30">
355365
<template shadowrootmode="open">
366+
<style>
367+
:host{display:block}
368+
</style>
356369
<div c-id="30.0.0.0" class="some-other-class">
357370
<slot c-id="30.1.1.0"></slot>
358371
</div>

0 commit comments

Comments
 (0)