Skip to content

Commit fe92fa8

Browse files
committed
feat(overflow-menu): add overflow menu components
1 parent d955f44 commit fe92fa8

File tree

8 files changed

+247
-38
lines changed

8 files changed

+247
-38
lines changed

src/dialog/dialog.module.ts

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,31 @@ import { Dialog } from "./dialog.component";
1111
import { DialogDirective } from "./dialog.directive";
1212
import { DialogPlaceholderComponent } from "./dialog-placeholder.component";
1313

14-
import { Popover } from "./popover/popover.component";
15-
import { PopoverDirective } from "./popover/popover.directive";
16-
import { PopoverMenu } from "./popover/popover-menu.component";
17-
import { PopoverMenuDirective } from "./popover/popover-menu.directive";
18-
1914
import { Tooltip } from "./tooltip/tooltip.component";
2015
import { TooltipDirective } from "./tooltip/tooltip.directive";
2116
import { EllipsisTooltipDirective } from "./tooltip/ellipsis-tooltip.directive";
2217

18+
import { OverflowMenu } from "./overflow-menu/overflow-menu.component";
19+
import { OverflowMenuPane } from "./overflow-menu/overflow-menu-pane.component";
20+
import { OverflowMenuDirective } from "./overflow-menu/overflow-menu.directive";
21+
import { OverflowMenuOption } from "./overflow-menu/overflow-menu-option.component";
22+
2323
// exports
2424
export { DialogService } from "./dialog.service";
2525
export { DialogPlaceholderService } from "./dialog-placeholder.service";
2626
export { Dialog } from "./dialog.component";
2727
export { DialogDirective } from "./dialog.directive";
2828
export { DialogPlaceholderComponent } from "./dialog-placeholder.component";
2929

30-
export { Popover } from "./popover/popover.component";
31-
export { PopoverDirective } from "./popover/popover.directive";
32-
export { PopoverMenu } from "./popover/popover-menu.component";
33-
export { PopoverMenuDirective } from "./popover/popover-menu.directive";
34-
3530
export { Tooltip } from "./tooltip/tooltip.component";
3631
export { TooltipDirective } from "./tooltip/tooltip.directive";
3732
export { EllipsisTooltipDirective } from "./tooltip/ellipsis-tooltip.directive";
3833

34+
export { OverflowMenu } from "./overflow-menu/overflow-menu.component";
35+
export { OverflowMenuPane } from "./overflow-menu/overflow-menu-pane.component";
36+
export { OverflowMenuDirective } from "./overflow-menu/overflow-menu.directive";
37+
export { OverflowMenuOption } from "./overflow-menu/overflow-menu-option.component";
38+
3939
// either provides a new instance of DialogPlaceholderService, or returns the parent
4040
export function DIALOG_PLACEHOLDER_SERVICE_PROVIDER_FACTORY(parentService: DialogPlaceholderService) {
4141
return parentService || new DialogPlaceholderService();
@@ -51,26 +51,26 @@ export const DIALOG_PLACEHOLDER_SERVICE_PROVIDER = {
5151
@NgModule({
5252
declarations: [
5353
Dialog,
54-
Popover,
55-
PopoverMenu,
5654
Tooltip,
55+
OverflowMenu,
56+
OverflowMenuPane,
5757
DialogDirective,
58-
PopoverDirective,
59-
PopoverMenuDirective,
6058
TooltipDirective,
6159
EllipsisTooltipDirective,
60+
OverflowMenuDirective,
61+
OverflowMenuOption,
6262
DialogPlaceholderComponent
6363
],
6464
exports: [
6565
Dialog,
66-
Popover,
67-
PopoverMenu,
6866
Tooltip,
67+
OverflowMenu,
68+
OverflowMenuPane,
6969
DialogDirective,
70-
PopoverDirective,
71-
PopoverMenuDirective,
7270
TooltipDirective,
7371
EllipsisTooltipDirective,
72+
OverflowMenuDirective,
73+
OverflowMenuOption,
7474
DialogPlaceholderComponent
7575
],
7676
providers: [
@@ -79,9 +79,8 @@ export const DIALOG_PLACEHOLDER_SERVICE_PROVIDER = {
7979
],
8080
entryComponents: [
8181
Dialog,
82-
Popover,
83-
PopoverMenu,
84-
Tooltip
82+
Tooltip,
83+
OverflowMenuPane
8584
],
8685
imports: [CommonModule, TranslateModule, StaticIconModule]
8786
})

src/dialog/dialog.service.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,15 @@
11
import {
22
EventEmitter,
33
Injector,
4-
Component,
54
ComponentRef,
65
ComponentFactory,
76
ComponentFactoryResolver,
87
Injectable,
9-
ApplicationRef,
108
ViewContainerRef,
11-
Host
129
} from "@angular/core";
1310
import { Subscription } from "rxjs";
1411
import { DialogConfig } from "./dialog-config.interface";
1512
import { DialogPlaceholderService } from "./dialog-placeholder.service";
16-
import { Popover } from "..";
17-
1813

1914
/**
2015
* `Dialog` object to be injected into other components.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import {
2+
HostBinding,
3+
Component,
4+
Input,
5+
ElementRef,
6+
AfterViewInit,
7+
} from "@angular/core";
8+
9+
/**
10+
* `OverflowMenuOption` represents a single option in an overflow menu
11+
*
12+
* Presently it has three possible states - normal, disabled, and danger:
13+
* ```
14+
* <ibm-overflow-menu-option>Simple option</ibm-overflow-menu-option>
15+
* <ibm-overflow-menu-option disabled="true">Disabled</ibm-overflow-menu-option>
16+
* <ibm-overflow-menu-option type="danger">Danger option</ibm-overflow-menu-option>
17+
* ```
18+
*
19+
* For content that expands beyod the overflow menu `OverflowMenuOption` automatically adds a title attribute.
20+
*/
21+
@Component({
22+
selector: "ibm-overflow-menu-option",
23+
template: `
24+
<button
25+
class="bx--overflow-menu-options__btn"
26+
[ngClass]="{
27+
'bx--overflow-menu-options__option--danger': type === 'danger',
28+
'bx--overflow-menu-options__option--disabled': disabled
29+
}"
30+
[tabindex]="(disabled?-1:null)"
31+
[title]="(titleEnabled?getContent():'')">
32+
<ng-content></ng-content>
33+
</button>
34+
`
35+
})
36+
export class OverflowMenuOption implements AfterViewInit {
37+
@HostBinding("class") optionClass = "bx--overflow-menu-options__option";
38+
@HostBinding("attr.role") role = "list-item";
39+
40+
/**
41+
* toggles between `normal` and `danger` states
42+
*/
43+
@Input() type: "normal" | "danger" = "normal";
44+
/**
45+
* disable/enable interactions
46+
*/
47+
@Input() disabled = false;
48+
49+
public titleEnabled = false;
50+
51+
constructor(private elementRef: ElementRef) {}
52+
53+
ngAfterViewInit() {
54+
const button = this.elementRef.nativeElement.querySelector("button");
55+
if (button.scrollWidth > button.offsetWidth) {
56+
this.titleEnabled = true;
57+
}
58+
}
59+
60+
/**
61+
* Returns the text content projected into the component
62+
*/
63+
getContent(): string {
64+
return this.elementRef.nativeElement.querySelector("button").textContent;
65+
}
66+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import {
2+
Component,
3+
HostBinding
4+
} from "@angular/core";
5+
import { Dialog } from "../dialog.component";
6+
7+
/**
8+
* Extend the `Dialog` component to create an overflow menu.
9+
*
10+
* Not used directly. See overflow-menu.component and overflow-menu.directive for more
11+
*/
12+
@Component({
13+
selector: "ibm-overflow-menu-pane",
14+
template: `
15+
<div #dialog>
16+
<ul
17+
class="bx--overflow-menu-options bx--overflow-menu-options--open"
18+
tabindex="-1">
19+
<ng-template
20+
[ngTemplateOutlet]="dialogConfig.content"
21+
[ngTemplateOutletContext]="{overflowMenu: this}">
22+
</ng-template>
23+
</ul>
24+
</div>
25+
`
26+
})
27+
export class OverflowMenuPane extends Dialog {}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import {
2+
Component,
3+
HostBinding,
4+
Input,
5+
TemplateRef
6+
} from "@angular/core";
7+
8+
/**
9+
* The OverFlow menu component encapsulates the OverFlowMenu directive, and the menu iconography into one convienent component
10+
*
11+
* html:
12+
* ```
13+
* <ibm-overflow-menu [options]="overflowContent"></ibm-overflow-menu>
14+
* <ng-template #overflowContent>
15+
* <ibm-overflow-menu-option>Option 1</ibm-overflow-menu-option>
16+
* <ibm-overflow-menu-option>Option 2</ibm-overflow-menu-option>
17+
* </ng-template>
18+
* ```
19+
*/
20+
@Component({
21+
selector: "ibm-overflow-menu",
22+
template: `
23+
<div
24+
[ibmOverflowMenu]="options"
25+
class="bx--overflow-menu"
26+
style="display: block;">
27+
<svg class="bx--overflow-menu__icon" width="3" height="15" viewBox="0 0 3 15">
28+
<g fill-rule="evenodd">
29+
<circle cx="1.5" cy="1.5" r="1.5" />
30+
<circle cx="1.5" cy="7.5" r="1.5" />
31+
<circle cx="1.5" cy="13.5" r="1.5" />
32+
</g>
33+
</svg>
34+
</div>
35+
`
36+
})
37+
export class OverflowMenu {
38+
/**
39+
* TemplateRef of `OverflowMenuOption`s (or compliant HTML) to render in the `OverflowMenuPane`s
40+
*/
41+
@Input() options: TemplateRef<any>;
42+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import {
2+
Directive,
3+
ElementRef,
4+
ViewContainerRef,
5+
ContentChildren,
6+
QueryList,
7+
AfterViewInit,
8+
ViewChildren,
9+
Input,
10+
TemplateRef
11+
} from "@angular/core";
12+
import { DialogDirective } from "./../dialog.directive";
13+
import { DialogService } from "./../dialog.service";
14+
import { OverflowMenuOption } from "./overflow-menu-option.component";
15+
import { OverflowMenuPane } from "./overflow-menu-pane.component";
16+
17+
18+
/**
19+
* Directive for extending `Dialog` to create overflow menus.
20+
*
21+
* class: OverflowMenuDirective (extends DialogDirective)
22+
*
23+
*
24+
* selector: `ibmOverflowMenu`
25+
*
26+
*
27+
* ```html
28+
* <div [ibmOverflowMenu]="templateRef"></div>
29+
* <ng-template #templateRef>
30+
* <!-- overflow menu options here -->
31+
* </ng-template>
32+
* ```
33+
*/
34+
@Directive({
35+
selector: "[ibmOverflowMenu]",
36+
exportAs: "ibmOverflowMenu",
37+
providers: [
38+
DialogService
39+
]
40+
})
41+
export class OverflowMenuDirective extends DialogDirective {
42+
@Input() ibmOverflowMenu: TemplateRef<any>;
43+
44+
/**
45+
* Creates an instance of `OverflowMenuDirective`.
46+
*/
47+
constructor(
48+
protected elementRef: ElementRef,
49+
protected viewContainerRef: ViewContainerRef,
50+
protected dialogService: DialogService
51+
) {
52+
super(elementRef, viewContainerRef, dialogService);
53+
dialogService.create(OverflowMenuPane);
54+
}
55+
56+
onDialogInit() {
57+
this.dialogConfig.content = this.ibmOverflowMenu;
58+
}
59+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { storiesOf, moduleMetadata } from "@storybook/angular";
2+
3+
import { TranslateModule } from "@ngx-translate/core";
4+
5+
import { DialogModule } from "../../";
6+
7+
storiesOf("Overflow Menu", module)
8+
.addDecorator(
9+
moduleMetadata({
10+
imports: [
11+
DialogModule,
12+
TranslateModule.forRoot()
13+
],
14+
})
15+
)
16+
.add("Basic", () => ({
17+
template: `
18+
<ibm-overflow-menu [options]="overflowContent"></ibm-overflow-menu>
19+
<ng-template #overflowContent>
20+
<ibm-overflow-menu-option>
21+
An example option that is really long to show what should be done to handle long text
22+
</ibm-overflow-menu-option>
23+
<ibm-overflow-menu-option>Option 2</ibm-overflow-menu-option>
24+
<li class="bx--overflow-menu-options__option">
25+
<button class="bx--overflow-menu-options__btn">A fully custom option</button>
26+
</li>
27+
<ibm-overflow-menu-option>Option 4</ibm-overflow-menu-option>
28+
<ibm-overflow-menu-option disabled="true">Disabled</ibm-overflow-menu-option>
29+
<ibm-overflow-menu-option type="danger">Danger option</ibm-overflow-menu-option>
30+
</ng-template>
31+
<ibm-dialog-placeholder></ibm-dialog-placeholder>
32+
`
33+
}));

src/dialog/tooltip/tooltip.component.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,4 @@ export class Tooltip extends Dialog {
4949
onDialogInit() {
5050
this.hasContentTemplate = this.dialogConfig.content instanceof TemplateRef;
5151
}
52-
53-
/**
54-
* Set the class of the `Tooltip`.
55-
* @returns null
56-
* @memberof Tooltip
57-
*/
58-
public getClass() {
59-
if (this.dialogConfig.type) {
60-
return `tooltip--${this.dialogConfig.type}-${this.placement}`;
61-
}
62-
return `tooltip--${this.placement}`;
63-
}
6452
}

0 commit comments

Comments
 (0)