1import { css } from '@emotion/core'; 2import { theme } from '@expo/styleguide'; 3import React from 'react'; 4import ReactMarkdown from 'react-markdown'; 5 6import { Code, InlineCode } from '~/components/base/code'; 7import { H4 } from '~/components/base/headings'; 8import { InternalLink } from '~/components/base/link'; 9import { LI, UL } from '~/components/base/list'; 10import { B, P, Quote } from '~/components/base/paragraph'; 11import { 12 CommentData, 13 MethodParamData, 14 TypeDefinitionData, 15 TypeDefinitionTypesData, 16} from '~/components/plugins/api/APIDataTypes'; 17 18export enum TypeDocKind { 19 Enum = 4, 20 Variable = 32, 21 Function = 64, 22 Class = 128, 23 Interface = 256, 24 Property = 1024, 25 TypeAlias = 4194304, 26} 27 28export type MDRenderers = React.ComponentProps<typeof ReactMarkdown>['renderers']; 29 30export const mdRenderers: MDRenderers = { 31 blockquote: ({ children }) => ( 32 <Quote> 33 {React.Children.map(children, child => 34 child.type.name === 'paragraph' ? child.props.children : child 35 )} 36 </Quote> 37 ), 38 code: ({ value, language }) => <Code className={`language-${language}`}>{value}</Code>, 39 heading: ({ children }) => <H4>{children}</H4>, 40 inlineCode: ({ value }) => <InlineCode>{value}</InlineCode>, 41 list: ({ children }) => <UL>{children}</UL>, 42 listItem: ({ children }) => <LI>{children}</LI>, 43 link: ({ href, children }) => <InternalLink href={href}>{children}</InternalLink>, 44 paragraph: ({ children }) => (children ? <P>{children}</P> : null), 45 strong: ({ children }) => <B>{children}</B>, 46 text: ({ value }) => (value ? <span>{value}</span> : null), 47}; 48 49export const mdInlineRenderers: MDRenderers = { 50 ...mdRenderers, 51 paragraph: ({ children }) => (children ? <span>{children}</span> : null), 52}; 53 54const nonLinkableTypes = ['Date', 'Uint8Array']; 55 56export const resolveTypeName = ({ 57 elementType, 58 name, 59 type, 60 types, 61 typeArguments, 62 declaration, 63}: TypeDefinitionData): string | JSX.Element => { 64 if (name) { 65 if (type === 'reference') { 66 if (typeArguments) { 67 if (name === 'Promise') { 68 return ( 69 <span> 70 {'Promise<'} 71 {typeArguments.map(resolveTypeName)} 72 {'>'} 73 </span> 74 ); 75 } else { 76 return `${typeArguments.map(resolveTypeName)}`; 77 } 78 } else { 79 if (nonLinkableTypes.includes(name)) { 80 return name; 81 } else { 82 return ( 83 <InternalLink href={`#${name.toLowerCase()}`} key={`type-link-${name}`}> 84 {name} 85 </InternalLink> 86 ); 87 } 88 } 89 } else { 90 return name; 91 } 92 } else if (elementType?.name) { 93 if (type === 'array') { 94 return elementType.name + '[]'; 95 } 96 return elementType.name + type; 97 } else if (type === 'union' && types?.length) { 98 return types 99 .map((t: TypeDefinitionTypesData) => 100 t.type === 'array' ? `${t.elementType?.name}[]` : `${t.name || t.value}` 101 ) 102 .join(' | '); 103 } else if (declaration?.signatures) { 104 return `() => ${resolveTypeName(declaration.signatures[0].type)}`; 105 } 106 return 'undefined'; 107}; 108 109export const renderParam = ({ comment, name, type }: MethodParamData): JSX.Element => ( 110 <LI key={`param-${name}`}> 111 <B> 112 {name} (<InlineCode>{resolveTypeName(type)}</InlineCode>) 113 </B> 114 <CommentTextBlock comment={comment} renderers={mdInlineRenderers} withDash /> 115 </LI> 116); 117 118export type CommentTextBlockProps = { 119 comment?: CommentData; 120 renderers?: MDRenderers; 121 withDash?: boolean; 122}; 123 124export const CommentTextBlock: React.FC<CommentTextBlockProps> = ({ 125 comment, 126 renderers = mdRenderers, 127 withDash, 128}) => { 129 const shortText = comment?.shortText?.trim().length ? ( 130 <ReactMarkdown renderers={renderers}>{comment.shortText}</ReactMarkdown> 131 ) : null; 132 const text = comment?.text?.trim().length ? ( 133 <ReactMarkdown renderers={renderers}>{comment.text}</ReactMarkdown> 134 ) : null; 135 return ( 136 <> 137 {withDash && (shortText || text) ? ' - ' : null} 138 {shortText} 139 {text} 140 </> 141 ); 142}; 143 144export const STYLES_OPTIONAL = css` 145 color: ${theme.text.secondary}; 146 font-size: 90%; 147 padding-top: 22px; 148`; 149