From cd9b249778ef8c552903e515443996a9eb0ce8ab Mon Sep 17 00:00:00 2001 From: Gerrit Birkeland Date: Sat, 17 Dec 2022 20:59:19 -0700 Subject: [PATCH] Ensure linked-to members are always visible Resolves #2092 --- CHANGELOG.md | 1 + .../default/assets/typedoc/Application.ts | 47 ++++++++++++++++++- .../default/assets/typedoc/Component.ts | 5 ++ .../assets/typedoc/components/Filter.ts | 2 + static/style.css | 23 +++++++++ 5 files changed, 76 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ab068103..bd14be321 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### Bug Fixes +- Links to members hidden by filter settings now temporarily override the filter, #2092. - If `src/` and `src/x` are specified as entry points, `src/` will no longer be ignored, #2121. ## v0.23.22 (2022-12-11) diff --git a/src/lib/output/themes/default/assets/typedoc/Application.ts b/src/lib/output/themes/default/assets/typedoc/Application.ts index 26232059d..e3f178f41 100644 --- a/src/lib/output/themes/default/assets/typedoc/Application.ts +++ b/src/lib/output/themes/default/assets/typedoc/Application.ts @@ -30,24 +30,67 @@ export function registerComponent( * TypeDoc application class. */ export class Application { + alwaysVisibleMember: HTMLElement | null = null; + /** * Create a new Application instance. */ constructor() { this.createComponents(document.body); + this.ensureFocusedElementVisible(); + window.addEventListener("hashchange", () => + this.ensureFocusedElementVisible() + ); } /** * Create all components beneath the given element. */ - public createComponents(context: HTMLElement) { + private createComponents(context: HTMLElement) { components.forEach((c) => { context.querySelectorAll(c.selector).forEach((el) => { if (!el.dataset["hasInstance"]) { - new c.constructor({ el: el }); + new c.constructor({ el, app: this }); el.dataset["hasInstance"] = String(true); } }); }); } + + public filterChanged() { + this.ensureFocusedElementVisible(); + } + + /** + * Ensures that if a user was linked to a reflection which is hidden because of filter + * settings, that reflection is still shown. + */ + private ensureFocusedElementVisible() { + if (this.alwaysVisibleMember) { + this.alwaysVisibleMember.classList.remove("always-visible"); + this.alwaysVisibleMember.firstElementChild!.remove(); + this.alwaysVisibleMember = null; + } + + const reflAnchor = document.getElementById(location.hash.substring(1)); + if (!reflAnchor) return; + + let reflContainer = reflAnchor.parentElement!; + while (reflContainer.tagName !== "SECTION") { + reflContainer = reflContainer.parentElement!; + } + + if (reflContainer.offsetParent == null) { + this.alwaysVisibleMember = reflContainer; + + reflContainer.classList.add("always-visible"); + + const warning = document.createElement("p"); + warning.classList.add("warning"); + warning.textContent = + "This member is normally hidden due to your filter settings."; + + reflContainer.prepend(warning); + } + } } diff --git a/src/lib/output/themes/default/assets/typedoc/Component.ts b/src/lib/output/themes/default/assets/typedoc/Component.ts index 1bc43752b..aec1672f5 100644 --- a/src/lib/output/themes/default/assets/typedoc/Component.ts +++ b/src/lib/output/themes/default/assets/typedoc/Component.ts @@ -1,4 +1,7 @@ +import { Application } from "./Application"; + export interface IComponentOptions { + app: Application; el: HTMLElement; } @@ -7,8 +10,10 @@ export interface IComponentOptions { */ export class Component { protected el: HTMLElement; + protected app: Application; constructor(options: IComponentOptions) { this.el = options.el; + this.app = options.app; } } diff --git a/src/lib/output/themes/default/assets/typedoc/components/Filter.ts b/src/lib/output/themes/default/assets/typedoc/components/Filter.ts index 7eec789e6..12fc6d83b 100644 --- a/src/lib/output/themes/default/assets/typedoc/components/Filter.ts +++ b/src/lib/output/themes/default/assets/typedoc/components/Filter.ts @@ -58,6 +58,8 @@ export class Filter extends Component { this.el.checked = this.value; document.documentElement.classList.toggle(this.key, this.value); + this.app.filterChanged(); + // Hide index headings where all index items are hidden. // offsetParent == null checks for display: none document diff --git a/static/style.css b/static/style.css index e5093854c..2d02570d0 100644 --- a/static/style.css +++ b/static/style.css @@ -2,6 +2,8 @@ /* Light */ --light-color-background: #f2f4f8; --light-color-background-secondary: #eff0f1; + --light-color-warning-text: #222; + --light-color-background-warning: #e6e600; --light-color-icon-background: var(--light-color-background); --light-color-accent: #c5c7c9; --light-color-text: #222; @@ -21,6 +23,8 @@ /* Dark */ --dark-color-background: #2b2e33; --dark-color-background-secondary: #1e2024; + --dark-color-background-warning: #bebe00; + --dark-color-warning-text: #222; --dark-color-icon-background: var(--dark-color-background-secondary); --dark-color-accent: #9096a2; --dark-color-text: #f5f5f5; @@ -42,6 +46,8 @@ :root { --color-background: var(--light-color-background); --color-background-secondary: var(--light-color-background-secondary); + --color-background-warning: var(--light-color-background-warning); + --color-warning-text: var(--light-color-warning-text); --color-icon-background: var(--light-color-icon-background); --color-accent: var(--light-color-accent); --color-text: var(--light-color-text); @@ -64,6 +70,8 @@ :root { --color-background: var(--dark-color-background); --color-background-secondary: var(--dark-color-background-secondary); + --color-background-warning: var(--dark-color-background-warning); + --color-warning-text: var(--dark-color-warning-text); --color-icon-background: var(--dark-color-icon-background); --color-accent: var(--dark-color-accent); --color-text: var(--dark-color-text); @@ -93,6 +101,8 @@ body { :root[data-theme="light"] { --color-background: var(--light-color-background); --color-background-secondary: var(--light-color-background-secondary); + --color-background-warning: var(--light-color-background-warning); + --color-warning-text: var(--light-color-warning-text); --color-icon-background: var(--light-color-icon-background); --color-accent: var(--light-color-accent); --color-text: var(--light-color-text); @@ -113,6 +123,8 @@ body { :root[data-theme="dark"] { --color-background: var(--dark-color-background); --color-background-secondary: var(--dark-color-background-secondary); + --color-background-warning: var(--dark-color-background-warning); + --color-warning-text: var(--dark-color-warning-text); --color-icon-background: var(--dark-color-icon-background); --color-accent: var(--dark-color-accent); --color-text: var(--dark-color-text); @@ -130,6 +142,11 @@ body { --color-scheme: var(--dark-color-scheme); } +.always-visible, +.always-visible .tsd-signatures { + display: inherit !important; +} + h1, h2, h3, @@ -1237,6 +1254,12 @@ img { text-decoration: line-through; } +.warning { + padding: 1rem; + color: var(--color-warning-text); + background: var(--color-background-warning); +} + * { scrollbar-width: thin; scrollbar-color: var(--color-accent) var(--color-icon-background);