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