diff options
Diffstat (limited to 'packages/react-docs/src/components')
-rw-r--r-- | packages/react-docs/src/components/badge.tsx | 2 | ||||
-rw-r--r-- | packages/react-docs/src/components/comment.tsx | 4 | ||||
-rw-r--r-- | packages/react-docs/src/components/custom_enum.tsx | 4 | ||||
-rw-r--r-- | packages/react-docs/src/components/doc_reference.tsx (renamed from packages/react-docs/src/components/documentation.tsx) | 285 | ||||
-rw-r--r-- | packages/react-docs/src/components/event_definition.tsx | 11 | ||||
-rw-r--r-- | packages/react-docs/src/components/interface.tsx | 38 | ||||
-rw-r--r-- | packages/react-docs/src/components/property_block.tsx | 78 | ||||
-rw-r--r-- | packages/react-docs/src/components/signature.tsx | 66 | ||||
-rw-r--r-- | packages/react-docs/src/components/signature_block.tsx | 33 | ||||
-rw-r--r-- | packages/react-docs/src/components/source_link.tsx | 11 | ||||
-rw-r--r-- | packages/react-docs/src/components/type.tsx | 208 | ||||
-rw-r--r-- | packages/react-docs/src/components/type_definition.tsx | 30 |
12 files changed, 443 insertions, 327 deletions
diff --git a/packages/react-docs/src/components/badge.tsx b/packages/react-docs/src/components/badge.tsx index d34f8a0fc..e3d5be273 100644 --- a/packages/react-docs/src/components/badge.tsx +++ b/packages/react-docs/src/components/badge.tsx @@ -1,4 +1,4 @@ -import { Styles } from '@0xproject/react-shared'; +import { Styles } from '@0x/react-shared'; import * as React from 'react'; const styles: Styles = { diff --git a/packages/react-docs/src/components/comment.tsx b/packages/react-docs/src/components/comment.tsx index c3687c510..4d34f711e 100644 --- a/packages/react-docs/src/components/comment.tsx +++ b/packages/react-docs/src/components/comment.tsx @@ -1,4 +1,4 @@ -import { MarkdownCodeBlock } from '@0xproject/react-shared'; +import { colors, MarkdownCodeBlock } from '@0x/react-shared'; import * as React from 'react'; import * as ReactMarkdown from 'react-markdown'; @@ -13,7 +13,7 @@ const defaultProps = { export const Comment: React.SFC<CommentProps> = (props: CommentProps) => { return ( - <div className={`${props.className} comment`}> + <div className={`${props.className} comment`} style={{ color: colors.greyTheme }}> <ReactMarkdown source={props.comment} renderers={{ code: MarkdownCodeBlock }} /> </div> ); diff --git a/packages/react-docs/src/components/custom_enum.tsx b/packages/react-docs/src/components/custom_enum.tsx index c4252d9e2..e971a012a 100644 --- a/packages/react-docs/src/components/custom_enum.tsx +++ b/packages/react-docs/src/components/custom_enum.tsx @@ -1,8 +1,8 @@ -import { logUtils } from '@0xproject/utils'; +import { logUtils } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; -import { CustomType } from '../types'; +import { CustomType } from '@0x/types'; const STRING_ENUM_CODE_PREFIX = ' strEnum('; diff --git a/packages/react-docs/src/components/documentation.tsx b/packages/react-docs/src/components/doc_reference.tsx index ff33220d2..85547576b 100644 --- a/packages/react-docs/src/components/documentation.tsx +++ b/packages/react-docs/src/components/doc_reference.tsx @@ -2,38 +2,36 @@ import { colors, constants as sharedConstants, EtherscanLinkSuffixes, + HeaderSizes, + Link, MarkdownSection, - NestedSidebarMenu, Networks, SectionHeader, - Styles, utils as sharedUtils, -} from '@0xproject/react-shared'; -import * as _ from 'lodash'; -import CircularProgress from 'material-ui/CircularProgress'; -import * as React from 'react'; -import * as semver from 'semver'; - -import { DocsInfo } from '../docs_info'; +} from '@0x/react-shared'; import { - AddressByContractName, DocAgnosticFormat, Event, + ExternalExportToLink, Property, SolidityMethod, - SupportedDocJson, TypeDefinitionByName, TypescriptFunction, TypescriptMethod, -} from '../types'; +} from '@0x/types'; +import * as _ from 'lodash'; +import * as React from 'react'; +import * as semver from 'semver'; + +import { DocsInfo } from '../docs_info'; +import { AddressByContractName, SupportedDocJson } from '../types'; import { constants } from '../utils/constants'; import { Badge } from './badge'; import { Comment } from './comment'; import { EventDefinition } from './event_definition'; +import { PropertyBlock } from './property_block'; import { SignatureBlock } from './signature_block'; -import { SourceLink } from './source_link'; -import { Type } from './type'; import { TypeDefinition } from './type_definition'; const networkNameToColor: { [network: string]: string } = { @@ -43,142 +41,36 @@ const networkNameToColor: { [network: string]: string } = { [Networks.Rinkeby]: colors.darkYellow, }; -export interface DocumentationProps { +export interface DocReferenceProps { selectedVersion: string; availableVersions: string[]; docsInfo: DocsInfo; sourceUrl: string; - onVersionSelected: (semver: string) => void; docAgnosticFormat?: DocAgnosticFormat; - sidebarHeader?: React.ReactNode; - topBarHeight?: number; } -export interface DocumentationState { - isHoveringSidebar: boolean; -} +export interface DocReferenceState {} -export class Documentation extends React.Component<DocumentationProps, DocumentationState> { - public static defaultProps: Partial<DocumentationProps> = { - topBarHeight: 0, - }; - constructor(props: DocumentationProps) { - super(props); - this.state = { - isHoveringSidebar: false, - }; - } - public componentDidMount(): void { - window.addEventListener('hashchange', this._onHashChanged.bind(this), false); - } - public componentWillUnmount(): void { - window.removeEventListener('hashchange', this._onHashChanged.bind(this), false); - } - public componentDidUpdate(prevProps: DocumentationProps, _prevState: DocumentationState): void { +export class DocReference extends React.Component<DocReferenceProps, DocReferenceState> { + public componentDidUpdate(prevProps: DocReferenceProps, _prevState: DocReferenceState): void { if (!_.isEqual(prevProps.docAgnosticFormat, this.props.docAgnosticFormat)) { const hash = window.location.hash.slice(1); sharedUtils.scrollToHash(hash, sharedConstants.SCROLL_CONTAINER_ID); } } public render(): React.ReactNode { - const styles: Styles = { - mainContainers: { - position: 'absolute', - top: 1, - left: 0, - bottom: 0, - right: 0, - overflowX: 'hidden', - overflowY: 'scroll', - minHeight: `calc(100vh - ${this.props.topBarHeight}px)`, - WebkitOverflowScrolling: 'touch', - }, - menuContainer: { - borderColor: colors.grey300, - maxWidth: 330, - marginLeft: 20, - }, - }; - const menuSubsectionsBySection = this.props.docsInfo.getMenuSubsectionsBySection(this.props.docAgnosticFormat); - return ( - <div> - {_.isUndefined(this.props.docAgnosticFormat) ? ( - this._renderLoading(styles.mainContainers) - ) : ( - <div style={{ width: '100%', height: '100%', backgroundColor: colors.gray40 }}> - <div - className="mx-auto max-width-4 flex" - style={{ color: colors.grey800, height: `calc(100vh - ${this.props.topBarHeight}px)` }} - > - <div - className="relative sm-hide xs-hide" - style={{ width: '36%', height: `calc(100vh - ${this.props.topBarHeight}px)` }} - > - <div - className="border-right absolute" - style={{ - ...styles.menuContainer, - ...styles.mainContainers, - height: `calc(100vh - ${this.props.topBarHeight}px)`, - overflow: this.state.isHoveringSidebar ? 'auto' : 'hidden', - }} - onMouseEnter={this._onSidebarHover.bind(this)} - onMouseLeave={this._onSidebarHoverOff.bind(this)} - > - <NestedSidebarMenu - selectedVersion={this.props.selectedVersion} - versions={this.props.availableVersions} - sidebarHeader={this.props.sidebarHeader} - topLevelMenu={this.props.docsInfo.getMenu(this.props.selectedVersion)} - menuSubsectionsBySection={menuSubsectionsBySection} - onVersionSelected={this.props.onVersionSelected} - /> - </div> - </div> - <div - className="relative col lg-col-9 md-col-9 sm-col-12 col-12" - style={{ backgroundColor: colors.white }} - > - <div - id={sharedConstants.SCROLL_CONTAINER_ID} - style={styles.mainContainers} - className="absolute px1" - > - <div id={sharedConstants.SCROLL_TOP_ID} /> - {this._renderDocumentation()} - </div> - </div> - </div> - </div> - )} - </div> - ); - } - private _renderLoading(mainContainersStyles: React.CSSProperties): React.ReactNode { - return ( - <div className="col col-12" style={mainContainersStyles}> - <div - className="relative sm-px2 sm-pt2 sm-m1" - style={{ height: 122, top: '50%', transform: 'translateY(-50%)' }} - > - <div className="center pb2"> - <CircularProgress size={40} thickness={5} /> - </div> - <div className="center pt2" style={{ paddingBottom: 11 }}> - Loading documentation... - </div> - </div> - </div> - ); - } - private _renderDocumentation(): React.ReactNode { - const subMenus = _.values(this.props.docsInfo.getMenu()); + const subMenus = _.values(this.props.docsInfo.markdownMenu); const orderedSectionNames = _.flatten(subMenus); const typeDefinitionByName = this.props.docsInfo.getTypeDefinitionsByName(this.props.docAgnosticFormat); const renderedSections = _.map(orderedSectionNames, this._renderSection.bind(this, typeDefinitionByName)); - return renderedSections; + return ( + <div> + <div id={sharedConstants.SCROLL_TOP_ID} /> + {renderedSections} + </div> + ); } private _renderSection(typeDefinitionByName: TypeDefinitionByName, sectionName: string): React.ReactNode { const markdownVersions = _.keys(this.props.docsInfo.sectionNameToMarkdownByVersion); @@ -196,11 +88,16 @@ export class Documentation extends React.Component<DocumentationProps, Documenta const closestVersion = sortedEligibleVersions[0]; const markdownFileIfExists = this.props.docsInfo.sectionNameToMarkdownByVersion[closestVersion][sectionName]; if (!_.isUndefined(markdownFileIfExists)) { + // Special-case replace the `introduction` sectionName with the package name + const isIntroductionSection = sectionName === 'introduction'; + const headerSize = isIntroductionSection ? HeaderSizes.H1 : HeaderSizes.H3; return ( <MarkdownSection key={`markdown-section-${sectionName}`} sectionName={sectionName} + headerSize={headerSize} markdownContent={markdownFileIfExists} + alternativeSectionTitle={isIntroductionSection ? this.props.docsInfo.displayName : undefined} /> ); } @@ -210,20 +107,33 @@ export class Documentation extends React.Component<DocumentationProps, Documenta return null; } + const isExportedFunctionSection = + docSection.functions.length === 1 && + _.isEmpty(docSection.types) && + _.isEmpty(docSection.methods) && + _.isEmpty(docSection.constructors) && + _.isEmpty(docSection.properties) && + _.isEmpty(docSection.events); + const sortedTypes = _.sortBy(docSection.types, 'name'); - const typeDefs = _.map(sortedTypes, customType => { + const typeDefs = _.map(sortedTypes, (customType, i) => { return ( <TypeDefinition sectionName={sectionName} - key={`type-${customType.name}`} + key={`type-${customType.name}-${i}`} customType={customType} docsInfo={this.props.docsInfo} + typeDefinitionByName={typeDefinitionByName} + isInPopover={false} /> ); }); const sortedProperties = _.sortBy(docSection.properties, 'name'); - const propertyDefs = _.map(sortedProperties, this._renderProperty.bind(this, sectionName)); + const propertyDefs = _.map( + sortedProperties, + this._renderProperty.bind(this, sectionName, typeDefinitionByName), + ); const sortedMethods = _.sortBy(docSection.methods, 'name'); const methodDefs = _.map(sortedMethods, method => { @@ -258,13 +168,12 @@ export class Documentation extends React.Component<DocumentationProps, Documenta {this._renderNetworkBadgesIfExists(sectionName)} </div> {docSection.comment && <Comment comment={docSection.comment} />} - {!_.isEmpty(docSection.constructors) && - this.props.docsInfo.isVisibleConstructor(sectionName) && ( - <div> - <h2 style={headerStyle}>Constructor</h2> - {this._renderConstructors(docSection.constructors, sectionName, typeDefinitionByName)} - </div> - )} + {!_.isEmpty(docSection.constructors) && ( + <div> + <h2 style={headerStyle}>Constructor</h2> + {this._renderConstructors(docSection.constructors, sectionName, typeDefinitionByName)} + </div> + )} {!_.isEmpty(docSection.properties) && ( <div> <h2 style={headerStyle}>Properties</h2> @@ -279,7 +188,9 @@ export class Documentation extends React.Component<DocumentationProps, Documenta )} {!_.isEmpty(docSection.functions) && ( <div> - <h2 style={headerStyle}>Functions</h2> + {!isExportedFunctionSection && ( + <div style={{ ...headerStyle, fontSize: '1.5em' }}>Functions</div> + )} <div>{functionDefs}</div> </div> )} @@ -290,17 +201,44 @@ export class Documentation extends React.Component<DocumentationProps, Documenta <div>{eventDefs}</div> </div> )} + {!_.isUndefined(docSection.externalExportToLink) && + this._renderExternalExports(docSection.externalExportToLink)} {!_.isUndefined(typeDefs) && typeDefs.length > 0 && ( <div> <div>{typeDefs}</div> </div> )} + <div + style={{ + width: '100%', + height: 1, + backgroundColor: colors.grey300, + marginTop: 32, + marginBottom: 12, + }} + /> </div> ); } + private _renderExternalExports(externalExportToLink: ExternalExportToLink): React.ReactNode { + const externalExports = _.map(externalExportToLink, (link: string, exportName: string) => { + return ( + <div className="pt2" key={`external-export-${exportName}`}> + <code className={`hljs ${constants.TYPE_TO_SYNTAX[this.props.docsInfo.type]}`}> + {`import { `} + <Link to={link} shouldOpenInNewTab={true} fontColor={colors.lightBlueA700}> + {exportName} + </Link> + {` } from '${this.props.docsInfo.packageName}'`} + </code> + </div> + ); + }); + return <div>{externalExports}</div>; + } private _renderNetworkBadgesIfExists(sectionName: string): React.ReactNode { - if (this.props.docsInfo.type !== SupportedDocJson.Doxity) { + if (this.props.docsInfo.type !== SupportedDocJson.SolDoc) { return null; } @@ -320,14 +258,16 @@ export class Documentation extends React.Component<DocumentationProps, Documenta EtherscanLinkSuffixes.Address, ); return ( - <a - key={`badge-${networkName}-${sectionName}`} - href={linkIfExists} - target="_blank" - style={{ color: colors.white, textDecoration: 'none' }} - > - <Badge title={networkName} backgroundColor={networkNameToColor[networkName]} /> - </a> + <div style={{ marginTop: 8 }}> + <Link + key={`badge-${networkName}-${sectionName}`} + to={linkIfExists} + shouldOpenInNewTab={true} + fontColor={colors.white} + > + <Badge title={networkName} backgroundColor={networkNameToColor[networkName]} /> + </Link> + </div> ); }, ); @@ -343,22 +283,21 @@ export class Documentation extends React.Component<DocumentationProps, Documenta }); return <div>{constructorDefs}</div>; } - private _renderProperty(sectionName: string, property: Property): React.ReactNode { + private _renderProperty( + sectionName: string, + typeDefinitionByName: TypeDefinitionByName, + property: Property, + ): React.ReactNode { return ( - <div key={`property-${property.name}-${property.type.name}`} className="pb3"> - <code className={`hljs ${constants.TYPE_TO_SYNTAX[this.props.docsInfo.type]}`}> - {property.name}:{' '} - <Type type={property.type} sectionName={sectionName} docsInfo={this.props.docsInfo} /> - </code> - {property.source && ( - <SourceLink - version={this.props.selectedVersion} - source={property.source} - sourceUrl={this.props.sourceUrl} - /> - )} - {property.comment && <Comment comment={property.comment} className="py2" />} - </div> + <PropertyBlock + key={`property-${property.name}-${property.type.name}`} + property={property} + sectionName={sectionName} + docsInfo={this.props.docsInfo} + sourceUrl={this.props.sourceUrl} + selectedVersion={this.props.selectedVersion} + typeDefinitionByName={typeDefinitionByName} + /> ); } private _renderSignatureBlocks( @@ -378,18 +317,4 @@ export class Documentation extends React.Component<DocumentationProps, Documenta /> ); } - private _onSidebarHover(_event: React.FormEvent<HTMLInputElement>): void { - this.setState({ - isHoveringSidebar: true, - }); - } - private _onSidebarHoverOff(): void { - this.setState({ - isHoveringSidebar: false, - }); - } - private _onHashChanged(_event: any): void { - const hash = window.location.hash.slice(1); - sharedUtils.scrollToHash(hash, sharedConstants.SCROLL_CONTAINER_ID); - } } diff --git a/packages/react-docs/src/components/event_definition.tsx b/packages/react-docs/src/components/event_definition.tsx index b4dc729a9..b76769788 100644 --- a/packages/react-docs/src/components/event_definition.tsx +++ b/packages/react-docs/src/components/event_definition.tsx @@ -1,9 +1,9 @@ -import { AnchorTitle, colors, HeaderSizes } from '@0xproject/react-shared'; +import { AnchorTitle, colors, HeaderSizes } from '@0x/react-shared'; +import { Event, EventArg } from '@0x/types'; import * as _ from 'lodash'; import * as React from 'react'; import { DocsInfo } from '../docs_info'; -import { Event, EventArg } from '../types'; import { Type } from './type'; @@ -53,7 +53,12 @@ export class EventDefinition extends React.Component<EventDefinitionProps, Event const indexed = <span style={{ color: colors.green }}> indexed</span>; const eventArgs = _.map(this.props.event.eventArgs, (eventArg: EventArg) => { const type = ( - <Type type={eventArg.type} sectionName={this.props.sectionName} docsInfo={this.props.docsInfo} /> + <Type + type={eventArg.type} + sectionName={this.props.sectionName} + docsInfo={this.props.docsInfo} + isInPopover={false} + /> ); return ( <span key={`eventArg-${eventArg.name}`}> diff --git a/packages/react-docs/src/components/interface.tsx b/packages/react-docs/src/components/interface.tsx index a881c7fec..0df44ca1c 100644 --- a/packages/react-docs/src/components/interface.tsx +++ b/packages/react-docs/src/components/interface.tsx @@ -1,27 +1,30 @@ import * as _ from 'lodash'; import * as React from 'react'; +import { CustomType, TypeDefinitionByName } from '@0x/types'; + import { DocsInfo } from '../docs_info'; -import { CustomType, TypeDocTypes } from '../types'; import { Signature } from './signature'; import { Type } from './type'; +const defaultProps = {}; + export interface InterfaceProps { type: CustomType; sectionName: string; docsInfo: DocsInfo; + typeDefinitionByName: TypeDefinitionByName; + isInPopover: boolean; } -export const Interface = (props: InterfaceProps) => { +export const Interface: React.SFC<InterfaceProps> = (props: InterfaceProps): any => { const type = props.type; - const properties = _.map(type.children, property => { + const properties = _.map(type.children, (property, i) => { return ( - <span key={`property-${property.name}-${property.type}-${type.name}`}> + <span key={`property-${property.name}-${property.type}-${type.name}-${i}`}> {property.name}:{' '} - {property.type && property.type.typeDocType !== TypeDocTypes.Reflection ? ( - <Type type={property.type} sectionName={props.sectionName} docsInfo={props.docsInfo} /> - ) : ( + {property.type && !_.isUndefined(property.type.method) ? ( <Signature name={property.type.method.name} returnType={property.type.method.returnType} @@ -31,6 +34,16 @@ export const Interface = (props: InterfaceProps) => { shouldHideMethodName={true} shouldUseArrowSyntax={true} docsInfo={props.docsInfo} + typeDefinitionByName={props.typeDefinitionByName} + isInPopover={props.isInPopover} + /> + ) : ( + <Type + type={property.type} + sectionName={props.sectionName} + docsInfo={props.docsInfo} + typeDefinitionByName={props.typeDefinitionByName} + isInPopover={props.isInPopover} /> )}, </span> @@ -41,7 +54,14 @@ export const Interface = (props: InterfaceProps) => { const is = type.indexSignature; const param = ( <span key={`indexSigParams-${is.keyName}-${is.keyType}-${type.name}`}> - {is.keyName}: <Type type={is.keyType} sectionName={props.sectionName} docsInfo={props.docsInfo} /> + {is.keyName}:{' '} + <Type + type={is.keyType} + sectionName={props.sectionName} + docsInfo={props.docsInfo} + typeDefinitionByName={props.typeDefinitionByName} + isInPopover={props.isInPopover} + /> </span> ); properties.push( @@ -64,3 +84,5 @@ export const Interface = (props: InterfaceProps) => { </span> ); }; + +Interface.defaultProps = defaultProps; diff --git a/packages/react-docs/src/components/property_block.tsx b/packages/react-docs/src/components/property_block.tsx new file mode 100644 index 000000000..d0bd84802 --- /dev/null +++ b/packages/react-docs/src/components/property_block.tsx @@ -0,0 +1,78 @@ +import { AnchorTitle, HeaderSizes } from '@0x/react-shared'; +import { Property, TypeDefinitionByName } from '@0x/types'; +import * as React from 'react'; + +import { DocsInfo } from '../docs_info'; +import { constants } from '../utils/constants'; + +import { Comment } from './comment'; +import { SourceLink } from './source_link'; +import { Type } from './type'; + +export interface PropertyBlockProps { + property: Property; + sectionName: string; + docsInfo: DocsInfo; + sourceUrl: string; + selectedVersion: string; + typeDefinitionByName: TypeDefinitionByName; +} + +export interface PropertyBlockState { + shouldShowAnchor: boolean; +} + +export class PropertyBlock extends React.Component<PropertyBlockProps, PropertyBlockState> { + constructor(props: PropertyBlockProps) { + super(props); + this.state = { + shouldShowAnchor: false, + }; + } + public render(): React.ReactNode { + const property = this.props.property; + const sectionName = this.props.sectionName; + return ( + <div + id={`${this.props.sectionName}-${property.name}`} + className="pb4 pt2" + key={`property-${property.name}-${property.type.name}`} + onMouseOver={this._setAnchorVisibility.bind(this, true)} + onMouseOut={this._setAnchorVisibility.bind(this, false)} + > + <div className="pb2" style={{ lineHeight: 1.3 }}> + <AnchorTitle + headerSize={HeaderSizes.H3} + title={property.name} + id={`${sectionName}-${property.name}`} + shouldShowAnchor={this.state.shouldShowAnchor} + /> + </div> + <code className={`hljs ${constants.TYPE_TO_SYNTAX[this.props.docsInfo.type]}`}> + {(property as any).callPath} + {property.name}:{' '} + <Type + type={property.type} + sectionName={sectionName} + docsInfo={this.props.docsInfo} + typeDefinitionByName={this.props.typeDefinitionByName} + isInPopover={false} + /> + </code> + {property.source && ( + <SourceLink + version={this.props.selectedVersion} + source={property.source} + sourceUrl={this.props.sourceUrl} + /> + )} + {property.comment && <Comment comment={property.comment} className="py2" />} + </div> + ); + } + private _setAnchorVisibility(shouldShowAnchor: boolean): void { + this.setState({ + shouldShowAnchor, + }); + } +} diff --git a/packages/react-docs/src/components/signature.tsx b/packages/react-docs/src/components/signature.tsx index 77e9cc909..c229999b1 100644 --- a/packages/react-docs/src/components/signature.tsx +++ b/packages/react-docs/src/components/signature.tsx @@ -1,9 +1,9 @@ import * as _ from 'lodash'; import * as React from 'react'; +import { Parameter, Type as TypeDef, TypeDefinitionByName, TypeParameter } from '@0x/types'; + import { DocsInfo } from '../docs_info'; -import { Parameter, Type as TypeDef, TypeDefinitionByName, TypeParameter } from '../types'; -import { constants } from '../utils/constants'; import { Type } from './type'; @@ -18,17 +18,27 @@ export interface SignatureProps { typeParameter?: TypeParameter; callPath?: string; docsInfo: DocsInfo; + isInPopover: boolean; + isFallback?: boolean; } const defaultProps = { shouldHideMethodName: false, shouldUseArrowSyntax: false, callPath: '', + isFallback: false, }; export const Signature: React.SFC<SignatureProps> = (props: SignatureProps) => { - const sectionName = constants.TYPES_SECTION_NAME; - const parameters = renderParameters(props.parameters, props.docsInfo, sectionName, props.typeDefinitionByName); + const sectionName = props.sectionName; + const parameters = renderParameters( + props.parameters, + props.docsInfo, + sectionName, + props.isInPopover, + props.name, + props.typeDefinitionByName, + ); const paramStringArray: any[] = []; // HACK: For now we don't put params on newlines if there are less then 2 of them. // Ideally we would check the character length of the resulting method signature and @@ -58,11 +68,17 @@ export const Signature: React.SFC<SignatureProps> = (props: SignatureProps) => { const methodName = props.shouldHideMethodName ? '' : props.name; const typeParameterIfExists = _.isUndefined(props.typeParameter) ? undefined - : renderTypeParameter(props.typeParameter, props.docsInfo, sectionName, props.typeDefinitionByName); + : renderTypeParameter( + props.typeParameter, + props.docsInfo, + sectionName, + props.isInPopover, + props.typeDefinitionByName, + ); return ( <span style={{ fontSize: 15 }}> {props.callPath} - {methodName} + {props.isFallback ? '' : methodName} {typeParameterIfExists}({hasMoreThenTwoParams && <br />} {paramStringArray}) {props.returnType && ( @@ -73,6 +89,7 @@ export const Signature: React.SFC<SignatureProps> = (props: SignatureProps) => { sectionName={sectionName} typeDefinitionByName={props.typeDefinitionByName} docsInfo={props.docsInfo} + isInPopover={props.isInPopover} /> </span> )} @@ -86,9 +103,11 @@ function renderParameters( parameters: Parameter[], docsInfo: DocsInfo, sectionName: string, + isInPopover: boolean, + name: string, typeDefinitionByName?: TypeDefinitionByName, ): React.ReactNode[] { - const params = _.map(parameters, (p: Parameter) => { + const params = _.map(parameters, (p: Parameter, i: number) => { const isOptional = p.isOptional; const hasDefaultValue = !_.isUndefined(p.defaultValue); const type = ( @@ -97,12 +116,18 @@ function renderParameters( sectionName={sectionName} typeDefinitionByName={typeDefinitionByName} docsInfo={docsInfo} + isInPopover={isInPopover} /> ); return ( - <span key={`param-${p.type}-${p.name}`}> - {p.name} - {isOptional && '?'}: {type} + <span key={`param-${JSON.stringify(p.type)}-${name}-${i}`}> + {!_.isEmpty(p.name) && ( + <span> + {p.name} + {isOptional && '?'}:{' '} + </span> + )} + {type} {hasDefaultValue && ` = ${p.defaultValue}`} </span> ); @@ -114,17 +139,24 @@ function renderTypeParameter( typeParameter: TypeParameter, docsInfo: DocsInfo, sectionName: string, + isInPopover: boolean, typeDefinitionByName?: TypeDefinitionByName, ): React.ReactNode { const typeParam = ( <span> - {`<${typeParameter.name} extends `} - <Type - type={typeParameter.type} - sectionName={sectionName} - typeDefinitionByName={typeDefinitionByName} - docsInfo={docsInfo} - /> + {`<${typeParameter.name}`} + {!_.isUndefined(typeParameter.type) && ( + <span> + {' extends '} + <Type + type={typeParameter.type} + sectionName={sectionName} + typeDefinitionByName={typeDefinitionByName} + docsInfo={docsInfo} + isInPopover={isInPopover} + /> + </span> + )} {`>`} </span> ); diff --git a/packages/react-docs/src/components/signature_block.tsx b/packages/react-docs/src/components/signature_block.tsx index 9e5198e16..7cdf19bb0 100644 --- a/packages/react-docs/src/components/signature_block.tsx +++ b/packages/react-docs/src/components/signature_block.tsx @@ -1,11 +1,10 @@ -import { AnchorTitle, colors, HeaderSizes, Styles } from '@0xproject/react-shared'; +import { AnchorTitle, colors, HeaderSizes, Styles } from '@0x/react-shared'; +import { Parameter, SolidityMethod, TypeDefinitionByName, TypescriptFunction, TypescriptMethod } from '@0x/types'; import * as _ from 'lodash'; import * as React from 'react'; import { DocsInfo } from '../docs_info'; -import { Parameter, SolidityMethod, TypeDefinitionByName, TypescriptFunction, TypescriptMethod } from '../types'; import { constants } from '../utils/constants'; -import { typeDocUtils } from '../utils/typedoc_utils'; import { Comment } from './comment'; import { Signature } from './signature'; @@ -27,7 +26,6 @@ export interface SignatureBlockState { const styles: Styles = { chip: { fontSize: 13, - backgroundColor: colors.lightBlueA700, color: colors.white, height: 11, borderRadius: 14, @@ -44,15 +42,14 @@ export class SignatureBlock extends React.Component<SignatureBlockProps, Signatu } public render(): React.ReactNode { const method = this.props.method; - if (typeDocUtils.isPrivateOrProtectedProperty(method.name)) { - return null; - } + const isFallback = (method as SolidityMethod).isFallback; + const hasExclusivelyNamedParams = !_.isUndefined(_.find(method.parameters, p => !_.isEmpty(p.name))); return ( <div id={`${this.props.sectionName}-${method.name}`} style={{ overflow: 'hidden', width: '100%' }} - className="pb4" + className="pb4 pt2" onMouseOver={this._setAnchorVisibility.bind(this, true)} onMouseOut={this._setAnchorVisibility.bind(this, false)} > @@ -61,10 +58,11 @@ export class SignatureBlock extends React.Component<SignatureBlockProps, Signatu {(method as TypescriptMethod).isStatic && this._renderChip('Static')} {(method as SolidityMethod).isConstant && this._renderChip('Constant')} {(method as SolidityMethod).isPayable && this._renderChip('Payable')} + {isFallback && this._renderChip('Fallback', colors.lightGreenA700)} <div style={{ lineHeight: 1.3 }}> <AnchorTitle headerSize={HeaderSizes.H3} - title={method.name} + title={isFallback ? '' : method.name} id={`${this.props.sectionName}-${method.name}`} shouldShowAnchor={this.state.shouldShowAnchor} /> @@ -81,6 +79,8 @@ export class SignatureBlock extends React.Component<SignatureBlockProps, Signatu sectionName={this.props.sectionName} typeDefinitionByName={this.props.typeDefinitionByName} docsInfo={this.props.docsInfo} + isInPopover={false} + isFallback={isFallback} /> </code> {(method as TypescriptMethod).source && ( @@ -92,12 +92,13 @@ export class SignatureBlock extends React.Component<SignatureBlockProps, Signatu )} {method.comment && <Comment comment={method.comment} className="py2" />} {method.parameters && - !_.isEmpty(method.parameters) && ( + !_.isEmpty(method.parameters) && + hasExclusivelyNamedParams && ( <div> <h4 className="pb1 thin" style={{ borderBottom: '1px solid #e1e8ed' }}> ARGUMENTS </h4> - {this._renderParameterDescriptions(method.parameters)} + {this._renderParameterDescriptions(method.parameters, method.name)} </div> )} {method.returnComment && ( @@ -111,19 +112,19 @@ export class SignatureBlock extends React.Component<SignatureBlockProps, Signatu </div> ); } - private _renderChip(text: string): React.ReactNode { + private _renderChip(text: string, backgroundColor: string = colors.lightBlueA700): React.ReactNode { return ( - <div className="p1 mr1" style={styles.chip}> + <div className="p1 mr1" style={{ ...styles.chip, backgroundColor }}> {text} </div> ); } - private _renderParameterDescriptions(parameters: Parameter[]): React.ReactNode { - const descriptions = _.map(parameters, parameter => { + private _renderParameterDescriptions(parameters: Parameter[], name: string): React.ReactNode { + const descriptions = _.map(parameters, (parameter: Parameter, i: number) => { const isOptional = parameter.isOptional; return ( <div - key={`param-description-${parameter.name}`} + key={`param-description-${parameter.name}-${name}-${i}`} className="flex pb1 mb2" style={{ borderBottom: '1px solid #f0f4f7' }} > diff --git a/packages/react-docs/src/components/source_link.tsx b/packages/react-docs/src/components/source_link.tsx index c60435ea6..6459824c2 100644 --- a/packages/react-docs/src/components/source_link.tsx +++ b/packages/react-docs/src/components/source_link.tsx @@ -1,8 +1,7 @@ -import { colors } from '@0xproject/react-shared'; +import { colors, Link } from '@0x/react-shared'; +import { Source } from '@0x/types'; import * as React from 'react'; -import { Source } from '../types'; - export interface SourceLinkProps { source: Source; sourceUrl: string; @@ -14,9 +13,9 @@ export const SourceLink = (props: SourceLinkProps) => { const sourceCodeUrl = `${props.sourceUrl}/${src.fileName}#L${src.line}`; return ( <div className="pt2" style={{ fontSize: 14 }}> - <a href={sourceCodeUrl} target="_blank" className="underline" style={{ color: colors.grey }}> - Source - </a> + <Link to={sourceCodeUrl} shouldOpenInNewTab={true} textDecoration="underline" fontColor={colors.grey}> + {'Source'} + </Link> </div> ); }; diff --git a/packages/react-docs/src/components/type.tsx b/packages/react-docs/src/components/type.tsx index e453349ef..412b99b9d 100644 --- a/packages/react-docs/src/components/type.tsx +++ b/packages/react-docs/src/components/type.tsx @@ -1,26 +1,32 @@ -import { colors, constants as sharedConstants, utils as sharedUtils } from '@0xproject/react-shared'; -import { errorUtils } from '@0xproject/utils'; +import { colors, constants as sharedConstants, Link, utils as sharedUtils } from '@0x/react-shared'; +import { Type as TypeDef, TypeDefinitionByName, TypeDocTypes } from '@0x/types'; +import { errorUtils } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; import { Link as ScrollLink } from 'react-scroll'; import * as ReactTooltip from 'react-tooltip'; import { DocsInfo } from '../docs_info'; -import { Type as TypeDef, TypeDefinitionByName, TypeDocTypes } from '../types'; import { Signature } from './signature'; import { TypeDefinition } from './type_definition'; +const basicJsTypes = ['string', 'number', 'undefined', 'null', 'boolean']; +const basicSolidityTypes = ['bytes', 'bytes4', 'bytes32', 'uint8', 'uint256', 'address']; + +const defaultProps = {}; + export interface TypeProps { type: TypeDef; docsInfo: DocsInfo; sectionName: string; typeDefinitionByName?: TypeDefinitionByName; + isInPopover: boolean; } // The return type needs to be `any` here so that we can recursively define <Type /> components within // <Type /> components (e.g when rendering the union type). -export function Type(props: TypeProps): any { +export const Type: React.SFC<TypeProps> = (props: TypeProps): any => { const type = props.type; const isReference = type.typeDocType === TypeDocTypes.Reference; const isArray = type.typeDocType === TypeDocTypes.Array; @@ -43,10 +49,11 @@ export function Type(props: TypeProps): any { <span> <Type key={key} - type={arg.elementType} + type={arg} sectionName={props.sectionName} typeDefinitionByName={props.typeDefinitionByName} docsInfo={props.docsInfo} + isInPopover={props.isInPopover} />[] </span> ); @@ -58,6 +65,7 @@ export function Type(props: TypeProps): any { sectionName={props.sectionName} typeDefinitionByName={props.typeDefinitionByName} docsInfo={props.docsInfo} + isInPopover={props.isInPopover} /> ); return subType; @@ -72,6 +80,9 @@ export function Type(props: TypeProps): any { case TypeDocTypes.Array: typeName = type.elementType.name; + if (_.includes(basicJsTypes, typeName) || _.includes(basicSolidityTypes, typeName)) { + typeNameColor = colors.orange; + } break; case TypeDocTypes.Union: @@ -83,6 +94,7 @@ export function Type(props: TypeProps): any { sectionName={props.sectionName} typeDefinitionByName={props.typeDefinitionByName} docsInfo={props.docsInfo} + isInPopover={props.isInPopover} /> ); }); @@ -92,19 +104,45 @@ export function Type(props: TypeProps): any { break; case TypeDocTypes.Reflection: - typeName = ( - <Signature - name={type.method.name} - returnType={type.method.returnType} - parameters={type.method.parameters} - typeParameter={type.method.typeParameter} - sectionName={props.sectionName} - shouldHideMethodName={true} - shouldUseArrowSyntax={true} - docsInfo={props.docsInfo} - typeDefinitionByName={props.typeDefinitionByName} - /> - ); + if (!_.isUndefined(type.method)) { + typeName = ( + <Signature + name={type.method.name} + returnType={type.method.returnType} + parameters={type.method.parameters} + typeParameter={type.method.typeParameter} + sectionName={props.sectionName} + shouldHideMethodName={true} + shouldUseArrowSyntax={true} + docsInfo={props.docsInfo} + typeDefinitionByName={props.typeDefinitionByName} + isInPopover={props.isInPopover} + /> + ); + } else if (!_.isUndefined(type.indexSignature)) { + const is = type.indexSignature; + const param = ( + <span key={`indexSigParams-${is.keyName}-${is.keyType}-${type.name}`}> + {is.keyName}:{' '} + <Type + type={is.keyType} + sectionName={props.sectionName} + docsInfo={props.docsInfo} + typeDefinitionByName={props.typeDefinitionByName} + isInPopover={props.isInPopover} + /> + </span> + ); + typeName = ( + <span key={`indexSignature-${type.name}-${is.keyType.name}`}> + {'{'}[{param}]: {is.valueName} + {'}'} + </span> + ); + } else { + throw new Error(`Unrecognized Reflection type that isn't a Method nor an Index Signature`); + } + break; case TypeDocTypes.TypeParameter: @@ -120,6 +158,7 @@ export function Type(props: TypeProps): any { sectionName={props.sectionName} typeDefinitionByName={props.typeDefinitionByName} docsInfo={props.docsInfo} + isInPopover={props.isInPopover} /> ); }); @@ -128,6 +167,28 @@ export function Type(props: TypeProps): any { }); break; + case TypeDocTypes.Tuple: + const tupleTypes = _.map(type.tupleElements, (t, i) => { + return ( + <Type + key={`type-tuple-${t.name}-${t.typeDocType}-${i}`} + type={t} + sectionName={props.sectionName} + typeDefinitionByName={props.typeDefinitionByName} + docsInfo={props.docsInfo} + isInPopover={props.isInPopover} + /> + ); + }); + typeName = ( + <div> + [{_.reduce(tupleTypes, (prev: React.ReactNode, curr: React.ReactNode) => { + return [prev, ', ', curr]; + })}] + </div> + ); + break; + default: throw errorUtils.spawnSwitchErr('type.typeDocType', type.typeDocType); } @@ -140,81 +201,60 @@ export function Type(props: TypeProps): any { return [prev, ', ', curr]; }); - let typeNameUrlIfExists; - let typePrefixIfExists; - let sectionNameIfExists; - if (!_.isUndefined(props.docsInfo.typeConfigs)) { - typeNameUrlIfExists = !_.isUndefined(props.docsInfo.typeConfigs.typeNameToExternalLink) - ? props.docsInfo.typeConfigs.typeNameToExternalLink[typeName as string] - : undefined; - typePrefixIfExists = !_.isUndefined(props.docsInfo.typeConfigs.typeNameToPrefix) - ? props.docsInfo.typeConfigs.typeNameToPrefix[typeName as string] - : undefined; - sectionNameIfExists = !_.isUndefined(props.docsInfo.typeConfigs.typeNameToDocSection) - ? props.docsInfo.typeConfigs.typeNameToDocSection[typeName as string] - : undefined; - } + const isExportedClassReference = !!props.type.isExportedClassReference; + const typeNameUrlIfExists = !_.isUndefined(props.type.externalLink) ? props.type.externalLink : undefined; if (!_.isUndefined(typeNameUrlIfExists)) { - typeName = ( - <a - href={typeNameUrlIfExists} - target="_blank" - className="text-decoration-none" - style={{ color: colors.lightBlueA700 }} - > - {!_.isUndefined(typePrefixIfExists) ? `${typePrefixIfExists}.` : ''} + typeName = props.isInPopover ? ( + <span style={{ color: colors.lightBlueA700, cursor: 'pointer' }}>{typeName}</span> + ) : ( + <Link to={typeNameUrlIfExists} shouldOpenInNewTab={true} fontColor={colors.lightBlueA700}> {typeName} - </a> + </Link> ); } else if ( (isReference || isArray) && - (props.docsInfo.isPublicType(typeName as string) || !_.isUndefined(sectionNameIfExists)) + ((props.typeDefinitionByName && props.typeDefinitionByName[typeName as string]) || isExportedClassReference) ) { const id = Math.random().toString(); - const typeDefinitionAnchorId = _.isUndefined(sectionNameIfExists) - ? `${props.sectionName}-${typeName}` - : sectionNameIfExists; - let typeDefinition; - if (props.typeDefinitionByName) { - typeDefinition = props.typeDefinitionByName[typeName as string]; - } + const typeDefinitionAnchorId = isExportedClassReference + ? props.type.name + : `${props.docsInfo.typeSectionName}-${typeName}`; typeName = ( - <ScrollLink - to={typeDefinitionAnchorId} - offset={0} - duration={sharedConstants.DOCS_SCROLL_DURATION_MS} - containerId={sharedConstants.DOCS_CONTAINER_ID} - > - {_.isUndefined(typeDefinition) || sharedUtils.isUserOnMobile() ? ( - <span - onClick={sharedUtils.setUrlHash.bind(null, typeDefinitionAnchorId)} - style={{ color: colors.lightBlueA700, cursor: 'pointer' }} - > - {typeName} - </span> + <span> + {sharedUtils.isUserOnMobile() || props.isInPopover || isExportedClassReference ? ( + <span style={{ color: colors.lightBlueA700, cursor: 'pointer' }}>{typeName}</span> ) : ( - <span - data-tip={true} - data-for={id} - onClick={sharedUtils.setUrlHash.bind(null, typeDefinitionAnchorId)} - style={{ - color: colors.lightBlueA700, - cursor: 'pointer', - display: 'inline-block', - }} + <ScrollLink + to={typeDefinitionAnchorId} + offset={0} + hashSpy={true} + duration={sharedConstants.DOCS_SCROLL_DURATION_MS} + containerId={sharedConstants.SCROLL_CONTAINER_ID} > - {typeName} - <ReactTooltip type="light" effect="solid" id={id} className="typeTooltip"> - <TypeDefinition - sectionName={props.sectionName} - customType={typeDefinition} - shouldAddId={false} - docsInfo={props.docsInfo} - /> - </ReactTooltip> - </span> + <span + data-tip={true} + data-for={id} + style={{ + color: colors.lightBlueA700, + cursor: 'pointer', + display: 'inline-block', + }} + > + {typeName} + <ReactTooltip type="light" effect="solid" id={id} className="typeTooltip"> + <TypeDefinition + sectionName={props.sectionName} + customType={props.typeDefinitionByName[typeName as string]} + shouldAddId={false} + docsInfo={props.docsInfo} + typeDefinitionByName={props.typeDefinitionByName} + isInPopover={true} + /> + </ReactTooltip> + </span> + </ScrollLink> )} - </ScrollLink> + </span> ); } return ( @@ -230,4 +270,6 @@ export function Type(props: TypeProps): any { )} </span> ); -} +}; + +Type.defaultProps = defaultProps; diff --git a/packages/react-docs/src/components/type_definition.tsx b/packages/react-docs/src/components/type_definition.tsx index c4bd7359a..a1fde51da 100644 --- a/packages/react-docs/src/components/type_definition.tsx +++ b/packages/react-docs/src/components/type_definition.tsx @@ -1,10 +1,11 @@ -import { AnchorTitle, colors, HeaderSizes } from '@0xproject/react-shared'; -import { errorUtils } from '@0xproject/utils'; +import { AnchorTitle, colors, HeaderSizes } from '@0x/react-shared'; +import { CustomType, CustomTypeChild, TypeDefinitionByName, TypeDocTypes } from '@0x/types'; +import { errorUtils } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; import { DocsInfo } from '../docs_info'; -import { CustomType, CustomTypeChild, KindString, TypeDocTypes } from '../types'; +import { KindString, SupportedDocJson } from '../types'; import { constants } from '../utils/constants'; import { Comment } from './comment'; @@ -19,6 +20,8 @@ export interface TypeDefinitionProps { customType: CustomType; shouldAddId?: boolean; docsInfo: DocsInfo; + typeDefinitionByName?: TypeDefinitionByName; + isInPopover?: boolean; } export interface TypeDefinitionState { @@ -28,6 +31,7 @@ export interface TypeDefinitionState { export class TypeDefinition extends React.Component<TypeDefinitionProps, TypeDefinitionState> { public static defaultProps: Partial<TypeDefinitionProps> = { shouldAddId: true, + isInPopover: false, }; constructor(props: TypeDefinitionProps) { super(props); @@ -37,17 +41,20 @@ export class TypeDefinition extends React.Component<TypeDefinitionProps, TypeDef } public render(): React.ReactNode { const customType = this.props.customType; - if (!this.props.docsInfo.isPublicType(customType.name)) { - return null; // no-op - } let typePrefix: string; let codeSnippet: React.ReactNode; switch (customType.kindString) { case KindString.Interface: - typePrefix = 'Interface'; + typePrefix = this.props.docsInfo.type === SupportedDocJson.SolDoc ? 'Struct' : 'Interface'; codeSnippet = ( - <Interface type={customType} sectionName={this.props.sectionName} docsInfo={this.props.docsInfo} /> + <Interface + type={customType} + sectionName={this.props.sectionName} + docsInfo={this.props.docsInfo} + typeDefinitionByName={this.props.typeDefinitionByName} + isInPopover={this.props.isInPopover} + /> ); break; @@ -77,6 +84,8 @@ export class TypeDefinition extends React.Component<TypeDefinitionProps, TypeDef type={customType.type} sectionName={this.props.sectionName} docsInfo={this.props.docsInfo} + typeDefinitionByName={this.props.typeDefinitionByName} + isInPopover={this.props.isInPopover} /> ) : ( <Signature @@ -89,6 +98,8 @@ export class TypeDefinition extends React.Component<TypeDefinitionProps, TypeDef shouldHideMethodName={true} shouldUseArrowSyntax={true} docsInfo={this.props.docsInfo} + typeDefinitionByName={this.props.typeDefinitionByName} + isInPopover={this.props.isInPopover} /> )} </span> @@ -103,7 +114,7 @@ export class TypeDefinition extends React.Component<TypeDefinitionProps, TypeDef return ( <div id={this.props.shouldAddId ? typeDefinitionAnchorId : ''} - className="pb2" + className="pb2 pt2" style={{ overflow: 'hidden', width: '100%' }} onMouseOver={this._setAnchorVisibility.bind(this, true)} onMouseOut={this._setAnchorVisibility.bind(this, false)} @@ -113,6 +124,7 @@ export class TypeDefinition extends React.Component<TypeDefinitionProps, TypeDef title={`${typePrefix} ${customType.name}`} id={this.props.shouldAddId ? typeDefinitionAnchorId : ''} shouldShowAnchor={this.state.shouldShowAnchor} + isDisabled={this.props.isInPopover} /> <div style={{ fontSize: 16 }}> <pre> |