Merge branch 'main' into feature/templates-scaffold

This commit is contained in:
Mads Rasmussen
2023-02-01 15:23:38 +01:00
53 changed files with 514 additions and 316 deletions

View File

@@ -0,0 +1,10 @@
import { createExtensionElement } from './create-extension-element.function';
import { isManifestElementableType } from './is-manifest-elementable-type.function';
export async function createExtensionElementOrFallback(manifest: any, fallbackElementName: string): Promise<HTMLElement | undefined> {
if (isManifestElementableType(manifest)) {
return createExtensionElement(manifest);
}
return Promise.resolve(document.createElement(fallbackElementName));
}

View File

@@ -8,5 +8,6 @@ export * from './is-manifest-elementable-type.function';
export * from './is-manifest-js-type.function';
export * from './is-manifest-loader-type.function';
export * from './load-extension.function';
export * from './create-extension-element-or-fallback.function';
export const umbExtensionsRegistry = new UmbExtensionRegistry();

View File

@@ -1,5 +1,5 @@
import { BehaviorSubject, map, Observable } from 'rxjs';
import type { ManifestTypes, ManifestTypeMap, ManifestBase } from '../../models';
import type { ManifestTypes, ManifestTypeMap, ManifestBase, ManifestWithLoader, ManifestEntrypoint } from '../../models';
import { hasDefaultExport } from '../has-default-export.function';
import { loadExtension } from '../load-extension.function';
@@ -13,7 +13,7 @@ export class UmbExtensionRegistry {
private _extensions = new BehaviorSubject<Array<ManifestBase>>([]);
public readonly extensions = this._extensions.asObservable();
register(manifest: ManifestTypes & { loader?: () => Promise<object | HTMLElement> }): void {
register(manifest: ManifestTypes): void {
const extensionsValues = this._extensions.getValue();
const extension = extensionsValues.find((extension) => extension.alias === manifest.alias);
@@ -26,7 +26,7 @@ export class UmbExtensionRegistry {
// If entrypoint extension, we should load and run it immediately
if (manifest.type === 'entrypoint') {
loadExtension(manifest).then((js) => {
loadExtension(manifest as ManifestEntrypoint).then((js) => {
if (hasDefaultExport(js)) {
new js.default();
} else {

View File

@@ -18,6 +18,7 @@ import type { ManifestCollectionBulkAction } from './collection-bulk-action.mode
import type { ManifestCollectionView } from './collection-view.models';
import type { ManifestHealthCheck } from './health-check.models';
import type { ManifestSidebarMenuItem } from './sidebar-menu-item.models';
import type { ManifestTheme } from './theme.models';
export * from './header-app.models';
export * from './section.models';
@@ -39,6 +40,7 @@ export * from './collection-bulk-action.models';
export * from './collection-view.models';
export * from './health-check.models';
export * from './sidebar-menu-item.models';
export * from './theme.models';
export type ManifestTypes =
| ManifestCustom
@@ -63,7 +65,8 @@ export type ManifestTypes =
| ManifestCollectionBulkAction
| ManifestCollectionView
| ManifestHealthCheck
| ManifestSidebarMenuItem;
| ManifestSidebarMenuItem
| ManifestTheme;
export type ManifestStandardTypes = ManifestTypes['type'];
@@ -78,14 +81,29 @@ export interface ManifestBase {
weight?: number;
}
export interface ManifestElement extends ManifestBase {
export interface ManifestWithLoader<LoaderReturnType> extends ManifestBase {
loader?: () => Promise<LoaderReturnType>;
}
export interface ManifestElement extends ManifestWithLoader<object | HTMLElement> {
type: ManifestStandardTypes;
js?: string;
elementName?: string;
loader?: () => Promise<object | HTMLElement>;
//loader?: () => Promise<object | HTMLElement>;
meta?: any;
}
export interface ManifestWithView extends ManifestElement {
meta: MetaManifestWithView;
}
export interface MetaManifestWithView {
pathname: string;
label: string;
icon: string;
}
export interface ManifestElementWithElementName extends ManifestElement {
elementName: string;
}

View File

@@ -0,0 +1,8 @@
import type { ManifestWithLoader } from "./models";
// TODO: make or find type for JS Module with default export: Would be nice to support css file directly.
export interface ManifestTheme extends ManifestWithLoader<string> {
type: 'theme';
css?: string;
}

View File

@@ -1,6 +1,6 @@
import type { ManifestElement } from './models';
import type { ManifestWithView } from './models';
export interface ManifestWorkspaceView extends ManifestElement {
export interface ManifestWorkspaceView extends ManifestWithView {
type: 'workspaceView';
meta: MetaEditorView;
}

View File

@@ -0,0 +1,3 @@
export * from './router-slot.element';
export * from './router-slot-change.event';
export * from './router-slot-init.event';

View File

@@ -0,0 +1,4 @@
import config from '../../utils/rollup.config.js';
export default {
...config,
};

View File

@@ -0,0 +1,7 @@
import { UUIEvent } from '@umbraco-ui/uui-base/lib/events';
import type { UmbRouterSlotElement } from './router-slot.element';
export class UmbRouterSlotChangeEvent extends UUIEvent<never, UmbRouterSlotElement> {
constructor() {
super('change');
}
}

View File

@@ -0,0 +1,7 @@
import { UUIEvent } from '@umbraco-ui/uui-base/lib/events';
import type { UmbRouterSlotElement } from './router-slot.element';
export class UmbRouterSlotInitEvent extends UUIEvent<never, UmbRouterSlotElement> {
constructor() {
super('init');
}
}

View File

@@ -0,0 +1,79 @@
import { LitElement, PropertyValueMap } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { IRoute, RouterSlot } from 'router-slot';
import { UmbRouterSlotChangeEvent, UmbRouterSlotInitEvent } from '@umbraco-cms/router';
/**
* @element umb-router-slot-element
* @description - Component for wrapping Router Slot element, providing some local events for implementation.
* @extends UmbRouterSlotElement
*/
@customElement('umb-router-slot')
export class UmbRouterSlotElement extends LitElement {
#router: RouterSlot;
#listening = false;
@property()
public get routes(): IRoute[] | undefined {
return (this.#router as any).routes;
}
public set routes(value: IRoute[] | undefined) {
(this.#router as any).routes = value;
}
private _routerPath?: string;
public get absoluteRouterPath() {
return this._routerPath;
}
private _activeLocalPath?: string;
public get localActiveViewPath() {
return this._activeLocalPath;
}
public get absoluteActiveViewPath() {
return this._routerPath + '/' + this._activeLocalPath;
}
constructor() {
super();
this.#router = document.createElement('router-slot');
}
connectedCallback() {
super.connectedCallback();
if (this.#listening === false) {
window.addEventListener('navigationsuccess', this._onNavigationChanged);
this.#listening = true;
}
}
disconnectedCallback() {
super.disconnectedCallback();
window.removeEventListener('navigationsuccess', this._onNavigationChanged);
this.#listening = false;
}
protected firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
super.firstUpdated(_changedProperties);
this._routerPath = this.#router.constructAbsolutePath('') || '';
this.dispatchEvent(new UmbRouterSlotInitEvent());
}
private _onNavigationChanged = (event?: any) => {
if (event.detail.slot === this.#router) {
this._activeLocalPath = event.detail.match.route.path;
this.dispatchEvent(new UmbRouterSlotChangeEvent());
}
};
render() {
return this.#router;
}
}
declare global {
interface HTMLElementTagNameMap {
'umb-router-slot': UmbRouterSlotElement;
}
}

View File

@@ -1,4 +1,3 @@
import type { Path } from 'msw';
export function umbracoPath(path: string): Path {
export function umbracoPath(path: string) {
return `/umbraco/management/api/v1${path}`;
}