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