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