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