Skip to content

Commit

Permalink
Add reflectionPreview template, rendering improvements
Browse files Browse the repository at this point in the history
Resolves #2449
  • Loading branch information
Gerrit0 committed Nov 26, 2023
1 parent fbe939a commit 9ffa0db
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 28 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Unreleased

### Features

- Added support for TypeScript 5.3, #2446.
- TypeDoc will now render interfaces as code at the top of the page describing interfaces, #2449.
This can be controlled through the new `DefaultThemeRenderContext.reflectionPreview` helper.
- Improved type rendering to highlight keywords differently than symbols.

### Bug Fixes

- Fixed automatic declaration file resolution on Windows, #2416.
Expand All @@ -11,6 +18,7 @@
- `@example` tag titles will now be rendered in the example heading, #2440.
- Correctly handle transient symbols in `@namespace`-created namespaces, #2444.
- TypeDoc no longer displays the "Hierarchy" section if there is no inheritance hierarchy to display.
- Direct links to individual signatures no longer results in the signature being partially scrolled off the screen.

### Thanks!

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"doc:c": "node bin/typedoc --tsconfig src/test/converter/tsconfig.json",
"doc:c2": "node bin/typedoc --tsconfig src/test/converter2/tsconfig.json",
"doc:c2d": "node --inspect-brk bin/typedoc --tsconfig src/test/converter2/tsconfig.json",
"example": "cd example && node ../bin/typedoc",
"test:full": "c8 mocha --config .config/mocha.full.json",
"test:visual": "ts-node ./src/test/capture-screenshots.ts && ./scripts/compare_screenshots.sh",
"test:visual:accept": "node scripts/accept_visual_regression.js",
Expand Down
11 changes: 11 additions & 0 deletions src/lib/output/themes/default/DefaultThemeRenderContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
sidebarLinks,
} from "./partials/navigation";
import { parameter } from "./partials/parameter";
import { reflectionPreview } from "./partials/reflectionPreview";
import { toolbar } from "./partials/toolbar";
import { type } from "./partials/type";
import { typeAndParent } from "./partials/typeAndParent";
Expand Down Expand Up @@ -117,6 +118,16 @@ export class DefaultThemeRenderContext {
indexTemplate = bind(indexTemplate, this);
defaultLayout = bind(defaultLayout, this);

/**
* Rendered just after the description for a reflection.
* This can be used to render a shortened type display of a reflection that the
* rest of the page expands on.
*
* Note: Will not be called for variables/type aliases, as they are summarized
* by their type declaration, which is already rendered by {@link DefaultThemeRenderContext.memberDeclaration}
*/
reflectionPreview = bind(reflectionPreview, this);

analytics = bind(analytics, this);
breadcrumb = bind(breadcrumb, this);
commentSummary = bind(commentSummary, this);
Expand Down
3 changes: 2 additions & 1 deletion src/lib/output/themes/default/partials/member.signatures.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ export const memberSignatures = (context: DefaultThemeRenderContext, props: Decl
<ul class={classNames({ "tsd-signatures": true }, context.getReflectionClasses(props))}>
{props.signatures?.map((item) => (
<>
<li class="tsd-signature tsd-anchor-link" id={item.anchor}>
<li class="tsd-signature tsd-anchor-link">
<a id={item.anchor} class="tsd-anchor"></a>
{context.memberSignatureTitle(item)}
{anchorIcon(context, item.anchor)}
</li>
Expand Down
20 changes: 20 additions & 0 deletions src/lib/output/themes/default/partials/reflectionPreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { DeclarationReflection, ReflectionKind, type Reflection, ReflectionType } from "../../../../models";
import { JSX } from "../../../../utils";
import { getKindClass } from "../../lib";
import type { DefaultThemeRenderContext } from "../DefaultThemeRenderContext";

export function reflectionPreview(context: DefaultThemeRenderContext, props: Reflection) {
if (!(props instanceof DeclarationReflection)) return;

// Each property of the interface will have a member rendered later on the page describing it, so generate
// a type-like object with links to each member.
if (props.kindOf(ReflectionKind.Interface)) {
return (
<div class="tsd-signature">
<span class="tsd-signature-keyword">interface </span>
<span class={getKindClass(props)}>{props.name} </span>
{context.type(new ReflectionType(props), { topLevelLinks: true })}
</div>
);
}
}
77 changes: 52 additions & 25 deletions src/lib/output/themes/default/partials/type.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ export function validateStateIsClean(page: string) {
// 1 | 2[] !== (1 | 2)[]
// () => 1 | 2 !== (() => 1) | 2
const typeRenderers: {
[K in keyof TypeKindMap]: (context: DefaultThemeRenderContext, type: TypeKindMap[K]) => JSX.Element;
[K in keyof TypeKindMap]: (
context: DefaultThemeRenderContext,
type: TypeKindMap[K],
options: { topLevelLinks: boolean },
) => JSX.Element;
} = {
array(context, type) {
return (
Expand All @@ -100,7 +104,7 @@ const typeRenderers: {
indentationDepth++;
const parts: JSX.Element[] = [
renderType(context, type.checkType, TypeContext.conditionalCheck),
<span class="tsd-signature-symbol"> extends </span>,
<span class="tsd-signature-keyword"> extends </span>,
renderType(context, type.extendsType, TypeContext.conditionalExtends),
<br />,
includeIndentation(),
Expand Down Expand Up @@ -142,11 +146,11 @@ const typeRenderers: {
inferred(context, type) {
return (
<>
<span class="tsd-signature-symbol">infer </span>{" "}
<span class="tsd-signature-keyword">infer </span>{" "}
<span class="tsd-kind-type-parameter">{type.name}</span>
{type.constraint && (
<>
<span class="tsd-signature-symbol"> extends </span>
<span class="tsd-signature-keyword"> extends </span>
{renderType(context, type.constraint, TypeContext.inferredConstraint)}
</>
)}
Expand All @@ -170,23 +174,28 @@ const typeRenderers: {

switch (type.readonlyModifier) {
case "+":
parts.push(<span class="tsd-signature-symbol">readonly </span>);
parts.push(<span class="tsd-signature-keyword">readonly </span>);
break;
case "-":
parts.push(<span class="tsd-signature-symbol">-readonly </span>);
parts.push(
<>
<span class="tsd-signature-symbol">-</span>
<span class="tsd-signature-keyword">readonly </span>
</>,
);
break;
}

parts.push(
<span class="tsd-signature-symbol">[</span>,
<span class="tsd-kind-type-parameter">{type.parameter}</span>,
<span class="tsd-signature-symbol"> in </span>,
<span class="tsd-signature-keyword"> in </span>,
renderType(context, type.parameterType, TypeContext.mappedParameter),
);

if (type.nameType) {
parts.push(
<span class="tsd-signature-symbol"> as </span>,
<span class="tsd-signature-keyword"> as </span>,
renderType(context, type.nameType, TypeContext.mappedName),
);
}
Expand Down Expand Up @@ -241,11 +250,11 @@ const typeRenderers: {
predicate(context, type) {
return (
<>
{!!type.asserts && <span class="tsd-signature-symbol">asserts </span>}
{!!type.asserts && <span class="tsd-signature-keyword">asserts </span>}
<span class="tsd-kind-parameter">{type.name}</span>
{!!type.targetType && (
<>
<span class="tsd-signature-symbol"> is </span>
<span class="tsd-signature-keyword"> is </span>
{renderType(context, type.targetType, TypeContext.predicateTarget)}
</>
)}
Expand All @@ -255,7 +264,7 @@ const typeRenderers: {
query(context, type) {
return (
<>
<span class="tsd-signature-symbol">typeof </span>
<span class="tsd-signature-keyword">typeof </span>
{renderType(context, type.queryType, TypeContext.queryTypeTarget)}
</>
);
Expand Down Expand Up @@ -299,17 +308,26 @@ const typeRenderers: {

return name;
},
reflection(context, type) {
reflection(context, type, { topLevelLinks }) {
const members: JSX.Element[] = [];
const children: DeclarationReflection[] = type.declaration.children || [];

indentationDepth++;

const renderName = (named: Reflection) =>
topLevelLinks ? (
<a class={getKindClass(named)} href={context.urlTo(named)}>
{named.name}
</a>
) : (
<span class={getKindClass(named)}>{named.name}</span>
);

for (const item of children) {
if (item.getSignature && item.setSignature) {
members.push(
<>
<span class={getKindClass(item)}>{item.name}</span>
{renderName(item)}
<span class="tsd-signature-symbol">: </span>
{renderType(context, item.getSignature.type, TypeContext.none)}
</>,
Expand All @@ -320,8 +338,8 @@ const typeRenderers: {
if (item.getSignature) {
members.push(
<>
<span class="tsd-signature-symbol">get </span>
<span class={getKindClass(item.getSignature)}>{item.name}</span>
<span class="tsd-signature-keyword">get </span>
{renderName(item.getSignature)}
<span class="tsd-signature-symbol">(): </span>
{renderType(context, item.getSignature.type, TypeContext.none)}
</>,
Expand All @@ -332,8 +350,8 @@ const typeRenderers: {
if (item.setSignature) {
members.push(
<>
<span class="tsd-signature-symbol">set </span>
<span class={getKindClass(item.setSignature)}>{item.name}</span>
<span class="tsd-signature-keyword">set </span>
{renderName(item.setSignature)}
<span class="tsd-signature-symbol">(</span>
{item.setSignature.parameters?.map((item) => (
<>
Expand All @@ -352,11 +370,11 @@ const typeRenderers: {
for (const sig of item.signatures) {
members.push(
<>
<span class={getKindClass(sig)}>{item.name}</span>
{renderName(sig)}
{item.flags.isOptional && <span class="tsd-signature-symbol">?</span>}
{context.memberSignatureTitle(sig, {
hideName: true,
arrowStyle: true,
arrowStyle: false,
})}
</>,
);
Expand All @@ -366,7 +384,7 @@ const typeRenderers: {

members.push(
<>
<span class={getKindClass(item)}>{item.name}</span>
{renderName(item)}
<span class="tsd-signature-symbol">{item.flags.isOptional ? "?: " : ": "}</span>
{renderType(context, item.type, TypeContext.none)}
</>,
Expand Down Expand Up @@ -468,7 +486,7 @@ const typeRenderers: {
typeOperator(context, type) {
return (
<>
<span class="tsd-signature-symbol">{type.operator} </span>
<span class="tsd-signature-keyword">{type.operator} </span>
{renderType(context, type.target, TypeContext.typeOperatorTarget)}
</>
);
Expand All @@ -483,13 +501,18 @@ const typeRenderers: {
},
};

function renderType(context: DefaultThemeRenderContext, type: Type | undefined, where: TypeContext) {
function renderType(
context: DefaultThemeRenderContext,
type: Type | undefined,
where: TypeContext,
options: { topLevelLinks: boolean } = { topLevelLinks: false },
) {
if (!type) {
return <span class="tsd-signature-type">any</span>;
}

const renderFn = typeRenderers[type.type];
const rendered = renderFn(context, type as never);
const rendered = renderFn(context, type as never, options);

if (type.needsParenthesis(where)) {
return (
Expand All @@ -504,6 +527,10 @@ function renderType(context: DefaultThemeRenderContext, type: Type | undefined,
return rendered;
}

export function type(context: DefaultThemeRenderContext, type: Type | undefined) {
return renderType(context, type, TypeContext.none);
export function type(
context: DefaultThemeRenderContext,
type: Type | undefined,
options: { topLevelLinks: boolean } = { topLevelLinks: false },
) {
return renderType(context, type, TypeContext.none, options);
}
5 changes: 3 additions & 2 deletions src/lib/output/themes/default/templates/reflection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { JSX, Raw } from "../../../../utils";

export function reflectionTemplate(context: DefaultThemeRenderContext, props: PageEvent<ContainerReflection>) {
if (
[ReflectionKind.TypeAlias, ReflectionKind.Variable].includes(props.model.kind) &&
props.model.kindOf(ReflectionKind.TypeAlias | ReflectionKind.Variable) &&
props.model instanceof DeclarationReflection
) {
return context.memberDeclaration(props.model);
Expand All @@ -20,7 +20,6 @@ export function reflectionTemplate(context: DefaultThemeRenderContext, props: Pa
{context.commentTags(props.model)}
</section>
)}

{props.model instanceof DeclarationReflection &&
props.model.kind === ReflectionKind.Module &&
props.model.readme?.length && (
Expand All @@ -29,6 +28,8 @@ export function reflectionTemplate(context: DefaultThemeRenderContext, props: Pa
</section>
)}

{context.reflectionPreview(props.model)}

{hasTypeParameters(props.model) && <> {context.typeParameters(props.model.typeParameters)} </>}
{props.model instanceof DeclarationReflection && (
<>
Expand Down
11 changes: 11 additions & 0 deletions static/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
--light-color-text-aside: #6e6e6e;
--light-color-link: #1f70c2;

--light-color-ts-keyword: #056bd6;
--light-color-ts-project: #b111c9;
--light-color-ts-module: var(--light-color-ts-project);
--light-color-ts-namespace: var(--light-color-ts-project);
Expand Down Expand Up @@ -50,6 +51,7 @@
--dark-color-text-aside: #dddddd;
--dark-color-link: #00aff4;

--dark-color-ts-keyword: #3399ff;
--dark-color-ts-project: #e358ff;
--dark-color-ts-module: var(--dark-color-ts-project);
--dark-color-ts-namespace: var(--dark-color-ts-project);
Expand Down Expand Up @@ -91,6 +93,7 @@
--color-text-aside: var(--light-color-text-aside);
--color-link: var(--light-color-link);

--color-ts-keyword: var(--light-color-ts-keyword);
--color-ts-module: var(--light-color-ts-module);
--color-ts-namespace: var(--light-color-ts-namespace);
--color-ts-enum: var(--light-color-ts-enum);
Expand Down Expand Up @@ -132,6 +135,7 @@
--color-text-aside: var(--dark-color-text-aside);
--color-link: var(--dark-color-link);

--color-ts-keyword: var(--dark-color-ts-keyword);
--color-ts-module: var(--dark-color-ts-module);
--color-ts-namespace: var(--dark-color-ts-namespace);
--color-ts-enum: var(--dark-color-ts-enum);
Expand Down Expand Up @@ -180,6 +184,7 @@ body {
--color-text-aside: var(--light-color-text-aside);
--color-link: var(--light-color-link);

--color-ts-keyword: var(--light-color-ts-keyword);
--color-ts-module: var(--light-color-ts-module);
--color-ts-namespace: var(--light-color-ts-namespace);
--color-ts-enum: var(--light-color-ts-enum);
Expand Down Expand Up @@ -219,6 +224,7 @@ body {
--color-text-aside: var(--dark-color-text-aside);
--color-link: var(--dark-color-link);

--color-ts-keyword: var(--dark-color-ts-keyword);
--color-ts-module: var(--dark-color-ts-module);
--color-ts-namespace: var(--dark-color-ts-namespace);
--color-ts-enum: var(--dark-color-ts-enum);
Expand Down Expand Up @@ -984,6 +990,11 @@ a.tsd-index-link {
overflow-x: auto;
}

.tsd-signature-keyword {
color: var(--color-ts-keyword);
font-weight: normal;
}

.tsd-signature-symbol {
color: var(--color-text-aside);
font-weight: normal;
Expand Down

0 comments on commit 9ffa0db

Please sign in to comment.