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