introduce modal tokens

This commit is contained in:
Mads Rasmussen
2023-03-08 10:17:10 +01:00
parent e68ed984e7
commit 3d3bfa1e16
8 changed files with 90 additions and 29 deletions

View File

@@ -1,3 +1,4 @@
export * from './modal.context';
export * from './modal-handler';
export * from './layouts/modal-layout.element';
export * from './token/modal-token';

View File

@@ -3,7 +3,8 @@ import type { UUIModalDialogElement } from '@umbraco-ui/uui-modal-dialog';
import type { UUIModalSidebarElement, UUIModalSidebarSize } from '@umbraco-ui/uui-modal-sidebar';
import { v4 as uuidv4 } from 'uuid';
import { BehaviorSubject } from 'rxjs';
import { UmbModalOptions } from './modal.context';
import { UmbModalConfig, UmbModalType } from './modal.context';
import { UmbModalToken } from './token/modal-token';
import { createExtensionElement, umbExtensionsRegistry } from '@umbraco-cms/extensions-api';
import { UmbObserverController } from '@umbraco-cms/observable-api';
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
@@ -21,15 +22,25 @@ export class UmbModalHandler {
public readonly element = this.#element.asObservable();
public key: string;
public type: string;
public size: UUIModalSidebarSize;
public type: UmbModalType = 'dialog';
public size: UUIModalSidebarSize = 'small';
constructor(host: UmbControllerHostInterface, modalAlias: string, options?: UmbModalOptions<unknown>) {
constructor(
host: UmbControllerHostInterface,
modalAlias: string | UmbModalToken,
data: unknown,
config?: UmbModalConfig
) {
this.#host = host;
this.key = uuidv4();
this.type = options?.type || 'dialog';
this.size = options?.size || 'small';
if (modalAlias instanceof UmbModalToken) {
this.type = modalAlias.getDefaultConfig().type || this.type;
this.size = modalAlias.getDefaultConfig().size || this.size;
}
this.type = config?.type || this.type;
this.size = config?.size || this.size;
// TODO: Consider if its right to use Promises, or use another event based system? Would we need to be able to cancel an event, to then prevent the closing..?
this._closePromise = new Promise((resolve) => {
@@ -37,7 +48,7 @@ export class UmbModalHandler {
});
this.containerElement = this.#createContainerElement();
this.#observeModal(modalAlias, options?.data);
this.#observeModal(modalAlias.toString(), data);
}
#createContainerElement() {

View File

@@ -13,26 +13,26 @@ import './layouts/search/modal-layout-search.element.ts';
import { UUIModalSidebarSize } from '@umbraco-ui/uui-modal-sidebar';
import { BehaviorSubject } from 'rxjs';
import type { UUIModalDialogElement } from '@umbraco-ui/uui-modal-dialog';
import type { UmbModalDocumentPickerData } from '../../src/backoffice/documents/documents/modals/document-picker';
import { UmbModalChangePasswordData } from './layouts/modal-layout-change-password.element';
import type { UmbModalIconPickerData } from './layouts/icon-picker/modal-layout-icon-picker.element';
import type { UmbModalConfirmData } from './layouts/confirm/modal-layout-confirm.element';
import type { UmbModalContentPickerData } from '../../src/backoffice/documents/documents/modals/document-picker/document-picker-modal.element';
import type { UmbModalPropertyEditorUIPickerData } from './layouts/property-editor-ui-picker/modal-layout-property-editor-ui-picker.element';
import type { UmbModalMediaPickerData } from './layouts/media-picker/modal-layout-media-picker.element';
import type { UmbModalLinkPickerData } from './layouts/link-picker/modal-layout-link-picker.element';
import { UmbModalHandler } from './modal-handler';
import type { UmbBasicModalData } from './layouts/basic/modal-layout-basic.element';
import { UmbPickerModalData } from './layouts/modal-layout-picker-base';
import { UmbModalToken } from './token/modal-token';
import { UmbContextToken } from '@umbraco-cms/context-api';
import { LanguageModel } from '@umbraco-cms/backend-api';
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
export type UmbModalType = 'dialog' | 'sidebar';
export interface UmbModalOptions<UmbModalData> {
export interface UmbModalConfig {
type?: UmbModalType;
size?: UUIModalSidebarSize;
data?: UmbModalData;
}
// TODO: we should find a way to easily open a modal without adding custom methods to this context. It would result in a better separation of concerns.
@@ -61,11 +61,11 @@ export class UmbModalContext {
/**
* Opens a Content Picker sidebar modal
* @public
* @param {UmbModalContentPickerData} [data]
* @param {UmbModalDocumentPickerData} [data]
* @return {*} {UmbModalHandler}
* @memberof UmbModalContext
*/
public documentPicker(data?: UmbModalContentPickerData): UmbModalHandler {
public documentPicker(data?: UmbModalDocumentPickerData): UmbModalHandler {
return this.open('umb-document-picker-modal', { data, type: 'sidebar', size: 'small' });
}
@@ -204,8 +204,8 @@ export class UmbModalContext {
* @return {*} {UmbModalHandler}
* @memberof UmbModalContext
*/
public open(modalAlias: string, options?: UmbModalOptions<unknown>): UmbModalHandler {
const modalHandler = new UmbModalHandler(this.host, modalAlias, options);
public open<T = unknown>(modalAlias: string | UmbModalToken<T>, data: T, config?: UmbModalConfig): UmbModalHandler {
const modalHandler = new UmbModalHandler(this.host, modalAlias, data, config);
modalHandler.containerElement.addEventListener('close-end', () => this.#onCloseEnd(modalHandler));

View File

@@ -0,0 +1,37 @@
import { UmbModalConfig } from '../modal.context';
export class UmbModalToken<T = unknown> {
/**
* Get the type of the token
*
* @public
* @type {T}
* @memberOf UmbModalToken
* @example `typeof MyToken.TYPE`
* @returns undefined
*/
readonly TYPE: T = undefined as never;
/**
* @param alias Unique identifier for the token,
* @param defaultConfig Default configuration for the modal,
* @param _desc Description for the token,
* used only for debugging purposes,
* it should but does not need to be unique
*/
constructor(protected alias: string, protected defaultConfig: UmbModalConfig, protected _desc?: string) {}
/**
* This method must always return the unique alias of the token since that
* will be used to look up the token in the injector.
*
* @returns the unique alias of the token
*/
toString(): string {
return this.alias;
}
public getDefaultConfig(): UmbModalConfig {
return this.defaultConfig;
}
}

View File

@@ -2,16 +2,12 @@ import { css, html } from 'lit';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { customElement, state } from 'lit/decorators.js';
import { UmbModalLayoutElement } from '../../../../../../libs/modal/layouts/modal-layout.element';
import { UmbModalDocumentPickerData } from '.';
import type { UmbTreeElement } from 'src/backoffice/shared/components/tree/tree.element';
export interface UmbModalContentPickerData {
multiple?: boolean;
selection?: Array<string>;
}
// TODO: make use of UmbPickerLayoutBase
@customElement('umb-document-picker-modal')
export class UmbDocumentPickerModalElement extends UmbModalLayoutElement<UmbModalContentPickerData> {
export class UmbDocumentPickerModalElement extends UmbModalLayoutElement<UmbModalDocumentPickerData> {
static styles = [
UUITextStyles,
css`

View File

@@ -4,7 +4,8 @@ import './document-picker-modal.element';
import { Meta, Story } from '@storybook/web-components';
import { html } from 'lit';
import type { UmbDocumentPickerModalElement, UmbModalContentPickerData } from './document-picker-modal.element';
import type { UmbDocumentPickerModalElement } from './document-picker-modal.element';
import type { UmbModalDocumentPickerData } from './index';
export default {
title: 'API/Modals/Layouts/Content Picker',
@@ -12,7 +13,7 @@ export default {
id: 'umb-document-picker-modal',
} as Meta;
const data: UmbModalContentPickerData = {
const data: UmbModalDocumentPickerData = {
multiple: true,
selection: [],
};

View File

@@ -0,0 +1,18 @@
import { UmbModalToken } from 'libs/modal';
export interface UmbModalDocumentPickerData {
multiple?: boolean;
selection?: Array<string>;
}
export interface UmbModalDocumentPickerResponse {
selection: Array<string>;
}
export const UMB_DOCUMENT_PICKER_MODAL_TOKEN = new UmbModalToken<UmbModalDocumentPickerData>(
'Umb.Modal.DocumentPicker',
{
type: 'sidebar',
size: 'small',
}
);

View File

@@ -9,6 +9,7 @@ import type { UmbDocumentTreeStore } from '../../../documents/documents/reposito
import { UmbLitElement } from '@umbraco-cms/element';
import type { DocumentTreeItemModel, FolderTreeItemModel } from '@umbraco-cms/backend-api';
import type { UmbObserverController } from '@umbraco-cms/observable-api';
import { UMB_DOCUMENT_PICKER_MODAL_TOKEN } from 'src/backoffice/documents/documents/modals/document-picker';
@customElement('umb-input-document-picker')
export class UmbInputDocumentPickerElement extends FormControlMixin(UmbLitElement) {
@@ -121,13 +122,9 @@ export class UmbInputDocumentPickerElement extends FormControlMixin(UmbLitElemen
private _openPicker() {
// We send a shallow copy(good enough as its just an array of keys) of our this._selectedKeys, as we don't want the modal to manipulate our data:
const modalHandler = this._modalContext?.open('Umb.Modal.DocumentPicker', {
data: {
multiple: this.max === 1 ? false : true,
selection: [...this._selectedKeys],
},
type: 'sidebar',
size: 'small',
const modalHandler = this._modalContext?.open(UMB_DOCUMENT_PICKER_MODAL_TOKEN, {
multiple: this.max === 1 ? false : true,
selection: [...this._selectedKeys],
});
modalHandler?.onClose().then(({ selection }: any) => {