Skip to content

Commit 1d97ae5

Browse files
authored
Merge pull request #511 from cal-smith/master
fix(modal): add overlaySelected handler to alert-modal
2 parents 6b6a063 + 594e943 commit 1d97ae5

File tree

8 files changed

+243
-488
lines changed

8 files changed

+243
-488
lines changed

package-lock.json

Lines changed: 177 additions & 419 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
"@carbon/icons-angular": "10.1.0",
8686
"@commitlint/cli": "7.5.2",
8787
"@commitlint/config-conventional": "7.5.0",
88-
"@compodoc/compodoc": "1.1.9",
88+
"@compodoc/compodoc": "1.1.7",
8989
"@storybook/addon-actions": "5.0.6",
9090
"@storybook/addon-knobs": "5.0.6",
9191
"@storybook/addon-links": "5.0.6",

src/modal/alert-modal.component.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ import { BaseModal } from "./base-modal.class";
4848
@Component({
4949
selector: "ibm-alert-modal",
5050
template: `
51-
<ibm-modal [theme]="modalType" [modalLabel]="modalTitle">
52-
<ibm-modal-header (closeSelect)="closeModal()">
51+
<ibm-modal [theme]="modalType" [modalLabel]="modalTitle" (overlaySelected)="dismissModal()">
52+
<ibm-modal-header (closeSelect)="dismissModal()">
5353
<p class="bx--modal-header__label bx--type-delta">{{modalLabel}}</p>
5454
<p class="bx--modal-header__heading bx--type-beta">{{modalTitle}}</p>
5555
</ibm-modal-header>
@@ -59,7 +59,7 @@ import { BaseModal } from "./base-modal.class";
5959
<ibm-modal-footer *ngIf="buttons.length > 0">
6060
<ng-container *ngFor="let button of buttons; let i = index">
6161
<button
62-
ibmButton="{{button.type}}"
62+
[ibmButton]="button.type"
6363
(click)="buttonClicked(i)"
6464
[id]="button.id"
6565
[attr.modal-primary-focus]="(button.type.indexOf('primary') !== -1 ? '' : null)">
@@ -73,15 +73,14 @@ import { BaseModal } from "./base-modal.class";
7373
export class AlertModal extends BaseModal {
7474
/**
7575
* Creates an instance of `AlertModal`.
76-
* @param {ModalService} modalService
77-
* @memberof AlertModal
7876
*/
7977
constructor(
8078
@Inject("modalType") public modalType = "default",
8179
@Inject("modalLabel") public modalLabel: string,
8280
@Inject("modalTitle") public modalTitle: string,
8381
@Inject("modalContent") public modalContent: string,
84-
@Inject("buttons") public buttons = []
82+
@Inject("buttons") public buttons = [],
83+
@Inject("close") public onClose: Function
8584
) {
8685
super();
8786
for (let i = 0; i < this.buttons.length; i++) {
@@ -103,4 +102,11 @@ export class AlertModal extends BaseModal {
103102

104103
this.closeModal();
105104
}
105+
106+
dismissModal() {
107+
if (this.onClose && this.onClose() === false) {
108+
return;
109+
}
110+
this.closeModal();
111+
}
106112
}

src/modal/alert-modal.interface.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ export interface AlertModalData {
4040
* Array of `ModalButton`s
4141
*/
4242
buttons?: Array<ModalButton>;
43+
/**
44+
* Callback for non-specific close events. `return false;` to prevent the modal from closing
45+
*/
46+
close?: Function;
4347
}
4448

4549
export enum ModalButtonType {

src/modal/base-modal.class.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Output, EventEmitter } from "@angular/core";
22

33
/**
4-
* Extend `BaseModal` in your custom modal implementations to ensure consistent close behaviour.
4+
* Extend `BaseModal` in your custom modal implementations to ensure consistent close behavior.
55
*
66
* `ModalService` depends on the `close` event to correctly clean up the component.
77
*/

src/modal/modal.component.ts

Lines changed: 45 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -24,60 +24,60 @@ import { cycleTabs, getFocusElementList } from "./../common/tab.service";
2424
/**
2525
* Component to create modals for presenting content.
2626
*
27-
* Using a modal in your application requires `ibm-modal-placeholder` which would generally be
27+
* Using a modal in your application requires `ibm-placeholder` which would generally be
2828
* placed near the end of your app component template (app.component.ts or app.component.html) as:
2929
*
30-
* ```html
31-
* <ibm-modal-placeholder></ibm-modal-placeholder>
32-
* ```
30+
```html
31+
<ibm-modal-placeholder></ibm-modal-placeholder>
32+
```
3333
*
3434
* A more complete example for `Modal` is given as follows:
3535
*
3636
* Example modal definition:
3737
*
38-
* ```typescript
39-
* \@Modal()
40-
* \@Component({
41-
* selector: "app-sample-modal",
42-
* template: `
43-
* <ibm-modal size="xl">
44-
* <ibm-modal-header (closeSelect)="closeModal()">Header text</ibm-modal-header>
45-
* <section class="modal-body">
46-
* <h1>Sample modal works.</h1>
47-
* <button class="btn--icon-link" nPopover="Hello there" title="Popover title" placement="right" appendInline="true">
48-
* <ibm-icon icon="info" size="sm"></ibm-icon>
49-
* </button>
50-
* {{modalText}}
51-
* </section>
52-
* <ibm-modal-footer><button ibmButton="primary" (click)="closeModal()">Close</button></ibm-modal-footer>
53-
* </ibm-modal>`,
54-
* styleUrls: ["./sample-modal.component.scss"]
55-
* })
56-
* export class SampleModal extends BaseModal {
57-
* modalText: string;
58-
* constructor(protected injector: Injector) {
59-
* super();
60-
* this.modalText = this.injector.get("modalText");
61-
* }
62-
* }
63-
* ```
38+
```typescript
39+
@Component({
40+
selector: "app-sample-modal",
41+
template: `
42+
<ibm-modal size="xl" (overlaySelected)="closeModal()">
43+
<ibm-modal-header (closeSelect)="closeModal()">Header text</ibm-modal-header>
44+
<section class="modal-body">
45+
<h1>Sample modal works.</h1>
46+
<button class="btn--icon-link" nPopover="Hello there" title="Popover title" placement="right" appendInline="true">
47+
<ibm-icon icon="info" size="sm"></ibm-icon>
48+
</button>
49+
{{modalText}}
50+
</section>
51+
<ibm-modal-footer><button ibmButton="primary" (click)="closeModal()">Close</button></ibm-modal-footer>
52+
</ibm-modal>`,
53+
styleUrls: ["./sample-modal.component.scss"]
54+
})
55+
export class SampleModal extends BaseModal {
56+
modalText: string;
57+
constructor(protected injector: Injector) {
58+
super();
59+
this.modalText = this.injector.get("modalText");
60+
}
61+
}
62+
```
6463
*
6564
* Example of opening the modal:
6665
*
67-
* ```typescript
68-
* \@Component({
69-
* selector: "app-modal-demo",
70-
* template: `
71-
* <button ibmButton="primary" (click)="openModal('drill')">Drill-down modal</button>
72-
* <ibm-modal-placeholder></ibm-modal-placeholder>`
73-
* })
74-
* export class ModalDemo {
75-
* openModal() {
76-
* this.modalService.create({component: SampleModal, inputs: {modalText: "Hello universe."}});
77-
* }
78-
* }
79-
* ```
66+
```typescript
67+
@Component({
68+
selector: "app-modal-demo",
69+
template: `
70+
<button ibmButton="primary" (click)="openModal('drill')">Drill-down modal</button>
71+
<ibm-placeholder></ibm-placeholder>`
72+
})
73+
export class ModalDemo {
74+
openModal() {
75+
this.modalService.create({component: SampleModal, inputs: {modalText: "Hello universe."}});
76+
}
77+
}
78+
```
8079
*
80+
* <example-url>https://angular.carbondesignsystem.com/iframe.html?id=modal--basic</example-url>
8181
*/
8282
@Component({
8383
selector: "ibm-modal",
@@ -124,7 +124,7 @@ export class Modal implements AfterViewInit, OnInit, OnDestroy {
124124
@Input() modalLabel = "default";
125125

126126
/**
127-
* Emits event when click occurs within `n-overlay` element. This is to track click events occuring outside bounds of the `Modal` object.
127+
* Emits event when click occurs within `n-overlay` element. This is to track click events occurring outside bounds of the `Modal` object.
128128
*/
129129
@Output() overlaySelected = new EventEmitter();
130130
/**
@@ -142,7 +142,7 @@ export class Modal implements AfterViewInit, OnInit, OnDestroy {
142142
modalState: "in" | "out" = "out";
143143

144144
/**
145-
* An element should have 'data-modal-primary-focus' as an attribute to receive initial focus within the `Modal` component.
145+
* An element should have 'modal-primary-focus' as an attribute to receive initial focus within the `Modal` component.
146146
*/
147147
selectorPrimaryFocus = "[modal-primary-focus]";
148148

src/modal/modal.service.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ import { PlaceholderService } from "./../placeholder/placeholder.module";
2222
* destroy(index: number = -1): void {}
2323
* }
2424
* ```
25-
* @export
26-
* @class ModalService
2725
*/
2826
@Injectable()
2927
export class ModalService {
@@ -32,18 +30,12 @@ export class ModalService {
3230

3331
/**
3432
* Creates an instance of `ModalService`.
35-
* @param {ComponentFactoryResolver} resolver
36-
* @memberof ModalService
3733
*/
3834
constructor(public resolver: ComponentFactoryResolver, public placeholderService: PlaceholderService) {}
3935

4036
/**
4137
* Creates and renders the modal component that is passed in.
4238
* `inputs` is an optional parameter of `data` that can be passed to the `Modal` component.
43-
* @template T
44-
* @param {{component: any, inputs?: any}} data
45-
* @returns {ComponentRef<any>}
46-
* @memberof ModalService
4739
*/
4840
create<T>(data: {component: any, inputs?: any}): ComponentRef<any> {
4941
let defaults = {inputs: {}};
@@ -88,8 +80,6 @@ export class ModalService {
8880
* click: clickFunction,
8981
* }
9082
* ```
91-
* @returns {ComponentRef<any>}
92-
* @memberof ModalService
9383
*/
9484
show(data: AlertModalData) {
9585
for (let key of Object.keys(data)) {
@@ -108,18 +98,15 @@ export class ModalService {
10898
modalLabel: data.label || data.modalLabel,
10999
modalTitle: data.title || data.modalTitle,
110100
modalContent: data.content || data.modalContent,
111-
buttons: data.buttons || []
101+
buttons: data.buttons || [],
102+
close: data.close || (() => {})
112103
}
113104
});
114105
}
115106

116107
/**
117108
* Destroys the modal on the supplied index.
118109
* When called without parameters it destroys the most recently created/top most modal.
119-
*
120-
* @param {any} [index=-1]
121-
* @returns
122-
* @memberof ModalService
123110
*/
124111
destroy(index = -1) {
125112
// return if nothing to destroy because it's already destroyed

src/modal/modal.stories.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { BaseModal } from "./base-modal.class";
1212
@Component({
1313
selector: "app-sample-modal",
1414
template: `
15-
<ibm-modal>
15+
<ibm-modal (overlaySelected)="closeModal()">
1616
<ibm-modal-header (closeSelect)="closeModal()">Header label</ibm-modal-header>
1717
<section class="bx--modal-content">
1818
<h1>Sample modal works.</h1>

0 commit comments

Comments
 (0)