mirror of
https://github.com/goauthentik/authentik
synced 2026-04-25 17:15:26 +02:00
web/elements: add scrollbar helpers and apply to Interface (#21511)
Introduce `elements/utils/scrollbars.ts` with `measureScrollbarWidth` and `applyScrollbarClass`, and call it from `Interface` so the root document picks up `ak-m-visible-scrollbars` / `ak-m-overlay-scrollbars` depending on the platform. Add an `ak-m-thin-scrollbar` selector to `base/scrollbars.css` so ad-hoc containers can opt in. Drop the unused `elements/utils/isVisible.ts`. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ import { ModalOrchestrationController } from "#elements/controllers/ModalOrchest
|
||||
import { ReactiveContextController } from "#elements/controllers/ReactiveContextController";
|
||||
import { BrandingContext } from "#elements/mixins/branding";
|
||||
import { AuthentikConfigContext } from "#elements/mixins/config";
|
||||
import { applyScrollbarClass } from "#elements/utils/scrollbars";
|
||||
|
||||
import { ConsoleLogger, Logger } from "#logger/browser";
|
||||
|
||||
@@ -43,11 +44,12 @@ export abstract class Interface extends AKElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.logger = ConsoleLogger.prefix(this.tagName.toLowerCase());
|
||||
this.logger = ConsoleLogger.prefix(this.localName);
|
||||
|
||||
const { config, brand, locale } = globalAK();
|
||||
|
||||
createUIThemeEffect(applyDocumentTheme);
|
||||
applyScrollbarClass(this.ownerDocument);
|
||||
|
||||
this.addController(new LocaleContextController(this, locale));
|
||||
this.addController(new ConfigContextController(this, config), AuthentikConfigContext);
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
const isStyledVisible = ({ visibility, display }: CSSStyleDeclaration) =>
|
||||
visibility !== "hidden" && display !== "none";
|
||||
|
||||
const isDisplayContents = ({ display }: CSSStyleDeclaration) => display === "contents";
|
||||
|
||||
function computedStyleIsVisible(element: HTMLElement) {
|
||||
const computedStyle = window.getComputedStyle(element);
|
||||
return (
|
||||
isStyledVisible(computedStyle) &&
|
||||
(isDisplayContents(computedStyle) ||
|
||||
!!(element.offsetWidth || element.offsetHeight || element.getClientRects().length))
|
||||
);
|
||||
}
|
||||
|
||||
export function isVisible(element: HTMLElement) {
|
||||
return (
|
||||
element &&
|
||||
element.isConnected &&
|
||||
isStyledVisible(element.style) &&
|
||||
computedStyleIsVisible(element)
|
||||
);
|
||||
}
|
||||
47
web/src/elements/utils/scrollbars.ts
Normal file
47
web/src/elements/utils/scrollbars.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @file Scrollbar utilities.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @returns The width of the scrollbar in pixels, or 0 if the browser uses overlay scrollbars.
|
||||
*/
|
||||
export function measureScrollbarWidth(container: HTMLElement = document.body): number {
|
||||
const outer = container.ownerDocument.createElement("div");
|
||||
|
||||
outer.style.overflow = "scroll";
|
||||
outer.style.width = "100px";
|
||||
outer.style.visibility = "hidden";
|
||||
|
||||
container.appendChild(outer);
|
||||
|
||||
const width = outer.offsetWidth - outer.clientWidth;
|
||||
|
||||
container.removeChild(outer);
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
export const ScrollbarClassName = {
|
||||
Visible: "ak-m-visible-scrollbars",
|
||||
Overlay: "ak-m-overlay-scrollbars",
|
||||
} as const;
|
||||
|
||||
export type ScrollbarClassName = (typeof ScrollbarClassName)[keyof typeof ScrollbarClassName];
|
||||
|
||||
/**
|
||||
* Applies the appropriate scrollbar class to the given container element
|
||||
* based on whether the browser uses visible or overlay scrollbars.
|
||||
*
|
||||
* @param ownerDocument The document to apply the scrollbar class to.
|
||||
*/
|
||||
export function applyScrollbarClass(ownerDocument: Document = document): void {
|
||||
const scrollbarWidth = measureScrollbarWidth(ownerDocument.body);
|
||||
|
||||
if (scrollbarWidth) {
|
||||
ownerDocument.documentElement.classList.add(ScrollbarClassName.Visible);
|
||||
ownerDocument.documentElement.classList.remove(ScrollbarClassName.Overlay);
|
||||
} else {
|
||||
ownerDocument.documentElement.classList.add(ScrollbarClassName.Overlay);
|
||||
ownerDocument.documentElement.classList.remove(ScrollbarClassName.Visible);
|
||||
}
|
||||
}
|
||||
@@ -89,6 +89,7 @@ html[data-theme="dark"],
|
||||
}
|
||||
|
||||
@supports (scrollbar-width: thin) {
|
||||
.ak-m-thin-scrollbar,
|
||||
.pf-c-page__main,
|
||||
.pf-c-nav__list,
|
||||
.pf-c-card__body {
|
||||
|
||||
Reference in New Issue
Block a user