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 {
10  MethodDefinitionData,
11  MethodSignatureData,
12  PropData,
13} from '~/components/plugins/api/APIDataTypes';
14import { PlatformTags } from '~/components/plugins/api/APISectionPlatformTags';
15import {
16  CommentTextBlock,
17  listParams,
18  mdComponents,
19  renderParams,
20  resolveTypeName,
21  STYLES_APIBOX,
22  STYLES_APIBOX_NESTED,
23  STYLES_NESTED_SECTION_HEADER,
24  STYLES_NOT_EXPOSED_HEADER,
25} from '~/components/plugins/api/APISectionUtils';
26
27export type APISectionMethodsProps = {
28  data: (MethodDefinitionData | PropData)[];
29  apiName?: string;
30  header?: string;
31};
32
33export const renderMethod = (
34  { signatures = [] }: MethodDefinitionData | PropData,
35  index?: number,
36  dataLength?: number,
37  apiName?: string,
38  header?: string,
39  exposeInSidebar: boolean = true
40): JSX.Element[] => {
41  const HeaderComponent = exposeInSidebar ? H3Code : H4Code;
42  return signatures.map(({ name, parameters, comment, type }: MethodSignatureData) => (
43    <div
44      key={`method-signature-${name}-${parameters?.length || 0}`}
45      css={[STYLES_APIBOX, !exposeInSidebar && STYLES_APIBOX_NESTED]}>
46      <PlatformTags comment={comment} prefix="Only for:" firstElement />
47      <HeaderComponent>
48        <InlineCode customCss={!exposeInSidebar ? STYLES_NOT_EXPOSED_HEADER : undefined}>
49          {apiName && `${apiName}.`}
50          {header !== 'Hooks' ? `${name}(${listParams(parameters)})` : name}
51        </InlineCode>
52      </HeaderComponent>
53      {parameters && renderParams(parameters)}
54      <CommentTextBlock comment={comment} includePlatforms={false} />
55      {resolveTypeName(type) !== 'undefined' && (
56        <>
57          <div css={STYLES_NESTED_SECTION_HEADER}>
58            <H4>Returns</H4>
59          </div>
60          <UL hideBullets>
61            <LI>
62              <UndoIcon color={theme.icon.secondary} size={iconSize.small} css={returnIconStyles} />
63              <InlineCode>{resolveTypeName(type)}</InlineCode>
64            </LI>
65          </UL>
66          {comment?.returns && (
67            <ReactMarkdown components={mdComponents}>{comment.returns}</ReactMarkdown>
68          )}
69        </>
70      )}
71    </div>
72  ));
73};
74
75const APISectionMethods = ({ data, apiName, header = 'Methods' }: APISectionMethodsProps) =>
76  data?.length ? (
77    <>
78      <H2 key="methods-header">{header}</H2>
79      {data.map((method: MethodDefinitionData | PropData, index: number) =>
80        renderMethod(method, index, data.length, apiName, header)
81      )}
82    </>
83  ) : null;
84
85const returnIconStyles = css({
86  transform: 'rotate(180deg)',
87  marginRight: spacing[2],
88  verticalAlign: 'middle',
89});
90
91export default APISectionMethods;
92