mirror of
https://github.com/jlengrand/open-wc.git
synced 2026-03-10 08:31:19 +00:00
docs(testing-helpers): types for ScopedElementsMixin
This commit is contained in:
committed by
Benny Powers
parent
f265d9e9d5
commit
9b827e7156
@@ -6,7 +6,9 @@ import { defineScopedElement, registerElement } from './registerElement.js';
|
||||
import { shadyTemplateFactory } from './shadyTemplateFactory.js';
|
||||
|
||||
/**
|
||||
* @typedef {import('./types').ScopedElementsMixin} ScopedElementsMixin
|
||||
* @typedef {import('./types').ScopedElementsMap} ScopedElementsMap
|
||||
* @typedef {import("lit-element").LitElement} LitElement
|
||||
* @typedef {import('lit-html/lib/shady-render').ShadyRenderOptions} ShadyRenderOptions
|
||||
* @typedef {function(TemplateResult, Element|DocumentFragment|ShadowRoot, ShadyRenderOptions): void} RenderFunction
|
||||
*/
|
||||
@@ -111,64 +113,63 @@ const scopedElementsTemplateFactory = (
|
||||
return shadyTemplateFactory(scopeName)(newTemplate);
|
||||
};
|
||||
|
||||
export const ScopedElementsMixin = dedupeMixin(
|
||||
superclass =>
|
||||
// eslint-disable-next-line no-shadow
|
||||
class ScopedElementsMixin extends superclass {
|
||||
/**
|
||||
* Obtains the scoped elements definitions map
|
||||
*
|
||||
* @returns {ScopedElementsMap}
|
||||
*/
|
||||
static get scopedElements() {
|
||||
return {};
|
||||
/** @type {ScopedElementsMixin} */
|
||||
const ScopedElementsMixinImplementation = superclass =>
|
||||
class ScopedElementsHost extends superclass {
|
||||
/**
|
||||
* Obtains the scoped elements definitions map
|
||||
*
|
||||
* @returns {ScopedElementsMap}
|
||||
*/
|
||||
static get scopedElements() {
|
||||
return {};
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static render(template, container, options) {
|
||||
if (!options || typeof options !== 'object' || !options.scopeName) {
|
||||
throw new Error('The `scopeName` option is required.');
|
||||
}
|
||||
const { scopeName } = options;
|
||||
|
||||
/** @override */
|
||||
static render(template, container, options) {
|
||||
if (!options || typeof options !== 'object' || !options.scopeName) {
|
||||
throw new Error('The `scopeName` option is required.');
|
||||
}
|
||||
const { scopeName } = options;
|
||||
const templateCache = getTemplateCache(this);
|
||||
const tagsCache = getTagsCache(this);
|
||||
const { scopedElements } = this;
|
||||
|
||||
const templateCache = getTemplateCache(this);
|
||||
const tagsCache = getTagsCache(this);
|
||||
const { scopedElements } = this;
|
||||
return super.render(template, container, {
|
||||
...options,
|
||||
templateFactory: scopedElementsTemplateFactory(
|
||||
scopeName,
|
||||
scopedElements,
|
||||
templateCache,
|
||||
tagsCache,
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
return super.render(template, container, {
|
||||
...options,
|
||||
templateFactory: scopedElementsTemplateFactory(
|
||||
scopeName,
|
||||
scopedElements,
|
||||
templateCache,
|
||||
tagsCache,
|
||||
),
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Defines a scoped element
|
||||
*
|
||||
* @param {string} tagName
|
||||
* @param {typeof HTMLElement} klass
|
||||
*/
|
||||
defineScopedElement(tagName, klass) {
|
||||
return defineScopedElement(tagName, klass, getTagsCache(this.constructor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a scoped element
|
||||
*
|
||||
* @param {string} tagName
|
||||
* @param {typeof HTMLElement} klass
|
||||
*/
|
||||
defineScopedElement(tagName, klass) {
|
||||
return defineScopedElement(tagName, klass, getTagsCache(this.constructor));
|
||||
}
|
||||
/**
|
||||
* Returns a scoped tag name
|
||||
*
|
||||
* @param {string} tagName
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
static getScopedTagName(tagName) {
|
||||
const klass = this.scopedElements[tagName];
|
||||
|
||||
/**
|
||||
* Returns a scoped tag name
|
||||
*
|
||||
* @param {string} tagName
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
static getScopedTagName(tagName) {
|
||||
const klass = this.scopedElements[tagName];
|
||||
return klass
|
||||
? registerElement(tagName, klass, getTagsCache(this))
|
||||
: getTagsCache(this).get(tagName);
|
||||
}
|
||||
};
|
||||
|
||||
return klass
|
||||
? registerElement(tagName, klass, getTagsCache(this))
|
||||
: getTagsCache(this).get(tagName);
|
||||
}
|
||||
},
|
||||
);
|
||||
export const ScopedElementsMixin = dedupeMixin(ScopedElementsMixinImplementation);
|
||||
|
||||
24
packages/scoped-elements/src/types.d.ts
vendored
24
packages/scoped-elements/src/types.d.ts
vendored
@@ -1,3 +1,27 @@
|
||||
import { Constructor } from "@open-wc/dedupe-mixin";
|
||||
import { LitElement } from "lit-element";
|
||||
|
||||
export type ScopedElementsMap = {
|
||||
[key: string]: typeof HTMLElement;
|
||||
}
|
||||
|
||||
export declare class ScopedElementsHost {
|
||||
/**
|
||||
* Obtains the scoped elements definitions map
|
||||
*/
|
||||
static scopedElements: ScopedElementsMap;
|
||||
|
||||
/**
|
||||
* Returns a scoped tag name
|
||||
*/
|
||||
static getScopedTagName(tagName: string): string;
|
||||
|
||||
/**
|
||||
* Defines a scoped element
|
||||
*/
|
||||
defineScopedElement<T extends HTMLElement>(tagName: string, klass: Constructor<T>): void
|
||||
}
|
||||
|
||||
declare function ScopedElementsMixinImplementation<T extends Constructor<LitElement>>(superclass: T): T & Constructor<ScopedElementsHost>
|
||||
|
||||
export type ScopedElementsMixin = typeof ScopedElementsMixinImplementation;
|
||||
|
||||
@@ -22,7 +22,6 @@ describe('ScopedElementsMixin', () => {
|
||||
it('has a default value for "static get scopedElements()" of {}', async () => {
|
||||
const tag = defineCE(class extends ScopedElementsMixin(LitElement) {});
|
||||
const el = await fixture(`<${tag}></${tag}>`);
|
||||
// @ts-ignore
|
||||
expect(el.constructor.scopedElements).to.deep.equal({});
|
||||
});
|
||||
|
||||
@@ -257,7 +256,6 @@ describe('ScopedElementsMixin', () => {
|
||||
expect(el.shadowRoot.children[1]).to.not.be.an.instanceOf(FeatureB);
|
||||
expect(el.shadowRoot.children[2]).to.not.undefined;
|
||||
|
||||
// @ts-ignore
|
||||
el.defineScopedElement('feature-b', FeatureB);
|
||||
|
||||
expect(el.shadowRoot.children[1]).to.be.an.instanceOf(FeatureB);
|
||||
@@ -359,9 +357,7 @@ describe('ScopedElementsMixin', () => {
|
||||
|
||||
const el = await fixture(`<${tag}></${tag}>`);
|
||||
|
||||
// @ts-ignore
|
||||
expect(el.constructor.getScopedTagName('feature-a')).to.match(tagRegExp);
|
||||
// @ts-ignore
|
||||
expect(el.constructor.getScopedTagName('feature-b')).to.match(tagRegExp);
|
||||
});
|
||||
|
||||
@@ -387,7 +383,6 @@ describe('ScopedElementsMixin', () => {
|
||||
|
||||
const el = await fixture(`<${tag}></${tag}>`);
|
||||
|
||||
// @ts-ignore
|
||||
expect(el.constructor.getScopedTagName('unregistered-feature')).to.match(tagRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,8 @@ import { getScopedElementsTemplate } from './scopedElementsWrapper.js';
|
||||
|
||||
/**
|
||||
* @typedef {
|
||||
import('lit-html').TemplateResult | import('lit-html').TemplateResult[]
|
||||
import('lit-html').TemplateResult
|
||||
| import('lit-html').TemplateResult[]
|
||||
| Node | Node[]
|
||||
| string | string[]
|
||||
| number | number[]
|
||||
@@ -59,16 +60,20 @@ export function litFixtureSync(template, options = {}) {
|
||||
* @returns {Promise<T>}
|
||||
*/
|
||||
export async function litFixture(template, options = {}) {
|
||||
/** @type {T} */
|
||||
// NB: in the case of scopedElements, this is ScopedElementsTestWrapper, not T,
|
||||
// but that's only a small lie
|
||||
const el = litFixtureSync(template, options);
|
||||
await elementUpdated(el);
|
||||
|
||||
if (options.scopedElements) {
|
||||
const [node] = Array.from(el.shadowRoot.childNodes).filter(isUsefulNode);
|
||||
await elementUpdated(/** @type {T} */ (node));
|
||||
const [node] =
|
||||
/** @type {T[]} */
|
||||
(Array.from(el.shadowRoot.childNodes).filter(isUsefulNode));
|
||||
await elementUpdated(node.firstElementChild);
|
||||
|
||||
return /** @type {T} */ (node);
|
||||
return node;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
return el;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ScopedElementsMixin } from '@open-wc/scoped-elements';
|
||||
import { html, LitElement, TemplateResult } from 'lit-element';
|
||||
import { nothing } from 'lit-html';
|
||||
import { isIterable } from './lib.js';
|
||||
|
||||
/** @typedef {import('@open-wc/scoped-elements').ScopedElementsMap} ScopedElementsMap */
|
||||
@@ -31,13 +30,13 @@ class ScopedElementsTestWrapper extends ScopedElementsMixin(LitElement) {
|
||||
/** @type {ScopedElementsMap} */
|
||||
this.scopedElements = {};
|
||||
|
||||
/** @type {TemplateResult|{}} */
|
||||
this.template = nothing;
|
||||
/** @type {import('./litFixture').LitHTMLRenderable} */
|
||||
// eslint-disable-next-line babel/no-unused-expressions
|
||||
this.template;
|
||||
}
|
||||
|
||||
async firstUpdated() {
|
||||
// @ts-ignore
|
||||
await super.firstUpdated();
|
||||
firstUpdated(_changed) {
|
||||
super.firstUpdated(_changed);
|
||||
|
||||
Object.keys(this.scopedElements).forEach(key =>
|
||||
this.defineScopedElement(key, this.scopedElements[key]),
|
||||
@@ -49,7 +48,6 @@ class ScopedElementsTestWrapper extends ScopedElementsMixin(LitElement) {
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
customElements.define('scoped-elements-test-wrapper', ScopedElementsTestWrapper);
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user