Skip to content

Commit b6afd41

Browse files
authored
Merge branch 'master' into toggle-label
2 parents 0c57cc8 + 1d97ae5 commit b6afd41

19 files changed

+366
-790
lines changed

package-lock.json

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

package.json

Lines changed: 2 additions & 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",
@@ -146,6 +146,7 @@
146146
"zone.js": "0.9.0"
147147
},
148148
"dependencies": {
149+
"@carbon/utils-position": "1.0.0",
149150
"flatpickr": "4.5.7",
150151
"ng2-flatpickr": "7.0.3"
151152
}

src/dialog/dialog.component.ts

Lines changed: 9 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
} from "rxjs";
1919
import { throttleTime } from "rxjs/operators";
2020
// the AbsolutePosition is required to import the declaration correctly
21-
import position, { AbsolutePosition } from "./../utils/position";
21+
import { position, AbsolutePosition } from "@carbon/utils-position";
2222
import { cycleTabs, getFocusElementList } from "./../common/tab.service";
2323
import { DialogConfig } from "./dialog-config.interface";
2424

@@ -40,63 +40,46 @@ import { DialogConfig } from "./dialog-config.interface";
4040
export class Dialog implements OnInit, AfterViewInit, OnDestroy {
4141
/**
4242
* One static event observable to handle window resizing.
43-
* @protected
44-
* @static
45-
* @type {Observable<any>}
46-
* @memberof Dialog
4743
*/
4844
protected static resizeObservable: Observable<any> = fromEvent(window, "resize").pipe(throttleTime(100));
4945
/**
5046
* Emits event that handles the closing of a `Dialog` object.
51-
* @type {EventEmitter<any>}
52-
* @memberof Dialog
5347
*/
5448
@Output() close: EventEmitter<any> = new EventEmitter();
5549
/**
5650
* Receives `DialogConfig` interface object with properties of `Dialog`
57-
* explictly defined.
58-
* @type {DialogConfig}
59-
* @memberof Dialog
51+
* explicitly defined.
6052
*/
6153
@Input() dialogConfig: DialogConfig;
6254
/**
6355
* Maintains a reference to the view DOM element of the `Dialog`.
64-
* @type {ElementRef}
65-
* @memberof Dialog
6656
*/
6757
@ViewChild("dialog") dialog: ElementRef;
6858

6959
/**
7060
* Stores the data received from `dialogConfig`.
71-
* @memberof Dialog
7261
*/
7362
public data = {};
7463

7564
/**
76-
* The placement of the `Dialog` is recieved from the `Position` service.
77-
* @type {Placement}
78-
* @memberof Dialog
65+
* The placement of the `Dialog` is received from the `Position` service.
7966
*/
8067
public placement: string;
8168

8269
/**
8370
* `Subscription` used to update placement in the event of a window resize.
84-
* @protected
85-
* @type {Subscription}
86-
* @memberof Dialog
8771
*/
8872
protected resizeSubscription: Subscription;
8973
/**
9074
* Subscription to all the scrollable parents `scroll` event
9175
*/
92-
// add a new subscription temprarily so that contexts (such as tests)
76+
// add a new subscription temporarily so that contexts (such as tests)
9377
// that don't run ngAfterViewInit have something to unsubscribe in ngOnDestroy
9478
protected scrollSubscription: Subscription = new Subscription();
9579
/**
9680
* Handles offsetting the `Dialog` item based on the defined position
9781
* to not obscure the content beneath.
9882
* @protected
99-
* @memberof Dialog
10083
*/
10184
protected addGap = {
10285
"left": pos => position.addOffset(pos, 0, -this.dialogConfig.gap),
@@ -110,13 +93,11 @@ export class Dialog implements OnInit, AfterViewInit, OnDestroy {
11093
/**
11194
* Creates an instance of `Dialog`.
11295
* @param {ElementRef} elementRef
113-
* @memberof Dialog
11496
*/
115-
constructor(protected elementRef: ElementRef) {}
97+
constructor(protected elementRef: ElementRef) { }
11698

11799
/**
118-
* Initilize the `Dialog`, set the placement and gap, and add a `Subscription` to resize events.
119-
* @memberof Dialog
100+
* Initialize the `Dialog`, set the placement and gap, and add a `Subscription` to resize events.
120101
*/
121102
ngOnInit() {
122103
this.placement = this.dialogConfig.placement.split(",")[0];
@@ -126,14 +107,13 @@ export class Dialog implements OnInit, AfterViewInit, OnDestroy {
126107
this.placeDialog();
127108
});
128109

129-
// run any additional initlization code that consuming classes may have
110+
// run any additional initialization code that consuming classes may have
130111
this.onDialogInit();
131112
}
132113

133114
/**
134115
* After the DOM is ready, focus is set and dialog is placed
135116
* in respect to the parent element.
136-
* @memberof Dialog
137117
*/
138118
ngAfterViewInit() {
139119
const dialogElement = this.dialog.nativeElement;
@@ -236,30 +216,9 @@ export class Dialog implements OnInit, AfterViewInit, OnDestroy {
236216
// split always returns an array, so we can just use the auto position logic
237217
// for single positions too
238218
const placements = this.dialogConfig.placement.split(",");
239-
const weightedPlacements = placements.map(placement => {
240-
const pos = findPosition(parentEl, el, placement);
241-
let box = position.getPlacementBox(el, pos);
242-
let hiddenHeight = box.bottom - window.innerHeight - window.scrollY;
243-
let hiddenWidth = box.right - window.innerWidth - window.scrollX;
244-
// if the hiddenHeight or hiddenWidth is negative, reset to offsetHeight or offsetWidth
245-
hiddenHeight = hiddenHeight < 0 ? el.offsetHeight : hiddenHeight;
246-
hiddenWidth = hiddenWidth < 0 ? el.offsetWidth : hiddenWidth;
247-
const area = el.offsetHeight * el.offsetWidth;
248-
const hiddenArea = hiddenHeight * hiddenWidth;
249-
let visibleArea = area - hiddenArea;
250-
// if the visibleArea is 0 set it back to area (to calculate the percentage in a useful way)
251-
visibleArea = visibleArea === 0 ? area : visibleArea;
252-
const visiblePercent = visibleArea / area;
253-
return {
254-
placement,
255-
weight: visiblePercent
256-
};
257-
});
258219

259-
// sort the placements from best to worst
260-
weightedPlacements.sort((a, b) => b.weight - a.weight);
261-
// pick the best!
262-
dialogPlacement = weightedPlacements[0].placement;
220+
// find the best placement
221+
dialogPlacement = position.findBestPlacement(parentEl, el, placements);
263222

264223
// calculate the final position
265224
const pos = findPosition(parentEl, el, dialogPlacement);
@@ -293,7 +252,6 @@ export class Dialog implements OnInit, AfterViewInit, OnDestroy {
293252
* Sets up a event Listener to close `Dialog` if click event occurs outside
294253
* `Dialog` object.
295254
* @param {any} event
296-
* @memberof Dialog
297255
*/
298256
@HostListener("document:click", ["$event"])
299257
clickClose(event) {
@@ -305,15 +263,13 @@ export class Dialog implements OnInit, AfterViewInit, OnDestroy {
305263

306264
/**
307265
* Closes `Dialog` object by emitting the close event upwards to parents.
308-
* @memberof Dialog
309266
*/
310267
public doClose() {
311268
this.close.emit();
312269
}
313270

314271
/**
315272
* At destruction of component, `Dialog` unsubscribes from handling window resizing changes.
316-
* @memberof Dialog
317273
*/
318274
ngOnDestroy() {
319275
this.resizeSubscription.unsubscribe();

src/dialog/overflow-menu/overflow-menu-pane.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Component, HostListener, ElementRef, AfterViewInit } from "@angular/core";
22
import { Dialog } from "../dialog.component";
3-
import { position } from "../../utils/position";
3+
import { position } from "@carbon/utils-position";
44
import { isFocusInLastItem, isFocusInFirstItem } from "./../../common/tab.service";
55
import { I18n } from "./../../i18n/i18n.module";
66
import { ExperimentalService } from "./../../experimental.module";

src/dialog/overflow-menu/overflow-menu.stories.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ storiesOf("Overflow Menu", module)
4848
}))
4949
.add("With links", () => ({
5050
template: `
51-
<app-experimental-component></app-experimental-component>
5251
<ibm-overflow-menu [flip]="flip" >
5352
<ibm-overflow-menu-option href="https://www.ibm.com" (selected)="selected($event)" (click)="click($event)">
5453
An example option that is really long to show what should be done to handle long text
@@ -57,7 +56,9 @@ storiesOf("Overflow Menu", module)
5756
<ibm-overflow-menu-option href="https://www.ibm.com" (selected)="selected($event)">Option 3</ibm-overflow-menu-option>
5857
<ibm-overflow-menu-option href="https://www.ibm.com" (selected)="selected($event)">Option 4</ibm-overflow-menu-option>
5958
<ibm-overflow-menu-option href="https://www.ibm.com" disabled="true" (selected)="selected($event)">Disabled</ibm-overflow-menu-option>
60-
<ibm-overflow-menu-option href="https://www.ibm.com" type="danger" (selected)="selected($event)">Danger option</ibm-overflow-menu-option>
59+
<ibm-overflow-menu-option href="https://www.ibm.com" type="danger" (selected)="selected($event)">
60+
Danger option
61+
</ibm-overflow-menu-option>
6162
</ibm-overflow-menu>
6263
<ibm-placeholder></ibm-placeholder>
6364
`,

src/dropdown/dropdown.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { NG_VALUE_ACCESSOR } from "@angular/forms";
1717
import { Observable, fromEvent, of, Subscription } from "rxjs";
1818

1919
import { AbstractDropdownView } from "./abstract-dropdown-view.class";
20-
import { position } from "../utils/position";
20+
import { position } from "@carbon/utils-position";
2121
import { I18n } from "./../i18n/i18n.module";
2222
import { ListItem } from "./list-item.interface";
2323
import { DropdownService } from "./dropdown.service";

src/dropdown/dropdown.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Injectable, ElementRef } from "@angular/core";
22
import { PlaceholderService } from "./../placeholder/placeholder.module";
33
import { fromEvent, Subscription } from "rxjs";
44
import { throttleTime } from "rxjs/operators";
5-
import position from "./../utils/position";
5+
import { position } from "@carbon/utils-position";
66

77
const defaultOffset = { top: 0, left: 0 };
88

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
*/

0 commit comments

Comments
 (0)