1import React from 'react';
2
3import { renderMethod } from './APISectionMethods';
4
5import { InlineCode } from '~/components/base/code';
6import { B, P } from '~/components/base/paragraph';
7import { H2, H3Code, H4 } from '~/components/plugins/Headings';
8import {
9  CommentData,
10  InterfaceDefinitionData,
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  getTagData,
19  mdInlineComponents,
20  parseCommentContent,
21  renderFlags,
22  renderParamRow,
23  renderTableHeadRow,
24  resolveTypeName,
25  renderDefaultValue,
26  STYLES_APIBOX,
27  STYLES_NESTED_SECTION_HEADER,
28} from '~/components/plugins/api/APISectionUtils';
29import { Cell, Row, Table } from '~/ui/components/Table';
30
31export type APISectionInterfacesProps = {
32  data: InterfaceDefinitionData[];
33};
34
35const renderInterfaceComment = (
36  comment?: CommentData,
37  signatures?: MethodSignatureData[],
38  defaultValue?: string
39) => {
40  if (signatures && signatures.length) {
41    const { type, parameters, comment: signatureComment } = signatures[0];
42    const initValue = defaultValue || getTagData('default', signatureComment)?.text;
43    return (
44      <>
45        {parameters?.length ? parameters.map(param => renderParamRow(param)) : null}
46        <B>Returns: </B>
47        <InlineCode>{resolveTypeName(type)}</InlineCode>
48        {signatureComment && (
49          <>
50            <br />
51            <APISectionDeprecationNote comment={comment} />
52            <CommentTextBlock
53              comment={signatureComment}
54              components={mdInlineComponents}
55              afterContent={renderDefaultValue(initValue)}
56            />
57          </>
58        )}
59      </>
60    );
61  } else {
62    const initValue = defaultValue || getTagData('default', comment)?.text;
63    return (
64      <>
65        <APISectionDeprecationNote comment={comment} />
66        <CommentTextBlock
67          comment={comment}
68          components={mdInlineComponents}
69          afterContent={renderDefaultValue(initValue)}
70          emptyCommentFallback="-"
71        />
72      </>
73    );
74  }
75};
76
77const renderInterfacePropertyRow = ({
78  name,
79  flags,
80  type,
81  comment,
82  signatures,
83  defaultValue,
84}: PropData): JSX.Element => {
85  const initValue = parseCommentContent(defaultValue || getTagData('default', comment)?.text);
86  return (
87    <Row key={name}>
88      <Cell fitContent>
89        <B>{name}</B>
90        {renderFlags(flags, initValue)}
91      </Cell>
92      <Cell fitContent>
93        <InlineCode>{resolveTypeName(type)}</InlineCode>
94      </Cell>
95      <Cell fitContent>{renderInterfaceComment(comment, signatures, initValue)}</Cell>
96    </Row>
97  );
98};
99
100const renderInterface = ({
101  name,
102  children,
103  comment,
104  extendedTypes,
105}: InterfaceDefinitionData): JSX.Element | null => {
106  const interfaceChildren = children?.filter(child => !child?.inheritedFrom) || [];
107
108  if (!interfaceChildren.length) return null;
109
110  const interfaceMethods = interfaceChildren.filter(child => child.signatures);
111  const interfaceFields = interfaceChildren.filter(child => !child.signatures);
112
113  return (
114    <div key={`interface-definition-${name}`} css={STYLES_APIBOX}>
115      <APISectionDeprecationNote comment={comment} />
116      <APISectionPlatformTags comment={comment} prefix="Only for:" firstElement />
117      <H3Code>
118        <InlineCode>{name}</InlineCode>
119      </H3Code>
120      {extendedTypes?.length ? (
121        <P>
122          <B>Extends: </B>
123          {extendedTypes.map(extendedType => (
124            <InlineCode key={`extend-${extendedType.name}`}>
125              {resolveTypeName(extendedType)}
126            </InlineCode>
127          ))}
128        </P>
129      ) : null}
130      <CommentTextBlock comment={comment} includePlatforms={false} />
131      {interfaceMethods.length ? (
132        <>
133          <div css={STYLES_NESTED_SECTION_HEADER}>
134            <H4>{name} Methods</H4>
135          </div>
136          {interfaceMethods.map(method => renderMethod(method, { exposeInSidebar: false }))}
137        </>
138      ) : undefined}
139      {interfaceFields.length ? (
140        <>
141          <div css={STYLES_NESTED_SECTION_HEADER}>
142            <H4>{name} Properties</H4>
143          </div>
144          <Table>
145            {renderTableHeadRow()}
146            <tbody>{interfaceFields.map(renderInterfacePropertyRow)}</tbody>
147          </Table>
148        </>
149      ) : undefined}
150    </div>
151  );
152};
153
154const APISectionInterfaces = ({ data }: APISectionInterfacesProps) =>
155  data?.length ? (
156    <>
157      <H2 key="interfaces-header">Interfaces</H2>
158      {data.map(renderInterface)}
159    </>
160  ) : null;
161
162export default APISectionInterfaces;
163