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