From c3d70bf620ec5bd4e6e91a295a83dec20ec9d43f Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Fri, 1 Nov 2019 19:04:36 +0800 Subject: [PATCH] Addon-docs: Improved angular props table support --- examples/angular-cli/.storybook/compodoc.ts | 91 ++++++++++++++++--- .../doc-button/doc-button.component.ts | 27 +++++- 2 files changed, 98 insertions(+), 20 deletions(-) diff --git a/examples/angular-cli/.storybook/compodoc.ts b/examples/angular-cli/.storybook/compodoc.ts index dffcfb701de..7968d0e0ffa 100644 --- a/examples/angular-cli/.storybook/compodoc.ts +++ b/examples/angular-cli/.storybook/compodoc.ts @@ -25,12 +25,35 @@ function isEmpty(obj) { return Object.entries(obj).length === 0 && obj.constructor === Object; } -const SECTIONS = [ - { label: 'properties', key: 'propertiesClass' }, - { label: 'methods', key: 'methodsClass' }, - { label: 'inputs', key: 'inputsClass' }, - { label: 'outputs', key: 'outputsClass' }, -]; +const hasDecorator = (item: any, decoratorName: string) => + item.decorators && item.decorators.find(x => x.name === decoratorName); + +const mapItemToSection = (key: string, item: any): string => { + switch (key) { + case 'methodsClass': + return 'methods'; + case 'inputsClass': + return 'inputs'; + case 'outputsClass': + return 'outputs'; + case 'propertiesClass': + if (hasDecorator(item, 'ViewChild')) { + return 'view child'; + } + if (hasDecorator(item, 'ViewChildren')) { + return 'view children'; + } + if (hasDecorator(item, 'ContentChild')) { + return 'content child'; + } + if (hasDecorator(item, 'ContentChildren')) { + return 'content children'; + } + return 'properties'; + default: + throw new Error(`Unknown key: ${key}`); + } +}; const getComponentData = (component: any) => { if (!component) { @@ -43,23 +66,61 @@ const getComponentData = (component: any) => { return compodocJson.components.find(c => c.name === name); }; +const displaySignature = (item: any): string => { + const args = item.args.map(arg => `${arg.name}${arg.optional ? '?' : ''}: ${arg.type}`); + return `(${args.join(', ')}) => ${item.returnType}`; +}; + export const extractProps = (component: any) => { const componentData = getComponentData(component); if (!componentData) { return null; } - const sections = {}; - SECTIONS.forEach(({ label, key }) => { + const sectionToItems = {}; + + const COMPODOC_CLASSES = ['propertiesClass', 'methodsClass', 'inputsClass', 'outputsClass']; + COMPODOC_CLASSES.forEach(key => { const data = componentData[key]; if (data && data.length) { - sections[label] = data.map(item => ({ - name: item.name, - type: { name: item.type }, - required: !!item.optional, - description: item.description, - defaultValue: item.defaultValue, - })); + data.forEach(item => { + const section = mapItemToSection(key, item); + if (!sectionToItems[section]) { + sectionToItems[section] = []; + } + let typeName = item.type; + let required = !item.optional; + if (key === 'methodsClass') { + typeName = displaySignature(item); + required = false; + } + sectionToItems[section].push({ + name: item.name, + type: { name: typeName }, + required, + description: item.description, + defaultValue: item.defaultValue, + }); + }); + } + }); + + // sort the sections + const SECTIONS = [ + 'inputs', + 'outputs', + 'properties', + 'methods', + 'view child', + 'view children', + 'content child', + 'content children', + ]; + const sections = {}; + SECTIONS.forEach(section => { + const items = sectionToItems[section]; + if (items) { + sections[section] = items; } }); diff --git a/examples/angular-cli/src/stories/doc-button/doc-button.component.ts b/examples/angular-cli/src/stories/doc-button/doc-button.component.ts index 3d8807381ce..7ef6c4627b4 100644 --- a/examples/angular-cli/src/stories/doc-button/doc-button.component.ts +++ b/examples/angular-cli/src/stories/doc-button/doc-button.component.ts @@ -1,6 +1,14 @@ /* eslint-disable no-console */ /* eslint-disable no-underscore-dangle */ -import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { + Component, + EventEmitter, + Input, + Output, + ViewChild, + HostListener, + HostBinding, +} from '@angular/core'; export const exportedConstant = 'An exported constant'; @@ -21,7 +29,7 @@ export interface ISomeInterface { * ornare risus_. In vitae ex eu lacus hendrerit elementum non ut massa. ~~Orci varius natoque penatibus et magnis dis * parturient montes~~, nascetur ridiculus mus. `Nullam vehicula lacus felis, ac aliquam nisl malesuada ac`. * - * > Cras varius aliquam tortor in efficitur. Proin in egestas libero, ac ullamcorper est. + * > Cras varius aliquam tortor in efficitur. Proin in egestas libero, ac ullamcoer est. * * HTML tags work just as they would in markup. * @@ -36,6 +44,8 @@ export interface ISomeInterface { styleUrls: ['./doc-button.component.scss'], }) export class ButtonComponent { + @ViewChild('buttonRef', { static: false }) buttonRef: HTMLElement; + /** Appearance style of the button. */ @Input() public appearance: 'primary' | 'secondary' = 'secondary'; @@ -54,7 +64,7 @@ export class ButtonComponent { /** Size of the button. */ @Input() - public size: ButtonSize = 'medium'; + public size?: ButtonSize = 'medium'; /** * Some input you shouldn't use. @@ -98,6 +108,13 @@ export class ButtonComponent { return this._inputValue; } + @HostListener('click', ['$event.target']) + onClickListener(btn) { + console.log('button', btn); + } + + @HostBinding('class.focused') focus = false; + /** * Returns all the CSS classes for the button. * @@ -148,7 +165,7 @@ export class ButtonComponent { * * @param id Some `id`. */ - protected protectedMethod(id: number) { + protected protectedMethod(id?: number) { console.log(id); } @@ -161,7 +178,7 @@ export class ButtonComponent { console.log(password); } - @Input() + @Input('showKeyAlias') public showKey: keyof T; @Input()