Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an AlertModalComponent #100

Merged
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f808411
Removed hidden header column to fix missing most right header border.
stanislavgeorgiev Sep 13, 2018
dc4a6fc
Merge branch 'master' of https://github.com/IBM/carbon-components-ang…
stanislavgeorgiev Sep 13, 2018
eb2234d
Merge branch 'master' of https://github.com/IBM/carbon-components-ang…
stanislavgeorgiev Sep 14, 2018
69fe2b4
Merge branch 'master' of https://github.com/IBM/carbon-components-ang…
stanislavgeorgiev Sep 18, 2018
aa74a11
Added ignore forwardRef
stanislavgeorgiev Sep 18, 2018
96f6221
Merge branch 'master' into master
stanislavgeorgiev Sep 19, 2018
51ebc13
Revert "Removed hidden header column to fix missing most right header…
stanislavgeorgiev Sep 19, 2018
bf40260
Added a default Modal implementation accessible through `modalService…
stanislavgeorgiev Sep 20, 2018
f3c438e
Updated `headerText` to `headerLabel`.
stanislavgeorgiev Sep 20, 2018
03376f6
Fixed TSLint errors and syntax comments.
stanislavgeorgiev Sep 21, 2018
24f63cd
Fixed code styling.
stanislavgeorgiev Sep 24, 2018
30cd6cb
More code style fixes.
stanislavgeorgiev Sep 25, 2018
b8c3c83
Merge branch 'master' into AlertModalComponent
zvonimirfras Sep 26, 2018
c64851c
Merge branch 'master' of https://github.com/IBM/carbon-components-ang…
stanislavgeorgiev Sep 26, 2018
cc66803
Updated primary button focus to use the `modal-primary-focus` attribute.
stanislavgeorgiev Sep 27, 2018
f9b0019
Fixed lint errors in merged files from `master`...
stanislavgeorgiev Sep 27, 2018
a39e94c
Merge branch 'AlertModalComponent' of https://github.com/stanislavgeo…
stanislavgeorgiev Sep 27, 2018
c8b926e
Merge branch 'master' into AlertModalComponent
zvonimirfras Sep 27, 2018
c9c76fe
Renamed component props.
stanislavgeorgiev Sep 27, 2018
419073b
Merge branch 'AlertModalComponent' of https://github.com/stanislavgeo…
stanislavgeorgiev Sep 27, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

143 changes: 143 additions & 0 deletions src/modal/alert-modal.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import {
Component,
Injector,
OnInit,
ElementRef,
AfterViewInit
} from "@angular/core";
import {
trigger,
state,
style,
transition,
animate
} from "@angular/animations";
import Modal from "./modal.decorator";
import { ModalService } from "./modal.service";

/**
* Component to create standard modals for presenting content or asking for user's input.
* It can show as a passive modal showing only text or show as a transactional modal with
* multiple buttons for different actions for the user to choose from.
*
* Using a modal in your application requires `ibm-modal-placeholder` which would generally be
* placed near the end of your app component template (app.component.ts or app.component.html) as:
*
* ```html
* <ibm-modal-placeholder></ibm-modal-placeholder>
* ```
*
* Example of opening the modal:
*
* ```typescript
* \@Component({
* selector: "app-modal-demo",
* template: `
* <button class="btn--primary" (click)="openModal()">Open modal</button>
* <ibm-modal-placeholder></ibm-modal-placeholder>`
* })
* export class ModalDemo {
*
stanislavgeorgiev marked this conversation as resolved.
Show resolved Hide resolved
* openModal() {
* this.modalService.show({
* modalType: "default" | "danger",
stanislavgeorgiev marked this conversation as resolved.
Show resolved Hide resolved
* headerLabel: "optional header text",
* title: "Modal title",
* text: "Modal text",
* buttons: [{
* text: "Button text",
* type: "primary" | "secondary" | "tertiary" | "ghost" | "danger" | "danger--primary" = "primary",
stanislavgeorgiev marked this conversation as resolved.
Show resolved Hide resolved
* click: clickFunction,
stanislavgeorgiev marked this conversation as resolved.
Show resolved Hide resolved
* }]
* });
* }
* }
* ```
*
* @export
* @class AlertModalComponent
*/
@Modal()
@Component({
selector: "ibm-alert-modal",
template: `
<ibm-modal [modalType]="modalType">
<ibm-modal-header (closeSelect)="closeModal()">
<p class="bx--modal-header__label bx--type-delta">{{headerLabel}}</p>
<p class="bx--modal-header__heading bx--type-beta">{{title}}</p>
cal-smith marked this conversation as resolved.
Show resolved Hide resolved
</ibm-modal-header>
<div class="bx--modal-content">
<p>{{text}}</p>
</div>
<ibm-modal-footer *ngIf="buttons.length > 0">
<button
*ngFor="let button of buttons; let i = index"
ibmButton="{{button.type}}"
(click)="buttonClicked(i)"
[id]="button.id">
{{button.text}}
</button>
</ibm-modal-footer>
</ibm-modal>
`
})
export class AlertModalComponent implements AfterViewInit {

stanislavgeorgiev marked this conversation as resolved.
Show resolved Hide resolved
modalType = "default";
headerLabel: string;
title: string;
text: string;
buttons = [];

/**
* Creates an instance of `AlertModalComponent`.
* @param {ModalService} modalService
* @memberof AlertModalComponent
*/
constructor(
private injector: Injector,
private elementRef: ElementRef
) {
this.modalType = this.injector.get("modalType");
this.headerLabel = this.injector.get("headerLabel");
this.title = this.injector.get("title");
this.text = this.injector.get("text");

this.buttons = this.injector.get("buttons") || [];
for (let i = 0; i < this.buttons.length; i++) {
const button = this.buttons[i];
if (!button.id) {
button.id = `alert-modal-button-${i}`;
}
if (!button.type) {
button.type = "secondary";
}
}
}

ngAfterViewInit(): void {
// focus the primary button if there's one
stanislavgeorgiev marked this conversation as resolved.
Show resolved Hide resolved
if (this.buttons && this.buttons.length > 0) {
const primaryButtonIndex = this.buttons.findIndex(
button => button.type.indexOf("primary") !== -1) || 0;
const primaryButton = this.buttons[primaryButtonIndex];
const buttonNode = this.elementRef.nativeElement.querySelector(`#${primaryButton.id}`);
if (buttonNode) {
buttonNode.focus();
}
}
}

buttonClicked(buttonIndex) {
const button = this.buttons[buttonIndex];
if (button.click) {
button.click();
}

this.closeModal();
}

closeModal() {
this["destroy"]();
stanislavgeorgiev marked this conversation as resolved.
Show resolved Hide resolved
}
}
6 changes: 3 additions & 3 deletions src/modal/modal-header.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ import { Component, Output, EventEmitter, Input } from "@angular/core";
selector: "ibm-modal-header",
template: `
<header class="{{modalType}} bx--modal-header" role="banner">
<h5 class="bx--modal-header__heading">
<div class="bx--modal-header">
<ng-content></ng-content>
</h5>
</div>
<button
class="bx--modal-close"
attr.aria-label="{{'MODAL.CLOSE' | translate}}"
Expand All @@ -35,7 +35,7 @@ import { Component, Output, EventEmitter, Input } from "@angular/core";
width="10"
aria-label="close the modal"
alt="close the modal">
<title>close the modal</title>
<title>{{'MODAL.CLOSE' | translate}}</title>
<path d="M6.32 5L10 8.68 8.68 10 5 6.32 1.32 10 0 8.68 3.68 5 0 1.32 1.32 0 5 3.68 8.68 0 10 1.32 6.32 5z"></path>
</svg>
</button>
Expand Down
8 changes: 4 additions & 4 deletions src/modal/modal.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { cycleTabs } from "./../common/tab.service";
/**
* Component to create modals for presenting content.
*
* Using a modal in your application requires `n-modal-placeholder` which would generally be
* Using a modal in your application requires `ibm-modal-placeholder` which would generally be
* placed near the end of your app component template (app.component.ts or app.component.html) as:
*
* ```html
Expand All @@ -48,7 +48,7 @@ import { cycleTabs } from "./../common/tab.service";
* </button>
* {{modalText}}
* </section>
* <ibm-modal-footer><button class="btn--primary cancel-button" (click)="closeModal()">Close</button></ibm-modal-footer>
* <ibm-modal-footer><button class="bx--btn bx--btn--primary" (click)="closeModal()">Close</button></ibm-modal-footer>
stanislavgeorgiev marked this conversation as resolved.
Show resolved Hide resolved
* </ibm-modal>`,
* styleUrls: ["./sample-modal.component.scss"]
* })
Expand Down Expand Up @@ -85,7 +85,7 @@ import { cycleTabs } from "./../common/tab.service";
@Component({
selector: "ibm-modal",
template: `
<ibm-overlay (overlaySelect)="overlaySelected.emit()">
<ibm-overlay [modalType]="modalType" (overlaySelect)="overlaySelected.emit()">
<div
class="bx--modal-container"
[@modalState]="modalState"
Expand Down Expand Up @@ -120,7 +120,7 @@ export class ModalComponent implements OnInit, OnDestroy {
@Input() size = "default";
/**
* Classification of the modal.
* @type {"default" | "warning" | "error"}
* @type {"default" | "danger"}
* @memberof ModalComponent
*/
@Input() modalType = "default";
Expand Down
6 changes: 6 additions & 0 deletions src/modal/modal.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { ModalComponent } from "./modal.component";
import { ModalFooterComponent } from "./modal-footer.component";
import { OverlayComponent } from "./overlay.component";
import { ModalHeaderComponent } from "./modal-header.component";
import { AlertModalComponent } from "./alert-modal.component";
import { ButtonModule } from "../forms/forms.module";

// exports
export { default as Modal } from "./modal.decorator";
Expand All @@ -36,19 +38,22 @@ export const MODAL_PLACEHOLDER_SERVICE_PROVIDER = {

@NgModule({
declarations: [
AlertModalComponent,
ModalPlaceholderComponent,
ModalComponent,
ModalHeaderComponent,
ModalFooterComponent,
OverlayComponent
],
exports: [
AlertModalComponent,
ModalPlaceholderComponent,
ModalComponent,
ModalHeaderComponent,
ModalFooterComponent
],
entryComponents: [
AlertModalComponent,
ModalComponent,
ModalFooterComponent,
ModalHeaderComponent
Expand All @@ -61,6 +66,7 @@ export const MODAL_PLACEHOLDER_SERVICE_PROVIDER = {
],
imports: [
CommonModule,
ButtonModule,
TranslateModule,
StaticIconModule
]
Expand Down
28 changes: 28 additions & 0 deletions src/modal/modal.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ModalComponent } from "./modal.component";
import { ModalPlaceholderService } from "./modal-placeholder.service";
import { ReplaySubject } from "rxjs";
import { Injectable } from "@angular/core";
import { AlertModalComponent } from "./alert-modal.component";


/**
Expand Down Expand Up @@ -67,6 +68,33 @@ export class ModalService {
return component;
}

/**
* Creates and renders a new alert modal component.
* @param data You can pass in `title`, `text` and `buttons` to be used in the modal.
* `buttons` is an array of objects
* ```
* {
* text: "Button text",
* type: "primary" | "secondary" | "tertiary" | "ghost" | "danger" | "danger--primary" = "primary",
* click: clickFunction,
* }
* ```
* @returns {ComponentRef<any>}
* @memberof ModalService
*/
show(data: {modalType?: string, headerLabel?: string, title: string, text: string, buttons?: null}) {
return this.create({
component: AlertModalComponent,
inputs: {
modalType: data.modalType,
headerLabel: data.headerLabel,
title: data.title,
text: data.text,
buttons: data.buttons || []
}
});
}

/**
* Destroys the modal on the supplied index.
* When called without parameters it destroys the most recently created/top most modal.
Expand Down
Loading