Skip to content

Commit cc911b6

Browse files
authored
feat: add methods tab to API documentation (#145)
1 parent 2adce0e commit cc911b6

File tree

8 files changed

+193
-36
lines changed

8 files changed

+193
-36
lines changed

.changeset/smooth-avocados-move.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'@api-viewer/common': patch
3+
'@api-viewer/docs': patch
4+
'api-viewer-element': patch
5+
'@api-viewer/demo': patch
6+
'@api-viewer/tabs': patch
7+
---
8+
9+
Add methods tab to API documentation

docs/assets/custom-elements.json

Lines changed: 102 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,6 @@
5858
}
5959
],
6060
"members": [
61-
{
62-
"kind": "field",
63-
"name": "opened",
64-
"type": {
65-
"text": "boolean | null | undefined"
66-
},
67-
"default": "false",
68-
"description": "When true, the panel content is expanded and visible",
69-
"attribute": "opened",
70-
"reflects": true
71-
},
7261
{
7362
"kind": "field",
7463
"name": "disabled",
@@ -123,7 +112,8 @@
123112
"type": {
124113
"text": "void"
125114
}
126-
}
115+
},
116+
"privacy": "protected"
127117
},
128118
{
129119
"kind": "method",
@@ -198,6 +188,30 @@
198188
"text": "void"
199189
}
200190
}
191+
},
192+
{
193+
"kind": "field",
194+
"name": "opened",
195+
"type": {
196+
"text": "boolean | null | undefined"
197+
},
198+
"default": "false",
199+
"description": "When true, the content is visible.",
200+
"attribute": "opened",
201+
"reflects": true,
202+
"inheritedFrom": {
203+
"name": "OpenedMixin",
204+
"module": "src/opened-mixin.ts"
205+
}
206+
},
207+
{
208+
"kind": "method",
209+
"name": "toggle",
210+
"description": "Toggle the opened property value.",
211+
"inheritedFrom": {
212+
"name": "OpenedMixin",
213+
"module": "src/opened-mixin.ts"
214+
}
201215
}
202216
],
203217
"events": [
@@ -225,22 +239,32 @@
225239
"name": "focus-ring"
226240
},
227241
{
228-
"name": "opened",
242+
"name": "disabled",
229243
"type": {
230-
"text": "boolean | null | undefined"
244+
"text": "boolean"
231245
},
232246
"default": "false",
233-
"description": "When true, the panel content is expanded and visible",
234-
"fieldName": "opened"
247+
"description": "Disabled panel can not be expanded or collapsed",
248+
"fieldName": "disabled"
235249
},
236250
{
237-
"name": "disabled",
251+
"name": "opened",
238252
"type": {
239-
"text": "boolean"
253+
"text": "boolean | null | undefined"
240254
},
241255
"default": "false",
242-
"description": "Disabled panel can not be expanded or collapsed",
243-
"fieldName": "disabled"
256+
"description": "When true, the content is visible.",
257+
"fieldName": "opened",
258+
"inheritedFrom": {
259+
"name": "OpenedMixin",
260+
"module": "src/opened-mixin.ts"
261+
}
262+
}
263+
],
264+
"mixins": [
265+
{
266+
"name": "OpenedMixin",
267+
"module": "/src/opened-mixin.js"
244268
}
245269
],
246270
"superclass": {
@@ -533,6 +557,64 @@
533557
}
534558
]
535559
},
560+
{
561+
"kind": "javascript-module",
562+
"path": "src/opened-mixin.ts",
563+
"declarations": [
564+
{
565+
"kind": "mixin",
566+
"description": "",
567+
"name": "OpenedMixin",
568+
"members": [
569+
{
570+
"kind": "field",
571+
"name": "opened",
572+
"type": {
573+
"text": "boolean | null | undefined"
574+
},
575+
"default": "false",
576+
"description": "When true, the content is visible.",
577+
"attribute": "opened",
578+
"reflects": true
579+
},
580+
{
581+
"kind": "method",
582+
"name": "toggle",
583+
"description": "Toggle the opened property value."
584+
}
585+
],
586+
"attributes": [
587+
{
588+
"name": "opened",
589+
"type": {
590+
"text": "boolean | null | undefined"
591+
},
592+
"default": "false",
593+
"description": "When true, the content is visible.",
594+
"fieldName": "opened"
595+
}
596+
],
597+
"parameters": [
598+
{
599+
"name": "base",
600+
"type": {
601+
"text": "T"
602+
}
603+
}
604+
]
605+
}
606+
],
607+
"exports": [
608+
{
609+
"kind": "js",
610+
"name": "OpenedMixin",
611+
"declaration": {
612+
"name": "OpenedMixin",
613+
"module": "src/opened-mixin.ts"
614+
}
615+
}
616+
]
617+
},
536618
{
537619
"kind": "javascript-module",
538620
"path": "src/progress-bar.ts",

fixtures/lit/src/expansion-panel.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { customElement } from 'lit/decorators/custom-element.js';
33
import { property } from 'lit/decorators/property.js';
44
import { query } from 'lit/decorators/query.js';
55
import { styleMap } from 'lit/directives/style-map.js';
6+
import { OpenedMixin } from './opened-mixin.js';
67

78
/**
89
* A custom element similar to the HTML5 `<details>` element.
@@ -26,12 +27,7 @@ import { styleMap } from 'lit/directives/style-map.js';
2627
* @fires opened-changed - Event fired when expanding / collapsing
2728
*/
2829
@customElement('expansion-panel')
29-
export class ExpansionPanel extends LitElement {
30-
/**
31-
* When true, the panel content is expanded and visible
32-
*/
33-
@property({ type: Boolean, reflect: true }) opened?: boolean | null = false;
34-
30+
export class ExpansionPanel extends OpenedMixin(LitElement) {
3531
/**
3632
* Disabled panel can not be expanded or collapsed
3733
*/
@@ -207,6 +203,7 @@ export class ExpansionPanel extends LitElement {
207203
document.body.removeEventListener('keyup', this._boundBodyKeyup, true);
208204
}
209205

206+
/** @protected */
210207
focus(): void {
211208
if (this.header) {
212209
this.header.focus();
@@ -280,13 +277,13 @@ export class ExpansionPanel extends LitElement {
280277
}
281278

282279
private _onToggleClick(): void {
283-
this.opened = !this.opened;
280+
this.toggle();
284281
}
285282

286283
private _onToggleKeyDown(e: KeyboardEvent): void {
287284
if ([13, 32].indexOf(e.keyCode) > -1) {
288285
e.preventDefault();
289-
this.opened = !this.opened;
286+
this.toggle();
290287
}
291288
}
292289

fixtures/lit/src/opened-mixin.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { LitElement } from 'lit';
2+
import { property } from 'lit/decorators/property.js';
3+
4+
/* eslint-disable @typescript-eslint/no-explicit-any */
5+
export type Constructor<T = unknown> = new (...args: any[]) => T;
6+
7+
export interface OpenedMixinInterface {
8+
opened: boolean | null | undefined;
9+
10+
toggle(): void;
11+
}
12+
13+
export const OpenedMixin = <T extends Constructor<LitElement>>(
14+
base: T
15+
): T & Constructor<OpenedMixinInterface> => {
16+
class OpenedMixinClass extends base {
17+
/**
18+
* When true, the content is visible.
19+
*/
20+
@property({ type: Boolean, reflect: true })
21+
opened: boolean | null | undefined = false;
22+
23+
/**
24+
* Toggle the opened property value.
25+
*/
26+
toggle() {
27+
this.opened = !this.opened;
28+
}
29+
}
30+
31+
return OpenedMixinClass;
32+
};

packages/api-common/src/manifest.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type {
33
ClassField,
44
ClassLike,
55
ClassMember,
6+
ClassMethod,
67
CssCustomProperty,
78
CssPart,
89
CustomElement,
@@ -18,6 +19,7 @@ export {
1819
Attribute,
1920
ClassField,
2021
ClassMember,
22+
ClassMethod,
2123
CssCustomProperty,
2224
CssPart,
2325
CustomElement,
@@ -46,8 +48,8 @@ const isCustomElementExport = (y: Export): y is CustomElementExport =>
4648
const isCustomElementDeclaration = (y: ClassLike): y is CustomElement =>
4749
(y as CustomElement).customElement;
4850

49-
const isPublicProperty = (x: ClassMember): x is ClassField =>
50-
x.kind === 'field' && !(x.privacy === 'private' || x.privacy === 'protected');
51+
const isPublic = (x: ClassMember): boolean =>
52+
!(x.privacy === 'private' || x.privacy === 'protected');
5153

5254
export async function fetchManifest(src: string): Promise<Package | null> {
5355
try {
@@ -112,5 +114,15 @@ export const getElementData = (
112114
};
113115

114116
export const getPublicFields = (members: ClassMember[] = []): ClassField[] => {
115-
return members.filter(isPublicProperty);
117+
return members.filter(
118+
(x: ClassMember): x is ClassField => x.kind === 'field' && isPublic(x)
119+
);
120+
};
121+
122+
export const getPublicMethods = (
123+
members: ClassMember[] = []
124+
): ClassMethod[] => {
125+
return members.filter(
126+
(x: ClassMember): x is ClassMethod => x.kind === 'method' && isPublic(x)
127+
);
116128
};

packages/api-docs/src/base.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
getCustomElements,
77
getElementData,
88
getPublicFields,
9+
getPublicMethods,
910
hasCustomElements,
1011
ManifestMixin,
1112
Package
@@ -28,6 +29,7 @@ async function renderDocs(
2829

2930
const data = getElementData(manifest, selected) as CustomElement;
3031
const props = getPublicFields(data.members);
32+
const methods = getPublicMethods(data.members);
3133

3234
return html`
3335
<header part="header">
@@ -54,6 +56,7 @@ async function renderDocs(
5456
.name=${data.name}
5557
.props=${props}
5658
.attrs=${data.attributes ?? []}
59+
.methods=${methods}
5760
.events=${data.events ?? []}
5861
.slots=${data.slots ?? []}
5962
.cssParts=${data.cssParts ?? []}

packages/api-docs/src/layout.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { property } from 'lit/decorators/property.js';
33
import {
44
Attribute,
55
ClassField,
6+
ClassMethod,
67
CssCustomProperty,
78
CssPart,
89
Event,
@@ -83,6 +84,9 @@ class ApiDocsLayout extends LitElement {
8384
@property({ attribute: false })
8485
attrs: Attribute[] = [];
8586

87+
@property({ attribute: false })
88+
methods: ClassMethod[] = [];
89+
8690
@property({ attribute: false })
8791
slots: Slot[] = [];
8892

@@ -100,11 +104,17 @@ class ApiDocsLayout extends LitElement {
100104
}
101105

102106
protected render(): TemplateResult {
103-
const { slots, props, attrs, events, cssParts, cssProps } = this;
104-
105-
const emptyDocs = [props, attrs, slots, events, cssProps, cssParts].every(
106-
(arr) => arr.length === 0
107-
);
107+
const { slots, props, attrs, methods, events, cssParts, cssProps } = this;
108+
109+
const emptyDocs = [
110+
props,
111+
attrs,
112+
methods,
113+
slots,
114+
events,
115+
cssProps,
116+
cssParts
117+
].every((arr) => arr.length === 0);
108118

109119
const attributes = (attrs || []).filter(
110120
(x) => !props.some((y) => y.name === x.fieldName)
@@ -148,6 +158,15 @@ class ApiDocsLayout extends LitElement {
148158
)}
149159
`
150160
)}
161+
${renderTab(
162+
'Methods',
163+
methods,
164+
html`
165+
${methods.map(({ name, description }) =>
166+
renderItem('method', `${name}()`, description)
167+
)}
168+
`
169+
)}
151170
${renderTab(
152171
'Slots',
153172
slots,

0 commit comments

Comments
 (0)