1import { css } from '@emotion/react'; 2import { theme, spacing, UndoIcon, iconSize } from '@expo/styleguide'; 3import React from 'react'; 4import ReactMarkdown from 'react-markdown'; 5 6import { InlineCode } from '~/components/base/code'; 7import { LI, UL } from '~/components/base/list'; 8import { H2, H3Code, H4, H4Code } from '~/components/plugins/Headings'; 9import { APIDataType } from '~/components/plugins/api/APIDataType'; 10import { 11 AccessorDefinitionData, 12 MethodDefinitionData, 13 MethodSignatureData, 14 PropData, 15 TypeSignaturesData, 16} from '~/components/plugins/api/APIDataTypes'; 17import { APISectionDeprecationNote } from '~/components/plugins/api/APISectionDeprecationNote'; 18import { APISectionPlatformTags } from '~/components/plugins/api/APISectionPlatformTags'; 19import { 20 CommentTextBlock, 21 getMethodName, 22 getTagNamesList, 23 mdComponents, 24 renderParams, 25 resolveTypeName, 26 STYLES_APIBOX, 27 STYLES_APIBOX_NESTED, 28 STYLES_NESTED_SECTION_HEADER, 29 STYLES_NOT_EXPOSED_HEADER, 30 TypeDocKind, 31} from '~/components/plugins/api/APISectionUtils'; 32 33export type APISectionMethodsProps = { 34 data: (MethodDefinitionData | PropData)[]; 35 apiName?: string; 36 header?: string; 37 exposeInSidebar?: boolean; 38}; 39 40export type RenderMethodOptions = { 41 apiName?: string; 42 header?: string; 43 exposeInSidebar?: boolean; 44}; 45 46export const renderMethod = ( 47 method: MethodDefinitionData | AccessorDefinitionData | PropData, 48 { apiName, exposeInSidebar = true }: RenderMethodOptions = {} 49): JSX.Element[] => { 50 const signatures = 51 (method as MethodDefinitionData).signatures || 52 (method as PropData)?.type?.declaration?.signatures || 53 (method as AccessorDefinitionData)?.getSignature || 54 []; 55 const HeaderComponent = exposeInSidebar ? H3Code : H4Code; 56 return signatures.map( 57 ({ name, parameters, comment, type }: MethodSignatureData | TypeSignaturesData) => ( 58 <div 59 key={`method-signature-${method.name || name}-${parameters?.length || 0}`} 60 css={[STYLES_APIBOX, !exposeInSidebar && STYLES_APIBOX_NESTED]}> 61 <APISectionDeprecationNote comment={comment} /> 62 <APISectionPlatformTags comment={comment} prefix="Only for:" /> 63 <HeaderComponent tags={getTagNamesList(comment)}> 64 <InlineCode css={!exposeInSidebar ? STYLES_NOT_EXPOSED_HEADER : undefined}> 65 {getMethodName(method as MethodDefinitionData, apiName, name, parameters)} 66 </InlineCode> 67 </HeaderComponent> 68 {parameters && parameters.length > 0 && renderParams(parameters)} 69 <CommentTextBlock comment={comment} includePlatforms={false} /> 70 {resolveTypeName(type) !== 'undefined' && ( 71 <> 72 <div css={STYLES_NESTED_SECTION_HEADER}> 73 <H4>Returns</H4> 74 </div> 75 <UL hideBullets> 76 <LI> 77 <UndoIcon 78 color={theme.icon.secondary} 79 size={iconSize.small} 80 css={returnIconStyles} 81 /> 82 <APIDataType typeDefinition={type} /> 83 </LI> 84 </UL> 85 {comment?.returns && ( 86 <ReactMarkdown components={mdComponents}>{comment.returns}</ReactMarkdown> 87 )} 88 </> 89 )} 90 </div> 91 ) 92 ); 93}; 94 95const APISectionMethods = ({ 96 data, 97 apiName, 98 header = 'Methods', 99 exposeInSidebar = true, 100}: APISectionMethodsProps) => 101 data?.length ? ( 102 <> 103 <H2 key="methods-header">{header}</H2> 104 {data.map((method: MethodDefinitionData | PropData) => 105 renderMethod(method, { apiName, header, exposeInSidebar }) 106 )} 107 </> 108 ) : null; 109 110const returnIconStyles = css({ 111 transform: 'rotate(180deg)', 112 marginRight: spacing[2], 113 verticalAlign: 'middle', 114}); 115 116export default APISectionMethods; 117 118export const APIMethod = ({ 119 name, 120 comment, 121 returnTypeName, 122 isProperty = false, 123 isReturnTypeReference = false, 124 exposeInSidebar = false, 125 parameters = [], 126 platforms = [], 127}: { 128 exposeInSidebar?: boolean; 129 name: string; 130 comment: string; 131 returnTypeName: string; 132 isProperty: boolean; 133 isReturnTypeReference: boolean; 134 platforms: ('Android' | 'iOS' | 'Web')[]; 135 parameters: { 136 name: string; 137 comment?: string; 138 typeName: string; 139 isReference?: boolean; 140 }[]; 141}): JSX.Element[] => { 142 const parsedParameters = parameters.map(param => ({ 143 name: param.name, 144 type: { name: param.typeName, type: param.isReference ? 'reference' : 'literal' }, 145 comment: { 146 text: param.comment, 147 }, 148 })); 149 return renderMethod( 150 { 151 name, 152 signatures: [ 153 { 154 name, 155 parameters: parsedParameters, 156 comment: { 157 text: comment, 158 tags: platforms.map(text => ({ 159 tag: 'platform', 160 text, 161 })), 162 }, 163 type: { name: returnTypeName, type: isReturnTypeReference ? 'reference' : 'literal' }, 164 }, 165 ], 166 kind: isProperty ? TypeDocKind.Property : TypeDocKind.Function, 167 }, 168 { exposeInSidebar } 169 ); 170}; 171