fix loader helpers
This commit is contained in:
committed by
Jacob Overgaard
parent
2655a555ea
commit
8250575422
@@ -1,31 +1,44 @@
|
||||
import type { UmbApi } from "../models/api.interface.js";
|
||||
import type { ApiLoaderExports, ApiLoaderProperty, ClassConstructor, ElementAndApiLoaderProperty, ElementLoaderExports } from "../types/utils.js";
|
||||
import type { UmbApi } from '../models/api.interface.js';
|
||||
import type {
|
||||
ApiLoaderExports,
|
||||
ApiLoaderProperty,
|
||||
ClassConstructor,
|
||||
ElementAndApiLoaderProperty,
|
||||
ElementLoaderExports,
|
||||
} from '../types/utils.js';
|
||||
|
||||
export async function loadManifestApi<ApiType extends UmbApi>(property: ApiLoaderProperty<ApiType> | ElementAndApiLoaderProperty<any, ApiType>): Promise<ClassConstructor<ApiType> | undefined> {
|
||||
const propType = typeof property
|
||||
if(propType === 'function') {
|
||||
if((property as ClassConstructor).prototype) {
|
||||
export async function loadManifestApi<ApiType extends UmbApi>(
|
||||
property: ApiLoaderProperty<ApiType> | ElementAndApiLoaderProperty<any, ApiType>,
|
||||
): Promise<ClassConstructor<ApiType> | undefined> {
|
||||
const propType = typeof property;
|
||||
if (propType === 'function') {
|
||||
if ((property as ClassConstructor).prototype) {
|
||||
// Class Constructor
|
||||
return property as ClassConstructor<ApiType>;
|
||||
} else {
|
||||
// Promise function
|
||||
const result = await (property as (Exclude<Exclude<ApiLoaderProperty<ApiType>, string>, ClassConstructor<ApiType>>))();
|
||||
if(typeof result === 'object' && result != null) {
|
||||
const exportValue = 'api' in result ? result.api : undefined || 'default' in result ? (result as Exclude<(typeof result), ElementLoaderExports>).default : undefined;
|
||||
if(exportValue && typeof exportValue === 'function') {
|
||||
const result = await (
|
||||
property as Exclude<Exclude<ApiLoaderProperty<ApiType>, string>, ClassConstructor<ApiType>>
|
||||
)();
|
||||
if (typeof result === 'object' && result != null) {
|
||||
const exportValue =
|
||||
('api' in result ? result.api : undefined) ||
|
||||
('default' in result ? (result as Exclude<typeof result, ElementLoaderExports>).default : undefined);
|
||||
if (exportValue && typeof exportValue === 'function') {
|
||||
return exportValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(propType === 'string') {
|
||||
} else if (propType === 'string') {
|
||||
// Import string
|
||||
const result = await (import(/* @vite-ignore */ property as string) as unknown as ApiLoaderExports<ApiType>);
|
||||
if(typeof result === 'object' && result != null) {
|
||||
const exportValue = 'api' in result ? result.api : undefined || 'default' in result ? result.default : undefined;
|
||||
if(exportValue && typeof exportValue === 'function') {
|
||||
if (result && typeof result === 'object') {
|
||||
const exportValue =
|
||||
('api' in result ? result.api : undefined) || ('default' in result ? result.default : undefined);
|
||||
if (exportValue && typeof exportValue === 'function') {
|
||||
return exportValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,40 @@
|
||||
import type { ApiLoaderExports, ClassConstructor, ElementAndApiLoaderProperty, ElementLoaderExports, ElementLoaderProperty } from "../types/utils.js";
|
||||
import type {
|
||||
ApiLoaderExports,
|
||||
ClassConstructor,
|
||||
ElementAndApiLoaderProperty,
|
||||
ElementLoaderExports,
|
||||
ElementLoaderProperty,
|
||||
} from '../types/utils.js';
|
||||
|
||||
|
||||
export async function loadManifestElement<ElementType extends HTMLElement>(property: ElementLoaderProperty<ElementType> | ElementAndApiLoaderProperty<ElementType>): Promise<ClassConstructor<ElementType> | undefined> {
|
||||
const propType = typeof property
|
||||
if(propType === 'function') {
|
||||
if((property as ClassConstructor).prototype) {
|
||||
export async function loadManifestElement<ElementType extends HTMLElement>(
|
||||
property: ElementLoaderProperty<ElementType> | ElementAndApiLoaderProperty<ElementType>,
|
||||
): Promise<ClassConstructor<ElementType> | undefined> {
|
||||
const propType = typeof property;
|
||||
if (propType === 'function') {
|
||||
if ((property as ClassConstructor).prototype) {
|
||||
// Class Constructor
|
||||
return property as ClassConstructor<ElementType>;
|
||||
} else {
|
||||
// Promise function
|
||||
const result = await (property as (Exclude<Exclude<typeof property, string>, ClassConstructor<ElementType>>))();
|
||||
if(typeof result === 'object' && result !== null) {
|
||||
const exportValue = 'element' in result ? result.element : undefined || 'default' in result ? (result as Exclude<(typeof result), ApiLoaderExports>).default : undefined;
|
||||
if(exportValue && typeof exportValue === 'function') {
|
||||
const result = await (property as Exclude<Exclude<typeof property, string>, ClassConstructor<ElementType>>)();
|
||||
if (typeof result === 'object' && result !== null) {
|
||||
const exportValue =
|
||||
('element' in result ? result.element : undefined) ||
|
||||
('default' in result ? (result as Exclude<typeof result, ApiLoaderExports>).default : undefined);
|
||||
if (exportValue && typeof exportValue === 'function') {
|
||||
return exportValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(propType === 'string') {
|
||||
} else if (propType === 'string') {
|
||||
// Import string
|
||||
const result = await (import(/* @vite-ignore */ property as string) as unknown as ElementLoaderExports<ElementType>);
|
||||
if(typeof result === 'object' && result != null) {
|
||||
const exportValue = 'element' in result ? result.element : undefined || 'default' in result ? result.default : undefined;
|
||||
if(exportValue && typeof exportValue === 'function') {
|
||||
const result = await (import(
|
||||
/* @vite-ignore */ property as string
|
||||
) as unknown as ElementLoaderExports<ElementType>);
|
||||
if (result && typeof result === 'object') {
|
||||
const exportValue =
|
||||
('element' in result ? result.element : undefined) || ('default' in result ? result.default : undefined);
|
||||
if (exportValue && typeof exportValue === 'function') {
|
||||
return exportValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,29 @@
|
||||
import type { JsLoaderProperty } from "../types/utils.js";
|
||||
import type { CssLoaderExports, CssLoaderProperty } from '../types/utils.js';
|
||||
|
||||
export async function loadManifestPlainCss<CssType = string>(property: JsLoaderProperty<CssType>): Promise<CssType | undefined> {
|
||||
export async function loadManifestPlainCss<CssType extends string>(
|
||||
property: CssLoaderProperty<CssType>,
|
||||
): Promise<CssType | undefined> {
|
||||
const propType = typeof property;
|
||||
if(propType === 'function') {
|
||||
const result = await (property as (Exclude<(typeof property), string>))();
|
||||
if(result != null) {
|
||||
return result;
|
||||
if (propType === 'function') {
|
||||
// Promise function
|
||||
const result = await (property as Exclude<typeof property, string>)();
|
||||
if (typeof result === 'object' && result != null) {
|
||||
const exportValue =
|
||||
('css' in result ? result.css : undefined) || ('default' in result ? result.default : undefined);
|
||||
if (exportValue && typeof exportValue === 'string') {
|
||||
return exportValue as CssType;
|
||||
}
|
||||
}
|
||||
} else if(propType === 'string') {
|
||||
} else if (propType === 'string') {
|
||||
// Import string
|
||||
const result = await (import(/* @vite-ignore */ property as string) as unknown as CssType);
|
||||
if(result != null) {
|
||||
return result;
|
||||
const result = await (import(/* @vite-ignore */ property as string) as unknown as CssLoaderExports<CssType>);
|
||||
if (typeof result === 'object' && result != null) {
|
||||
const exportValue =
|
||||
('css' in result ? result.css : undefined) || ('default' in result ? result.default : undefined);
|
||||
if (exportValue && typeof exportValue === 'string') {
|
||||
return exportValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
import type { JsLoaderProperty } from "../types/utils.js";
|
||||
import type { JsLoaderProperty } from '../types/utils.js';
|
||||
|
||||
export async function loadManifestPlainJs<JsType extends object>(property: JsLoaderProperty<JsType>): Promise<JsType | undefined> {
|
||||
export async function loadManifestPlainJs<JsType extends object>(
|
||||
property: JsLoaderProperty<JsType>,
|
||||
): Promise<JsType | undefined> {
|
||||
const propType = typeof property;
|
||||
if(propType === 'function') {
|
||||
const result = await (property as (Exclude<(typeof property), string>))();
|
||||
if(typeof result === 'object' && result != null) {
|
||||
if (propType === 'function') {
|
||||
// Promise function
|
||||
const result = await (property as Exclude<typeof property, string>)();
|
||||
if (typeof result === 'object' && result != null) {
|
||||
return result;
|
||||
}
|
||||
} else if(propType === 'string') {
|
||||
} else if (propType === 'string') {
|
||||
// Import string
|
||||
const result = await (import(/* @vite-ignore */ property as string) as unknown as JsType);
|
||||
if(typeof result === 'object' && result != null) {
|
||||
if (typeof result === 'object' && result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,12 +26,12 @@ export interface ManifestElementWithElementName extends ManifestElement {
|
||||
elementName: string;
|
||||
}
|
||||
|
||||
export interface ManifestPlainCss<CssType = unknown> extends ManifestBase {
|
||||
export interface ManifestPlainCss extends ManifestBase {
|
||||
/**
|
||||
* The file location of the stylesheet file to load
|
||||
* @TJS-type string
|
||||
*/
|
||||
css?: CssLoaderProperty<CssType>;
|
||||
css?: CssLoaderProperty;
|
||||
}
|
||||
|
||||
export interface ManifestPlainJs<JsType> extends ManifestBase {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { UmbApi } from "../models/index.js";
|
||||
|
||||
import type { UmbApi } from '../models/index.js';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export type HTMLElementConstructor<T = HTMLElement> = new (...args: any[]) => T;
|
||||
@@ -7,80 +6,60 @@ export type HTMLElementConstructor<T = HTMLElement> = new (...args: any[]) => T;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export type ClassConstructor<T = object> = new (...args: any[]) => T;
|
||||
|
||||
|
||||
|
||||
// Module Export Types:
|
||||
|
||||
export type ElementLoaderExports<
|
||||
ElementType extends HTMLElement = HTMLElement
|
||||
> = ({default: ClassConstructor<ElementType>} | {element: ClassConstructor<ElementType>})// | Omit<Omit<object, 'element'>, 'default'>
|
||||
export type CssLoaderExports<CssType extends string = string> = { default: CssType } | { css: CssType };
|
||||
|
||||
export type ApiLoaderExports<
|
||||
ApiType extends UmbApi = UmbApi
|
||||
> = ({default: ClassConstructor<ApiType>} | {api: ClassConstructor<ApiType>})//| Omit<Omit<object, 'api'>, 'default'>
|
||||
export type ElementLoaderExports<ElementType extends HTMLElement = HTMLElement> =
|
||||
| { default: ClassConstructor<ElementType> }
|
||||
| { element: ClassConstructor<ElementType> }; // | Omit<Omit<object, 'element'>, 'default'>
|
||||
|
||||
export type ApiLoaderExports<ApiType extends UmbApi = UmbApi> =
|
||||
| { default: ClassConstructor<ApiType> }
|
||||
| { api: ClassConstructor<ApiType> }; //| Omit<Omit<object, 'api'>, 'default'>
|
||||
|
||||
export type ElementAndApiLoaderExports<
|
||||
ElementType extends HTMLElement = HTMLElement,
|
||||
ApiType extends UmbApi = UmbApi
|
||||
> = ({api: ClassConstructor<ApiType>} | {element: ClassConstructor<ElementType>} | {api: ClassConstructor<ApiType>, element: ClassConstructor<ElementType>})// | Omit<Omit<Omit<object, 'element'>, 'api'>, 'default'>
|
||||
|
||||
ApiType extends UmbApi = UmbApi,
|
||||
> =
|
||||
| { api: ClassConstructor<ApiType> }
|
||||
| { element: ClassConstructor<ElementType> }
|
||||
| { api: ClassConstructor<ApiType>; element: ClassConstructor<ElementType> }; // | Omit<Omit<Omit<object, 'element'>, 'api'>, 'default'>
|
||||
|
||||
// Promise Types:
|
||||
|
||||
export type CssLoaderPromise<
|
||||
CssType = unknown
|
||||
> = (() => Promise<CssType>)
|
||||
export type CssLoaderPromise<CssType extends string = string> = () => Promise<CssLoaderExports<CssType>>;
|
||||
|
||||
export type JsLoaderPromise<
|
||||
JsType
|
||||
> = (() => Promise<JsType>)
|
||||
export type JsLoaderPromise<JsExportType> = () => Promise<JsExportType>;
|
||||
|
||||
export type ElementLoaderPromise<
|
||||
ElementType extends HTMLElement = HTMLElement
|
||||
> = (() => Promise<ElementLoaderExports<ElementType>>)
|
||||
export type ElementLoaderPromise<ElementType extends HTMLElement = HTMLElement> = () => Promise<
|
||||
ElementLoaderExports<ElementType>
|
||||
>;
|
||||
|
||||
export type ApiLoaderPromise<
|
||||
ApiType extends UmbApi = UmbApi
|
||||
> = (() => Promise<ApiLoaderExports<ApiType>>)
|
||||
export type ApiLoaderPromise<ApiType extends UmbApi = UmbApi> = () => Promise<ApiLoaderExports<ApiType>>;
|
||||
|
||||
export type ElementAndApiLoaderPromise<
|
||||
ElementType extends HTMLElement = HTMLElement,
|
||||
ApiType extends UmbApi = UmbApi
|
||||
> = (() => Promise<ElementAndApiLoaderExports<ElementType, ApiType>>)
|
||||
|
||||
ApiType extends UmbApi = UmbApi,
|
||||
> = () => Promise<ElementAndApiLoaderExports<ElementType, ApiType>>;
|
||||
|
||||
// Property Types:
|
||||
|
||||
export type CssLoaderProperty<CssType = string> = (
|
||||
string
|
||||
|
|
||||
CssLoaderPromise<CssType>
|
||||
);
|
||||
export type JsLoaderProperty<JsType> = (
|
||||
string
|
||||
|
|
||||
JsLoaderPromise<JsType>
|
||||
);
|
||||
export type ElementLoaderProperty<ElementType extends HTMLElement = HTMLElement> = (
|
||||
string
|
||||
|
|
||||
ElementLoaderPromise<ElementType>
|
||||
|
|
||||
ClassConstructor<ElementType>
|
||||
);
|
||||
export type ApiLoaderProperty<ApiType extends UmbApi = UmbApi> = (
|
||||
string
|
||||
|
|
||||
ApiLoaderPromise<ApiType>
|
||||
|
|
||||
ClassConstructor<ApiType>
|
||||
);
|
||||
export type ElementAndApiLoaderProperty<ElementType extends HTMLElement = HTMLElement, ApiType extends UmbApi = UmbApi> = (
|
||||
string
|
||||
|
|
||||
ElementAndApiLoaderPromise<ElementType, ApiType>
|
||||
|
|
||||
ElementLoaderPromise<ElementType>
|
||||
|
|
||||
ApiLoaderPromise<ApiType>
|
||||
);
|
||||
export type CssLoaderProperty<CssType extends string = string> = string | CssLoaderPromise<CssType>;
|
||||
export type JsLoaderProperty<JsExportType> = string | JsLoaderPromise<JsExportType>;
|
||||
export type ElementLoaderProperty<ElementType extends HTMLElement = HTMLElement> =
|
||||
| string
|
||||
| ElementLoaderPromise<ElementType>
|
||||
| ClassConstructor<ElementType>;
|
||||
export type ApiLoaderProperty<ApiType extends UmbApi = UmbApi> =
|
||||
| string
|
||||
| ApiLoaderPromise<ApiType>
|
||||
| ClassConstructor<ApiType>;
|
||||
export type ElementAndApiLoaderProperty<
|
||||
ElementType extends HTMLElement = HTMLElement,
|
||||
ApiType extends UmbApi = UmbApi,
|
||||
> =
|
||||
| string
|
||||
| ElementAndApiLoaderPromise<ElementType, ApiType>
|
||||
| ElementLoaderPromise<ElementType>
|
||||
| ApiLoaderPromise<ApiType>;
|
||||
|
||||
@@ -2,6 +2,6 @@ import type { ManifestPlainCss } from '@umbraco-cms/backoffice/extension-api';
|
||||
/**
|
||||
* Theme manifest for styling the backoffice of Umbraco such as dark, high contrast etc
|
||||
*/
|
||||
export interface ManifestTheme extends ManifestPlainCss<string> {
|
||||
export interface ManifestTheme extends ManifestPlainCss {
|
||||
type: 'theme';
|
||||
}
|
||||
|
||||
@@ -42,14 +42,16 @@ export class UmbThemeContext extends UmbBaseController {
|
||||
if (themes.length > 0 && themes[0].css) {
|
||||
const activeTheme = themes[0];
|
||||
if (typeof activeTheme.css === 'function') {
|
||||
const styleEl = (this.#styleElement = document.createElement('style'));
|
||||
styleEl.setAttribute('type', 'text/css');
|
||||
document.head.appendChild(styleEl);
|
||||
this.#styleElement = document.createElement('style') as HTMLStyleElement;
|
||||
// We store the current style element so we can check if it has been replaced by another theme in between.
|
||||
const currentStyleEl = this.#styleElement;
|
||||
currentStyleEl.setAttribute('type', 'text/css');
|
||||
|
||||
const result = await loadManifestPlainCss(activeTheme.css);
|
||||
// Checking that this is still our styleElement, it has not been replaced with another theme in between.
|
||||
if (result && styleEl === this.#styleElement) {
|
||||
styleEl.appendChild(document.createTextNode(result));
|
||||
if (result && currentStyleEl === this.#styleElement) {
|
||||
currentStyleEl.appendChild(document.createTextNode(result));
|
||||
document.head.appendChild(currentStyleEl);
|
||||
}
|
||||
} else if (typeof activeTheme.css === 'string') {
|
||||
this.#styleElement = document.createElement('link');
|
||||
@@ -58,16 +60,23 @@ export class UmbThemeContext extends UmbBaseController {
|
||||
document.head.appendChild(this.#styleElement);
|
||||
}
|
||||
} else {
|
||||
console.log('remove style element', this.#styleElement);
|
||||
// We could not load a theme for this alias, so we remove the theme.
|
||||
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
||||
this.#styleElement?.childNodes.forEach((node) => node.remove());
|
||||
this.#styleElement?.setAttribute('href', '');
|
||||
this.#styleElement = null;
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
// Super clean, we got a falsy value, so we remove the theme.
|
||||
|
||||
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
||||
this.#styleElement?.remove();
|
||||
this.#styleElement?.childNodes.forEach((node) => node.remove());
|
||||
this.#styleElement?.setAttribute('href', '');
|
||||
this.#styleElement = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user