Skip to content

Commit 603344e

Browse files
committed
Allow more granular control over reflection icons
1 parent 8d0ea4a commit 603344e

File tree

10 files changed

+62
-9
lines changed

10 files changed

+62
-9
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ title: Changelog
5151
- Introduced `@function` tag to force TypeDoc to convert variable declarations with a type annotation as functions, #2881.
5252
- Exposed a `TypeDoc` global object in the HTML theme which can be used to prevent TypeDoc from using `localStorage`, #2872.
5353
- Introduced `@preventInline` and `@inlineType` tags for further control extending the `@inline` tag, #2862.
54+
- API: Introduced `DefaultThemeRenderContext.reflectionIcon` for more granular control over displayed reflection icons.
5455

5556
### Bug Fixes
5657

src/lib/output/plugins/JavascriptIndexPlugin.ts

+6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ interface SearchDocument {
2121
url: string;
2222
classes?: string;
2323
parent?: string;
24+
icon?: string | number;
2425
}
2526

2627
/**
@@ -112,6 +113,11 @@ export class JavascriptIndexPlugin extends RendererComponent {
112113
classes: theme.getReflectionClasses(reflection),
113114
};
114115

116+
const icon = theme.getReflectionIcon(reflection);
117+
if (icon !== reflection.kind) {
118+
row.icon = icon;
119+
}
120+
115121
if (parent) {
116122
row.parent = parent.getFullName();
117123
}

src/lib/output/themes/default/DefaultTheme.tsx

+13
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export interface NavigationElement {
2727
kind?: ReflectionKind;
2828
class?: string;
2929
children?: NavigationElement[];
30+
icon?: string | number;
3031
}
3132

3233
/**
@@ -99,6 +100,13 @@ export class DefaultTheme extends Theme {
99100
return getReflectionClasses(reflection, filters);
100101
}
101102

103+
/**
104+
* This is used so that themes may define multiple icons for modified icons (e.g. method, and inherited method)
105+
*/
106+
getReflectionIcon(reflection: Reflection): keyof this["icons"] & (string | number) {
107+
return reflection.kind;
108+
}
109+
102110
/**
103111
* Create a new DefaultTheme instance.
104112
*
@@ -176,12 +184,17 @@ export class DefaultTheme extends Theme {
176184
};
177185
}
178186

187+
const icon = theme.getReflectionIcon(element) === element.kind
188+
? undefined
189+
: theme.getReflectionIcon(element);
190+
179191
return {
180192
text: getDisplayName(element),
181193
path: router.getFullUrl(element),
182194
kind: element.kind & ReflectionKind.Project ? undefined : element.kind,
183195
class: classNames({ deprecated: element.isDeprecated() }, theme.getReflectionClasses(element)),
184196
children: children?.length ? children : undefined,
197+
icon,
185198
};
186199
}
187200

src/lib/output/themes/default/DefaultThemeRenderContext.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import { reflectionTemplate } from "./templates/reflection.js";
3737
import { typeDeclaration, typeDetails, typeDetailsIfUseful } from "./partials/typeDetails.js";
3838
import { moduleMemberSummary, moduleReflection } from "./partials/moduleReflection.js";
3939
import type { Router } from "../../router.js";
40-
import type { NeverIfInternal } from "#utils";
40+
import type { JSX, NeverIfInternal } from "#utils";
4141

4242
function bind<F, L extends any[], R>(fn: (f: F, ...a: L) => R, first: F) {
4343
return (...r: L) => fn(first, ...r);
@@ -62,6 +62,9 @@ export class DefaultThemeRenderContext {
6262

6363
/**
6464
* Icons available for use within the page.
65+
* When getting an icon for a reflection, {@link reflectionIcon} should be used so
66+
* that themes which define multiple icon variants can correctly specify which icon
67+
* they want to be used.
6568
*
6669
* Note: This creates a reference to icons declared by {@link DefaultTheme.icons},
6770
* to customize icons, that object must be modified instead.
@@ -70,6 +73,13 @@ export class DefaultThemeRenderContext {
7073
return this._refIcons;
7174
}
7275

76+
/**
77+
* Do not override this method, override {@link DefaultTheme.getReflectionIcon} instead.
78+
*/
79+
reflectionIcon = (reflection: Reflection): JSX.Element => {
80+
return this.icons[this.theme.getReflectionIcon(reflection)]();
81+
};
82+
7383
get slugger() {
7484
return this.router.getSlugger(this.page.model);
7585
}

src/lib/output/themes/default/assets/typedoc/Navigation.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export interface NavigationElement {
66
kind?: number;
77
class?: string;
88
children?: NavigationElement[];
9+
icon?: string | number;
910
}
1011

1112
let BASE_URL: string;
@@ -105,7 +106,9 @@ function addNavText(
105106
"&quot;",
106107
);
107108
a.innerHTML =
108-
`<svg width="20" height="20" viewBox="0 0 24 24" fill="none" class="tsd-kind-icon" aria-label="${label}"><use href="#icon-${el.kind}"></use></svg>`;
109+
`<svg width="20" height="20" viewBox="0 0 24 24" fill="none" class="tsd-kind-icon" aria-label="${label}"><use href="#icon-${
110+
el.icon || el.kind
111+
}"></use></svg>`;
109112
}
110113
a.appendChild(document.createElement("span")).textContent = el.text;
111114
} else {

src/lib/output/themes/default/assets/typedoc/components/Search.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ interface SearchDocument {
1616
url: string;
1717
classes?: string;
1818
parent?: string;
19+
icon?: string | number;
1920
}
2021

2122
interface IData {
@@ -274,7 +275,9 @@ function updateResults(
274275
"&quot;",
275276
);
276277
const icon =
277-
`<svg width="20" height="20" viewBox="0 0 24 24" fill="none" class="tsd-kind-icon" aria-label="${label}"><use href="#icon-${row.kind}"></use></svg>`;
278+
`<svg width="20" height="20" viewBox="0 0 24 24" fill="none" class="tsd-kind-icon" aria-label="${label}"><use href="#icon-${
279+
row.icon || row.kind
280+
}"></use></svg>`;
278281

279282
// Highlight the matched part of the query in the search results
280283
let name = highlightMatches(row.name, searchText);

src/lib/output/themes/default/partials/index.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { i18n, JSX } from "#utils";
44
import type { ContainerReflection, ReflectionCategory, ReflectionGroup } from "../../../../models/index.js";
55

66
function renderCategory(
7-
{ urlTo, icons, getReflectionClasses, markdown }: DefaultThemeRenderContext,
7+
{ urlTo, reflectionIcon, getReflectionClasses, markdown }: DefaultThemeRenderContext,
88
item: ReflectionCategory | ReflectionGroup,
99
prependName = "",
1010
) {
@@ -26,7 +26,7 @@ function renderCategory(
2626
getReflectionClasses(item),
2727
)}
2828
>
29-
{icons[item.kind]()}
29+
{reflectionIcon(item)}
3030
<span>{renderName(item)}</span>
3131
</a>
3232
{"\n"}

src/lib/output/themes/default/partials/moduleReflection.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export function moduleMemberSummary(
7272

7373
name = (
7474
<span class="tsd-member-summary-name">
75-
{context.icons[target.kind]()}
75+
{context.reflectionIcon(target)}
7676
<span class={classNames({ deprecated: member.isDeprecated() })}>{member.name}</span>
7777
<span>&nbsp;{"\u2192"}&nbsp;</span>
7878
{uniqueName(context, target)}
@@ -82,7 +82,7 @@ export function moduleMemberSummary(
8282
} else {
8383
name = (
8484
<span class="tsd-member-summary-name">
85-
{context.icons[member.kind]()}
85+
{context.reflectionIcon(member)}
8686
<a class={classNames({ deprecated: member.isDeprecated() })} href={context.urlTo(member)}>
8787
{member.name}
8888
</a>

src/lib/output/themes/default/templates/hierarchy.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ function fullHierarchy(
1313
return (
1414
<li data-refl={root.id}>
1515
<a href={context.urlTo(root)}>
16-
{context.icons[root.kind]()}
16+
{context.reflectionIcon(root)}
1717
{root.name}
1818
</a>
1919
</li>
@@ -34,7 +34,7 @@ function fullHierarchy(
3434
return (
3535
<li data-refl={root.id} id={root.getFullName()}>
3636
<a href={context.urlTo(root)}>
37-
{context.icons[root.kind]()}
37+
{context.reflectionIcon(root)}
3838
{root.name}
3939
</a>
4040
{children.length && <ul>{children}</ul>}

src/lib/utils-common/jsx.elements.ts

+17
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ export interface IntrinsicElements {
125125
line: JsxLineElementProps;
126126
use: JsxUseElementProps;
127127
text: JsxTextElementProps;
128+
image: JsxImageElementProps;
128129
}
129130

130131
export function JsxFragment(): never {
@@ -1174,3 +1175,19 @@ export interface JsxTextElementProps extends JsxSvgCoreProps, JsxSvgStyleProps,
11741175
x?: string | number;
11751176
y?: string | number;
11761177
}
1178+
1179+
/**
1180+
* Properties permitted on the `<image>` element.
1181+
*
1182+
* Reference: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image
1183+
*/
1184+
export interface JsxImageElementProps extends JsxSvgCoreProps {
1185+
x?: string | number;
1186+
y?: string | number;
1187+
width?: string | number;
1188+
height?: string | number;
1189+
href: string;
1190+
preserveAspectRatio?: string;
1191+
crossorigin?: "anonymous" | "use-credentials";
1192+
decoding?: "async" | "sync" | "auto";
1193+
}

0 commit comments

Comments
 (0)