Skip to content

Commit fe1eb19

Browse files
authored
Merge branch 'master' into dropdown
2 parents 58b16b1 + bb165b1 commit fe1eb19

17 files changed

+2722
-1007
lines changed

.storybook/webpack.config.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const path = require('path');
22

3-
module.exports = (baseConfig, env, defaultConfig) => {
4-
defaultConfig.module.rules.push({
3+
module.exports = ({config, mode}) => {
4+
config.module.rules.push({
55
test: [/\.stories\.tsx?$/, /index\.ts$/],
66
loaders: [
77
{
@@ -15,7 +15,7 @@ module.exports = (baseConfig, env, defaultConfig) => {
1515
enforce: 'pre',
1616
});
1717

18-
defaultConfig.mode = "development";
19-
defaultConfig.devtool = "source-map";
20-
return defaultConfig;
18+
config.mode = "development";
19+
config.devtool = "source-map";
20+
return config;
2121
};

package-lock.json

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

package.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,19 +86,19 @@
8686
"@commitlint/cli": "7.2.1",
8787
"@commitlint/config-conventional": "7.0.1",
8888
"@compodoc/compodoc": "1.1.7",
89-
"@storybook/addon-actions": "4.0.6",
90-
"@storybook/addon-knobs": "4.0.6",
91-
"@storybook/addon-links": "4.0.6",
92-
"@storybook/addon-notes": "4.0.6",
93-
"@storybook/addon-options": "4.1.4",
94-
"@storybook/addon-storysource": "4.1.2",
95-
"@storybook/addons": "4.0.6",
96-
"@storybook/angular": "4.0.6",
89+
"@storybook/addon-actions": "5.0.0",
90+
"@storybook/addon-knobs": "5.0.0",
91+
"@storybook/addon-links": "5.0.0",
92+
"@storybook/addon-notes": "5.0.0",
93+
"@storybook/addon-options": "5.0.0",
94+
"@storybook/addon-storysource": "5.0.0",
95+
"@storybook/addons": "5.0.0",
96+
"@storybook/angular": "5.0.0",
9797
"@types/jasmine": "2.8.6",
9898
"@types/node": "8.5.2",
9999
"angular2-template-loader": "0.6.2",
100100
"babel-loader": "8.0.4",
101-
"carbon-components": "9.70.3",
101+
"carbon-components": "9.82.17",
102102
"codelyzer": "4.5.0",
103103
"commitizen": "2.10.1",
104104
"core-js": "2.5.5",
@@ -148,6 +148,6 @@
148148
},
149149
"dependencies": {
150150
"flatpickr": "4.5.2",
151-
"ng2-flatpickr": "7.0.1"
151+
"ng2-flatpickr": "7.0.2"
152152
}
153153
}

src/dialog/dialog.directive.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,15 @@ export class DialogDirective implements OnInit, OnDestroy, OnChanges {
8787
/**
8888
* Config object passed to the rendered component
8989
*/
90-
@Output() onClose: EventEmitter<any> = new EventEmitter<any>();
9190
dialogConfig: DialogConfig;
91+
/**
92+
* Emits an event when the dialog is closed
93+
*/
94+
@Output() onClose: EventEmitter<any> = new EventEmitter();
95+
/**
96+
* Emits an event when the dialog is opened
97+
*/
98+
@Output() onOpen: EventEmitter<any> = new EventEmitter();
9299

93100
@HostBinding("attr.role") role = "button";
94101
@HostBinding("attr.aria-expanded") expanded = false;
@@ -197,6 +204,7 @@ export class DialogDirective implements OnInit, OnDestroy, OnChanges {
197204
open() {
198205
this.dialogService.open(this.viewContainerRef, this.dialogConfig);
199206
this.expanded = true;
207+
this.onOpen.emit();
200208
}
201209

202210
/**
@@ -206,6 +214,9 @@ export class DialogDirective implements OnInit, OnDestroy, OnChanges {
206214
toggle() {
207215
this.dialogService.toggle(this.viewContainerRef, this.dialogConfig);
208216
this.expanded = this.dialogService.isOpen;
217+
if (this.expanded) {
218+
this.onOpen.emit();
219+
}
209220
}
210221

211222
/**

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

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import {
44
Input,
55
ElementRef,
66
Output,
7-
EventEmitter
7+
EventEmitter,
8+
AfterViewInit
89
} from "@angular/core";
910

1011
/**
@@ -17,7 +18,7 @@ import {
1718
* <ibm-overflow-menu-option type="danger">Danger option</ibm-overflow-menu-option>
1819
* ```
1920
*
20-
* For content that expands beyod the overflow menu `OverflowMenuOption` automatically adds a title attribute.
21+
* For content that expands beyond the overflow menu `OverflowMenuOption` automatically adds a title attribute.
2122
*/
2223
@Component({
2324
selector: "ibm-overflow-menu-option",
@@ -30,12 +31,12 @@ import {
3031
(blur)="tabIndex = -1"
3132
(click)="onClick($event)"
3233
[disabled]="disabled"
33-
[title]="(titleEnabled ? content : '')">
34+
[title]="title">
3435
<ng-content></ng-content>
3536
</button>
3637
`
3738
})
38-
export class OverflowMenuOption {
39+
export class OverflowMenuOption implements AfterViewInit {
3940
@HostBinding("class") optionClass = "bx--overflow-menu-options__option";
4041
@HostBinding("attr.role") role = "presentation";
4142

@@ -60,30 +61,20 @@ export class OverflowMenuOption {
6061
@Output() selected: EventEmitter<any> = new EventEmitter();
6162

6263
public tabIndex = -1;
64+
// note: title must be a real attribute (i.e. not a getter) as of Angular@6 due to
65+
// change after checked errors
66+
public title = null;
6367

6468
constructor(protected elementRef: ElementRef) {}
6569

6670
onClick(event) {
6771
this.selected.emit();
6872
}
6973

70-
/**
71-
* Returns true if the content string is longer than the width of the containing button
72-
*
73-
* note: getter ties into the view check cycle so we always get an accurate value
74-
*/
75-
get titleEnabled() {
74+
ngAfterViewInit() {
7675
const button = this.elementRef.nativeElement.querySelector("button");
7776
if (button.scrollWidth > button.offsetWidth) {
78-
return true;
77+
this.title = this.elementRef.nativeElement.querySelector("button").textContent;
7978
}
80-
return false;
81-
}
82-
83-
/**
84-
* Returns the text content projected into the component
85-
*/
86-
get content(): string {
87-
return this.elementRef.nativeElement.querySelector("button").textContent;
8879
}
8980
}

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

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import {
22
Component,
33
ElementRef,
44
Input,
5-
ViewEncapsulation
5+
ViewEncapsulation,
6+
ContentChild
67
} from "@angular/core";
78
import { I18n } from "./../../i18n/i18n.module";
9+
import { OverflowMenuDirective } from "./overflow-menu.directive";
810

911
/**
1012
* The OverFlow menu component encapsulates the OverFlowMenu directive, and the menu iconography into one convienent component
@@ -22,9 +24,11 @@ import { I18n } from "./../../i18n/i18n.module";
2224
template: `
2325
<div
2426
[ibmOverflowMenu]="options"
25-
[ngClass]="{'bx--overflow-menu--open': open === true}"
27+
[ngClass]="{'bx--overflow-menu--open': open}"
2628
[attr.aria-label]="buttonLabel"
2729
[flip]="flip"
30+
(onOpen)="open = true"
31+
(onClose)="open = false"
2832
role="button"
2933
aria-haspopup="true"
3034
class="bx--overflow-menu"
@@ -67,12 +71,9 @@ export class OverflowMenu {
6771

6872
@Input() flip = false;
6973

70-
constructor(protected elementRef: ElementRef, protected i18n: I18n) {}
74+
@ContentChild(OverflowMenuDirective) overflowMenuDirective: OverflowMenuDirective;
7175

72-
get open() {
73-
if (this.elementRef.nativeElement.children[0].getAttribute("aria-expanded") === "true") {
74-
return true;
75-
}
76-
return false;
77-
}
76+
open = false;
77+
78+
constructor(protected elementRef: ElementRef, protected i18n: I18n) {}
7879
}

src/dropdown/dropdown.component.spec.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { DropdownList } from "./list/dropdown-list.component";
88
import { ListItem } from "./list-item.interface";
99
import { ScrollableList } from "./scrollable-list.directive";
1010
import { I18nModule } from "../i18n/i18n.module";
11+
import { DropdownService } from "./dropdown.service";
12+
import { PlaceholderModule } from "./../placeholder/placeholder.module";
1113

1214
@Component({
1315
template: `
@@ -38,8 +40,10 @@ describe("Dropdown", () => {
3840
],
3941
imports: [
4042
StaticIconModule,
41-
I18nModule
42-
]
43+
I18nModule,
44+
PlaceholderModule
45+
],
46+
providers: [ DropdownService ]
4347
});
4448
});
4549

src/dropdown/dropdown.component.ts

Lines changed: 10 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ import { NG_VALUE_ACCESSOR } from "@angular/forms";
1515

1616
// Observable import is required here so typescript can compile correctly
1717
import { Observable, fromEvent, of, Subscription } from "rxjs";
18-
import { throttleTime } from "rxjs/operators";
1918

2019
import { AbstractDropdownView } from "./abstract-dropdown-view.class";
2120
import { position } from "../utils/position";
2221
import { I18n } from "./../i18n/i18n.module";
2322
import { ListItem } from "./list-item.interface";
23+
import { DropdownService } from "./dropdown.service";
2424

2525
/**
2626
* Drop-down lists enable users to select one or more items from a list.
@@ -183,21 +183,12 @@ export class Dropdown implements OnInit, AfterContentInit, OnDestroy {
183183
*/
184184
dropUp = false;
185185

186-
/**
187-
* Used by the various appendToX methods to keep a reference to our wrapper div
188-
*/
189-
dropdownWrapper: HTMLElement;
190186
// .bind creates a new function, so we declare the methods below
191187
// but .bind them up here
192188
noop = this._noop.bind(this);
193189
outsideClick = this._outsideClick.bind(this);
194190
outsideKey = this._outsideKey.bind(this);
195191
keyboardNav = this._keyboardNav.bind(this);
196-
/**
197-
* Maintains an Event Observable Subscription for tracking window resizes.
198-
* Window resizing is tracked if the `Dropdown` is appended to the body, otherwise it does not need to be supported.
199-
*/
200-
resize: Subscription;
201192
/**
202193
* Maintians an Event Observable Subscription for tracking scrolling within the open `Dropdown` list.
203194
*/
@@ -208,7 +199,7 @@ export class Dropdown implements OnInit, AfterContentInit, OnDestroy {
208199
/**
209200
* Creates an instance of Dropdown.
210201
*/
211-
constructor(protected elementRef: ElementRef, protected i18n: I18n) {}
202+
constructor(protected elementRef: ElementRef, protected i18n: I18n, protected dropdownService: DropdownService) {}
212203

213204
/**
214205
* Updates the `type` property in the `@ContentChild`.
@@ -413,37 +404,19 @@ export class Dropdown implements OnInit, AfterContentInit, OnDestroy {
413404
* Creates the `Dropdown` list appending it to the dropdown parent object instead of the body.
414405
*/
415406
_appendToDropdown() {
416-
if (document.body.contains(this.dropdownWrapper)) {
417-
this.dropdownMenu.nativeElement.style.display = "none";
418-
this.elementRef.nativeElement.appendChild(this.dropdownMenu.nativeElement);
419-
document.body.removeChild(this.dropdownWrapper);
420-
this.resize.unsubscribe();
421-
this.dropdownWrapper.removeEventListener("keydown", this.keyboardNav, true);
422-
}
407+
this.dropdownService.appendToDropdown(this.elementRef.nativeElement);
408+
this.dropdownMenu.nativeElement.removeEventListener("keydown", this.keyboardNav, true);
423409
}
424410

425411
/**
426412
* Creates the `Dropdown` list as an element that is appended to the DOM body.
427413
*/
428414
_appendToBody() {
429-
const positionDropdown = () => {
430-
let pos = position.findAbsolute(this.dropdownButton.nativeElement, this.dropdownWrapper, "bottom");
431-
// add -40 to the top position to account for carbon styles
432-
pos = position.addOffset(pos, -40, 0);
433-
position.setElement(this.dropdownWrapper, pos);
434-
};
435-
this.dropdownMenu.nativeElement.style.display = "block";
436-
this.dropdownWrapper = document.createElement("div");
437-
this.dropdownWrapper.className = `dropdown ${this.elementRef.nativeElement.className}`;
438-
this.dropdownWrapper.style.width = this.dropdownButton.nativeElement.offsetWidth + "px";
439-
this.dropdownWrapper.style.position = "absolute";
440-
this.dropdownWrapper.appendChild(this.dropdownMenu.nativeElement);
441-
document.body.appendChild(this.dropdownWrapper);
442-
positionDropdown();
443-
this.dropdownWrapper.addEventListener("keydown", this.keyboardNav, true);
444-
this.resize = fromEvent(window, "resize")
445-
.pipe(throttleTime(100))
446-
.subscribe(() => positionDropdown());
415+
this.dropdownService.appendToBody(
416+
this.dropdownButton.nativeElement,
417+
this.dropdownMenu.nativeElement,
418+
this.elementRef.nativeElement.className);
419+
this.dropdownMenu.nativeElement.addEventListener("keydown", this.keyboardNav, true);
447420
}
448421

449422
/**
@@ -529,12 +502,7 @@ export class Dropdown implements OnInit, AfterContentInit, OnDestroy {
529502
this.scroll = fromEvent(container, "scroll")
530503
.subscribe(() => {
531504
if (this.isVisibleInContainer(this.elementRef.nativeElement, container)) {
532-
position.setElement(
533-
this.dropdownWrapper,
534-
position.addOffset(
535-
position.findAbsolute(this.elementRef.nativeElement, this.dropdownWrapper, "bottom")
536-
)
537-
);
505+
this.dropdownService.updatePosition(this.dropdownButton.nativeElement);
538506
} else {
539507
this.closeMenu();
540508
}

src/dropdown/dropdown.module.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@ import { DropdownList } from "./list/dropdown-list.component";
88

99
import { ScrollableList } from "./scrollable-list.directive";
1010
import { I18nModule } from "./../i18n/i18n.module";
11+
import { PlaceholderModule } from "./../placeholder/placeholder.module";
12+
import { DropdownService } from "./dropdown.service";
1113

1214
export { Dropdown } from "./dropdown.component";
1315
export { DropdownList } from "./list/dropdown-list.component";
1416

1517
export { ScrollableList } from "./scrollable-list.directive";
1618
export { AbstractDropdownView } from "./abstract-dropdown-view.class";
1719
export { ListItem } from "./list-item.interface";
20+
export { DropdownService } from "./dropdown.service";
1821

1922
@NgModule({
2023
declarations: [
@@ -31,7 +34,9 @@ export { ListItem } from "./list-item.interface";
3134
CommonModule,
3235
FormsModule,
3336
StaticIconModule,
34-
I18nModule
35-
]
37+
I18nModule,
38+
PlaceholderModule
39+
],
40+
providers: [ DropdownService ]
3641
})
3742
export class DropdownModule {}

0 commit comments

Comments
 (0)