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