From 7afcb1a08aa6334c108cda3683588b681e29c6b9 Mon Sep 17 00:00:00 2001 From: web-padawan Date: Fri, 28 Jan 2022 12:21:43 +0200 Subject: [PATCH 1/2] feat: add methods tab to API documentation --- docs/assets/custom-elements.json | 122 +++++++++++++++++++++++----- fixtures/lit/src/expansion-panel.ts | 13 ++- fixtures/lit/src/opened-mixin.ts | 32 ++++++++ packages/api-common/src/manifest.ts | 18 +++- packages/api-docs/src/base.ts | 3 + packages/api-docs/src/layout.ts | 29 +++++-- packages/api-viewer/src/base.ts | 3 + 7 files changed, 184 insertions(+), 36 deletions(-) create mode 100644 fixtures/lit/src/opened-mixin.ts diff --git a/docs/assets/custom-elements.json b/docs/assets/custom-elements.json index e25f30f..3ebd7f4 100644 --- a/docs/assets/custom-elements.json +++ b/docs/assets/custom-elements.json @@ -58,17 +58,6 @@ } ], "members": [ - { - "kind": "field", - "name": "opened", - "type": { - "text": "boolean | null | undefined" - }, - "default": "false", - "description": "When true, the panel content is expanded and visible", - "attribute": "opened", - "reflects": true - }, { "kind": "field", "name": "disabled", @@ -123,7 +112,8 @@ "type": { "text": "void" } - } + }, + "privacy": "protected" }, { "kind": "method", @@ -198,6 +188,30 @@ "text": "void" } } + }, + { + "kind": "field", + "name": "opened", + "type": { + "text": "boolean | null | undefined" + }, + "default": "false", + "description": "When true, the content is visible.", + "attribute": "opened", + "reflects": true, + "inheritedFrom": { + "name": "OpenedMixin", + "module": "src/opened-mixin.ts" + } + }, + { + "kind": "method", + "name": "toggle", + "description": "Toggle the opened property value.", + "inheritedFrom": { + "name": "OpenedMixin", + "module": "src/opened-mixin.ts" + } } ], "events": [ @@ -225,22 +239,32 @@ "name": "focus-ring" }, { - "name": "opened", + "name": "disabled", "type": { - "text": "boolean | null | undefined" + "text": "boolean" }, "default": "false", - "description": "When true, the panel content is expanded and visible", - "fieldName": "opened" + "description": "Disabled panel can not be expanded or collapsed", + "fieldName": "disabled" }, { - "name": "disabled", + "name": "opened", "type": { - "text": "boolean" + "text": "boolean | null | undefined" }, "default": "false", - "description": "Disabled panel can not be expanded or collapsed", - "fieldName": "disabled" + "description": "When true, the content is visible.", + "fieldName": "opened", + "inheritedFrom": { + "name": "OpenedMixin", + "module": "src/opened-mixin.ts" + } + } + ], + "mixins": [ + { + "name": "OpenedMixin", + "module": "/src/opened-mixin.js" } ], "superclass": { @@ -533,6 +557,64 @@ } ] }, + { + "kind": "javascript-module", + "path": "src/opened-mixin.ts", + "declarations": [ + { + "kind": "mixin", + "description": "", + "name": "OpenedMixin", + "members": [ + { + "kind": "field", + "name": "opened", + "type": { + "text": "boolean | null | undefined" + }, + "default": "false", + "description": "When true, the content is visible.", + "attribute": "opened", + "reflects": true + }, + { + "kind": "method", + "name": "toggle", + "description": "Toggle the opened property value." + } + ], + "attributes": [ + { + "name": "opened", + "type": { + "text": "boolean | null | undefined" + }, + "default": "false", + "description": "When true, the content is visible.", + "fieldName": "opened" + } + ], + "parameters": [ + { + "name": "base", + "type": { + "text": "T" + } + } + ] + } + ], + "exports": [ + { + "kind": "js", + "name": "OpenedMixin", + "declaration": { + "name": "OpenedMixin", + "module": "src/opened-mixin.ts" + } + } + ] + }, { "kind": "javascript-module", "path": "src/progress-bar.ts", diff --git a/fixtures/lit/src/expansion-panel.ts b/fixtures/lit/src/expansion-panel.ts index a89b31c..4a1314f 100644 --- a/fixtures/lit/src/expansion-panel.ts +++ b/fixtures/lit/src/expansion-panel.ts @@ -3,6 +3,7 @@ import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; import { query } from 'lit/decorators/query.js'; import { styleMap } from 'lit/directives/style-map.js'; +import { OpenedMixin } from './opened-mixin.js'; /** * A custom element similar to the HTML5 `
` element. @@ -26,12 +27,7 @@ import { styleMap } from 'lit/directives/style-map.js'; * @fires opened-changed - Event fired when expanding / collapsing */ @customElement('expansion-panel') -export class ExpansionPanel extends LitElement { - /** - * When true, the panel content is expanded and visible - */ - @property({ type: Boolean, reflect: true }) opened?: boolean | null = false; - +export class ExpansionPanel extends OpenedMixin(LitElement) { /** * Disabled panel can not be expanded or collapsed */ @@ -207,6 +203,7 @@ export class ExpansionPanel extends LitElement { document.body.removeEventListener('keyup', this._boundBodyKeyup, true); } + /** @protected */ focus(): void { if (this.header) { this.header.focus(); @@ -280,13 +277,13 @@ export class ExpansionPanel extends LitElement { } private _onToggleClick(): void { - this.opened = !this.opened; + this.toggle(); } private _onToggleKeyDown(e: KeyboardEvent): void { if ([13, 32].indexOf(e.keyCode) > -1) { e.preventDefault(); - this.opened = !this.opened; + this.toggle(); } } diff --git a/fixtures/lit/src/opened-mixin.ts b/fixtures/lit/src/opened-mixin.ts new file mode 100644 index 0000000..ae70905 --- /dev/null +++ b/fixtures/lit/src/opened-mixin.ts @@ -0,0 +1,32 @@ +import { LitElement } from 'lit'; +import { property } from 'lit/decorators/property.js'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ +export type Constructor = new (...args: any[]) => T; + +export interface OpenedMixinInterface { + opened: boolean | null | undefined; + + toggle(): void; +} + +export const OpenedMixin = >( + base: T +): T & Constructor => { + class OpenedMixinClass extends base { + /** + * When true, the content is visible. + */ + @property({ type: Boolean, reflect: true }) + opened: boolean | null | undefined = false; + + /** + * Toggle the opened property value. + */ + toggle() { + this.opened = !this.opened; + } + } + + return OpenedMixinClass; +}; diff --git a/packages/api-common/src/manifest.ts b/packages/api-common/src/manifest.ts index ebecbc2..2f3e941 100644 --- a/packages/api-common/src/manifest.ts +++ b/packages/api-common/src/manifest.ts @@ -3,6 +3,7 @@ import type { ClassField, ClassLike, ClassMember, + ClassMethod, CssCustomProperty, CssPart, CustomElement, @@ -18,6 +19,7 @@ export { Attribute, ClassField, ClassMember, + ClassMethod, CssCustomProperty, CssPart, CustomElement, @@ -46,8 +48,8 @@ const isCustomElementExport = (y: Export): y is CustomElementExport => const isCustomElementDeclaration = (y: ClassLike): y is CustomElement => (y as CustomElement).customElement; -const isPublicProperty = (x: ClassMember): x is ClassField => - x.kind === 'field' && !(x.privacy === 'private' || x.privacy === 'protected'); +const isPublic = (x: ClassMember): boolean => + !(x.privacy === 'private' || x.privacy === 'protected'); export async function fetchManifest(src: string): Promise { try { @@ -112,5 +114,15 @@ export const getElementData = ( }; export const getPublicFields = (members: ClassMember[] = []): ClassField[] => { - return members.filter(isPublicProperty); + return members.filter( + (x: ClassMember): x is ClassField => x.kind === 'field' && isPublic(x) + ); +}; + +export const getPublicMethods = ( + members: ClassMember[] = [] +): ClassMethod[] => { + return members.filter( + (x: ClassMember): x is ClassMethod => x.kind === 'method' && isPublic(x) + ); }; diff --git a/packages/api-docs/src/base.ts b/packages/api-docs/src/base.ts index d38c55b..9f9ef7c 100644 --- a/packages/api-docs/src/base.ts +++ b/packages/api-docs/src/base.ts @@ -6,6 +6,7 @@ import { getCustomElements, getElementData, getPublicFields, + getPublicMethods, hasCustomElements, ManifestMixin, Package @@ -28,6 +29,7 @@ async function renderDocs( const data = getElementData(manifest, selected) as CustomElement; const props = getPublicFields(data.members); + const methods = getPublicMethods(data.members); return html`
@@ -54,6 +56,7 @@ async function renderDocs( .name=${data.name} .props=${props} .attrs=${data.attributes ?? []} + .methods=${methods} .events=${data.events ?? []} .slots=${data.slots ?? []} .cssParts=${data.cssParts ?? []} diff --git a/packages/api-docs/src/layout.ts b/packages/api-docs/src/layout.ts index de5ae2e..7329c99 100644 --- a/packages/api-docs/src/layout.ts +++ b/packages/api-docs/src/layout.ts @@ -3,6 +3,7 @@ import { property } from 'lit/decorators/property.js'; import { Attribute, ClassField, + ClassMethod, CssCustomProperty, CssPart, Event, @@ -83,6 +84,9 @@ class ApiDocsLayout extends LitElement { @property({ attribute: false }) attrs: Attribute[] = []; + @property({ attribute: false }) + methods: ClassMethod[] = []; + @property({ attribute: false }) slots: Slot[] = []; @@ -100,11 +104,17 @@ class ApiDocsLayout extends LitElement { } protected render(): TemplateResult { - const { slots, props, attrs, events, cssParts, cssProps } = this; - - const emptyDocs = [props, attrs, slots, events, cssProps, cssParts].every( - (arr) => arr.length === 0 - ); + const { slots, props, attrs, methods, events, cssParts, cssProps } = this; + + const emptyDocs = [ + props, + attrs, + methods, + slots, + events, + cssProps, + cssParts + ].every((arr) => arr.length === 0); const attributes = (attrs || []).filter( (x) => !props.some((y) => y.name === x.fieldName) @@ -148,6 +158,15 @@ class ApiDocsLayout extends LitElement { )} ` )} + ${renderTab( + 'Methods', + methods, + html` + ${methods.map(({ name, description }) => + renderItem('method', `${name}()`, description) + )} + ` + )} ${renderTab( 'Slots', slots, diff --git a/packages/api-viewer/src/base.ts b/packages/api-viewer/src/base.ts index c6277d2..423aac8 100644 --- a/packages/api-viewer/src/base.ts +++ b/packages/api-viewer/src/base.ts @@ -8,6 +8,7 @@ import { getCustomElements, getElementData, getPublicFields, + getPublicMethods, hasCustomElements, ManifestMixin, Package @@ -36,6 +37,7 @@ async function renderDocs( const data = getElementData(manifest, selected) as CustomElement; const props = getPublicFields(data.members); + const methods = getPublicMethods(data.members); return html`
@@ -85,6 +87,7 @@ async function renderDocs( .name=${data.name} .props=${props} .attrs=${data.attributes ?? []} + .methods=${methods} .events=${data.events ?? []} .slots=${data.slots ?? []} .cssParts=${data.cssParts ?? []} From 3c9f135cbcf794ff77953ae2746ab575994072d6 Mon Sep 17 00:00:00 2001 From: web-padawan Date: Fri, 28 Jan 2022 12:25:04 +0200 Subject: [PATCH 2/2] chore: add changeset --- .changeset/smooth-avocados-move.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .changeset/smooth-avocados-move.md diff --git a/.changeset/smooth-avocados-move.md b/.changeset/smooth-avocados-move.md new file mode 100644 index 0000000..85db89b --- /dev/null +++ b/.changeset/smooth-avocados-move.md @@ -0,0 +1,9 @@ +--- +'@api-viewer/common': patch +'@api-viewer/docs': patch +'api-viewer-element': patch +'@api-viewer/demo': patch +'@api-viewer/tabs': patch +--- + +Add methods tab to API documentation