Skip to content

Commit

Permalink
feat(core/modal): return modal instance when opening a new modal (#215)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Leroux <daniel.leroux@siemens.com>
  • Loading branch information
nuke-ellington and danielleroux committed Dec 6, 2022
1 parent e29271b commit 097acfc
Show file tree
Hide file tree
Showing 14 changed files with 99 additions and 61 deletions.
17 changes: 12 additions & 5 deletions packages/angular-test-app/src/preview-examples/modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { ModalService } from '@siemens/ix-angular';
@Component({
selector: 'app-modal',
template: `
<ix-button (click)="test()">Show modal</ix-button>
<ix-button (click)="openModal()">Show modal</ix-button>
<ng-template #customModal let-modal>
<div>
Expand All @@ -36,9 +36,9 @@ import { ModalService } from '@siemens/ix-angular';
>
Cancel
</ix-button>
<ix-button class="close-modal" (click)="modal.close('okay')"
>OK</ix-button
>
<ix-button class="close-modal" (click)="modal.close('okay')">
OK
</ix-button>
</div>
</div>
</ng-template>
Expand All @@ -50,7 +50,7 @@ export class Modal {

constructor(private readonly modalService: ModalService) {}

async test() {
async openModal() {
const instance = await this.modalService.open({
content: this.customModalRef,
title: '',
Expand All @@ -60,5 +60,12 @@ export class Modal {
instance.onClose.on((a) => {
console.log(a);
});

instance.htmlElement.addEventListener(
'keydown',
(keyboardEvent: KeyboardEvent) => {
console.log(keyboardEvent.key);
}
);
}
}
6 changes: 3 additions & 3 deletions packages/angular/src/modal/modal.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ import { ModalConfig } from './modal.config';
export class ModalService {
constructor() {}

async open<TDATA = any>(config: ModalConfig) {
async open<TData = any, TReason = any>(config: ModalConfig<TData>) {
const context: {
close: ((result: any) => void) | null;
dismiss: ((result?: any) => void) | null;
data?: TDATA;
data?: TData;
} = {
close: null,
dismiss: null,
Expand All @@ -43,7 +43,7 @@ export class ModalService {

embeddedView.detectChanges();

const modalInstance = await modal({
const modalInstance = await modal<TReason>({
...config,
title: '',
content: node,
Expand Down
8 changes: 4 additions & 4 deletions packages/core/component-doc.json
Original file line number Diff line number Diff line change
Expand Up @@ -6084,7 +6084,7 @@
"type": "Promise<void>",
"docs": ""
},
"signature": "close(result: any) => Promise<void>",
"signature": "close<T = any>(result: T) => Promise<void>",
"parameters": [],
"docs": "Close modal",
"docsTags": [
Expand All @@ -6100,7 +6100,7 @@
"type": "Promise<void>",
"docs": ""
},
"signature": "dismiss(reason?: any) => Promise<void>",
"signature": "dismiss<T = any>(reason?: T) => Promise<void>",
"parameters": [],
"docs": "Dismiss modal instance",
"docsTags": [
Expand Down Expand Up @@ -6171,10 +6171,10 @@
{
"name": "showModal",
"returns": {
"type": "Promise<{ onClose: TypedEvent<any>; onDismiss: TypedEvent<any>; }>",
"type": "Promise<ModalInstance<any>>",
"docs": ""
},
"signature": "showModal(config: ModalConfig) => Promise<{ onClose: TypedEvent<any>; onDismiss: TypedEvent<any>; }>",
"signature": "showModal(config: ModalConfig) => Promise<ModalInstance>",
"parameters": [],
"docs": "Display modal dialog",
"docsTags": [
Expand Down
10 changes: 5 additions & 5 deletions packages/core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import { DateTimeSelectEvent } from "./components/datetime-picker/event";
import { Placement, PositioningStrategy } from "@popperjs/core";
import { FlipTileState } from "./components/flip-tile/flip-tile-state";
import { NotificationColor } from "./components/utils/notification-color";
import { TypedEvent } from "./components/utils/typed-event";
import { ModalConfig } from "./components/modal/modal-utils";
import { ModalConfig, ModalInstance } from "./components/modal/modal-utils";
import { ToastConfig, ToastType } from "./components/toast/toast-utils";
import { TypedEvent } from "./components/utils/typed-event";
import { TreeContext, TreeItemContext, TreeModel, UpdateCallback } from "./components/tree/tree-model";
import { UploadFileState } from "./components/upload/upload-file-state";
export namespace Components {
Expand Down Expand Up @@ -945,7 +945,7 @@ export namespace Components {
* Close modal
* @param result
*/
"close": (result: any) => Promise<void>;
"close": <T = any>(result: T) => Promise<void>;
/**
* Content of modal
*/
Expand All @@ -954,7 +954,7 @@ export namespace Components {
* Dismiss modal instance
* @param reason
*/
"dismiss": (reason?: any) => Promise<void>;
"dismiss": <T = any>(reason?: T) => Promise<void>;
/**
* Header title
*/
Expand Down Expand Up @@ -993,7 +993,7 @@ export namespace Components {
* Display modal dialog
* @param config
*/
"showModal": (config: ModalConfig) => Promise<{ onClose: TypedEvent<any>; onDismiss: TypedEvent<any>; }>;
"showModal": (config: ModalConfig) => Promise<ModalInstance>;
}
interface IxModalExample {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

import { Component, Element, h, Host, Method } from '@stencil/core';
import { ModalConfig } from '../modal/modal-utils';
import { ModalConfig, ModalInstance } from '../modal/modal-utils';
import { TypedEvent } from '../utils/typed-event';

@Component({
Expand All @@ -25,7 +25,7 @@ export class ModalContainer {
* @param config
*/
@Method()
async showModal(config: ModalConfig) {
async showModal(config: ModalConfig): Promise<ModalInstance> {
const onClose = new TypedEvent<any>();
const onDismiss = new TypedEvent<any>();

Expand Down Expand Up @@ -54,6 +54,7 @@ export class ModalContainer {
});

return {
htmlElement: modal,
onClose,
onDismiss,
};
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/modal-container/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ SPDX-License-Identifier: MIT

## Methods

### `showModal(config: ModalConfig) => Promise<{ onClose: TypedEvent<any>; onDismiss: TypedEvent<any>; }>`
### `showModal(config: ModalConfig) => Promise<ModalInstance>`

Display modal dialog

#### Returns

Type: `Promise<{ onClose: TypedEvent<any>; onDismiss: TypedEvent<any>; }>`
Type: `Promise<ModalInstance<any>>`



Expand Down
22 changes: 17 additions & 5 deletions packages/core/src/components/modal/modal-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
*/

import { NotificationColor } from '../utils/notification-color';
import { TypedEvent } from '../utils/typed-event';

export interface ModalConfig {
export interface ModalConfig<TReason = any> {
animation?: boolean;
ariaDescribedBy?: string;
ariaLabelledBy?: string;
backdrop?: boolean | 'static';
backdropClass?: string;
beforeDismiss?: (reason?: any) => boolean | Promise<boolean>;
beforeDismiss?: (reason?: TReason) => boolean | Promise<boolean>;
centered?: boolean;
container?: string | HTMLElement;
content: string | HTMLElement;
Expand All @@ -29,14 +30,20 @@ export interface ModalConfig {
iconColor?: NotificationColor;
}

export interface ModalInstance<TReason = any> {
htmlElement: HTMLIxModalElement;
onClose: TypedEvent<TReason>;
onDismiss: TypedEvent<TReason>;
}

function getModalContainer() {
const containerList = Array.from(
document.querySelectorAll('ix-modal-container')
);
const [container] = containerList;
if (containerList.length > 1) {
console.warn(
'Multiple modal container are found. Only there first is used.'
'Multiple modal containers were found. The one instatiated first will be used.'
);
return container;
}
Expand All @@ -49,7 +56,9 @@ function getModalContainer() {
return container;
}

export async function modal(config: ModalConfig) {
export async function modal<TReson = any>(
config: ModalConfig<TReson>
): Promise<ModalInstance<TReson>> {
const modalContainer = getModalContainer();
const modalInstance = await modalContainer.showModal(config);

Expand All @@ -60,7 +69,10 @@ function getIxModal(element: Element) {
return element.closest('ix-modal');
}

export function closeModal(element: Element, closeResult: any) {
export function closeModal<TClose = any>(
element: Element,
closeResult: TClose
) {
getIxModal(element).close(closeResult);
}

Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/modal/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ export class Modal {
* @param reason
*/
@Method()
async dismiss(reason?: any) {
async dismiss<T = any>(reason?: T) {
if (this.beforeDismiss) {
const result = await this.beforeDismiss(reason);
if (result !== false) {
Expand All @@ -222,7 +222,7 @@ export class Modal {
* @param result
*/
@Method()
async close(result: any) {
async close<T = any>(result: T) {
this.slideUp(this.modalContent, () => this.closed.emit(result));
}

Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/modal/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ SPDX-License-Identifier: MIT

## Methods

### `close(result: any) => Promise<void>`
### `close<T = any>(result: T) => Promise<void>`

Close modal

Expand All @@ -51,7 +51,7 @@ Type: `Promise<void>`



### `dismiss(reason?: any) => Promise<void>`
### `dismiss<T = any>(reason?: T) => Promise<void>`

Dismiss modal instance

Expand Down
2 changes: 1 addition & 1 deletion packages/core/stencil.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export const config: Config = {
},
{
type: 'www',
serviceWorker: null, // disable service workers
serviceWorker: null,
copy: copyAssets,
},
],
Expand Down
7 changes: 5 additions & 2 deletions packages/html-test-app/src/preview-examples/modal.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,13 @@
);

const button = document.querySelector('ix-button');
button.addEventListener('click', () => {
modal({
button.addEventListener('click', async () => {
const m = await modal({
content: customModal,
});
m.htmlElement.addEventListener('keydown', (keyEvent) => {
console.log(keyEvent.key);
});
});
})();
</script>
Expand Down
8 changes: 6 additions & 2 deletions packages/react-test-app/src/preview-examples/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,15 @@ function CustomModal() {
}

export const ModalExample: React.FC = () => {
function show() {
showModal({
async function show() {
const modal = await showModal({
title: 'test',
content: <CustomModal />,
});

modal.htmlElement.addEventListener('keypress', (keyboardEvent) => {
console.log(keyboardEvent.key);
});
}

return (
Expand Down
7 changes: 4 additions & 3 deletions packages/react/src/modal/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,19 @@ export type ModalConfig = {
content: React.ReactNode;
};

export async function showModal(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export async function showModal<TReason = any>(
config: Omit<IxModalConfig, 'content'> & ModalConfig
) {
if (typeof config.content === 'string') {
return modal(config as IxModalConfig);
return modal<TReason>(config as IxModalConfig);
}

const container = document.createElement('DIV');
const root = ReactDOMClient.createRoot(container);
root.render(config.content);

const modalInstance = await modal({
const modalInstance = await modal<TReason>({
...config,
content: container,
});
Expand Down
Loading

0 comments on commit 097acfc

Please sign in to comment.