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_NESTED_SECTION_HEADER, 26 STYLES_NOT_EXPOSED_HEADER, 27 TypeDocKind, 28 H3Code, 29 H4Code, 30 getTagData, 31 getCommentContent, 32} from '~/components/plugins/api/APISectionUtils'; 33import { H2, H4, 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 <div css={STYLES_NESTED_SECTION_HEADER}> 83 <H4>Returns</H4> 84 </div> 85 <UL css={STYLES_NO_BULLET_LIST}> 86 <LI> 87 <UndoIcon 88 color={theme.icon.secondary} 89 size={iconSize.sm} 90 css={returnIconStyles} 91 /> 92 <APIDataType typeDefinition={type} /> 93 </LI> 94 </UL> 95 <> 96 <br /> 97 {returnComment ? ( 98 <ReactMarkdown components={mdComponents}> 99 {getCommentContent(returnComment.content)} 100 </ReactMarkdown> 101 ) : undefined} 102 </> 103 </> 104 )} 105 </div> 106 ); 107 } 108 ); 109}; 110 111const APISectionMethods = ({ 112 data, 113 apiName, 114 header = 'Methods', 115 exposeInSidebar = true, 116}: APISectionMethodsProps) => 117 data?.length ? ( 118 <> 119 <H2 key={`${header}-header`}>{header}</H2> 120 {data.map((method: MethodDefinitionData | PropData) => 121 renderMethod(method, { apiName, header, exposeInSidebar }) 122 )} 123 </> 124 ) : null; 125 126const returnIconStyles = css({ 127 transform: 'rotate(180deg)', 128 marginRight: spacing[2], 129 verticalAlign: 'middle', 130}); 131 132export default APISectionMethods; 133 134export const APIMethod = ({ 135 name, 136 comment, 137 returnTypeName, 138 isProperty = false, 139 isReturnTypeReference = false, 140 exposeInSidebar = false, 141 parameters = [], 142 platforms = [], 143}: { 144 exposeInSidebar?: boolean; 145 name: string; 146 comment: string; 147 returnTypeName: string; 148 isProperty: boolean; 149 isReturnTypeReference: boolean; 150 platforms: ('Android' | 'iOS' | 'Web')[]; 151 parameters: { 152 name: string; 153 comment?: string; 154 typeName: string; 155 isReference?: boolean; 156 }[]; 157}) => { 158 const parsedParameters = parameters.map( 159 param => 160 ({ 161 name: param.name, 162 type: { name: param.typeName, type: param.isReference ? 'reference' : 'literal' }, 163 comment: { 164 summary: [{ kind: 'text', text: param.comment }], 165 }, 166 } as MethodParamData) 167 ); 168 return renderMethod( 169 { 170 name, 171 signatures: [ 172 { 173 name, 174 parameters: parsedParameters, 175 comment: { 176 summary: [{ kind: 'text', text: comment }], 177 blockTags: platforms.map(text => ({ 178 tag: 'platform', 179 content: [{ kind: 'text', text }], 180 })), 181 }, 182 type: { name: returnTypeName, type: isReturnTypeReference ? 'reference' : 'literal' }, 183 }, 184 ], 185 kind: isProperty ? TypeDocKind.Property : TypeDocKind.Function, 186 }, 187 { exposeInSidebar } 188 ); 189}; 190 191const STYLES_NO_BULLET_LIST = css({ 192 listStyle: 'none', 193 marginLeft: spacing[2], 194}); 195