Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 12 commits into from
Feb 7, 2018
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