Skip to content

Primitive shadow parts support #329

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 8, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"singleQuote": true,
"bracketSpacing": false
}
5 changes: 4 additions & 1 deletion packages/shadycss/externs/shadycss-externs.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
* styleDocument: function(Object<string, string>=),
* flushCustomStyles: function(),
* getComputedStyleValue: function(!Element, string): string,
* onInsertBefore: function(!HTMLElement, !HTMLElement, ?HTMLElement): void,
* ScopingShim: (Object|undefined),
* ApplyShim: (Object|undefined),
* CustomStyleInterface: (Object|undefined),
* nativeCss: boolean,
* nativeShadow: boolean,
* cssBuild: (string | undefined),
* disableRuntime: boolean,
* disableShadowParts: (boolean | undefined),
* }}
*/
let ShadyCSSInterface; //eslint-disable-line no-unused-vars
Expand All @@ -26,6 +28,7 @@ let ShadyCSSInterface; //eslint-disable-line no-unused-vars
* shimshadow: (boolean | undefined),
* cssBuild: (string | undefined),
* disableRuntime: (boolean | undefined),
* disableShadowParts: (boolean | undefined),
* }}
*/
let ShadyCSSOptions; //eslint-disable-line no-unused-vars
Expand Down Expand Up @@ -63,4 +66,4 @@ HTMLTemplateElement.prototype._style;
/**
* @type {string | undefined}
*/
DOMTokenList.prototype.value;
DOMTokenList.prototype.value;
17 changes: 17 additions & 0 deletions packages/shadycss/src/scoping-shim.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import templateMap from './template-map.js';
import * as ApplyShimUtils from './apply-shim-utils.js';
import {updateNativeProperties, detectMixin} from './common-utils.js';
import {CustomStyleInterfaceInterface, CustomStyleProvider} from './custom-style-interface.js'; // eslint-disable-line no-unused-vars
import * as shadowParts from './shadow-parts.js';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you consider whether shadow parts should be a part of the scoping shim or given separate opt-in support in ShadyCSS, like @apply or custom style interface?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good thought, hadn't considered that. What are the main advantages you are thinking of?

The main one I can think of is that there would be more options for shipping smaller bundles to users who don't need shadow parts. We could create more permutations of the bundles, and update the loader to check the disableShadowParts flag, and only load shadow parts support when not true.

Does this suggestion imply you think shadow parts should be opt-in rather than opt-out? I've been thinking we should do opt-out, because 1) shadow parts are so widely supported now that it feels like they are part of the core set of web components APIs, and 2) I think the performance cost to applications that don't end up using shadow parts is very small (since we will do almost nothing until a ::part style is first detected in at least one template).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you've evaluated it correctly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed #339, will think about this a little more and refactor in a separate PR.

import {disableShadowParts} from './style-settings.js';

/** @type {!Object<string, string>} */
const adoptedCssTextMap = {};
Expand Down Expand Up @@ -275,6 +277,21 @@ export default class ScopingShim {
// sort ast ordering for document
this._documentOwnerStyleInfo.styleRules['rules'] = styles.map(s => StyleUtil.rulesForStyle(s));
}

/**
* Hook for performing ShadyCSS behavior for each ShadyDOM insertBefore call.
*
* @param {!HTMLElement} parentNode
* @param {!HTMLElement} newNode
* @param {?HTMLElement} referenceNode
* @return {void}
*/
onInsertBefore(parentNode, newNode, referenceNode) {
if (!disableShadowParts) {
shadowParts.onInsertBefore(parentNode, newNode, referenceNode);
}
}

/**
* Apply styles for the given element
*
Expand Down
52 changes: 48 additions & 4 deletions packages/shadycss/src/shadow-parts.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export function parseExportPartsAttribute(attr) {
// matches native behavior).
continue;
}
parts.push({ inner, outer });
parts.push({inner, outer});
}
return parts;
}
Expand Down Expand Up @@ -90,7 +90,7 @@ const PART_REGEX = /(.*?)([a-z]+-\w+)([^\s]*?)::part\((.*)?\)(::?.*)?/;
* spec-compliant.
*
* Example:
* [0 ][1 ][2 ] [3 ] [4 ]
* [0 ][1 ][2 ] [3 ] [4 ]
* #parent > my-button.fancy::part(foo bar):hover
*
* @param {!string} selector The selector.
Expand All @@ -108,7 +108,7 @@ export function parsePartSelector(selector) {
return null;
}
const [, combinators, elementName, selectors, parts, pseudos] = match;
return { combinators, elementName, selectors, parts, pseudos: pseudos || "" };
return {combinators, elementName, selectors, parts, pseudos: pseudos || ''};
}

/**
Expand Down Expand Up @@ -163,5 +163,49 @@ export function formatShadyPartSelector(
);
return `[shady-part~="${attr}"]`;
})
.join("");
.join('');
}

/* eslint-disable no-unused-vars */
/**
* Perform any needed Shadow Parts updates after a ShadyDOM insertBefore call
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you describe in more detail what this does and why it's necessary?

Copy link
Collaborator

@sorvell sorvell May 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be much less stress if we didn't have to alter the part attribute. Can you describe how this would limit the fidelity of the shim?

In particular, naively, a rule like x-super x-host [part~=foo] is at least somewhat similar to what you have. This doesn't do lower bound encapsulation at all, but ShadyCSS already addresses this, so could it be x-super .x-host[part~=foo] ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, interesting. I thought of an example that seemed sort of realistic where your suggestion would have caused an error, but then I thought of a modification that resolves it:

(1)

<style>
  /* error, the <div> grand-child of <x-other> shouldn't match */
  x-super .x-host[part~=foo] { color: red; }
  /* but is OK with this modification */
  x-super x-host.x-super .x-host[part~=foo] { color: red; }
</style>

<x-super>
  <x-host class="x-super">
    <div class="x-host" part="foo">
  <x-other class="x-super">
    <x-host class="x-other">
      <div class="x-host" part="foo">

However, you can still construct some patterns that fail:

(2)

<style>
  x-super x-host.x-super .x-host[part~=foo] { color: red; }
</style>

<x-super>
  <x-host class="x-super">
    <div class="x-host" part="foo">
    <x-other class="x-super">
      <x-host class="x-other">
        <!-- error: should not be red -->
        <div class="x-host" part="foo">

Whereas with the shady-parts attribute, the selectors are much tighter:

(3)

<style>
  x-super x-host [shady-part~="x-super:x-host:foo"] { color: red; }
</style>

<x-super>
  <x-host>
    <div class="x-host" part="foo" shady-part="x-super:x-host:foo">
    <x-other>
      <x-host>
        <!-- OK -->
        <div class="x-host" part="foo" shady-part="x-other:x-host:foo">

This is not to say that the shady-parts approach is perfect -- once you start repeating the same elements in a nesting hierarchy then you get similar problems (as described at https://github.com/webcomponents/polyfills/blob/shady-parts-basic/packages/shadycss/shadow-parts.md#3-recursion-is-crude). But it is at least a more limited set of patterns.

I guess the next question is, are examples like (2) above acceptable gaps in fidelity? It seems a little tricky to workaround the (2) example unless you can control the part names. WDYT? Can you think of any other selector tricks that would work even better?


The other consideration here is exported parts. In the implementation in #331, the way we support export parts is by adding additional shady-parts attributes to each part node based on the exportparts attributes found when we walk up the tree of shadow hosts. This allows one transformed style rule to match parts in all possible export paths.

I guess the way to do this if we used this other approach would be: each time we discover that an exported part needs to receive some style, we clone that style rule (or update its selector) with the new scope. We'd need to do per-instance styling here, though, in cases where two instances of the same element have different exportparts attributes. I already interact with per-instance styling in #333 to support custom properties within part rules, so it wouldn't be that wild. The difference here, though, would be that we'd be doing per-instance styling for more cases, even in Edge when native custom property support is available.

WDYT, am I thinking about this right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for considering this so carefully. To summarize, nesting is a problem with any of our approaches, but with the current approach nesting of (A->B) inside an (A->B) is problematic whereas with the proposed approach nesting an A inside an A is problematic.

I was considering this without exportparts. I think considering that argues for how you've done it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged.

* has been made.
*
* @param {!HTMLElement} parentNode
* @param {!HTMLElement} newNode
* @param {?HTMLElement} referenceNode
* @return {void}
*/
export function onInsertBefore(parentNode, newNode, referenceNode) {
/* eslint-enable no-unused-vars */
if (!parentNode.getRootNode) {
// TODO(aomarks) Why is it in noPatch mode on Chrome 41 and other older
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In noPatch mode, the DOM is not patched so getRootNode is not brought into existence because of the polyfill. On browsers that don't require the polyfill, getRootNode already exists.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To include support for noPatch mode, ShadyDOM.wrap must be called.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm having trouble getting tests to work with noPatch enabled -- it looks like there are no tests under shadycss with noPatch enabled yet. I'll need to spend some more time on it, so I've updated the TODO and filed #343 and will do noPatch support as a separate PR in next sprint, if that's ok.

// browsers that getRootNode is sometimes undefined?
return;
}
const root = parentNode.getRootNode();
if (root === document) {
// Parts in the document scope would never have any effect. Return early so
// we don't waste time querying it.
return;
}
const parts = parentNode.querySelectorAll('[part]');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, to support noPatch mode any DOM API must use ShadyDOM.wrap.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this do a querySelectorAll on every call to insertBefore? If so, have you measured the performance impact of this? I'd expect it to be noticeable. ShadyDOM already conditionally does a walk during insertBefore (for example, to find slots); maybe consider a tighter integration to be able to participate in that walk.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also consider doing this in prepareTemplateDom so that only dynamic parts need to be changed here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be searching newNode and newNode.querySelectorAll, not parentNode.querySelectorAll.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also consider doing this in prepareTemplateDom so that only dynamic parts need to be changed here.

Good idea. Probably missing something obvious here and I can look into it myself, but how can I avoid not querying the template again to look for parts when the template is stamped? Would I need to add some new tracing to understand when an insertBefore is happening as a result of the element's shadycss-registered template stamping, or is there already a way I could figure that out?

Also, it seems like this could cut down on the cost of the querySelectorAll since I guess I could store some kind of index of the part locations (or at the very least, a bit to tell me if it is even worth querying for parts), but I couldn't actually fully pre-process the template to add the shady-part attribute, since the value of that attribute depends on knowing the super-scope, which we don't know until we're connected. Does that sound right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'd need to add support for knowing when to not support the querySelector, but there's precedent for this: https://github.com/webcomponents/polyfills/blob/master/packages/shadydom/src/patches/Node.js#L309.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be searching newNode and newNode.querySelectorAll, not parentNode.querySelectorAll.

Done. I also needed some other changes to make this happen (since newNode can sometimes be a DocumentFragment or Text), and added tests for various kinds of inserts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, to support noPatch mode any DOM API must use ShadyDOM.wrap.

As mentioned in other comment, will do in follow up (#343).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this do a querySelectorAll on every call to insertBefore? If so, have you measured the performance impact of this? I'd expect it to be noticeable. ShadyDOM already conditionally does a walk during insertBefore (for example, to find slots); maybe consider a tighter integration to be able to participate in that walk.

No benchmarks yet. I will add them in an upcoming task: #344

Will look into replacing the querySelectorAll with an integration into the ShadyDOM walk as an upcoming task: #345

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, it seems like this could cut down on the cost of the querySelectorAll since I guess I could store some kind of index of the part locations (or at the very least, a bit to tell me if it is even worth querying for parts), but I couldn't actually fully pre-process the template to add the shady-part attribute, since the value of that attribute depends on knowing the super-scope, which we don't know until we're connected. Does that sound right?

@sorvell any thoughts on this? I've filed #346 for future investigation.

if (parts.length === 0) {
return;
}
const host = root.host;
const receiverScope = host.localName;
const superRoot = host.getRootNode();
const providerScope =
superRoot === document ? 'document' : superRoot.host.localName;
for (const part of parts) {
part.setAttribute(
'shady-part',
formatShadyPartAttribute(
providerScope,
receiverScope,
part.getAttribute('part')
)
);
}
}
6 changes: 5 additions & 1 deletion packages/shadycss/src/style-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ if (window.ShadyCSS && window.ShadyCSS.cssBuild !== undefined) {
/** @type {boolean} */
export const disableRuntime = Boolean(window.ShadyCSS && window.ShadyCSS.disableRuntime);

/** @type {boolean} */
export const disableShadowParts =
Boolean(window.ShadyCSS && window.ShadyCSS.disableShadowParts);

if (window.ShadyCSS && window.ShadyCSS.nativeCss !== undefined) {
nativeCssVariables_ = window.ShadyCSS.nativeCss;
} else if (window.ShadyCSS) {
Expand All @@ -53,4 +57,4 @@ if (window.ShadyCSS && window.ShadyCSS.nativeCss !== undefined) {
// Hack for type error under new type inference which doesn't like that
// nativeCssVariables is updated in a function and assigns the type
// `function(): ?` instead of `boolean`.
export const nativeCssVariables = /** @type {boolean} */(nativeCssVariables_);
export const nativeCssVariables = /** @type {boolean} */(nativeCssVariables_);
30 changes: 28 additions & 2 deletions packages/shadycss/src/style-transformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN

'use strict';

import {StyleNode} from './css-parse.js'; // eslint-disable-line no-unused-vars
import {StyleNode, parse} from './css-parse.js'; // eslint-disable-line no-unused-vars
import * as StyleUtil from './style-util.js';
import {nativeShadow} from './style-settings.js';
import {nativeShadow, disableShadowParts} from './style-settings.js';
import {parsePartSelector, formatShadyPartSelector} from './shadow-parts.js';

/* Transforms ShadowDOM styling into ShadyDOM styling

Expand Down Expand Up @@ -315,6 +316,12 @@ class StyleTransformer {
NTH, (m, type, inner) => `:${type}(${inner.replace(/\s/g, '')})`);
selector = this._twiddleNthPlus(selector);
}
if (!disableShadowParts && PART.test(selector)) {
// Hacky transform "::part(foo bar)" to "::part(foo,bar)" so that
// SIMPLE_SELECTOR_SEP isn't confused by the spaces.
// TODO(aomarks) Can we make SIMPLE_SELECTOR_SEP smarter instead?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to work this out, but acknowledge that it may be non-trivial.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged. Leaving for now with TODO.

selector = selector.replace(PART, (m) => m.replace(' ', ','));
}
// Preserve selectors like `:-webkit-any` so that SIMPLE_SELECTOR_SEP does
// not get confused by spaces inside the pseudo selector
const isMatches = MATCHES.test(selector);
Expand Down Expand Up @@ -350,6 +357,8 @@ class StyleTransformer {
let slottedIndex = selector.indexOf(SLOTTED);
if (selector.indexOf(HOST) >= 0) {
selector = this._transformHostSelector(selector, hostScope);
} else if (!disableShadowParts && selector.match(PART)) {
selector = this._transformPartSelector(selector, hostScope);
// replace other selectors with scoping class
} else if (slottedIndex !== 0) {
selector = scope ? this._transformSimpleSelector(selector, scope) :
Expand Down Expand Up @@ -396,6 +405,20 @@ class StyleTransformer {
return output.join('');
}

_transformPartSelector(selector, scope) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doc with an example transformation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

const parsed = parsePartSelector(selector);
if (parsed === null) {
return selector;
}
const {combinators, elementName, selectors, parts, pseudos} = parsed;
// Earlier we did a hacky transform from "part(foo bar)" to "part(foo,bar)"
// so that the SIMPLE_SELECTOR regex didn't get confused by spaces.
const partSelector =
formatShadyPartSelector(scope, elementName, parts.replace(',', ' '));
return (scope === 'document' ? '' : scope + ' ') +
`${combinators}${elementName}${selectors} ${partSelector}${pseudos}`;
}

// :host(...) -> scopeName...
_transformHostSelector(selector, hostScope) {
let m = selector.match(HOST_PAREN);
Expand Down Expand Up @@ -457,6 +480,8 @@ class StyleTransformer {
return '';
} else if (selector.match(SLOTTED)) {
return this._transformComplexSelector(selector, SCOPE_DOC_SELECTOR);
} else if (!disableShadowParts && selector.match(PART)) {
return this._transformPartSelector(selector, 'document');
} else {
return this._transformSimpleSelector(selector.trim(), SCOPE_DOC_SELECTOR);
}
Expand All @@ -470,6 +495,7 @@ const SIMPLE_SELECTOR_SEP = /(^|[\s>+~]+)((?:\[.+?\]|[^\s>+~=[])+)/g;
const SIMPLE_SELECTOR_PREFIX = /[[.:#*]/;
const HOST = ':host';
const ROOT = ':root';
const PART = /::part\([^)]*\)/;
const SLOTTED = '::slotted';
const SLOTTED_START = new RegExp(`^(${SLOTTED})`);
// NOTE: this supports 1 nested () pair for things like
Expand Down
6 changes: 6 additions & 0 deletions packages/shadydom/src/patches/Node.js
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,12 @@ export const NodePatches = utils.getOwnPropertyDescriptors({
} else if (node.ownerDocument !== this.ownerDocument) {
this.ownerDocument.adoptNode(node);
}
if (!utils.disableShadowParts) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See previous comment about performance concerns and consider instead a tighter integration at https://github.com/webcomponents/polyfills/blob/master/packages/shadydom/src/patches/Node.js#L311-L333.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged. Added TODO and filed #345 for upcoming task.

const shim = getScopingShim();
if (shim) {
shim['onInsertBefore'](this, node, ref_node);
}
}
return node;
},

Expand Down
2 changes: 1 addition & 1 deletion packages/shadydom/src/style-scoping.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,4 @@ export function treeVisitor(node, visitorFn) {
treeVisitor(n, visitorFn);
}
}
}
}
4 changes: 4 additions & 0 deletions packages/shadydom/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import {shadyDataForNode} from './shady-data.js';
/** @type {!Object} */
export const settings = window['ShadyDOM'] || {};

/** @type {boolean} */
export const disableShadowParts =
Boolean(window['ShadyCSS'] && window['ShadyCSS']['disableShadowParts']);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be true if ShadyCSS does not exist?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, should it? If there's no ShadyCSS, then the user hasn't set any initialization flags, so the default should hold, which would be disableShadowParts set to false.


settings.hasNativeShadowDOM = Boolean(Element.prototype.attachShadow && Node.prototype.getRootNode);

// The user might need to pass the custom elements polyfill a flag by setting an
Expand Down
22 changes: 17 additions & 5 deletions packages/tests/shadycss/runner.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@

<script src="../node_modules/wct-browser-legacy/browser.js"></script>

<script>
(function(){
<script type="module">
import {suites as shadowPartsSuites} from './shadow-parts/suites.js';

var suites = [
'css-parse.html',
'apply-shim.html',
Expand All @@ -38,7 +39,8 @@
'wc-1.html',
'scoping-api.html',
'mixin-fallbacks.html',
'interface.html'
'interface.html',
...shadowPartsSuites.map((file) => `shadow-parts/${file}`),
];

// http://eddmann.com/posts/cartesian-product-in-javascript/
Expand Down Expand Up @@ -71,7 +73,9 @@
webcomponents = 'wc-register=true';
}
// if native is available, make sure to test polyfill
if (Element.prototype.attachShadow && document.documentElement.getRootNode) {
const hasNativeShadow =
Element.prototype.attachShadow && document.documentElement.getRootNode;
if (hasNativeShadow) {
webcomponents = addUrlOption(webcomponents, 'wc-shadydom=true');
}
// ce + sd becomes a single test iteration.
Expand Down Expand Up @@ -110,6 +114,14 @@
]);
}

// Skip shadow part tests if the browser supports shadow DOM but not shadow
// parts, unless we are forcing the polyfill on. ShadyCSS doesn't polyfill
// just shadow parts on top of native shadow DOM, so these would fail.
const hasNativeParts = 'part' in HTMLElement.prototype;
if (hasNativeShadow && !hasNativeParts) {
suites = suites.filter((url) =>
!(url.startsWith('shadow-parts/') && !url.includes('wc-shadydom')));
}

WCT.loadSuites(suites);
})();
</script>
21 changes: 21 additions & 0 deletions packages/tests/shadycss/shadow-parts/all-native.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<!--
@license
Copyright (c) 2020 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->

<title>shadycss/shadow-parts/all-native</title>

<script src="../../node_modules/wct-browser-legacy/browser.js"></script>

<!-- This suite is just for more convenient local test execution. -->
<script type="module">
import {suites} from './suites';

WCT.loadSuites(suites);
</script>
26 changes: 26 additions & 0 deletions packages/tests/shadycss/shadow-parts/all-polyfilled.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<!--
@license
Copyright (c) 2020 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->

<title>shadycss/shadow-parts/all-polyfilled</title>

<script src="../../node_modules/wct-browser-legacy/browser.js"></script>

<!-- This suite is just for more convenient local test execution. -->
<script type="module">
import {suites} from './suites';

WCT.loadSuites(
suites.map(
(url) =>
url + "?wc-register=true&wc-shadydom=true&wc-shimcssproperties=true"
)
);
</script>
Loading