refactor(website): consolidate badge logic (#9417)

Co-authored-by: Noel <buechler.noel@outlook.com>
This commit is contained in:
Suneet Tipirneni 2023-04-19 12:58:35 -04:00 committed by GitHub
parent 0eb866357b
commit ecd1b5da11
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 66 additions and 119 deletions

View file

@ -0,0 +1,37 @@
import type { ApiDocumentedItem } from '@microsoft/api-extractor-model';
import { ApiAbstractMixin, ApiProtectedMixin, ApiReadonlyMixin, ApiStaticMixin } from '@microsoft/api-extractor-model';
import type { PropsWithChildren } from 'react';
export enum BadgeColor {
Danger = 'bg-red-500',
Primary = 'bg-blurple',
Warning = 'bg-yellow-500',
}
export function Badge({ children, color = BadgeColor.Primary }: PropsWithChildren<{ color?: BadgeColor | undefined }>) {
return (
<span
className={`h-5 flex flex-row place-content-center place-items-center rounded-full px-3 text-center text-xs font-semibold uppercase text-white ${color}`}
>
{children}
</span>
);
}
export function Badges({ item }: { item: ApiDocumentedItem }) {
const isStatic = ApiStaticMixin.isBaseClassOf(item) && item.isStatic;
const isProtected = ApiProtectedMixin.isBaseClassOf(item) && item.isProtected;
const isReadonly = ApiReadonlyMixin.isBaseClassOf(item) && item.isReadonly;
const isAbstract = ApiAbstractMixin.isBaseClassOf(item) && item.isAbstract;
const isDeprecated = Boolean(item.tsdocComment?.deprecatedBlock);
return (
<div className="flex flex-row gap-1 md:ml-7">
{isDeprecated ? <Badge color={BadgeColor.Danger}>Deprecated</Badge> : null}
{isProtected ? <Badge>Protected</Badge> : null}
{isStatic ? <Badge>Static</Badge> : null}
{isAbstract ? <Badge>Abstract</Badge> : null}
{isReadonly ? <Badge>Readonly</Badge> : null}
</div>
);
}

View file

@ -20,7 +20,7 @@ export interface ExcerptTextProps {
*/
export function ExcerptText({ model, excerpt }: ExcerptTextProps) {
return (
<>
<span>
{excerpt.spannedTokens.map((token, idx) => {
if (token.kind === ExcerptTokenKind.Reference) {
const source = token.canonicalReference?.source;
@ -59,6 +59,6 @@ export function ExcerptText({ model, excerpt }: ExcerptTextProps) {
return token.text;
})}
</>
</span>
);
}

View file

@ -5,59 +5,29 @@ import type {
ApiPropertySignature,
} from '@microsoft/api-extractor-model';
import type { PropsWithChildren } from 'react';
import { Badges } from './Badges';
import { CodeHeading } from './CodeHeading';
import { ExcerptText } from './ExcerptText';
import { InheritanceText } from './InheritanceText';
import { TSDoc } from './documentation/tsdoc/TSDoc';
export enum PropertySeparatorType {
Type = ':',
Value = '=',
}
export function Property({
item,
children,
separator,
inheritedFrom,
}: PropsWithChildren<{
inheritedFrom?: (ApiDeclaredItem & ApiItemContainerMixin) | undefined;
item: ApiProperty | ApiPropertySignature;
separator?: PropertySeparatorType;
}>) {
const isDeprecated = Boolean(item.tsdocComment?.deprecatedBlock);
const hasSummary = Boolean(item.tsdocComment?.summarySection);
return (
<div className="flex flex-col scroll-mt-30 gap-4" id={item.displayName}>
<div className="flex flex-col gap-2 md:-ml-9">
{isDeprecated || item.isReadonly || item.isOptional || (item as ApiProperty).isStatic ? (
<div className="flex flex-row gap-1 md:ml-7">
{isDeprecated ? (
<div className="h-5 flex flex-row place-content-center place-items-center rounded-full bg-red-500 px-3 text-center text-xs font-semibold uppercase text-white">
Deprecated
</div>
) : null}
{(item as ApiProperty).isStatic ? (
<div className="h-5 flex flex-row place-content-center place-items-center rounded-full bg-blurple px-3 text-center text-xs font-semibold uppercase text-white">
Static
</div>
) : null}
{item.isReadonly ? (
<div className="h-5 flex flex-row place-content-center place-items-center rounded-full bg-blurple px-3 text-center text-xs font-semibold uppercase text-white">
Readonly
</div>
) : null}
{item.isOptional ? (
<div className="h-5 flex flex-row place-content-center place-items-center rounded-full bg-blurple px-3 text-center text-xs font-semibold uppercase text-white">
Optional
</div>
) : null}
</div>
) : null}
<Badges item={item} />
<CodeHeading href={`#${item.displayName}`}>
{`${item.displayName}${item.isOptional ? '?' : ''}`}
<span>{separator}</span>
<span>:</span>
{item.propertyTypeExcerpt.text ? (
<ExcerptText excerpt={item.propertyTypeExcerpt} model={item.getAssociatedModel()!} />
) : null}

View file

@ -7,7 +7,7 @@ import type {
} from '@microsoft/api-extractor-model';
import { ApiItemKind } from '@microsoft/api-extractor-model';
import { Fragment, useMemo } from 'react';
import { Property, PropertySeparatorType } from './Property';
import { Property } from './Property';
import { resolveMembers } from '~/util/members';
export function isPropertyLike(item: ApiItem): item is ApiProperty | ApiPropertySignature {
@ -25,7 +25,6 @@ export function PropertyList({ item }: { item: ApiItemContainerMixin }) {
<Property
inheritedFrom={prop.inherited as ApiDeclaredItem & ApiItemContainerMixin}
item={prop.item as ApiProperty}
separator={PropertySeparatorType.Type}
/>
<div className="border-t-2 border-light-900 dark:border-dark-100" />
</Fragment>

View file

@ -38,7 +38,7 @@ export function Header({
{name}
</span>
{sourceURL ? (
<a className="text-blurple" href={sourceURL}>
<a className="text-blurple" href={sourceURL} rel="external noopener noreferrer" target="_blank">
<VscFileCode />
</a>
) : null}

View file

@ -1,32 +0,0 @@
import type { ApiDeclaredItem, ApiItemContainerMixin, ApiTypeParameterListMixin } from '@microsoft/api-extractor-model';
import type { ReactNode } from 'react';
// import { Outline } from '../Outline';
import { SyntaxHighlighter } from '../SyntaxHighlighter';
import { Documentation } from './Documentation';
import { MethodsSection } from './section/MethodsSection';
import { PropertiesSection } from './section/PropertiesSection';
import { SummarySection } from './section/SummarySection';
import { TypeParameterSection } from './section/TypeParametersSection';
import { hasProperties, hasMethods /* , serializeMembers */ } from './util';
export function MemberContainerDocumentation({
item,
subheading,
}: {
item: ApiDeclaredItem & ApiItemContainerMixin & ApiTypeParameterListMixin;
subheading?: ReactNode;
}) {
return (
<Documentation>
{subheading}
{/* @ts-expect-error async component */}
<SyntaxHighlighter code={item.excerpt.text} />
<SummarySection item={item} />
{item.typeParameters.length ? <TypeParameterSection item={item} /> : null}
{hasProperties(item) ? <PropertiesSection item={item} /> : null}
{hasMethods(item) ? <MethodsSection item={item} /> : null}
{/* <Outline members={serializeMembers(item)} /> */}
</Documentation>
);
}

View file

@ -2,23 +2,15 @@ import type { ApiConstructor } from '@microsoft/api-extractor-model';
import { VscSymbolMethod } from '@react-icons/all-files/vsc/VscSymbolMethod';
import { ParameterTable } from '../../ParameterTable';
import { TSDoc } from '../tsdoc/TSDoc';
import { parametersString } from '../util';
import { DocumentationSection } from './DocumentationSection';
function getShorthandName(ctor: ApiConstructor) {
return `constructor(${ctor.parameters.reduce((prev, cur, index) => {
if (index === 0) {
return `${prev}${cur.isOptional ? `${cur.name}?` : cur.name}`;
}
return `${prev}, ${cur.isOptional ? `${cur.name}?` : cur.name}`;
}, '')})`;
}
import { CodeHeading } from '~/components/CodeHeading';
export function ConstructorSection({ item }: { item: ApiConstructor }) {
return (
<DocumentationSection icon={<VscSymbolMethod size={20} />} padded title="Constructor">
<div className="flex flex-col gap-2">
<h4 className="break-all font-mono text-lg font-bold">{getShorthandName(item)}</h4>
<CodeHeading>{`constructor(${parametersString(item)})`}</CodeHeading>
{item.tsdocComment ? <TSDoc item={item} tsdoc={item.tsdocComment} /> : null}
<ParameterTable item={item} />
</div>

View file

@ -6,10 +6,13 @@ import type {
ApiMethodSignature,
ApiProperty,
ApiPropertySignature,
ApiDocumentedItem,
ApiParameterListMixin,
} from '@microsoft/api-extractor-model';
import type { TableOfContentsSerialized } from '../TableOfContentItems';
import { METHOD_SEPARATOR, OVERLOAD_SEPARATOR } from '~/util/constants';
import { resolveMembers } from '~/util/members';
import { resolveParameters } from '~/util/model';
export function hasProperties(item: ApiItemContainerMixin) {
return resolveMembers(item, memberPredicate).some(
@ -56,3 +59,13 @@ export function serializeMembers(clazz: ApiItemContainerMixin): TableOfContentsS
}
});
}
export function parametersString(item: ApiDocumentedItem & ApiParameterListMixin) {
return resolveParameters(item).reduce((prev, cur, index) => {
if (index === 0) {
return `${prev}${cur.isOptional ? `${cur.name}?` : cur.name}`;
}
return `${prev}, ${cur.isOptional ? `${cur.name}?` : cur.name}`;
}, '');
}

View file

@ -1,6 +1,7 @@
import type { ApiClass, ApiConstructor } from '@microsoft/api-extractor-model';
import { ApiItemKind } from '@microsoft/api-extractor-model';
// import { Outline } from '../Outline';
import { Badges } from '../Badges';
import { Documentation } from '../documentation/Documentation';
import { HierarchyText } from '../documentation/HierarchyText';
import { Members } from '../documentation/Members';
@ -16,6 +17,7 @@ export function Class({ clazz }: { clazz: ApiClass }) {
return (
<Documentation>
<Badges item={clazz} />
<ObjectHeader item={clazz} />
<HierarchyText item={clazz} type="Extends" />
<HierarchyText item={clazz} type="Implements" />

View file

@ -1,25 +1,11 @@
import type { ApiMethod, ApiMethodSignature } from '@microsoft/api-extractor-model';
import { ApiItemKind } from '@microsoft/api-extractor-model';
import { useMemo } from 'react';
import { Badges } from '~/components/Badges';
import { CodeHeading } from '~/components/CodeHeading';
import { ExcerptText } from '~/components/ExcerptText';
import { resolveParameters } from '~/util/model';
function getShorthandName(method: ApiMethod | ApiMethodSignature) {
const params = resolveParameters(method);
return `${method.name}${method.isOptional ? '?' : ''}(${params.reduce((prev, cur, index) => {
if (index === 0) {
return `${prev}${cur.isOptional ? `${cur.name}?` : cur.name}`;
}
return `${prev}, ${cur.isOptional ? `${cur.name}?` : cur.name}`;
}, '')})`;
}
import { parametersString } from '~/components/documentation/util';
export function MethodHeader({ method }: { method: ApiMethod | ApiMethodSignature }) {
const isDeprecated = Boolean(method.tsdocComment?.deprecatedBlock);
const key = useMemo(
() => `${method.displayName}${method.overloadIndex && method.overloadIndex > 1 ? `:${method.overloadIndex}` : ''}`,
[method.displayName, method.overloadIndex],
@ -28,29 +14,9 @@ export function MethodHeader({ method }: { method: ApiMethod | ApiMethodSignatur
return (
<div className="flex flex-col scroll-mt-30" id={key}>
<div className="flex flex-col gap-2 md:-ml-9">
{isDeprecated ||
(method.kind === ApiItemKind.Method && (method as ApiMethod).isProtected) ||
(method.kind === ApiItemKind.Method && (method as ApiMethod).isStatic) ? (
<div className="flex flex-row gap-1 md:ml-7">
{isDeprecated ? (
<div className="h-5 flex flex-row place-content-center place-items-center rounded-full bg-red-500 px-3 text-center text-xs font-semibold uppercase text-white">
Deprecated
</div>
) : null}
{method.kind === ApiItemKind.Method && (method as ApiMethod).isProtected ? (
<div className="h-5 flex flex-row place-content-center place-items-center rounded-full bg-blurple px-3 text-center text-xs font-semibold uppercase text-white">
Protected
</div>
) : null}
{method.kind === ApiItemKind.Method && (method as ApiMethod).isStatic ? (
<div className="h-5 flex flex-row place-content-center place-items-center rounded-full bg-blurple px-3 text-center text-xs font-semibold uppercase text-white">
Static
</div>
) : null}
</div>
) : null}
<Badges item={method} />
<CodeHeading href={`#${key}`}>
{getShorthandName(method)}
{`${method.name}(${parametersString(method)})`}
<span>:</span>
<ExcerptText excerpt={method.returnTypeExcerpt} model={method.getAssociatedModel()!} />
</CodeHeading>