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 { PlatformTags } 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            <CommentTextBlock
52              comment={signatureComment}
53              components={mdInlineComponents}
54              afterContent={renderDefaultValue(initValue)}
55            />
56          </>
57        )}
58      </>
59    );
60  } else {
61    const initValue = defaultValue || getTagData('default', comment)?.text;
62    return (
63      <CommentTextBlock
64        comment={comment}
65        components={mdInlineComponents}
66        afterContent={renderDefaultValue(initValue)}
67        emptyCommentFallback="-"
68      />
69    );
70  }
71};
72
73const renderInterfacePropertyRow = ({
74  name,
75  flags,
76  type,
77  comment,
78  signatures,
79  defaultValue,
80}: PropData): JSX.Element => {
81  const initValue = parseCommentContent(defaultValue || getTagData('default', comment)?.text);
82  return (
83    <Row key={name}>
84      <Cell fitContent>
85        <B>{name}</B>
86        {renderFlags(flags, initValue)}
87      </Cell>
88      <Cell fitContent>
89        <InlineCode>{resolveTypeName(type)}</InlineCode>
90      </Cell>
91      <Cell fitContent>{renderInterfaceComment(comment, signatures, initValue)}</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      <APISectionDeprecationNote comment={comment} />
112      <PlatformTags comment={comment} prefix="Only for:" firstElement />
113      <H3Code>
114        <InlineCode>{name}</InlineCode>
115      </H3Code>
116      {extendedTypes?.length ? (
117        <P>
118          <B>Extends: </B>
119          {extendedTypes.map(extendedType => (
120            <InlineCode key={`extend-${extendedType.name}`}>
121              {resolveTypeName(extendedType)}
122            </InlineCode>
123          ))}
124        </P>
125      ) : null}
126      <CommentTextBlock comment={comment} includePlatforms={false} />
127      {interfaceMethods.length ? (
128        <>
129          <div css={STYLES_NESTED_SECTION_HEADER}>
130            <H4>{name} Methods</H4>
131          </div>
132          {interfaceMethods.map(method => renderMethod(method))}
133        </>
134      ) : undefined}
135      {interfaceFields.length ? (
136        <>
137          <div css={STYLES_NESTED_SECTION_HEADER}>
138            <H4>{name} Properties</H4>
139          </div>
140          <Table>
141            {renderTableHeadRow()}
142            <tbody>{interfaceFields.map(renderInterfacePropertyRow)}</tbody>
143          </Table>
144        </>
145      ) : undefined}
146    </div>
147  );
148};
149
150const APISectionInterfaces = ({ data }: APISectionInterfacesProps) =>
151  data?.length ? (
152    <>
153      <H2 key="interfaces-header">Interfaces</H2>
154      {data.map(renderInterface)}
155    </>
156  ) : null;
157
158export default APISectionInterfaces;
159