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