Conversation
|
To prevent future issues with conflicting with native implementations, let's consider offering a version of this that's more of a ponyfill. For example: pony(document).createElement(tag, {customElements})
pony(element).customElements
pony(element).attachShadow({mode: 'open', customElements})This might be fairly annoying in practice and there are some options:
|
| } | ||
|
|
||
| interface ShadowRoot { | ||
| readonly ['customElementRegistry']: CustomElementRegistry | null; |
There was a problem hiding this comment.
It'd be nice for reviewing and future readers to leave links to where public APIs are specced. I think this link would be good here: https://dom.spec.whatwg.org/#dom-documentorshadowroot-customelementregistry
| // > root avoids this. | ||
| const scopeForElement = new WeakMap<Node, Element | ShadowRoot>(); | ||
|
|
||
| const registryForElement = new WeakMap< |
There was a problem hiding this comment.
Maybe choose a more descriptive name or add a comment. Maybe setRegistryForSubtree?
Also, does this implement a spec operation? If so, it'd be useful to have a link.
| const {tagName, CustomElementClass} = getTestElement(); | ||
| registry.define(tagName, CustomElementClass); | ||
| shadowRoot.innerHTML = `<${tagName}></${tagName}><div></div>`; | ||
| registry.initialize(shadowRoot); |
There was a problem hiding this comment.
what about initializing a non-shadow root parent, or initializing a subtree where some elements already have registries?
Co-authored-by: Justin Fagnani <justinfagnani@google.com>
Co-authored-by: Justin Fagnani <justinfagnani@google.com>
Co-authored-by: Justin Fagnani <justinfagnani@google.com>
Co-authored-by: Justin Fagnani <justinfagnani@google.com>
Co-authored-by: Justin Fagnani <justinfagnani@google.com>
* status reported in CustomElementRegistryPolyfill.inUse * support DSD null registries via host attribute `polyfill-shadowrootcustomelementregistry` * add additional tests to address feedback * re-order some tests * tracked scoped context now only supports valid customElementRegistry values * added ability to test native impl on Safari + bail outs for known bugs
| import {expect} from '@open-wc/testing'; | ||
|
|
||
| // prettier-ignore | ||
| import {getTestTagName, getTestElement, getShadowRoot, getHTML, createTemplate} from './utils.js'; |
There was a problem hiding this comment.
what's this import for?
| steps: | ||
| - uses: actions/checkout@v2 | ||
| - uses: actions/setup-node@v2 | ||
| - uses: actions/checkout@v4 |
There was a problem hiding this comment.
Both checkout and setup-node are at version 6 atm
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 16 | ||
| node-version: 24.5 |
There was a problem hiding this comment.
Any reason why not just 24 (latest; 24.11 atm)
| ? globalCustomElementRegistry | ||
| : optionsRegistry; | ||
| creationContext.push(customElementRegistry); | ||
| const el = createElement.call( |
There was a problem hiding this comment.
if options has an .is property, its ignored in createElement here
There was a problem hiding this comment.
additionally if .is is non-null and options.customElementRegistry exists, a NotSupportedError DOMException should be thrown. Im guessing that wouldn't happen here, because the registry is assigned after the createElement call
| options?: boolean | ImportNodeOptions | ||
| ): T { | ||
| const deep = | ||
| typeof options === 'boolean' ? options : !options?.selfOnly; |
There was a problem hiding this comment.
I think this ternary is wrong,importNode(node) results in deep = true, but it should be shallow, no?
| registry as ShimmedCustomElementsRegistry | ||
| ); | ||
| if (deep) { | ||
| node.childNodes.forEach((n) => { |
There was a problem hiding this comment.
When deep is true, I dont think this works correctly for <template> elements:
with polyfill:
<!doctype html>
<html>
<body>
<script>
window.CustomElementRegistryPolyfill = { force: true };
</script>
<script src="polyfill.js"></script>
<template id="t"><p>hello</p></template>
<script>
const t = document.getElementById("t");
console.log(document.importNode(t, true).content.textContent); //❌ ""
console.log(t.cloneNode(true).content.textContent); //❌ ""
</script>
</body>
</html>without polyfill:
<!doctype html>
<html>
<body>
<template id="t"><p>hello</p></template>
<script>
const t = document.getElementById("t");
console.log(document.importNode(t, true).content.textContent); //✅ "hello"
console.log(t.cloneNode(true).content.textContent); //✅ "hello"
</script>
</body>
</html>| root as HTMLElement | ||
| ); | ||
| } | ||
| root.childNodes.forEach((n) => this.upgrade(n)); |
There was a problem hiding this comment.
This should include nested shadowroots, e.g.:
<!doctype html>
<body>
<script>
function check(label, tag) {
const host = document.createElement("div");
host.attachShadow({ mode: "open" }).innerHTML = `<${tag}></${tag}>`;
class El extends HTMLElement {}
customElements.define(tag, El);
customElements.upgrade(host);
console.log(
label,
"element inside shadow root upgraded?",
host.shadowRoot.firstElementChild instanceof El,
);
}
check("WITHOUT polyfill:", "x-native"); // ✅ true
</script>
<script>
window.CustomElementRegistryPolyfill = { force: true };
</script>
<script src="scoped-custom-element-registry.js"></script>
<script>
check("WITH polyfill: ", "x-polyfill"); // ❌ false
</script>
</body>|
Closing. This PR has been superseded by #668. |
Fixes: #603
New proposal: whatwg/html#10854