diff --git a/web/src/common/utils.ts b/web/src/common/utils.ts index d1e59e4a9..1ae395b4e 100644 --- a/web/src/common/utils.ts +++ b/web/src/common/utils.ts @@ -1,5 +1,7 @@ import { SentryIgnoredError } from "@goauthentik/common/errors"; +import { CSSResult, css } from "lit"; + export function getCookie(name: string): string { let cookieValue = ""; if (document.cookie && document.cookie !== "") { @@ -115,3 +117,28 @@ export function dateTimeLocal(date: Date): string { const parts = localISOTime.split(":"); return `${parts[0]}:${parts[1]}`; } + +// Lit is extremely well-typed with regard to CSS, and Storybook's `build` does not currently have a +// coherent way of importing CSS-as-text into CSSStyleSheet. It works well when Storybook is running +// in `dev,` but in `build` it fails. Storied components will have to map their textual CSS imports +// using the function below. +type AdaptableStylesheet = Readonly; +type AdaptedStylesheets = CSSStyleSheet | CSSStyleSheet[]; + +const isCSSResult = (v: unknown): v is CSSResult => + v instanceof CSSResult && v.styleSheet !== undefined; + +// prettier-ignore +export const _adaptCSS = (sheet: AdaptableStylesheet): CSSStyleSheet => + (typeof sheet === "string" ? css([sheet] as unknown as TemplateStringsArray, ...[]).styleSheet + : isCSSResult(sheet) ? sheet.styleSheet + : sheet) as CSSStyleSheet; + +// Overloaded function definitions inform consumers that if you pass it an array, expect an array in +// return; if you pass it a scaler, expect a scalar in return. + +export function adaptCSS(sheet: AdaptableStylesheet): CSSStyleSheet; +export function adaptCSS(sheet: AdaptableStylesheet[]): CSSStyleSheet[]; +export function adaptCSS(sheet: AdaptableStylesheet | AdaptableStylesheet[]): AdaptedStylesheets { + return Array.isArray(sheet) ? sheet.map(_adaptCSS) : _adaptCSS(sheet); +} diff --git a/web/src/elements/Base.ts b/web/src/elements/Base.ts index 8ffbbf3dc..f0e0b6108 100644 --- a/web/src/elements/Base.ts +++ b/web/src/elements/Base.ts @@ -1,8 +1,9 @@ import { config, tenant } from "@goauthentik/common/api/config"; import { EVENT_LOCALE_CHANGE, EVENT_THEME_CHANGE } from "@goauthentik/common/constants"; import { UIConfig, uiConfig } from "@goauthentik/common/ui/config"; +import { adaptCSS } from "@goauthentik/common/utils"; -import { CSSResult, LitElement } from "lit"; +import { LitElement } from "lit"; import { state } from "lit/decorators.js"; import AKGlobal from "@goauthentik/common/styles/authentik.css"; @@ -68,8 +69,7 @@ export class AKElement extends LitElement { if ("ShadyDOM" in window) { styleRoot = document; } - const globalStyleSheet = AKGlobal instanceof CSSResult ? AKGlobal.styleSheet : AKGlobal; - styleRoot.adoptedStyleSheets = [...styleRoot.adoptedStyleSheets, globalStyleSheet]; + styleRoot.adoptedStyleSheets = adaptCSS([...styleRoot.adoptedStyleSheets, AKGlobal]); this._initTheme(styleRoot); this._initCustomCSS(styleRoot); return root; diff --git a/web/src/user/LibraryPage/ApplicationEmptyState.ts b/web/src/user/LibraryPage/ApplicationEmptyState.ts index 314837926..11871c139 100644 --- a/web/src/user/LibraryPage/ApplicationEmptyState.ts +++ b/web/src/user/LibraryPage/ApplicationEmptyState.ts @@ -1,4 +1,5 @@ import { docLink } from "@goauthentik/common/global"; +import { adaptCSS } from "@goauthentik/common/utils"; import { AKElement } from "@goauthentik/elements/Base"; import { paramURL } from "@goauthentik/elements/router/RouterOutlet"; @@ -19,7 +20,7 @@ import PFSpacing from "@patternfly/patternfly/utilities/Spacing/spacing.css"; * administrator, provide a link to the "Create a new application" page. */ -const styles = [ +const styles = adaptCSS([ PFBase, PFEmptyState, PFButton, @@ -31,7 +32,7 @@ const styles = [ font-weight: bold; } `, -]; +]); @customElement("ak-library-application-empty-list") export class LibraryPageApplicationEmptyList extends AKElement {