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