From c5664b58aaca86639af4212adc617d6b7cbfafb0 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Mon, 18 Oct 2021 17:59:07 +0300 Subject: [PATCH] wip: manifest v1 and lit 2 --- package.json | 13 ++- src/api-demo-base.ts | 29 ++++-- src/api-demo-content.ts | 48 +++++---- src/api-demo-layout-mixin.ts | 123 +++++++++++----------- src/api-demo-styles.ts | 2 +- src/api-demo.ts | 27 +++-- src/api-docs-base.ts | 22 ++-- src/api-docs-content.ts | 44 ++++---- src/api-docs-styles.ts | 2 +- src/api-docs.ts | 22 ++-- src/api-viewer-base.ts | 32 +++--- src/api-viewer-content.ts | 65 ++++++------ src/api-viewer-demo-events.ts | 44 +++----- src/api-viewer-demo-layout.ts | 49 ++++----- src/api-viewer-demo-snippet.ts | 53 +++++----- src/api-viewer-demo.ts | 47 ++++----- src/api-viewer-docs.ts | 154 ++++++++++++++------------- src/api-viewer-mixin.ts | 47 +++++---- src/api-viewer-panel.ts | 33 +++--- src/api-viewer-styles.ts | 2 +- src/api-viewer-tab.ts | 163 ++++++++++++++--------------- src/api-viewer-tabs.ts | 46 ++++---- src/api-viewer.ts | 10 +- src/fixtures/expansion-panel.ts | 27 +++-- src/fixtures/fancy-accordion.ts | 77 +++++++------- src/fixtures/intl-currency.ts | 32 +++--- src/fixtures/progress-bar.ts | 179 +++++++++++++++----------------- src/lib/constants.ts | 7 +- src/lib/highlight-theme.ts | 2 +- src/lib/knobs.ts | 74 +++++++------ src/lib/markdown.ts | 28 +++-- src/lib/renderer.ts | 17 +-- src/lib/types.ts | 60 ++--------- src/lib/utils.ts | 30 +++++- src/shared-styles.ts | 2 +- tsconfig.json | 2 +- yarn.lock | 141 ++++++++++++++++++------- 37 files changed, 895 insertions(+), 860 deletions(-) diff --git a/package.json b/package.json index a0e967e..24c7932 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "build": "tsc", "dev": "npm run watch & npm run serve", "dist": "rimraf dist && rollup -c rollup.config.js && npm run fixtures && cp custom-elements.json dist", - "fixtures": "wca analyze src/fixtures/*.ts --format json --outFile custom-elements.json", + "fixtures": "cem analyze src/fixtures/*.ts", "lint:css": "stylelint src/*.ts", "lint:eslint": "eslint src --ext .ts", "lint:lit": "lit-analyzer src --strict", @@ -44,11 +44,10 @@ "!lib/fixtures" ], "dependencies": { - "@types/dompurify": "^2.0.4", - "dompurify": "^2.0.15", + "@types/dompurify": "^2.3.1", + "dompurify": "^2.3.3", "highlight-ts": "9.12.1-2", - "lit-element": "^2.0.0", - "lit-html": "^1.0.0", + "lit": "^2.0.2", "marked": "^2.0.0", "tslib": "^2.3.1" }, @@ -61,10 +60,10 @@ "@web/rollup-plugin-html": "^1.10.1", "deepmerge": "4.2.2", "eslint": "^8.0.0", - "eslint-config-airbnb-base": "^14.2.0", + "eslint-config-airbnb-base": "^14.2.1", "eslint-config-prettier": "^8.3.0", "eslint-plugin-import": "^2.25.2", - "eslint-plugin-lit": "1.3.0", + "eslint-plugin-lit": "1.6.1", "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-wc": "^1.3.2", "lint-staged": "^11.2.3", diff --git a/src/api-demo-base.ts b/src/api-demo-base.ts index 5550caf..1707efe 100644 --- a/src/api-demo-base.ts +++ b/src/api-demo-base.ts @@ -1,26 +1,30 @@ -import { LitElement, html, property, TemplateResult } from 'lit-element'; -import { until } from 'lit-html/directives/until.js'; -import { ElementPromise } from './lib/types.js'; +import type * as Manifest from 'custom-elements-manifest/schema'; +import type { TemplateResult } from 'lit'; + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { until } from 'lit/directives/until.js'; import { ApiViewerMixin, emptyDataWarning } from './api-viewer-mixin.js'; import './api-demo-content.js'; +import { getElements } from './lib/utils.js'; async function renderDemo( - jsonFetched: ElementPromise, + jsonFetched: Promise, selected?: string, id?: number, exclude = '' ): Promise { - const elements = await jsonFetched; + const elements = await getElements(jsonFetched); const index = elements.findIndex((el) => el.name === selected); return elements.length ? html` = 0 ? index : 0} + .exclude=${exclude} + .vid=${id} > ` : emptyDataWarning; @@ -42,7 +46,12 @@ export class ApiDemoBase extends ApiViewerMixin(LitElement) { protected render(): TemplateResult { return html` ${until( - renderDemo(this.jsonFetched, this.selected, this._id, this.excludeKnobs) + renderDemo( + Promise.resolve(this.jsonFetched ?? null), + this.selected, + this._id, + this.excludeKnobs + ) )} `; } diff --git a/src/api-demo-content.ts b/src/api-demo-content.ts index f330eb8..e2dc403 100644 --- a/src/api-demo-content.ts +++ b/src/api-demo-content.ts @@ -1,17 +1,15 @@ -import { - LitElement, - html, - customElement, - property, - TemplateResult -} from 'lit-element'; -import { ElementInfo } from './lib/types.js'; +import type * as Manifest from 'custom-elements-manifest/schema'; +import type { TemplateResult } from 'lit'; + +import { LitElement, html } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; + import { EMPTY_ELEMENT } from './lib/constants.js'; import './api-viewer-demo.js'; @customElement('api-demo-content') export class ApiDemoContent extends LitElement { - @property({ attribute: false }) elements: ElementInfo[] = []; + @property({ attribute: false }) elements: Manifest.CustomElement[] = []; @property({ type: Number }) selected = 0; @@ -19,14 +17,20 @@ export class ApiDemoContent extends LitElement { @property({ type: Number }) vid?: number; - protected createRenderRoot() { + protected createRenderRoot(): this { return this; } protected render(): TemplateResult { const { elements, selected, exclude, vid } = this; - const { name, properties, slots, events, cssProperties } = { + const { + name, + members = [], + slots, + events, + cssProperties + } = { ...EMPTY_ELEMENT, ...(elements[selected] || {}) }; @@ -42,26 +46,26 @@ export class ApiDemoContent extends LitElement { `; } diff --git a/src/api-demo-layout-mixin.ts b/src/api-demo-layout-mixin.ts index 3b94871..8042360 100644 --- a/src/api-demo-layout-mixin.ts +++ b/src/api-demo-layout-mixin.ts @@ -1,15 +1,20 @@ -import { LitElement, property, PropertyValues } from 'lit-element'; -import { getSlotDefault } from './lib/knobs.js'; +import type * as Manifest from 'custom-elements-manifest/schema'; +import type { PropertyValues } from 'lit'; + +import { LitElement } from 'lit'; +import { property } from 'lit/decorators.js'; + +import { getSlotDefault, Knob } from './lib/knobs.js'; + import { ComponentWithProps, - CSSPropertyInfo, - PropertyInfo, - SlotInfo, - SlotValue, - EventInfo, KnobValues, - KnobValue + KnobValue, + SlotWithContent, + Prop, + CSSProp } from './lib/types.js'; + import { getTemplates, hasTemplate, @@ -23,7 +28,7 @@ import { const { HOST, KNOB } = TemplateTypes; const getDefault = ( - prop: PropertyInfo + prop: Prop ): string | number | boolean | null | undefined => { const { type, default: value } = prop; switch (normalizeType(type)) { @@ -62,16 +67,16 @@ export type Constructor = new (...args: any[]) => T; export interface ApiDemoLayoutInterface { tag: string; - props: PropertyInfo[]; - slots: SlotInfo[]; - events: EventInfo[]; - cssProps: CSSPropertyInfo[]; + members: Prop[]; + slots: Manifest.Slot[]; + events: Manifest.Event[]; + cssProps: Manifest.CssCustomProperty[]; exclude: string; vid?: number; - processedSlots: SlotValue[]; - processedCss: CSSPropertyInfo[]; + processedSlots: SlotWithContent[]; + processedCss: Manifest.CssCustomProperty[]; eventLog: CustomEvent[]; - customKnobs: PropertyInfo[]; + customKnobs: Knob[]; knobs: KnobValues; setKnobs(target: HTMLInputElement): void; setSlots(target: HTMLInputElement): void; @@ -86,37 +91,37 @@ export const ApiDemoLayoutMixin = >( @property() tag = ''; @property({ attribute: false }) - props: PropertyInfo[] = []; + members: Prop[] = []; @property({ attribute: false }) - slots: SlotInfo[] = []; + slots: Manifest.Slot[] = []; @property({ attribute: false }) - events: EventInfo[] = []; + events: Manifest.Event[] = []; @property({ attribute: false }) - cssProps: CSSPropertyInfo[] = []; + cssProps: CSSProp[] = []; @property() exclude = ''; @property({ type: Number }) vid?: number; @property({ attribute: false }) - processedSlots: SlotValue[] = []; + processedSlots: SlotWithContent[] = []; @property({ attribute: false }) - processedCss: CSSPropertyInfo[] = []; + processedCss: Manifest.CssCustomProperty[] = []; @property({ attribute: false }) eventLog: CustomEvent[] = []; @property({ attribute: false }) - customKnobs: PropertyInfo[] = []; + customKnobs: Knob[] = []; @property({ attribute: false }) knobs: KnobValues = {}; - private _savedProps: PropertyInfo[] = []; + private _savedProps: Prop[] = []; protected firstUpdated(props: PropertyValues) { // When a selected tag name is changed by the user, @@ -125,7 +130,7 @@ export const ApiDemoLayoutMixin = >( if (props.has('props')) { const element = document.createElement(this.tag); // Store properties without getters - this._savedProps = this.props.filter( + this._savedProps = this.members.filter( ({ name }) => !isGetter(element, name) ); } @@ -134,12 +139,12 @@ export const ApiDemoLayoutMixin = >( protected updated(props: PropertyValues) { if (props.has('exclude')) { - this.props = this._filterProps(); + this.members = this._filterProps(); } if (props.has('slots') && this.slots) { this.processedSlots = this.slots - .sort((a: SlotInfo, b: SlotInfo) => { + .sort((a, b) => { if (a.name === '') { return 1; } @@ -148,20 +153,18 @@ export const ApiDemoLayoutMixin = >( } return a.name.localeCompare(b.name); }) - .map((slot: SlotInfo) => { - return { - ...slot, - content: getSlotDefault(slot.name, 'content') - }; - }); + .map((slot) => ({ + ...slot, + content: getSlotDefault(slot.name, 'content') + })); } } - private _getCustomKnobs() { + private _getCustomKnobs(): Knob[] { return getTemplates(this.vid as number, this.tag, KNOB) .map((template) => { const { attr, type } = template.dataset; - let result = null; + let result: Knob; if (attr) { if (type === 'select') { const node = getTemplateNode(template); @@ -177,7 +180,7 @@ export const ApiDemoLayoutMixin = >( result = { name: attr, attribute: attr, - type, + type: { text: type }, options }; } @@ -186,32 +189,32 @@ export const ApiDemoLayoutMixin = >( result = { name: attr, attribute: attr, - type + type: { text: type } }; } } return result; }) - .filter(Boolean) as PropertyInfo[]; + .filter(Boolean); } private _filterProps() { const exclude = this.exclude.split(','); return this._savedProps .filter(({ name }) => !exclude.includes(name)) - .map((prop: PropertyInfo) => { - return typeof prop.default === 'string' + .map((prop) => + typeof prop.default === 'string' ? { ...prop, value: getDefault(prop) } - : prop; - }); + : prop + ); } - private _getProp(name: string): { prop?: PropertyInfo; custom?: boolean } { + private _getProp(name: string): { prop?: Prop; custom?: boolean } { const isMatch = isPropMatch(name); - const prop = this.props.find(isMatch); + const prop = this.members.find(isMatch); return prop ? { prop } : { @@ -223,14 +226,14 @@ export const ApiDemoLayoutMixin = >( setCss(target: HTMLInputElement) { const { value, dataset } = target; - this.processedCss = this.processedCss.map((prop) => { - return prop.name === dataset.name + this.processedCss = this.processedCss.map((prop) => + prop.name === dataset.name ? { ...prop, value } - : prop; - }); + : prop + ); } setKnobs(target: HTMLInputElement) { @@ -261,14 +264,14 @@ export const ApiDemoLayoutMixin = >( const name = target.dataset.slot; const content = target.value; - this.processedSlots = this.processedSlots.map((slot) => { - return slot.name === name + this.processedSlots = this.processedSlots.map((slot) => + slot.name === name ? { ...slot, content } - : slot; - }); + : slot + ); } onRendered(e: CustomEvent) { @@ -276,8 +279,9 @@ export const ApiDemoLayoutMixin = >( if (hasTemplate(this.vid as number, this.tag, HOST)) { // Apply property values from template - this.props + this.members .filter((prop) => { + // todo: filter methods const { name, type } = prop; const defaultValue = getDefault(prop); return ( @@ -322,24 +326,25 @@ export const ApiDemoLayoutMixin = >( } } - private _syncKnob(component: Element, changed: PropertyInfo) { + private _syncKnob(component: Element, changed: Prop) { const { name, type, attribute } = changed; const value = (component as unknown as ComponentWithProps)[name]; // update knobs to avoid duplicate event this.knobs = { ...this.knobs, - [name]: { type, value, attribute } + [name]: { type: type?.text ?? '', value, attribute } }; - this.props = this.props.map((prop) => { - return prop.name === name + this.members = this.members.map((prop) => + // todo: filter methods + prop.name === name ? { ...prop, value } - : prop; - }); + : prop + ); } } diff --git a/src/api-demo-styles.ts b/src/api-demo-styles.ts index f674410..b58b815 100644 --- a/src/api-demo-styles.ts +++ b/src/api-demo-styles.ts @@ -1,4 +1,4 @@ -import { css } from 'lit-element'; +import { css } from 'lit'; export default css` button { diff --git a/src/api-demo.ts b/src/api-demo.ts index 996ea4d..96e39cc 100644 --- a/src/api-demo.ts +++ b/src/api-demo.ts @@ -1,4 +1,5 @@ -import { customElement, css } from 'lit-element'; +import { css } from 'lit'; +import { customElement } from 'lit/decorators.js'; import { ApiDemoBase } from './api-demo-base.js'; import { setTemplates } from './lib/utils.js'; import demoStyles from './api-demo-styles.js'; @@ -6,23 +7,21 @@ import sharedStyles from './shared-styles.js'; @customElement('api-demo') export class ApiDemo extends ApiDemoBase { - static get styles() { - return [ - sharedStyles, - demoStyles, - css` - api-demo-content { - display: block; - } - ` - ]; - } + static readonly styles = [ + sharedStyles, + demoStyles, + css` + api-demo-content { + display: block; + } + ` + ]; - protected firstUpdated() { + protected firstUpdated(): void { this.setTemplates(); } - public setTemplates(templates?: HTMLTemplateElement[]) { + public setTemplates(templates?: HTMLTemplateElement[]): void { setTemplates( this._id as number, templates || Array.from(this.querySelectorAll('template')) diff --git a/src/api-docs-base.ts b/src/api-docs-base.ts index 6d4faef..165622e 100644 --- a/src/api-docs-base.ts +++ b/src/api-docs-base.ts @@ -1,22 +1,26 @@ -import { LitElement, html, TemplateResult } from 'lit-element'; -import { until } from 'lit-html/directives/until.js'; -import { ElementPromise } from './lib/types.js'; +import type * as Manifest from 'custom-elements-manifest/schema'; +import type { TemplateResult } from 'lit'; + +import { LitElement, html } from 'lit'; +import { until } from 'lit/directives/until.js'; + import { ApiViewerMixin, emptyDataWarning } from './api-viewer-mixin.js'; import './api-docs-content.js'; +import { getElements } from './lib/utils.js'; async function renderDocs( - jsonFetched: ElementPromise, + jsonFetched: Promise, selected?: string ): Promise { - const elements = await jsonFetched; + const elements = await getElements(jsonFetched); const index = elements.findIndex((el) => el.name === selected); return elements.length ? html` = 0 ? index : 0} > ` : emptyDataWarning; @@ -24,6 +28,8 @@ async function renderDocs( export class ApiDocsBase extends ApiViewerMixin(LitElement) { protected render(): TemplateResult { - return html`${until(renderDocs(this.jsonFetched, this.selected))}`; + return html`${until( + renderDocs(Promise.resolve(this.jsonFetched ?? null), this.selected) + )}`; } } diff --git a/src/api-docs-content.ts b/src/api-docs-content.ts index 59c1841..b647780 100644 --- a/src/api-docs-content.ts +++ b/src/api-docs-content.ts @@ -1,22 +1,20 @@ -import { - LitElement, - html, - customElement, - property, - TemplateResult -} from 'lit-element'; -import { ElementInfo } from './lib/types.js'; +import type * as Manifest from 'custom-elements-manifest/schema'; +import type { TemplateResult } from 'lit'; + +import { LitElement, html } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; + import { EMPTY_ELEMENT } from './lib/constants.js'; import { parse } from './lib/markdown.js'; import './api-viewer-docs.js'; @customElement('api-docs-content') export class ApiDocsContent extends LitElement { - @property({ attribute: false }) elements: ElementInfo[] = []; + @property({ attribute: false }) elements: Manifest.CustomElement[] = []; @property({ type: Number }) selected = 0; - protected createRenderRoot() { + protected createRenderRoot(): this { return this; } @@ -26,7 +24,7 @@ export class ApiDocsContent extends LitElement { const { name, description, - properties, + members, attributes, slots, events, @@ -45,29 +43,29 @@ export class ApiDocsContent extends LitElement { -
+
${parse(description)}
`; } diff --git a/src/api-docs-styles.ts b/src/api-docs-styles.ts index 972b8ca..d2b20b6 100644 --- a/src/api-docs-styles.ts +++ b/src/api-docs-styles.ts @@ -1,4 +1,4 @@ -import { css } from 'lit-element'; +import { css } from 'lit'; export default css` p, diff --git a/src/api-docs.ts b/src/api-docs.ts index ce0bdf4..9bc7fa8 100644 --- a/src/api-docs.ts +++ b/src/api-docs.ts @@ -1,21 +1,19 @@ -import { customElement, css } from 'lit-element'; +import { customElement, css } from 'lit'; import { ApiDocsBase } from './api-docs-base.js'; import docsStyles from './api-docs-styles.js'; import sharedStyles from './shared-styles.js'; @customElement('api-docs') export class ApiDocs extends ApiDocsBase { - static get styles() { - return [ - sharedStyles, - docsStyles, - css` - api-docs-content { - display: block; - } - ` - ]; - } + static readonly styles = [ + sharedStyles, + docsStyles, + css` + api-docs-content { + display: block; + } + ` + ]; } declare global { diff --git a/src/api-viewer-base.ts b/src/api-viewer-base.ts index 6be3842..92f0a64 100644 --- a/src/api-viewer-base.ts +++ b/src/api-viewer-base.ts @@ -1,29 +1,33 @@ -import { LitElement, html, property, TemplateResult } from 'lit-element'; -import { until } from 'lit-html/directives/until.js'; -import { ElementPromise } from './lib/types.js'; -import { setTemplates } from './lib/utils.js'; +import type * as Manifest from 'custom-elements-manifest/schema'; +import type { TemplateResult } from 'lit'; + +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { until } from 'lit/directives/until.js'; + +import { getElements, setTemplates } from './lib/utils.js'; import { ApiViewerMixin, emptyDataWarning } from './api-viewer-mixin.js'; import './api-viewer-content.js'; async function renderDocs( - jsonFetched: ElementPromise, + jsonFetched: Promise, section: string, selected?: string, id?: number, exclude = '' ): Promise { - const elements = await jsonFetched; + const elements = await getElements(jsonFetched); const index = elements.findIndex((el) => el.name === selected); return elements.length ? html` = 0 ? index : 0} + .exclude=${exclude} + .vid=${id} > ` : emptyDataWarning; @@ -48,7 +52,7 @@ export class ApiViewerBase extends ApiViewerMixin(LitElement) { return html` ${until( renderDocs( - this.jsonFetched, + Promise.resolve(this.jsonFetched ?? null), this.section, this.selected, this._id, @@ -58,11 +62,11 @@ export class ApiViewerBase extends ApiViewerMixin(LitElement) { `; } - protected firstUpdated() { + protected firstUpdated(): void { this.setTemplates(); } - public setTemplates(templates?: HTMLTemplateElement[]) { + public setTemplates(templates?: HTMLTemplateElement[]): void { setTemplates( this._id as number, templates || Array.from(this.querySelectorAll('template')) diff --git a/src/api-viewer-content.ts b/src/api-viewer-content.ts index 8f1f17f..eb20696 100644 --- a/src/api-viewer-content.ts +++ b/src/api-viewer-content.ts @@ -1,12 +1,9 @@ -import { - LitElement, - html, - customElement, - property, - TemplateResult -} from 'lit-element'; -import { cache } from 'lit-html/directives/cache.js'; -import { ElementInfo } from './lib/types.js'; +import type * as Manifest from 'custom-elements-manifest/schema'; +import type { TemplateResult } from 'lit'; + +import { LitElement, html } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { cache } from 'lit/directives/cache.js'; import { EMPTY_ELEMENT } from './lib/constants.js'; import { parse } from './lib/markdown.js'; import './api-viewer-docs.js'; @@ -14,7 +11,7 @@ import './api-viewer-demo.js'; @customElement('api-viewer-content') export class ApiViewerContent extends LitElement { - @property({ attribute: false }) elements: ElementInfo[] = []; + @property({ attribute: false }) elements: Manifest.CustomElement[] = []; @property({ type: Number }) selected = 0; @@ -34,7 +31,7 @@ export class ApiViewerContent extends LitElement { const { name, description, - properties, + members, attributes, slots, events, @@ -56,8 +53,8 @@ export class ApiViewerContent extends LitElement { type="radio" name="section-${this.vid}" value="docs" - ?checked="${section === 'docs'}" - @change="${this._onToggle}" + ?checked=${section === 'docs'} + @change=${this._onToggle} part="radio-button" /> @@ -66,20 +63,20 @@ export class ApiViewerContent extends LitElement { type="radio" name="section-${this.vid}" value="demo" - ?checked="${section === 'demo'}" - @change="${this._onToggle}" + ?checked=${section === 'demo'} + @change=${this._onToggle} part="radio-button" /> @@ -88,28 +85,28 @@ export class ApiViewerContent extends LitElement { ${cache( section === 'docs' ? html` -
+
${parse(description)}
` : html` ` )} diff --git a/src/api-viewer-demo-events.ts b/src/api-viewer-demo-events.ts index 664ef84..620865e 100644 --- a/src/api-viewer-demo-events.ts +++ b/src/api-viewer-demo-events.ts @@ -1,12 +1,8 @@ -import { - LitElement, - html, - customElement, - property, - TemplateResult -} from 'lit-element'; -import { nothing } from 'lit-html'; -import { cache } from 'lit-html/directives/cache.js'; +import type { TemplateResult } from 'lit'; + +import { LitElement, html, nothing } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { cache } from 'lit/directives/cache.js'; interface EventDetail { value: string | number | boolean | null | undefined; @@ -21,36 +17,30 @@ const renderDetail = (detail: EventDetail): string => { return ` detail: ${JSON.stringify(detail).replace(`"${undef}"`, undef)}`; }; -const renderEvents = (log: CustomEvent[]): TemplateResult => { - return html` - ${log.map((e) => { - const { type, detail } = e; - return html` -

- event: "${type}".${detail == null ? nothing : renderDetail(detail)} -

- `; - })} - `; -}; +const renderEvents = (log: CustomEvent[]): TemplateResult => html` + ${log.map((e) => { + const { type, detail } = e; + return html` +

+ event: ${type}.${detail == null ? nothing : renderDetail(detail)} +

+ `; + })} +`; @customElement('api-viewer-demo-events') export class ApiViewerDemoEvents extends LitElement { @property({ attribute: false }) log: CustomEvent[] = []; - protected createRenderRoot() { + protected createRenderRoot(): this { return this; } protected render(): TemplateResult { const { log } = this; return html` - ${cache( diff --git a/src/api-viewer-demo-layout.ts b/src/api-viewer-demo-layout.ts index a3e8a9c..b082f14 100644 --- a/src/api-viewer-demo-layout.ts +++ b/src/api-viewer-demo-layout.ts @@ -1,10 +1,7 @@ -import { - LitElement, - html, - customElement, - property, - TemplateResult -} from 'lit-element'; +import type { TemplateResult } from 'lit'; + +import { LitElement, html } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; import { renderer } from './lib/renderer.js'; import { cssPropRenderer, @@ -24,7 +21,7 @@ import './api-viewer-tabs.js'; export class ApiViewerDemoLayout extends ApiDemoLayoutMixin(LitElement) { @property() copyBtnText = 'copy'; - protected createRenderRoot() { + protected createRenderRoot(): this { return this; } @@ -42,32 +39,32 @@ export class ApiViewerDemoLayout extends ApiDemoLayoutMixin(LitElement) { const hideSlots = noSlots || hasTemplate(id, this.tag, TemplateTypes.SLOT); return html` -
+
${renderer(id, this.tag, this.knobs, slots, this.processedCss)}
-
-
+
${renderKnobs(this.props, 'Properties', 'prop', propRenderer)} ${renderKnobs( this.customKnobs, @@ -77,9 +74,9 @@ export class ApiViewerDemoLayout extends ApiDemoLayoutMixin(LitElement) { )}
${renderKnobs(slots, 'Slots', 'slot', slotRenderer)}
@@ -89,11 +86,11 @@ export class ApiViewerDemoLayout extends ApiDemoLayoutMixin(LitElement) { heading="Styles" slot="tab" part="tab" - ?hidden="${noCss}" + ?hidden=${noCss} > -
-
+
+
${renderKnobs( this.cssProps, 'Custom CSS Properties', @@ -108,13 +105,13 @@ export class ApiViewerDemoLayout extends ApiDemoLayoutMixin(LitElement) { heading="Events" slot="tab" part="tab" - ?hidden="${noEvents}" + ?hidden=${noEvents} > diff --git a/src/api-viewer-demo-snippet.ts b/src/api-viewer-demo-snippet.ts index 6296c19..3fd10ab 100644 --- a/src/api-viewer-demo-snippet.ts +++ b/src/api-viewer-demo-snippet.ts @@ -1,18 +1,18 @@ -import { - LitElement, - html, - customElement, - css, - property, - TemplateResult -} from 'lit-element'; -import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'; +import type * as Manifest from 'custom-elements-manifest/schema'; +import { css, TemplateResult, LitElement, html } from 'lit'; + +import { customElement, property } from 'lit/decorators.js'; + +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; + import { htmlRender } from 'highlight-ts/es/render/html'; import { registerLanguages } from 'highlight-ts/es/languages'; import { XML } from 'highlight-ts/es/languages/xml'; import { init, process } from 'highlight-ts/es/process'; -import { CSSPropertyInfo, KnobValues, SlotValue } from './lib/types.js'; + +import { CSSProp, KnobValues, SlotWithContent } from './lib/types.js'; import { CSS } from './lib/highlight-css.js'; + import { getTemplate, getTemplateNode, @@ -20,6 +20,7 @@ import { normalizeType, TemplateTypes } from './lib/utils.js'; + import highlightTheme from './lib/highlight-theme.js'; // register languages @@ -61,8 +62,8 @@ const renderSnippet = ( id: number, tag: string, values: KnobValues, - slots: SlotValue[], - cssProps: CSSPropertyInfo[] + slots: SlotWithContent[], + cssProps: CSSProp[] ): TemplateResult => { let markup = ''; const prefix = getTemplate(id, tag, PREFIX); @@ -110,7 +111,7 @@ const renderSnippet = ( markup += `${getTplContent(template, `${prepend}${INDENT}`)}\n${prepend}`; } else if (slots.length) { if (slots.length === 1 && !slots[0].name) { - markup += slots[0].content; + markup += slots[0].description; } else { markup += slots.reduce((result: string, slot) => { const { name, content } = slot; @@ -156,24 +157,22 @@ export class ApiViewerDemoSnippet extends LitElement { knobs: KnobValues = {}; @property({ attribute: false }) - slots: SlotValue[] = []; + slots: SlotWithContent[] = []; @property({ attribute: false }) - cssProps: CSSPropertyInfo[] = []; + cssProps: Manifest.CssCustomProperty[] = []; @property({ type: Number }) vid?: number; - static get styles() { - return [ - highlightTheme, - css` - :host { - display: block; - padding: 0.75rem 1rem; - } - ` - ]; - } + static readonly styles = [ + highlightTheme, + css` + :host { + display: block; + padding: 0.75rem 1rem; + } + ` + ]; protected render(): TemplateResult { return html` @@ -187,7 +186,7 @@ export class ApiViewerDemoSnippet extends LitElement { `; } - get source() { + get source(): HTMLElement | null { return this.renderRoot.querySelector('code'); } } diff --git a/src/api-viewer-demo.ts b/src/api-viewer-demo.ts index b14001e..fcbab45 100644 --- a/src/api-viewer-demo.ts +++ b/src/api-viewer-demo.ts @@ -1,35 +1,28 @@ -import { - LitElement, - html, - customElement, - property, - TemplateResult -} from 'lit-element'; -import { until } from 'lit-html/directives/until.js'; -import { - CSSPropertyInfo, - PropertyInfo, - SlotInfo, - EventInfo -} from './lib/types.js'; +import type * as Manifest from 'custom-elements-manifest/schema'; +import type { TemplateResult } from 'lit'; + +import { LitElement, html } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { until } from 'lit/directives/until.js'; import './api-viewer-demo-layout.js'; +import { Prop } from './lib/types.js'; @customElement('api-viewer-demo') export class ApiViewerDemo extends LitElement { @property() name = ''; @property({ attribute: false }) - props: PropertyInfo[] = []; + members: Prop[] = []; @property({ attribute: false }) - slots: SlotInfo[] = []; + slots: Manifest.Slot[] = []; @property({ attribute: false }) - events: EventInfo[] = []; + events: Manifest.Event[] = []; @property({ attribute: false }) - cssProps: CSSPropertyInfo[] = []; + cssProps: Manifest.CssCustomProperty[] = []; @property() exclude = ''; @@ -46,18 +39,18 @@ export class ApiViewerDemo extends LitElement { return html` `; } - protected createRenderRoot() { + protected createRenderRoot(): this { return this; } @@ -74,7 +67,7 @@ export class ApiViewerDemo extends LitElement { this.renderDemoLayout(this.whenDefined), html`
- Element "${this.name}" is not defined. Have you imported it? + Element ${this.name} is not defined. Have you imported it?
` )} diff --git a/src/api-viewer-docs.ts b/src/api-viewer-docs.ts index b094089..2c74178 100644 --- a/src/api-viewer-docs.ts +++ b/src/api-viewer-docs.ts @@ -1,19 +1,9 @@ -import { - LitElement, - html, - customElement, - property, - PropertyValues -} from 'lit-element'; -import { nothing, TemplateResult } from 'lit-html'; -import { - PropertyInfo, - SlotInfo, - AttributeInfo, - EventInfo, - CSSPartInfo, - CSSPropertyInfo -} from './lib/types.js'; +import type * as Manifest from 'custom-elements-manifest/schema'; +import type { PropertyValues, TemplateResult } from 'lit'; + +import { LitElement, html, nothing } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; + import { isPropMatch, unquote } from './lib/utils.js'; import { parse } from './lib/markdown.js'; @@ -21,6 +11,11 @@ import './api-viewer-panel.js'; import './api-viewer-tab.js'; import './api-viewer-tabs.js'; +const isClassField = (m: Manifest.ClassMember): m is Manifest.ClassField => + m.kind !== 'method'; +const isClassMethod = (m: Manifest.ClassMember): m is Manifest.ClassMethod => + m.kind === 'method'; + const renderItem = ( prefix: string, name: string, @@ -28,59 +23,57 @@ const renderItem = ( valueType?: string, value?: unknown, attribute?: string -): TemplateResult => { - return html` -
-
-
-
Name
-
${name}
-
- ${attribute === undefined - ? nothing - : html` -
-
Attribute
-
${attribute}
-
- `} - ${valueType === undefined && value === undefined - ? nothing - : html` -
-
Type
-
- ${valueType || - (Number.isNaN(Number(value)) ? typeof value : 'number')} - ${value === undefined - ? nothing - : html` = ${value} `} -
-
- `} -
-
-
Description
-
${parse(description)}
+): TemplateResult => html` +
+
+
+
Name
+
${name}
+ ${attribute === undefined + ? nothing + : html` +
+
Attribute
+
${attribute}
+
+ `} + ${valueType === undefined && value === undefined + ? nothing + : html` +
+
Type
+
+ ${valueType || + (Number.isNaN(Number(value)) ? typeof value : 'number')} + ${value === undefined + ? nothing + : html` = ${value} `} +
+
+ `}
- `; -}; +
+
Description
+
${parse(description)}
+
+
+`; const renderTab = ( heading: string, - array: unknown[], + array: (Manifest.ClassMember | Manifest.Attribute)[], content: TemplateResult ): TemplateResult => { const hidden = array.length === 0; return html` - + ${content} `; @@ -91,37 +84,36 @@ export class ApiViewerDocs extends LitElement { @property() name = ''; @property({ attribute: false }) - props: PropertyInfo[] = []; + members: Manifest.ClassMember[] = []; @property({ attribute: false }) - attrs: AttributeInfo[] = []; + attrs: Manifest.Attribute[] = []; @property({ attribute: false }) - slots: SlotInfo[] = []; + slots: Manifest.Slot[] = []; @property({ attribute: false }) - events: EventInfo[] = []; + events: Manifest.Event[] = []; @property({ attribute: false }) - cssParts: CSSPartInfo[] = []; + cssParts: Manifest.CssPart[] = []; @property({ attribute: false }) - cssProps: CSSPropertyInfo[] = []; + cssProps: Manifest.CssCustomProperty[] = []; - protected createRenderRoot() { + protected createRenderRoot(): ApiViewerDocs { return this; } protected render(): TemplateResult { - const { slots, props, attrs, events, cssParts, cssProps } = this; + const { slots, members = [], attrs, events, cssParts, cssProps } = this; - const properties = props || []; const attributes = (attrs || []).filter( - ({ name }) => !properties.some(isPropMatch(name)) + ({ name }) => !members.some(isPropMatch(name)) ); const emptyDocs = [ - properties, + members, attributes, slots, events, @@ -129,6 +121,9 @@ export class ApiViewerDocs extends LitElement { cssParts ].every((arr) => arr.length === 0); + const properties = emptyDocs ? [] : members.filter(isClassField); + const methods = emptyDocs ? [] : members.filter(isClassMethod); + return emptyDocs ? html`
@@ -143,14 +138,17 @@ export class ApiViewerDocs extends LitElement { properties, html` ${properties.map((prop) => { - const { name, description, type, attribute } = prop; + const { name, description = '', type } = prop; + const attribute = attributes.find( + (attr) => attr.fieldName === name + ); return renderItem( 'prop', name, description, - type, + type?.text ?? '', prop.default, - attribute + attribute?.name ); })} ` @@ -159,8 +157,8 @@ export class ApiViewerDocs extends LitElement { 'Attributes', attributes, html` - ${attributes.map(({ name, description, type }) => - renderItem('attr', name, description, type) + ${attributes.map(({ name, description = '', type }) => + renderItem('attr', name, description, type?.text) )} ` )} @@ -168,7 +166,7 @@ export class ApiViewerDocs extends LitElement { 'Slots', slots, html` - ${slots.map(({ name, description }) => + ${slots.map(({ name, description = '' }) => renderItem('slot', name, description) )} ` @@ -177,7 +175,7 @@ export class ApiViewerDocs extends LitElement { 'Events', events, html` - ${events.map(({ name, description }) => + ${events.map(({ name, description = '' }) => renderItem('event', name, description) )} ` @@ -187,12 +185,12 @@ export class ApiViewerDocs extends LitElement { cssProps, html` ${cssProps.map((prop) => { - const { name, description, type } = prop; + const { name, description = '' } = prop; return renderItem( 'css', name, description, - type, + '', unquote(prop.default) ); })} @@ -202,7 +200,7 @@ export class ApiViewerDocs extends LitElement { 'CSS Shadow Parts', cssParts, html` - ${cssParts.map(({ name, description }) => + ${cssParts.map(({ name, description = '' }) => renderItem('part', name, description) )} ` @@ -211,7 +209,7 @@ export class ApiViewerDocs extends LitElement { `; } - protected updated(props: PropertyValues) { + protected updated(props: PropertyValues): void { if (props.has('name') && props.get('name')) { const tabs = this.renderRoot.querySelector('api-viewer-tabs'); if (tabs) { diff --git a/src/api-viewer-mixin.ts b/src/api-viewer-mixin.ts index af8dcbd..79a0ad7 100644 --- a/src/api-viewer-mixin.ts +++ b/src/api-viewer-mixin.ts @@ -1,37 +1,45 @@ -import { LitElement, html, property, PropertyValues } from 'lit-element'; -import { ElementInfo, ElementPromise, ElementSetInfo } from './lib/types.js'; +import type { CustomElement, Package } from 'custom-elements-manifest/schema'; +import type { PropertyValues } from 'lit'; -/* eslint-disable @typescript-eslint/no-explicit-any */ -export type Constructor = new (...args: any[]) => T; +import { LitElement, html } from 'lit'; +import { property } from 'lit/decorators.js'; +import { Constructor } from './lib/types.js'; export interface ApiViewerInterface { src?: string; - elements?: ElementInfo[]; + elements?: CustomElement[]; + + package?: Package | null; selected?: string; - jsonFetched: ElementPromise; + jsonFetched?: Promise; +} + +function hasCustomElements(pkg?: Package): boolean { + return !!pkg?.modules?.some?.((x) => + x.exports?.some?.((y) => y.kind === 'custom-element-definition') + ); } -export async function fetchJson(src: string): ElementPromise { - let result: ElementInfo[] = []; +export async function fetchJson(src: string): Promise { try { const file = await fetch(src); - const json = (await file.json()) as ElementSetInfo; - if (Array.isArray(json.tags) && json.tags.length) { - result = json.tags; + const json = (await file.json()) as Package; + if (!hasCustomElements(json)) { + throw new Error(`No element definitions found at ${src}`); } else { - console.error(`No element definitions found at ${src}`); + return json; } } catch (e) { console.error(e); + return null; } - return result; } export const emptyDataWarning = html` -
No custom elements found in the JSON file.
+
No custom elements found in the manifest.
`; export const ApiViewerMixin = >( @@ -41,20 +49,23 @@ export const ApiViewerMixin = >( @property() src?: string; @property({ attribute: false }) - elements?: ElementInfo[]; + package?: Package; + + @property({ attribute: false }) + elements?: CustomElement[]; @property() selected?: string; - jsonFetched: ElementPromise = Promise.resolve([]); + jsonFetched?: Promise = Promise.resolve(null); private lastSrc?: string; protected update(props: PropertyValues) { const { src } = this; - if (Array.isArray(this.elements)) { + if (hasCustomElements(this.package)) { this.lastSrc = undefined; - this.jsonFetched = Promise.resolve(this.elements); + this.jsonFetched = Promise.resolve(this.package ?? null); } else if (src && this.lastSrc !== src) { this.lastSrc = src; this.jsonFetched = fetchJson(src); diff --git a/src/api-viewer-panel.ts b/src/api-viewer-panel.ts index 9e9e49d..792b7d7 100644 --- a/src/api-viewer-panel.ts +++ b/src/api-viewer-panel.ts @@ -1,29 +1,22 @@ -import { - LitElement, - html, - customElement, - css, - TemplateResult -} from 'lit-element'; +import { LitElement, html, css } from 'lit'; +import { customElement } from 'lit/decorators.js'; let panelIdCounter = 0; @customElement('api-viewer-panel') export class ApiViewerPanel extends LitElement { - static get styles() { - return css` - :host { - display: block; - box-sizing: border-box; - width: 100%; - overflow: hidden; - } + static readonly styles = css` + :host { + display: block; + box-sizing: border-box; + width: 100%; + overflow: hidden; + } - :host([hidden]) { - display: none !important; - } - `; - } + :host([hidden]) { + display: none !important; + } + `; protected render(): TemplateResult { return html``; diff --git a/src/api-viewer-styles.ts b/src/api-viewer-styles.ts index 1bbff5b..7050aa1 100644 --- a/src/api-viewer-styles.ts +++ b/src/api-viewer-styles.ts @@ -1,4 +1,4 @@ -import { css } from 'lit-element'; +import { css } from 'lit'; import sharedStyles from './shared-styles.js'; import docsStyles from './api-docs-styles.js'; import demoStyles from './api-demo-styles.js'; diff --git a/src/api-viewer-tab.ts b/src/api-viewer-tab.ts index 60d9ca5..b1a0c41 100644 --- a/src/api-viewer-tab.ts +++ b/src/api-viewer-tab.ts @@ -1,12 +1,7 @@ -import { - LitElement, - html, - customElement, - css, - property, - PropertyValues, - TemplateResult -} from 'lit-element'; +import type { PropertyValues } from 'lit'; + +import { LitElement, css, html } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; let tabIdCounter = 0; @@ -20,93 +15,91 @@ export class ApiViewerTab extends LitElement { private _mousedown = false; - static get styles() { - return css` - :host { - display: flex; - align-items: center; - flex-shrink: 0; - box-sizing: border-box; - position: relative; - max-width: 150px; - overflow: hidden; - min-height: 3rem; - padding: 0 1rem; - color: var(--ave-tab-color); - font-size: 0.875rem; - line-height: 1.2; - font-weight: 500; - text-transform: uppercase; - outline: none; - cursor: pointer; - -webkit-user-select: none; - user-select: none; - -webkit-tap-highlight-color: transparent; - } + static styles = css` + :host { + display: flex; + align-items: center; + flex-shrink: 0; + box-sizing: border-box; + position: relative; + max-width: 150px; + overflow: hidden; + min-height: 3rem; + padding: 0 1rem; + color: var(--ave-tab-color); + font-size: 0.875rem; + line-height: 1.2; + font-weight: 500; + text-transform: uppercase; + outline: none; + cursor: pointer; + -webkit-user-select: none; + user-select: none; + -webkit-tap-highlight-color: transparent; + } - :host([hidden]) { - display: none !important; - } + :host([hidden]) { + display: none !important; + } - :host::before { - content: ''; - display: block; - position: absolute; - top: 0; - left: 0; - bottom: 0; - width: var(--ave-tab-indicator-size); - background-color: var(--ave-primary-color); - opacity: 0; - } + :host::before { + content: ''; + display: block; + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: var(--ave-tab-indicator-size); + background-color: var(--ave-primary-color); + opacity: 0; + } - :host([selected]) { - color: var(--ave-primary-color); - } + :host([selected]) { + color: var(--ave-primary-color); + } - :host([selected])::before { - opacity: 1; - } + :host([selected])::before { + opacity: 1; + } - :host::after { - content: ''; - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: var(--ave-primary-color); - opacity: 0; - transition: opacity 0.1s linear; - } + :host::after { + content: ''; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: var(--ave-primary-color); + opacity: 0; + transition: opacity 0.1s linear; + } - :host(:hover)::after { - opacity: 0.08; - } + :host(:hover)::after { + opacity: 0.08; + } - :host([focus-ring])::after { - opacity: 0.12; - } + :host([focus-ring])::after { + opacity: 0.12; + } - :host([active])::after { - opacity: 0.16; + :host([active])::after { + opacity: 0.16; + } + + @media (max-width: 600px) { + :host { + justify-content: center; + text-align: center; } - @media (max-width: 600px) { - :host { - justify-content: center; - text-align: center; - } - - :host::before { - top: auto; - right: 0; - width: 100%; - height: var(--ave-tab-indicator-size); - } + :host::before { + top: auto; + right: 0; + width: 100%; + height: var(--ave-tab-indicator-size); } - `; - } + } + `; protected render(): TemplateResult { return html`${this.heading}`; diff --git a/src/api-viewer-tabs.ts b/src/api-viewer-tabs.ts index e492c68..1321387 100644 --- a/src/api-viewer-tabs.ts +++ b/src/api-viewer-tabs.ts @@ -1,4 +1,8 @@ -import { LitElement, html, customElement, css } from 'lit-element'; +import type { TemplateResult } from 'lit'; + +import { LitElement, html, css } from 'lit'; +import { customElement } from 'lit/decorators.js'; + import { ApiViewerTab } from './api-viewer-tab.js'; import { ApiViewerPanel } from './api-viewer-panel.js'; @@ -15,33 +19,31 @@ const KEYCODE = { export class ApiViewerTabs extends LitElement { private _boundSlotChange = this._onSlotChange.bind(this); - static get styles() { - return css` + static readonly styles = css` + :host { + display: flex; + } + + .tabs { + display: block; + } + + @media (max-width: 600px) { :host { - display: flex; + flex-direction: column; } .tabs { - display: block; - } - - @media (max-width: 600px) { - :host { - flex-direction: column; - } - - .tabs { - flex-grow: 1; - display: flex; - align-self: stretch; - overflow-x: auto; - -webkit-overflow-scrolling: touch; - } + flex-grow: 1; + display: flex; + align-self: stretch; + overflow-x: auto; + -webkit-overflow-scrolling: touch; } - `; - } + } + `; - render() { + render(): TemplateResult { return html`
diff --git a/src/api-viewer.ts b/src/api-viewer.ts index c32a4cc..e2cf62f 100644 --- a/src/api-viewer.ts +++ b/src/api-viewer.ts @@ -1,19 +1,17 @@ -import { customElement } from 'lit-element'; +import { customElement } from 'lit/decorators.js'; import { ApiViewerBase } from './api-viewer-base.js'; import { setTemplates } from './lib/utils.js'; import styles from './api-viewer-styles.js'; @customElement('api-viewer') export class ApiViewer extends ApiViewerBase { - static get styles() { - return styles; - } + static readonly styles = styles; - protected firstUpdated() { + protected firstUpdated(): void { this.setTemplates(); } - public setTemplates(templates?: HTMLTemplateElement[]) { + public setTemplates(templates?: HTMLTemplateElement[]): void { setTemplates( this._id as number, templates || Array.from(this.querySelectorAll('template')) diff --git a/src/fixtures/expansion-panel.ts b/src/fixtures/expansion-panel.ts index 76a537d..f53bd4c 100644 --- a/src/fixtures/expansion-panel.ts +++ b/src/fixtures/expansion-panel.ts @@ -1,13 +1,10 @@ -import { - LitElement, - html, - css, - customElement, - property, - query, - PropertyValues -} from 'lit-element'; -import { styleMap } from 'lit-html/directives/style-map.js'; +import type { PropertyValues } from 'lit'; + +import { LitElement, html, css } from 'lit'; + +import { customElement, property, query } from 'lit/decorators.js'; + +import { styleMap } from 'lit/directives/style-map.js'; /** * A custom element similar to the HTML5 `
` element. @@ -179,9 +176,9 @@ export class ExpansionPanel extends LitElement {
@@ -190,8 +187,8 @@ export class ExpansionPanel extends LitElement {
diff --git a/src/fixtures/fancy-accordion.ts b/src/fixtures/fancy-accordion.ts index 9a682f3..7038ede 100644 --- a/src/fixtures/fancy-accordion.ts +++ b/src/fixtures/fancy-accordion.ts @@ -1,12 +1,9 @@ -import { - LitElement, - html, - css, - customElement, - property, - PropertyValues, - TemplateResult -} from 'lit-element'; +import type { PropertyValues, TemplateResult } from 'lit'; + +import { LitElement, html, css } from 'lit'; + +import { customElement, property } from 'lit/decorators.js'; + import { ExpansionPanel } from './expansion-panel.js'; /** @@ -40,47 +37,45 @@ export class FancyAccordion extends LitElement { private _boundOnOpened = this._onOpened.bind(this) as EventListener; - static get styles() { - return css` - :host { - display: block; - } + static readonly styles = css` + :host { + display: block; + } - :host([hidden]) { - display: none !important; - } + :host([hidden]) { + display: none !important; + } - ::slotted([opened]:not(:first-child)) { - margin-top: 16px; - } + ::slotted([opened]:not(:first-child)) { + margin-top: 16px; + } - ::slotted([opened]:not(:last-child)) { - margin-bottom: 16px; - } + ::slotted([opened]:not(:last-child)) { + margin-bottom: 16px; + } - ::slotted(:not([opened])) { - position: relative; - } + ::slotted(:not([opened])) { + position: relative; + } - ::slotted(:not([opened]))::after { - content: ''; - position: absolute; - bottom: -1px; - left: 0; - right: 0; - height: 1px; - opacity: 1; - z-index: 1; - background-color: rgba(0, 0, 0, 0.12); - } - `; - } + ::slotted(:not([opened]))::after { + content: ''; + position: absolute; + bottom: -1px; + left: 0; + right: 0; + height: 1px; + opacity: 1; + z-index: 1; + background-color: rgba(0, 0, 0, 0.12); + } + `; protected render(): TemplateResult { return html``; } - protected firstUpdated() { + protected firstUpdated(): void { this.addEventListener('keydown', (e) => this._onKeydown(e)); Array.from(this.children).forEach((node) => { @@ -91,7 +86,7 @@ export class FancyAccordion extends LitElement { }); } - protected update(props: PropertyValues) { + protected update(props: PropertyValues): void { if (props.has('openedIndex') && this._items) { const item = this.openedIndex == null ? null : this._items[this.openedIndex]; diff --git a/src/fixtures/intl-currency.ts b/src/fixtures/intl-currency.ts index 967f09f..9ac3e9e 100644 --- a/src/fixtures/intl-currency.ts +++ b/src/fixtures/intl-currency.ts @@ -1,11 +1,7 @@ -import { - LitElement, - html, - css, - customElement, - property, - TemplateResult -} from 'lit-element'; +import type { TemplateResult } from 'lit'; + +import { LitElement, html, css } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; const format = ( value: number, @@ -43,18 +39,16 @@ export class IntlCurrency extends LitElement { */ @property() locale: string | null | undefined = 'en-GB'; - static get styles() { - return css` - :host { - all: inherit; - display: inline-block; - } + static readonly styles = css` + :host { + all: inherit; + display: inline-block; + } - div { - text-decoration: inherit; - } - `; - } + div { + text-decoration: inherit; + } + `; protected render(): TemplateResult { return html` diff --git a/src/fixtures/progress-bar.ts b/src/fixtures/progress-bar.ts index 3c9ab05..7154df2 100644 --- a/src/fixtures/progress-bar.ts +++ b/src/fixtures/progress-bar.ts @@ -1,12 +1,8 @@ -import { - LitElement, - html, - css, - customElement, - property, - PropertyValues, - TemplateResult -} from 'lit-element'; +import type { PropertyValues, TemplateResult } from 'lit'; + +import { LitElement, html, css } from 'lit'; + +import { customElement, property } from 'lit/decorators.js'; const normalizeValue = (value: number, min: number, max: number) => { let nV; @@ -58,110 +54,103 @@ export class ProgressBar extends LitElement { */ @property({ type: Boolean, reflect: true }) indeterminate = false; - static get styles() { - return css` - :host { - display: block; - width: 100%; - height: 4px; - margin: 8px 0; - position: relative; - overflow: hidden; - - --progress-bar-fill-color: #6200ee; - --progress-bar-opacity: 0.16; - } + static readonly styles = css` + :host { + display: block; + width: 100%; + height: 4px; + margin: 8px 0; + position: relative; + overflow: hidden; + + --progress-bar-fill-color: #6200ee; + --progress-bar-opacity: 0.16; + } - :host::before { - content: ''; - display: block; - height: 100%; - background-color: var(--progress-bar-fill-color); - opacity: var(--progress-bar-opacity); - } + :host::before { + content: ''; + display: block; + height: 100%; + background-color: var(--progress-bar-fill-color); + opacity: var(--progress-bar-opacity); + } - :host([hidden]) { - display: none !important; - } + :host([hidden]) { + display: none !important; + } - [part='bar'] { - position: absolute; - top: 0; - width: 100%; - height: 100%; - transform: scaleX(var(--progress-value)); - transform-origin: 0 0; - } + [part='bar'] { + position: absolute; + top: 0; + width: 100%; + height: 100%; + transform: scaleX(var(--progress-value)); + transform-origin: 0 0; + } - [part='value'] { - height: 100%; - background-color: var(--progress-bar-fill-color); - } + [part='value'] { + height: 100%; + background-color: var(--progress-bar-fill-color); + } - :host([indeterminate]) [part='bar'] { - left: -100%; - animation: progress-indeterminate-translate 2s infinite linear; - } + :host([indeterminate]) [part='bar'] { + left: -100%; + animation: progress-indeterminate-translate 2s infinite linear; + } - :host([indeterminate]) [part='value'] { - animation: progress-indeterminate-scale 2s infinite linear; - } + :host([indeterminate]) [part='value'] { + animation: progress-indeterminate-scale 2s infinite linear; + } - @keyframes progress-indeterminate-translate { - 0% { - transform: translateX(0); - } - 20% { - animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819); - transform: translateX(0); - } - 59.15% { - animation-timing-function: cubic-bezier( - 0.302435, - 0.381352, - 0.55, - 0.956352 - ); - transform: translateX(83.67142%); - } - 100% { - transform: translateX(200.611057%); - } + @keyframes progress-indeterminate-translate { + 0% { + transform: translateX(0); + } + 20% { + animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819); + transform: translateX(0); + } + 59.15% { + animation-timing-function: cubic-bezier( + 0.302435, + 0.381352, + 0.55, + 0.956352 + ); + transform: translateX(83.67142%); + } + 100% { + transform: translateX(200.611057%); } + } - @keyframes progress-indeterminate-scale { - 0% { - transform: scaleX(0.08); - } - 36.65% { - animation-timing-function: cubic-bezier( - 0.334731, - 0.12482, - 0.785844, - 1 - ); - transform: scaleX(0.08); - } - 69.15% { - animation-timing-function: cubic-bezier(0.06, 0.11, 0.6, 1); - transform: scaleX(0.661479); - } - 100% { - transform: scaleX(0.08); - } + @keyframes progress-indeterminate-scale { + 0% { + transform: scaleX(0.08); } - `; - } + 36.65% { + animation-timing-function: cubic-bezier(0.334731, 0.12482, 0.785844, 1); + transform: scaleX(0.08); + } + 69.15% { + animation-timing-function: cubic-bezier(0.06, 0.11, 0.6, 1); + transform: scaleX(0.661479); + } + 100% { + transform: scaleX(0.08); + } + } + `; protected render(): TemplateResult { return html`
`; } - protected firstUpdated() { + protected firstUpdated(): void { this.setAttribute('role', 'progressbar'); } - protected updated(props: PropertyValues) { + protected updated(props: PropertyValues): void { const minChanged = props.has('min'); if (minChanged) { this._minChanged(this.min); diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 920f186..b8c395c 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -1,11 +1,12 @@ -import { ElementInfo } from './types.js'; +import type * as Manifest from 'custom-elements-manifest/schema'; -export const EMPTY_ELEMENT: ElementInfo = { +export const EMPTY_ELEMENT: Manifest.CustomElement = { + customElement: true, name: '', description: '', slots: [], attributes: [], - properties: [], + members: [], events: [], cssParts: [], cssProperties: [] diff --git a/src/lib/highlight-theme.ts b/src/lib/highlight-theme.ts index 328e9e0..0a71d4f 100644 --- a/src/lib/highlight-theme.ts +++ b/src/lib/highlight-theme.ts @@ -1,4 +1,4 @@ -import { css } from 'lit-element'; +import { css } from 'lit'; export default css` pre { diff --git a/src/lib/knobs.ts b/src/lib/knobs.ts index 25b44da..bb07111 100644 --- a/src/lib/knobs.ts +++ b/src/lib/knobs.ts @@ -1,12 +1,20 @@ -import { html, TemplateResult } from 'lit-html'; -import { CSSPropertyInfo, PropertyInfo, SlotValue } from './types.js'; +import type * as Manifest from 'custom-elements-manifest/schema'; + +import { html, TemplateResult } from 'lit'; +import { Prop } from './types.js'; import { normalizeType } from './utils.js'; const DEFAULT = 'default'; -type Knob = CSSPropertyInfo | PropertyInfo | SlotValue; +export type Knob = (Prop | Manifest.CssCustomProperty | Manifest.Slot) & { + value: string; + options: unknown; +}; -type InputRenderer = (item: Knob, id: string) => TemplateResult; +type InputRenderer = ( + item: T, + id: string +) => TemplateResult; const capitalize = (name: string) => name[0].toUpperCase() + name.slice(1); @@ -27,49 +35,49 @@ const getInputType = (type: string) => { }; export const cssPropRenderer: InputRenderer = (knob: Knob, id: string) => { - const { name, value } = knob as CSSPropertyInfo; + const { name, value } = knob; return html` `; }; export const propRenderer: InputRenderer = (knob: Knob, id: string) => { - const { name, type, value, options } = knob as PropertyInfo; + const { name, type, value, options } = knob as Knob & Prop; let input; - if (type === 'select' && Array.isArray(options)) { + if (type?.text === 'select' && Array.isArray(options)) { input = html` - ${options.map( - (option) => html`` + (option) => html`` )} `; } else if (normalizeType(type) === 'boolean') { input = html` `; } else { input = html` `; @@ -77,35 +85,37 @@ export const propRenderer: InputRenderer = (knob: Knob, id: string) => { return input; }; -export const slotRenderer: InputRenderer = (knob: Knob, id: string) => { - const { name, content } = knob as SlotValue; +export const slotRenderer: InputRenderer< + Knob & Manifest.Slot & { content: string } +> = (knob, id: string) => { + const { name, content } = knob; return html` `; }; -export const renderKnobs = ( - items: Knob[], +export const renderKnobs = ( + items: T[], header: string, type: string, - renderer: InputRenderer + renderer: InputRenderer ): TemplateResult => { - const rows = items.map((item: Knob) => { + const rows = items.map((item) => { const { name } = item; const id = `${type}-${name || DEFAULT}`; const label = type === 'slot' ? getSlotDefault(name, DEFAULT) : name; return html` - + ${renderer(item, id)} @@ -113,7 +123,7 @@ export const renderKnobs = ( }); return html` -

${header}

+

${header}

${rows}
diff --git a/src/lib/markdown.ts b/src/lib/markdown.ts index ab6272d..6f5c1fa 100644 --- a/src/lib/markdown.ts +++ b/src/lib/markdown.ts @@ -1,20 +1,18 @@ -import { html } from 'lit-element'; -import { nothing, TemplateResult } from 'lit-html'; -import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'; +import { html, nothing, TemplateResult } from 'lit'; + +import { unsafeHTML } from 'lit/directives/unsafe-html.js'; import marked from 'marked/lib/marked.esm.js'; import DOMPurify from 'dompurify'; marked.setOptions({ headerIds: false }); -export const parse = (markdown?: string): TemplateResult => { - return html` - ${!markdown - ? nothing - : unsafeHTML( - DOMPurify.sanitize(marked(markdown)).replace( - /<(h[1-6]|a|p|ul|ol|li|pre|code|strong|em|blockquote|del)(\s+href="[^"]+")*>/g, - '<$1 part="md-$1"$2>' - ) - )} - `; -}; +export const parse = (markdown?: string): TemplateResult => html` + ${!markdown + ? nothing + : unsafeHTML( + DOMPurify.sanitize(marked(markdown)).replace( + /<(h[1-6]|a|p|ul|ol|li|pre|code|strong|em|blockquote|del)(\s+href="[^"]+")*>/g, + '<$1 part="md-$1"$2>' + ) + )} +`; diff --git a/src/lib/renderer.ts b/src/lib/renderer.ts index 7e96b1f..54b774b 100644 --- a/src/lib/renderer.ts +++ b/src/lib/renderer.ts @@ -1,10 +1,13 @@ -import { directive, Part, NodePart } from 'lit-html'; +import type * as Manifest from 'custom-elements-manifest/schema'; +import { ChildPart, directive, Part } from 'lit/directive.js'; + import { ComponentWithProps, - CSSPropertyInfo, + CSSProp, KnobValues, - SlotValue + SlotWithContent } from './types.js'; + import { getTemplate, getTemplateNode, @@ -35,7 +38,7 @@ const applyKnobs = (component: Element, knobs: KnobValues) => { }); }; -const applySlots = (component: Element, slots: SlotValue[]) => { +const applySlots = (component: Element, slots: SlotWithContent[]) => { while (component.firstChild) { component.removeChild(component.firstChild); } @@ -53,7 +56,7 @@ const applySlots = (component: Element, slots: SlotValue[]) => { }); }; -const applyCssProps = (component: HTMLElement, cssProps: CSSPropertyInfo[]) => { +const applyCssProps = (component: HTMLElement, cssProps: CSSProp[]) => { cssProps.forEach((prop) => { const { name, value } = prop; if (value) { @@ -106,8 +109,8 @@ async function elementUpdated( return el; } -const makePart = (part: NodePart): NodePart => { - const newPart = new NodePart(part.options); +const makePart = (part: Part): ChildPart => { + const newPart = new ChildPart(part.options); newPart.appendIntoPart(part); return newPart; }; diff --git a/src/lib/types.ts b/src/lib/types.ts index 189f515..8886bba 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -1,49 +1,9 @@ -export interface Info { - name: string; - description: string; -} - -export interface AttributeInfo extends Info { - type: string | undefined; -} - -export interface PropertyInfo extends Info { - type: string; - attribute: string | undefined; - value: string | number | boolean | null | undefined; - default: string | number | boolean | null | undefined; - options?: string[]; -} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface SlotInfo extends Info {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface EventInfo extends Info {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface CSSPartInfo extends Info {} - -export interface CSSPropertyInfo extends Info { - value?: string; - default?: string; - type?: string; -} - -export interface ElementInfo extends Info { - attributes: AttributeInfo[]; - events: EventInfo[]; - properties: PropertyInfo[]; - slots: SlotInfo[]; - cssProperties: CSSPropertyInfo[]; - cssParts: CSSPartInfo[]; -} +import type * as Manifest from 'custom-elements-manifest/schema'; -export interface ElementSetInfo { - tags: ElementInfo[]; -} +export type ElementPromise = Promise; -export type ElementPromise = Promise; +export type Prop = Manifest.PropertyLike & { attribute?: string }; +export type CSSProp = Manifest.CssCustomProperty & { value?: string }; export interface KnobValue { type: string; @@ -54,11 +14,13 @@ export interface KnobValue { export type KnobValues = { [name: string]: KnobValue }; -export interface SlotValue { - name: string; - content: string; -} - export type ComponentWithProps = { [s: string]: string | number | boolean | null; }; + +/* eslint-disable @typescript-eslint/no-explicit-any */ +export type Constructor = new (...args: any[]) => T; + +export interface SlotWithContent extends Manifest.Slot { + content: string; +} diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 7c49580..d6dc5f2 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,4 +1,5 @@ -import { PropertyInfo } from './types'; +import type * as Manifest from 'custom-elements-manifest/schema'; +import { Prop } from './types'; const templates: Array = []; @@ -36,13 +37,34 @@ export const getTemplates = (id: number, name: string, type: string) => export const hasTemplate = (id: number, name: string, type: string) => templates[id].some(matchTemplate(name, type)); -export const isPropMatch = (name: string) => (prop: PropertyInfo) => +export const isPropMatch = (name: string) => (prop: Prop) => prop.attribute === name || prop.name === name; -export const normalizeType = (type: string | undefined = '') => - type.replace(' | undefined', '').replace(' | null', ''); +export const normalizeType = ( + type: Manifest.Type | string | undefined = '' +) => { + const t = typeof type === 'string' ? type : type.text; + return t.replace(' | undefined', '').replace(' | null', ''); +}; export const unquote = (value?: string) => typeof value === 'string' && value.startsWith('"') && value.endsWith('"') ? value.slice(1, value.length - 1) : value; + +const isClassDeclaration = (x: Manifest.Declaration) => x.kind === 'class'; +const isCustomElement = ( + x: Manifest.Declaration +): x is Manifest.CustomElementDeclaration => + isClassDeclaration(x) && + (x as unknown as Manifest.CustomElement).customElement; + +export async function getElements( + jsonFetched: Promise +): Promise { + const modules = await jsonFetched.then((x) => x?.modules ?? []); + const declarations = modules.flatMap((m) => m.declarations ?? []); + return declarations.filter( + isCustomElement + ) as unknown as Manifest.CustomElement[]; +} diff --git a/src/shared-styles.ts b/src/shared-styles.ts index 8fee58e..876299a 100644 --- a/src/shared-styles.ts +++ b/src/shared-styles.ts @@ -1,4 +1,4 @@ -import { css } from 'lit-element'; +import { css } from 'lit'; export default css` :host { diff --git a/tsconfig.json b/tsconfig.json index e435391..77e9fe0 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,7 @@ "declarationMap": true, "sourceMap": true, "inlineSources": true, - "lib": ["esnext", "es2017", "dom"], + "lib": ["esnext", "es2018", "dom"], "moduleResolution": "node", "noFallthroughCasesInSwitch": true, "noImplicitAny": true, diff --git a/yarn.lock b/yarn.lock index 9a502f3..fb9be8d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -183,6 +183,20 @@ lodash "^4.17.19" to-fast-properties "^2.0.0" +"@custom-elements-manifest/analyzer@^0.5.6": + version "0.5.6" + resolved "https://registry.yarnpkg.com/@custom-elements-manifest/analyzer/-/analyzer-0.5.6.tgz#0c179c2ed5e9a6679e2b7e5775d1fcdf6ef090a6" + integrity sha512-Tcl48ToHdVoVtB+1NBWKU16xGPE+bHebs5m9Fkj9aGsapVwduREBwx0AxBhGR/Nnk14vnkDIOswfsjRa7gKywQ== + dependencies: + "@web/config-loader" "0.1.3" + chokidar "3.5.2" + command-line-args "5.1.2" + comment-parser "1.2.4" + custom-elements-manifest "1.0.0" + debounce "1.2.1" + globby "11.0.4" + typescript "~4.3.2" + "@discoveryjs/json-ext@^0.5.5": version "0.5.5" resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz#9283c9ce5b289a3c4f61c12757469e59377f81f3" @@ -217,6 +231,11 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== +"@lit/reactive-element@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-1.0.1.tgz#853cacd4d78d79059f33f66f8e7b0e5c34bee294" + integrity sha512-nSD5AA2AZkKuXuvGs8IK7K5ZczLAogfDd26zT9l6S7WzvqALdVWcW5vMUiTnZyj5SPcNwNNANj0koeV1ieqTFQ== + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -508,10 +527,10 @@ "@types/keygrip" "*" "@types/node" "*" -"@types/dompurify@^2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.0.4.tgz#25fce15f1f4b1bc0df0ad957040cf226416ac2d7" - integrity sha512-y6K7NyXTQvjr8hJNsAFAD8yshCsIJ0d+OYEFzULuIqWyWOKL2hRru1I+rorI5U0K4SLAROTNuSUFXPDTu278YA== +"@types/dompurify@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.3.1.tgz#2934adcd31c4e6b02676f9c22f9756e5091c04dd" + integrity sha512-YJth9qa0V/E6/XPH1Jq4BC8uCMmO8V1fKWn8PCvuZcAhMn7q0ez9LW6naQT04UZzjFfAPhyRMZmI2a2rbMlEFA== dependencies: "@types/trusted-types" "*" @@ -690,6 +709,11 @@ resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-1.0.6.tgz#569b8a08121d3203398290d602d84d73c8dcf5da" integrity sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw== +"@types/trusted-types@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.2.tgz#fc25ad9943bcac11cceb8168db4f275e0e72e756" + integrity sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg== + "@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" @@ -781,7 +805,7 @@ "@typescript-eslint/types" "5.1.0" eslint-visitor-keys "^3.0.0" -"@web/config-loader@^0.1.3": +"@web/config-loader@0.1.3", "@web/config-loader@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@web/config-loader/-/config-loader-0.1.3.tgz#8325ea54f75ef2ee7166783e64e66936db25bff7" integrity sha512-XVKH79pk4d3EHRhofete8eAnqto1e8mCRAqPV00KLNFzCWSe8sWmLnqKCqkPNARC6nksMaGrATnA5sPDRllMpQ== @@ -1136,6 +1160,11 @@ array-back@^4.0.1: resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.1.tgz#9b80312935a52062e1a233a9c7abeb5481b30e90" integrity sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg== +array-back@^6.1.2: + version "6.2.0" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-6.2.0.tgz#83cc80fbef5a46269b1f6ecc82011cfc19cf1c1e" + integrity sha512-mixVv03GOOn/ubHE4STQ+uevX42ETdk0JoMVEjNkSOCT7WgERh7C8/+NyhWYNpE3BN69pxFyJIBcF7CxWz/+4A== + array-includes@^3.1.4: version "3.1.4" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" @@ -1421,7 +1450,7 @@ charenc@0.0.2: resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= -chokidar@^3.4.3, chokidar@^3.5.2: +chokidar@3.5.2, chokidar@^3.4.3, chokidar@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== @@ -1553,6 +1582,16 @@ colorette@^1.2.1, colorette@^1.4.0: resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== +command-line-args@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.1.2.tgz#25908e573d2214bc23a8437e3df853b02dffa425" + integrity sha512-fytTsbndLbl+pPWtS0CxLV3BEWw9wJayB8NnU2cbQqVPsNdYezQeT+uIQv009m+GShnMNyuoBrRo8DTmuTfSCA== + dependencies: + array-back "^6.1.2" + find-replace "^3.0.0" + lodash.camelcase "^4.3.0" + typical "^4.0.0" + command-line-args@^5.1.1: version "5.2.0" resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.0.tgz#087b02748272169741f1fd7c785b295df079b9be" @@ -1588,6 +1627,11 @@ commander@^8.1.0, commander@^8.2.0: resolved "https://registry.yarnpkg.com/commander/-/commander-8.2.0.tgz#37fe2bde301d87d47a53adeff8b5915db1381ca8" integrity sha512-LLKxDvHeL91/8MIyTAD5BFMNtoIwztGPMiM/7Bl8rIPmHCZXRxmSWr91h57dpOpnQ6jIUqEWdXE/uBYMfiVZDA== +comment-parser@1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.2.4.tgz#489f3ee55dfd184a6e4bffb31baba284453cb760" + integrity sha512-pm0b+qv+CkWNriSTMsfnjChF9kH0kxz55y44Wo5le9qLxMj5xDQAaEd9ZN1ovSuk9CsrncWaFwgpOMg7ClJwkw== + component-emitter@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" @@ -1598,10 +1642,10 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -confusing-browser-globals@^1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz#72bc13b483c0276801681871d4898516f8f54fdd" - integrity sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw== +confusing-browser-globals@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz#30d1e7f3d1b882b25ec4933d1d1adac353d20a59" + integrity sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA== content-disposition@~0.5.2: version "0.5.3" @@ -1796,6 +1840,16 @@ csso@^4.2.0: dependencies: css-tree "^1.1.2" +custom-elements-manifest@1.0.0, custom-elements-manifest@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/custom-elements-manifest/-/custom-elements-manifest-1.0.0.tgz#b35c2129076a1dc9f95d720c6f7b5b71a857274b" + integrity sha512-j59k0ExGCKA8T6Mzaq+7axc+KVHwpEphEERU7VZ99260npu/p/9kd+Db+I3cGKxHkM5y6q5gnlXn00mzRQkX2A== + +debounce@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" + integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== + debounce@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.0.tgz#44a540abc0ea9943018dc0eaa95cce87f65cd131" @@ -1985,10 +2039,10 @@ domhandler@^4.2.0: dependencies: domelementtype "^2.2.0" -dompurify@^2.0.15: - version "2.0.17" - resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.0.17.tgz#505ffa126a580603df4007e034bdc9b6b738668e" - integrity sha512-nNwwJfW55r8akD8MSFz6k75bzyT2y6JEa1O3JrZFBf+Y5R9JXXU4OsRl0B9hKoPgHTw2b7ER5yJ5Md97MMUJPg== +dompurify@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.3.tgz#c1af3eb88be47324432964d8abc75cf4b98d634c" + integrity sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg== domutils@^1.5.1: version "1.7.0" @@ -2132,13 +2186,13 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-config-airbnb-base@^14.2.0: - version "14.2.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz#fe89c24b3f9dc8008c9c0d0d88c28f95ed65e9c4" - integrity sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q== +eslint-config-airbnb-base@^14.2.1: + version "14.2.1" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz#8a2eb38455dc5a312550193b319cdaeef042cd1e" + integrity sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA== dependencies: - confusing-browser-globals "^1.0.9" - object.assign "^4.1.0" + confusing-browser-globals "^1.0.10" + object.assign "^4.1.2" object.entries "^1.1.2" eslint-config-prettier@^8.3.0: @@ -2182,10 +2236,10 @@ eslint-plugin-import@^2.25.2: resolve "^1.20.0" tsconfig-paths "^3.11.0" -eslint-plugin-lit@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-lit/-/eslint-plugin-lit-1.3.0.tgz#9971743d8d4f469bdf70b120908dcbc6ce958f2e" - integrity sha512-fy6Lr5vYI3kvCYaDXA20lwyKAp1keS9UjR5ntj8U2TeV+1yUta3S7xxXe+rABKRPbcNzi1ZvQLE1LmNKc9yr4Q== +eslint-plugin-lit@1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-lit/-/eslint-plugin-lit-1.6.1.tgz#e1f51fe9e580d4095b58cc4bc4dc6b44409af6b0" + integrity sha512-BpPoWVhf8dQ/Sz5Pi9NlqbGoH5BcMcVyXhi2XTx2XGMAO9U2lS+GTSsqJjI5hL3OuxCicNiUEWXazAwi9cAGxQ== dependencies: parse5 "^6.0.1" parse5-htmlparser2-tree-adapter "^6.0.1" @@ -2683,7 +2737,7 @@ globals@^13.6.0, globals@^13.9.0: dependencies: type-fest "^0.20.2" -globby@^11.0.3, globby@^11.0.4: +globby@11.0.4, globby@^11.0.3, globby@^11.0.4: version "11.0.4" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== @@ -3565,17 +3619,29 @@ lit-analyzer@^1.2.1: vscode-html-languageservice "3.1.0" web-component-analyzer "~1.1.1" -lit-element@^2.0.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-2.4.0.tgz#b22607a037a8fc08f5a80736dddf7f3f5d401452" - integrity sha512-pBGLglxyhq/Prk2H91nA0KByq/hx/wssJBQFiYqXhGDvEnY31PRGYf1RglVzyLeRysu0IHm2K0P196uLLWmwFg== +lit-element@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-3.0.1.tgz#3c545af17d8a46268bc1dd5623a47486e6ff76f4" + integrity sha512-vs9uybH9ORyK49CFjoNGN85HM9h5bmisU4TQ63phe/+GYlwvY/3SIFYKdjV6xNvzz8v2MnVC+9+QOkPqh+Q3Ew== dependencies: - lit-html "^1.1.1" + "@lit/reactive-element" "^1.0.0" + lit-html "^2.0.0" -lit-html@^1.0.0, lit-html@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-1.3.0.tgz#c80f3cc5793a6dea6c07172be90a70ab20e56034" - integrity sha512-0Q1bwmaFH9O14vycPHw8C/IeHMk/uSDldVLIefu/kfbTBGIc44KGH6A8p1bDfxUfHdc8q6Ct7kQklWoHgr4t1Q== +lit-html@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-2.0.1.tgz#63241015efa07bc9259b6f96f04abd052d2a1f95" + integrity sha512-KF5znvFdXbxTYM/GjpdOOnMsjgRcFGusTnB54ixnCTya5zUR0XqrDRj29ybuLS+jLXv1jji6Y8+g4W7WP8uL4w== + dependencies: + "@types/trusted-types" "^2.0.2" + +lit@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lit/-/lit-2.0.2.tgz#5e6f422924e0732258629fb379556b6d23f7179c" + integrity sha512-hKA/1YaSB+P+DvKWuR2q1Xzy/iayhNrJ3aveD0OQ9CKn6wUjsdnF/7LavDOJsKP/K5jzW/kXsuduPgRvTFrFJw== + dependencies: + "@lit/reactive-element" "^1.0.0" + lit-element "^3.0.0" + lit-html "^2.0.0" load-json-file@^4.0.0: version "4.0.0" @@ -4086,7 +4152,7 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.assign@^4.1.0, object.assign@^4.1.2: +object.assign@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== @@ -5770,6 +5836,11 @@ typescript@^4.4.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c" integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== +typescript@~4.3.2: + version "4.3.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" + integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== + typical@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"