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, 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, hasMultipleClasses: 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
50  return (
51    <div key={`class-definition-${name}`} css={STYLES_APIBOX}>
52      <APISectionDeprecationNote comment={comment} />
53      {hasMultipleClasses ? (
54        <H3Code tags={getTagNamesList(comment)}>
55          <InlineCode>{name}</InlineCode>
56        </H3Code>
57      ) : (
58        <H2>{name}</H2>
59      )}
60      {(extendedTypes?.length || implementedTypes?.length) && (
61        <P>
62          <B>Type: </B>
63          {type ? <InlineCode>{resolveTypeName(type)}</InlineCode> : 'Class'}
64          {extendedTypes?.length && (
65            <>
66              <span> extends </span>
67              {extendedTypes.map(extendedType => (
68                <InlineCode key={`extends-${extendedType.name}`}>
69                  {resolveTypeName(extendedType)}
70                </InlineCode>
71              ))}
72            </>
73          )}
74          {implementedTypes?.length && (
75            <>
76              <span> implements </span>
77              {implementedTypes.map(implementedType => (
78                <InlineCode key={`implements-${implementedType.name}`}>
79                  {resolveTypeName(implementedType)}
80                </InlineCode>
81              ))}
82            </>
83          )}
84        </P>
85      )}
86      <CommentTextBlock comment={comment} />
87      {returnComment && (
88        <>
89          <div css={STYLES_NESTED_SECTION_HEADER}>
90            <H4>Returns</H4>
91          </div>
92          <ReactMarkdown components={mdComponents}>{returnComment.text}</ReactMarkdown>
93        </>
94      )}
95      {properties?.length ? (
96        <>
97          {hasMultipleClasses ? (
98            <div css={STYLES_NESTED_SECTION_HEADER}>
99              <H4>{name} Properties</H4>
100            </div>
101          ) : (
102            <H2>{name} Properties</H2>
103          )}
104          <div>
105            {properties.map(property =>
106              renderProp(property, property?.defaultValue, !hasMultipleClasses)
107            )}
108          </div>
109        </>
110      ) : null}
111      {methods?.length && (
112        <>
113          {hasMultipleClasses ? (
114            <div css={STYLES_NESTED_SECTION_HEADER}>
115              <H4>{name} Methods</H4>
116            </div>
117          ) : (
118            <H2>{name} Methods</H2>
119          )}
120          {methods.map(method => renderMethod(method, { exposeInSidebar: !hasMultipleClasses }))}
121        </>
122      )}
123    </div>
124  );
125};
126
127const APISectionClasses = ({ data }: APISectionClassesProps) => {
128  if (data?.length) {
129    const hasMultipleClasses = data.length > 1;
130    return (
131      <>
132        {hasMultipleClasses ? <H2>Classes</H2> : null}
133        {data.map(cls => renderClass(cls, hasMultipleClasses))}
134      </>
135    );
136  }
137  return null;
138};
139
140export default APISectionClasses;
141