Skip to content

Commit

Permalink
fix: add fixes for 2 issues
Browse files Browse the repository at this point in the history
* Allow styling component if it is placed in the shadow root of the component without styles
* Update prototype of CSSStyleSheet in the iframe.
  • Loading branch information
Lodin committed Aug 26, 2019
1 parent 14bd948 commit 5546c8b
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 31 deletions.
28 changes: 18 additions & 10 deletions adoptedStyleSheets.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@
frameBody.append(basicStyleElement);

const nativeStyleSheet = basicStyleElement.sheet;
updatePrototype(nativeStyleSheet.constructor.prototype);

// A support object to preserve all the polyfill data
nativeStyleSheet[$constructStyleSheet] = {
Expand Down Expand Up @@ -134,6 +133,12 @@
}
}

updatePrototype(OldCSSStyleSheet.prototype);

// Since we get the sheet from iframe, we need to patch prototype of the
// CSSStyleSheet in iframe as well.
updatePrototype(iframe.contentWindow.CSSStyleSheet.prototype);

const adoptStyleSheets = location => {
const newStyles = document.createDocumentFragment();

Expand Down Expand Up @@ -197,9 +202,7 @@
continue;
}

const styleElement = sheet[$constructStyleSheet].adopters.get(
location,
);
const styleElement = sheet[$constructStyleSheet].adopters.get(location);

location[$observer].disconnect();
styleElement.remove();
Expand Down Expand Up @@ -291,12 +294,6 @@
const location = this.body ? this.body : this;
const uniqueSheets = [...new Set(sheets)];


if (!location[$adoptedStyleSheets] && location instanceof ShadowRoot) {
// Observer for document.body is already launched
createObserver(location);
}

const oldSheets = location[$adoptedStyleSheets] || [];
location[$adoptedStyleSheets] = uniqueSheets;

Expand All @@ -309,6 +306,17 @@
},
};

const oldAttachShadow = HTMLElement.prototype.attachShadow;

// Shadow root of each element should be observed to add styles to all
// elements added to this root.
HTMLElement.prototype.attachShadow = function(...args) {
const location = oldAttachShadow.apply(this, args);
createObserver(location);

return location;
};

Object.defineProperty(
ShadowRoot.prototype,
'adoptedStyleSheets',
Expand Down
68 changes: 47 additions & 21 deletions test/polyfill.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,11 @@ describe('Constructible Style Sheets polyfill', () => {
constructor() {
super();
const root = this.attachShadow({mode: 'open'});
root.adoptedStyleSheets = sheets;

if (sheets) {
root.adoptedStyleSheets = sheets;
}

root.innerHTML = html;
}
}
Expand Down Expand Up @@ -160,26 +164,6 @@ describe('Constructible Style Sheets polyfill', () => {
checkCss(element, {...defaultChecker, height: '82px'});
});

it('applies styling to deeply nested web components', async () => {
const [tag1] = createCustomElement([css]);
const [tag2] = createCustomElement(
[css],
`<div>
<div>
<div>
<${tag1} id="nested"></${tag1}>
</div>
</div>
</div>`,
);

const element = await fixture(`<${tag2}></${tag2}>`);
checkCss(element, defaultChecker);

const nested = element.shadowRoot.getElementById('nested');
checkCss(nested, defaultChecker);
});

it('restores styles if innerHTML is cleared', async () => {
const [tag] = createCustomElement([css]);
const element = await fixture(`<${tag}></${tag}>`);
Expand Down Expand Up @@ -210,6 +194,48 @@ describe('Constructible Style Sheets polyfill', () => {
checkCss(element, {...defaultChecker, height: '82px'});
});

describe('detached elements', () => {
const detachedFixture = async (rootTag, ...nestedTags) => {
const detachedElement = nestedTags.reduceRight((acc, tag) => {
const element = document.createElement(tag);

if (acc) {
element.append(acc);
}

return element;
}, null);

const rootElement = await fixture(`<${rootTag}></${rootTag}>`);
rootElement.shadowRoot.append(detachedElement);

return rootElement;
};

it('applies styling to deeply nested web components', async () => {
const [tag1] = createCustomElement([css]);
const [tag2] = createCustomElement([css]);

const element = await detachedFixture(tag2, 'div', 'div', 'div', tag1);
checkCss(element, defaultChecker);
// await null; // MutationObserver is asynchronous

const nested = element.shadowRoot.querySelector(tag1);
checkCss(nested, defaultChecker);
});

it('applies styling to deeply nested web components even if host component does not have adoptedStyleSheets set', async () => {
const [tag1] = createCustomElement([css]);
const [tag2] = createCustomElement();

const element = await detachedFixture(tag2, 'div', 'div', 'div', tag1);
await null; // MutationObserver is asynchronous

const nested = element.shadowRoot.querySelector(tag1);
checkCss(nested, defaultChecker);
});
});

describe('Polyfill only', () => {
it('does not re-create style element on removing the sibling node', async () => {
ignore();
Expand Down

0 comments on commit 5546c8b

Please sign in to comment.