fix(core): scoped slots
This commit is contained in:
parent
e913489344
commit
66531e3c93
3 changed files with 71 additions and 17 deletions
5
.changeset/green-rocks-rule.md
Normal file
5
.changeset/green-rocks-rule.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@lion/core': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
SlotMixin: support scoped elements
|
||||||
|
|
@ -39,7 +39,11 @@ const SlotMixinImplementation = superclass =>
|
||||||
* @param {import('@lion/core').TemplateResult} template
|
* @param {import('@lion/core').TemplateResult} template
|
||||||
*/
|
*/
|
||||||
__renderAsNodes(template) {
|
__renderAsNodes(template) {
|
||||||
const tempRenderTarget = document.createElement('div');
|
// @ts-expect-error wait for browser support
|
||||||
|
const supportsScopedRegistry = !!ShadowRoot.prototype.createElement;
|
||||||
|
const registryRoot = supportsScopedRegistry ? this.shadowRoot : document;
|
||||||
|
// @ts-expect-error wait for browser support
|
||||||
|
const tempRenderTarget = registryRoot.createElement('div');
|
||||||
render(template, tempRenderTarget, this.renderOptions);
|
render(template, tempRenderTarget, this.renderOptions);
|
||||||
return Array.from(tempRenderTarget.childNodes);
|
return Array.from(tempRenderTarget.childNodes);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,20 @@ import { defineCE, expect, fixture } from '@open-wc/testing';
|
||||||
import { SlotMixin } from '../src/SlotMixin.js';
|
import { SlotMixin } from '../src/SlotMixin.js';
|
||||||
import { LitElement, ScopedElementsMixin, html } from '../index.js';
|
import { LitElement, ScopedElementsMixin, html } from '../index.js';
|
||||||
|
|
||||||
|
function mockScopedRegistry() {
|
||||||
|
// @ts-expect-error wait for browser support
|
||||||
|
ShadowRoot.prototype.createElement = () => {};
|
||||||
|
// @ts-expect-error wait for browser support
|
||||||
|
window.CustomElementRegistry = class {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function unMockScopedRegistry() {
|
||||||
|
// @ts-expect-error wait for browser support
|
||||||
|
delete ShadowRoot.prototype.createElement;
|
||||||
|
// @ts-expect-error wait for browser support
|
||||||
|
delete window.CustomElementRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
describe('SlotMixin', () => {
|
describe('SlotMixin', () => {
|
||||||
it('inserts provided element into lightdom and sets slot', async () => {
|
it('inserts provided element into lightdom and sets slot', async () => {
|
||||||
const tag = defineCE(
|
const tag = defineCE(
|
||||||
|
|
@ -188,7 +202,7 @@ describe('SlotMixin', () => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const el = await fixture(`<${tag}><${tag}>`);
|
const el = await fixture(`<${tag}></${tag}>`);
|
||||||
const slot = /** @type HTMLSpanElement */ (
|
const slot = /** @type HTMLSpanElement */ (
|
||||||
Array.from(el.children).find(elm => elm.slot === 'template')
|
Array.from(el.children).find(elm => elm.slot === 'template')
|
||||||
);
|
);
|
||||||
|
|
@ -196,14 +210,10 @@ describe('SlotMixin', () => {
|
||||||
expect(slot.tagName).to.equal('SPAN');
|
expect(slot.tagName).to.equal('SPAN');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('supports scoped elements', async () => {
|
it('supports scoped elements when polyfill loaded', async () => {
|
||||||
const scopedSpy = sinon.spy();
|
mockScopedRegistry();
|
||||||
class ScopedEl extends LitElement {
|
|
||||||
connectedCallback() {
|
class ScopedEl extends LitElement {}
|
||||||
super.connectedCallback();
|
|
||||||
scopedSpy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const tag = defineCE(
|
const tag = defineCE(
|
||||||
class extends ScopedElementsMixin(SlotMixin(LitElement)) {
|
class extends ScopedElementsMixin(SlotMixin(LitElement)) {
|
||||||
|
|
@ -222,12 +232,44 @@ describe('SlotMixin', () => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
render() {
|
||||||
super.connectedCallback();
|
return html`<slot name="template"></slot>`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// Not rendered to shadowRoot, notScopedSpy should not be called
|
let error = '';
|
||||||
const notScoped = document.createElement('not-scoped');
|
try {
|
||||||
this.appendChild(notScoped);
|
// @ts-ignore
|
||||||
|
await fixture(html`<${tag}></${tag}>`, { scopedElements: true });
|
||||||
|
} catch (e) {
|
||||||
|
// @ts-ignore
|
||||||
|
error = e.toString();
|
||||||
|
}
|
||||||
|
// it throws when it uses our temp mock (error is browser specific, so we check overlapping part)
|
||||||
|
expect(error).to.include('.importNode is not a function');
|
||||||
|
|
||||||
|
unMockScopedRegistry();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not scope elements when polyfill not loaded', async () => {
|
||||||
|
class ScopedEl extends LitElement {}
|
||||||
|
|
||||||
|
const tag = defineCE(
|
||||||
|
class extends ScopedElementsMixin(SlotMixin(LitElement)) {
|
||||||
|
static get scopedElements() {
|
||||||
|
return {
|
||||||
|
// @ts-expect-error
|
||||||
|
...super.scopedElements,
|
||||||
|
'scoped-el': ScopedEl,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get slots() {
|
||||||
|
return {
|
||||||
|
...super.slots,
|
||||||
|
template: () => html`<scoped-el></scoped-el>`,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
@ -236,7 +278,10 @@ describe('SlotMixin', () => {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
await fixture(`<${tag}><${tag}>`);
|
const docSpy = sinon.spy(document, 'createElement');
|
||||||
expect(scopedSpy).to.have.been.called;
|
await fixture(html`<${tag}></${tag}>`);
|
||||||
|
// one for the fixture, one for the scoped slot
|
||||||
|
expect(docSpy).to.have.been.calledTwice;
|
||||||
|
docSpy.restore();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue