Skip to content

Commit

Permalink
[docs] API browser and "see" JSDoc tag support (#2041)
Browse files Browse the repository at this point in the history
  • Loading branch information
giladgray authored and adidahiya committed Feb 7, 2018
1 parent 5ae41ea commit 1d2ec47
Show file tree
Hide file tree
Showing 17 changed files with 171 additions and 59 deletions.
4 changes: 2 additions & 2 deletions packages/core/src/components/menu/menu.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ To add a submenu to a `Menu`, simply nest `MenuItem`s within another `MenuItem`.
The submenu opens to the right of its parent by default, but will adjust and flip to the left if
there is not enough room to the right.

```jsx
```tsx
<Menu>
<MenuItem text="Submenu">
<MenuItem text="Child one" />
Expand All @@ -104,7 +104,7 @@ there is not enough room to the right.
The `Menu` component by itself simply renders a menu list. To make a dropdown menu, use a `Menu`
element as the `content` property of a `Popover`:

```jsx
```tsx
<Popover content={<Menu>...</Menu>} position={Position.RIGHT_TOP}>
<Button iconName="share" text="Open in..." />
</Popover>
Expand Down
4 changes: 4 additions & 0 deletions packages/datetime/src/datePickerCore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import { Months } from "./common/months";

// DatePicker supports a simpler set of modifiers (for now).
// also we need an interface for the dictionary without `today` and `outside` injected by r-d-p.
/**
* Collection of functions that determine which modifier classes get applied to which days.
* See the [**react-day-picker** documentation](http://react-day-picker.js.org/Modifiers.html) to learn more.
*/
export interface IDatePickerModifiers {
[name: string]: (date: Date) => boolean;
}
Expand Down
4 changes: 4 additions & 0 deletions packages/docs-theme/src/common/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ export interface IDocumentationContext {

/** Render the text of a "View source" link. */
renderViewSourceLinkText(entry: ITsDocBase): React.ReactNode;

/** Open the API browser to the given member name. */
showApiDocs(name: string): void;
}

/**
Expand All @@ -66,6 +69,7 @@ export const DocumentationContextTypes: React.ValidationMap<IDocumentationContex
renderBlock: assertFunctionProp,
renderType: assertFunctionProp,
renderViewSourceLinkText: assertFunctionProp,
showApiDocs: assertFunctionProp,
};

// simple alternative to prop-types dependency
Expand Down
21 changes: 17 additions & 4 deletions packages/docs-theme/src/components/documentation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ import * as classNames from "classnames";
import { isPageNode, ITsDocBase, linkify } from "documentalist/dist/client";
import * as React from "react";

import { FocusStyleManager, Hotkey, Hotkeys, HotkeysTarget, IProps, Utils } from "@blueprintjs/core";
import { Dialog, FocusStyleManager, Hotkey, Hotkeys, HotkeysTarget, IProps, Utils } from "@blueprintjs/core";

import { DocumentationContextTypes, hasTypescriptData, IDocsData, IDocumentationContext } from "../common/context";
import { eachLayoutNode } from "../common/utils";
import { ITagRendererMap } from "../tags";
import { ITagRendererMap, TypescriptExample } from "../tags";
import { renderBlock } from "./block";
import { Navigator } from "./navigator";
import { NavMenu } from "./navMenu";
import { Page } from "./page";
import { ApiLink } from "./typescript/apiLink";

export interface IDocumentationProps extends IProps {
/**
Expand Down Expand Up @@ -62,8 +63,10 @@ export interface IDocumentationProps extends IProps {
}

export interface IDocumentationState {
activeApiMember: string;
activePageId: string;
activeSectionId: string;
isApiBrowserOpen: boolean;
}

@HotkeysTarget
Expand All @@ -87,8 +90,10 @@ export class Documentation extends React.PureComponent<IDocumentationProps, IDoc
public constructor(props: IDocumentationProps) {
super(props);
this.state = {
activeApiMember: "",
activePageId: props.defaultPageId,
activeSectionId: props.defaultPageId,
isApiBrowserOpen: false,
};

// build up static map of all references to their page, for navigation / routing
Expand All @@ -105,16 +110,17 @@ export class Documentation extends React.PureComponent<IDocumentationProps, IDoc
getDocsData: () => docs,
renderBlock: block => renderBlock(block, this.props.tagRenderers),
renderType: hasTypescriptData(docs)
? type => linkify(type, docs.typescript, name => <u key={name}>{name}</u>)
? type => linkify(type, docs.typescript, name => <ApiLink key={name} name={name} />)
: type => type,
renderViewSourceLinkText: Utils.isFunction(renderViewSourceLinkText)
? renderViewSourceLinkText
: () => "View source",
showApiDocs: this.handleApiBrowserOpen,
};
}

public render() {
const { activePageId, activeSectionId } = this.state;
const { activeApiMember, activePageId, activeSectionId, isApiBrowserOpen } = this.state;
const { nav, pages } = this.props.docs;
const examplesOnly = location.search === "?examples";
return (
Expand All @@ -138,6 +144,9 @@ export class Documentation extends React.PureComponent<IDocumentationProps, IDoc
<article className="docs-content" ref={this.refHandlers.content} role="main">
<Page page={pages[activePageId]} tagRenderers={this.props.tagRenderers} />
</article>
<Dialog className="docs-api-dialog" isOpen={isApiBrowserOpen} onClose={this.handleApiBrowserClose}>
<TypescriptExample tag="typescript" value={activeApiMember} />
</Dialog>
</div>
</div>
);
Expand Down Expand Up @@ -250,6 +259,10 @@ export class Documentation extends React.PureComponent<IDocumentationProps, IDoc
// updating hash triggers event listener which sets new state.
location.hash = sections[newIndex];
}

private handleApiBrowserOpen = (activeApiMember: string) =>
this.setState({ activeApiMember, isApiBrowserOpen: true });
private handleApiBrowserClose = () => this.setState({ isApiBrowserOpen: false });
}

/** Shorthand for element.querySelector() + cast to HTMLElement */
Expand Down
36 changes: 36 additions & 0 deletions packages/docs-theme/src/components/typescript/apiLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2017 Palantir Technologies, Inc. All rights reserved.
*
* Licensed under the terms of the LICENSE file distributed with this project.
*/

import { IProps } from "@blueprintjs/core";
import * as React from "react";
import { DocumentationContextTypes, IDocumentationContext } from "../../common/context";

export interface IApiLinkProps extends IProps {
children?: never;
name: string;
}

/**
* Renders a link to open a symbol in the API Browser.
*/
export class ApiLink extends React.PureComponent<IApiLinkProps> {
public static contextTypes = DocumentationContextTypes;
public context: IDocumentationContext;

public render() {
const { className, name } = this.props;
return (
<a className={className} href={`#api/${name}`} onClick={this.handleClick}>
{name}
</a>
);
}

private handleClick = (evt: React.MouseEvent<HTMLAnchorElement>) => {
evt.preventDefault();
this.context.showApiDocs(this.props.name);
};
}
20 changes: 11 additions & 9 deletions packages/docs-theme/src/components/typescript/enumTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,17 @@ export class EnumTable extends React.PureComponent<IEnumTableProps> {
<div className="docs-modifiers">
<ApiHeader {...data} />
{renderBlock(data.documentation)}
<table className="pt-html-table">
<thead>
<tr>
<th>Members</th>
<th>Description</th>
</tr>
</thead>
<tbody>{data.members.map(this.renderPropRow)}</tbody>
</table>
<div className="docs-interface-table">
<table className="pt-html-table">
<thead>
<tr>
<th>Members</th>
<th>Description</th>
</tr>
</thead>
<tbody>{data.members.map(this.renderPropRow)}</tbody>
</table>
</div>
</div>
);
}
Expand Down
46 changes: 36 additions & 10 deletions packages/docs-theme/src/components/typescript/interfaceTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import { Classes, Intent, Tag } from "@blueprintjs/core";
import * as classNames from "classnames";
import { isTsProperty, ITsClass, ITsInterface, ITsMethod, ITsProperty } from "documentalist/dist/client";
import { isTsProperty, ITsClass, ITsInterface, ITsMethod, ITsProperty, ITsSignature } from "documentalist/dist/client";
import * as React from "react";
import { DocumentationContextTypes, IDocumentationContext } from "../../common/context";
import { ApiHeader } from "./apiHeader";
Expand Down Expand Up @@ -35,15 +35,20 @@ export class InterfaceTable extends React.PureComponent<IInterfaceTableProps> {
<div className="docs-modifiers">
<ApiHeader {...data} />
{renderBlock(data.documentation)}
<table className="pt-html-table">
<thead>
<tr>
<th>{title}</th>
<th>Description</th>
</tr>
</thead>
<tbody>{propRows}</tbody>
</table>
<div className="docs-interface-table">
<table className="pt-html-table">
<thead>
<tr>
<th>{title}</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{propRows}
{this.renderIndexSignature(data.indexSignature)}
</tbody>
</table>
</div>
</div>
);
}
Expand Down Expand Up @@ -84,6 +89,27 @@ export class InterfaceTable extends React.PureComponent<IInterfaceTableProps> {
);
};

private renderIndexSignature(entry?: ITsSignature) {
if (entry == null) {
return null;
}
const { renderBlock, renderType } = this.context;
// HACKHACK: Documentalist's indexSignature support isn't _great_, but it's certainly _good enough_
// entry.type looks like "{ [name: string]: (date: Date) => boolean }"
const [signature, returnType] = entry.type.slice(2, -2).split("]: ");
return (
<tr key={name}>
<td className="docs-prop-name">
<code>{renderType(signature)}]</code>
</td>
<td className="docs-prop-details">
<code className="docs-prop-type">{renderType(returnType)}</code>
<div className="docs-prop-description">{renderBlock(entry.documentation)}</div>
</td>
</tr>
);
}

private renderTags(entry: ITsProperty | ITsMethod) {
const { renderType } = this.context;
const { flags: { isDeprecated, isOptional }, inheritedFrom } = entry;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ export class TypeAliasTable extends React.PureComponent<ITypeAliasTableProps> {
return (
<div className="docs-modifiers">
<ApiHeader {...data} />
<p className="docs-code">= {renderType(data.type)}</p>
{renderBlock(data.documentation)}
<div className="docs-interface-table">
{renderBlock(data.documentation)}
<p className="docs-code">= {renderType(data.type)}</p>
</div>
</div>
);
}
Expand Down
1 change: 1 addition & 0 deletions packages/docs-theme/src/docs-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Copyright 2015 Palantir Technologies, Inc. All rights reserved.
// Licensed under the terms of the LICENSE file distributed with this project.
*/

@import "styles/api";
@import "styles/content";
@import "styles/examples";
@import "styles/layout";
Expand Down
36 changes: 36 additions & 0 deletions packages/docs-theme/src/styles/_api.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2017 Palantir Technologies, Inc. All rights reserved.
// Licensed under the terms of the LICENSE file distributed with this project.

@import "variables";

.docs-api-dialog {
width: auto;
height: 80vh;
padding: 0;

.docs-modifiers {
display: flex;
flex-direction: column;
margin: 0;
width: $content-width;

> * {
padding: $pt-grid-size ($pt-grid-size * 2);
}
}

.docs-interface-header {
flex: 0 0 auto;
margin: 0;
}

.docs-interface-table {
overflow: auto;
padding-bottom: $pt-grid-size * 2;
}
}

.docs-code {
font-family: $pt-font-family-monospace;
font-weight: 600;
}
2 changes: 1 addition & 1 deletion packages/docs-theme/src/tags/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ export function createDefaultRenderers(): Record<string, React.ComponentType<ITa
heading: tags.Heading,
interface: tags.TypescriptExample,
page: () => null,
// TODO: @see
see: tags.SeeTag,
};
}
1 change: 1 addition & 0 deletions packages/docs-theme/src/tags/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ export * from "./defaults";
export * from "./heading";
export * from "./reactDocs";
export * from "./reactExample";
export * from "./see";
export * from "./typescript";
15 changes: 15 additions & 0 deletions packages/docs-theme/src/tags/see.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright 2017 Palantir Technologies, Inc. All rights reserved.
*
* Licensed under the terms of the LICENSE file distributed with this project.
*/

import { ITag } from "documentalist/dist/client";
import * as React from "react";
import { DocumentationContextTypes, IDocumentationContext } from "../common/context";

export const SeeTag: React.SFC<ITag> = ({ value }, { renderType }: IDocumentationContext) => (
<p>See: {renderType(value)}</p>
);
SeeTag.contextTypes = DocumentationContextTypes;
SeeTag.displayName = "Docs.SeeTag";
2 changes: 1 addition & 1 deletion packages/table/src/common/cell.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
/*
* Copyright 2017 Palantir Technologies, Inc. All rights reserved.
*
* Licensed under the terms of the LICENSE file distributed with this project.
Expand Down
28 changes: 0 additions & 28 deletions packages/table/src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,6 @@
* Licensed under the terms of the LICENSE file distributed with this project.
*/

import { IProps } from "@blueprintjs/core";
import * as classNames from "classnames";
import * as React from "react";

/**
* Re-declare matching types from the classnames library;
*/
export type ClassValue = string | number | ClassDictionary | ClassArray;

// tslint:disable interface-name no-empty-interface
export interface ClassDictionary {
[id: string]: boolean;
}

export interface ClassArray extends Array<ClassValue> {}
// tslint:enable

const CLASSNAME_EXCLUDED_FROM_TEXT_MEASUREMENT = "bp-table-text-no-measure";

/**
Expand All @@ -39,17 +22,6 @@ export interface IKeyBlacklist<T> {
}

export const Utils = {
/**
* Returns a clone of the ReactElement with a className that includes the
* element's original className and any other classes passed in with variadic
* arguments matching the `classNames` api.
*/
assignClasses<P extends IProps>(elem: React.ReactElement<P>, ...extendedClasses: ClassValue[]): React.ReactNode {
const classes = classNames(elem.props.className, ...extendedClasses);
const props: IProps = { className: classes };
return React.cloneElement(elem, props);
},

/**
* Invokes the callback `n` times, collecting the results in an array, which
* is the return value. Similar to _.times
Expand Down
Loading

1 comment on commit 1d2ec47

@blueprint-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[docs] API browser and "see" JSDoc tag support (#2041)

Preview: documentation | landing | table

Please sign in to comment.