1import React from 'react';
2import ReactMarkdown from 'react-markdown';
3
4import { InlineCode } from '~/components/base/code';
5import { B, P } from '~/components/base/paragraph';
6import { H2, H2Nested, H3Code, H4 } from '~/components/plugins/Headings';
7import {
8  ClassDefinitionData,
9  GeneratedData,
10  PropData,
11} from '~/components/plugins/api/APIDataTypes';
12import { APISectionDeprecationNote } from '~/components/plugins/api/APISectionDeprecationNote';
13import { renderMethod } from '~/components/plugins/api/APISectionMethods';
14import { renderProp } from '~/components/plugins/api/APISectionProps';
15import {
16  CommentTextBlock,
17  getTagData,
18  getTagNamesList,
19  mdComponents,
20  resolveTypeName,
21  STYLES_APIBOX,
22  STYLES_NESTED_SECTION_HEADER,
23  TypeDocKind,
24} from '~/components/plugins/api/APISectionUtils';
25
26export type APISectionClassesProps = {
27  data: GeneratedData[];
28};
29
30const isProp = (child: PropData) =>
31  child.kind === TypeDocKind.Property &&
32  !child.overwrites &&
33  !child.name.startsWith('_') &&
34  !child.implementationOf;
35
36const isMethod = (child: PropData) =>
37  child.kind === TypeDocKind.Method &&
38  !child.overwrites &&
39  !child.name.startsWith('_') &&
40  !child?.implementationOf;
41
42const renderClass = (clx: ClassDefinitionData, exposeInSidebar: boolean): JSX.Element => {
43  const { name, comment, type, extendedTypes, children, implementedTypes } = clx;
44  const properties = children?.filter(isProp);
45  const methods = children
46    ?.filter(isMethod)
47    .sort((a: PropData, b: PropData) => a.name.localeCompare(b.name));
48  const returnComment = getTagData('returns', comment);
49  const Header = exposeInSidebar ? H2Nested : H4;
50
51  return (
52    <div key={`class-definition-${name}`} css={STYLES_APIBOX}>
53      <APISectionDeprecationNote comment={comment} />
54      <H3Code tags={getTagNamesList(comment)}>
55        <InlineCode>{name}</InlineCode>
56      </H3Code>
57      {(extendedTypes?.length || implementedTypes?.length) && (
58        <P>
59          <B>Type: </B>
60          {type ? <InlineCode>{resolveTypeName(type)}</InlineCode> : 'Class'}
61          {extendedTypes?.length && (
62            <>
63              <span> extends </span>
64              {extendedTypes.map(extendedType => (
65                <InlineCode key={`extends-${extendedType.name}`}>
66                  {resolveTypeName(extendedType)}
67                </InlineCode>
68              ))}
69            </>
70          )}
71          {implementedTypes?.length && (
72            <>
73              <span> implements </span>
74              {implementedTypes.map(implementedType => (
75                <InlineCode key={`implements-${implementedType.name}`}>
76                  {resolveTypeName(implementedType)}
77                </InlineCode>
78              ))}
79            </>
80          )}
81        </P>
82      )}
83      <CommentTextBlock comment={comment} />
84      {returnComment && (
85        <>
86          <div css={STYLES_NESTED_SECTION_HEADER}>
87            <H4>Returns</H4>
88          </div>
89          <ReactMarkdown components={mdComponents}>{returnComment.text}</ReactMarkdown>
90        </>
91      )}
92      {properties?.length ? (
93        <>
94          <div css={STYLES_NESTED_SECTION_HEADER}>
95            <Header>{name} Properties</Header>
96          </div>
97          <div>
98            {properties.map(property =>
99              renderProp(property, property?.defaultValue, exposeInSidebar)
100            )}
101          </div>
102        </>
103      ) : null}
104      {methods?.length && (
105        <>
106          <div css={STYLES_NESTED_SECTION_HEADER}>
107            <Header>{name} Methods</Header>
108          </div>
109          {methods.map(method => renderMethod(method, { exposeInSidebar }))}
110        </>
111      )}
112    </div>
113  );
114};
115
116const APISectionClasses = ({ data }: APISectionClassesProps) => {
117  if (data?.length) {
118    const exposeInSidebar = data.length < 2;
119    return (
120      <>
121        <H2>Classes</H2>
122        {data.map(cls => renderClass(cls, exposeInSidebar))}
123      </>
124    );
125  }
126  return null;
127};
128
129export default APISectionClasses;
130