src/dialog/overflow-menu/overflow-menu-pane.component.ts
Extend the Dialog
component to create an overflow menu.
Not used directly. See overflow-menu.component and overflow-menu.directive for more
AfterViewInit
selector | cds-overflow-menu-pane, ibm-overflow-menu-pane |
template |
|
Properties |
|
Methods |
Inputs |
Outputs |
HostListeners |
constructor(elementRef: ElementRef, i18n: I18n, experimental: ExperimentalService, animationFrameService: AnimationFrameService, elementService: ElementService)
|
||||||||||||||||||
Parameters :
|
dialogConfig | |
Type : DialogConfig
|
|
Inherited from
Dialog
|
|
Defined in
Dialog:41
|
|
Receives |
close | |
Type : EventEmitter<CloseMeta>
|
|
Inherited from
Dialog
|
|
Defined in
Dialog:36
|
|
Emits event that handles the closing of a |
keydown |
Arguments : '$event'
|
keydown(event: KeyboardEvent)
|
Inherited from
Dialog
|
Defined in
Dialog:82
|
document:click | ||||
Arguments : '$event'
|
||||
document:click(event)
|
||||
Inherited from
Dialog
|
||||
Defined in
Dialog:229
|
||||
Sets up a event Listener to close
Parameters :
|
afterDialogViewInit |
afterDialogViewInit()
|
Inherited from
Dialog
|
Defined in
Dialog:135
|
Returns :
void
|
hostkeys | ||||||
hostkeys(event: KeyboardEvent)
|
||||||
Decorators :
@HostListener('keydown', ['$event'])
|
||||||
Parameters :
Returns :
void
|
Protected listItems |
listItems()
|
Returns :
any
|
onClose | ||||
onClose(event)
|
||||
Parameters :
Returns :
void
|
onDialogInit |
onDialogInit()
|
Inherited from
Dialog
|
Defined in
Dialog:53
|
Returns :
void
|
clickClose | ||||
clickClose(event)
|
||||
Decorators :
@HostListener('document:click', ['$event'])
|
||||
Inherited from
Dialog
|
||||
Defined in
Dialog:229
|
||||
Sets up a event Listener to close
Parameters :
Returns :
void
|
Public doClose | ||||||||
doClose(meta: CloseMeta)
|
||||||||
Inherited from
Dialog
|
||||||||
Defined in
Dialog:242
|
||||||||
Closes
Parameters :
Returns :
void
|
escapeClose | ||||||
escapeClose(event: KeyboardEvent)
|
||||||
Decorators :
@HostListener('keydown', ['$event'])
|
||||||
Inherited from
Dialog
|
||||||
Defined in
Dialog:206
|
||||||
Sets up a KeyboardEvent to close
Parameters :
Returns :
void
|
ngAfterViewInit |
ngAfterViewInit()
|
Inherited from
Dialog
|
Defined in
Dialog:105
|
After the DOM is ready, focus is set and dialog is placed in respect to the parent element.
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Inherited from
Dialog
|
Defined in
Dialog:249
|
At destruction of component,
Returns :
void
|
ngOnInit |
ngOnInit()
|
Inherited from
Dialog
|
Defined in
Dialog:93
|
Initialize the
Returns :
void
|
placeDialog |
placeDialog()
|
Inherited from
Dialog
|
Defined in
Dialog:162
|
Uses the position service to position the
Returns :
void
|
Protected addGap |
Type : object
|
Default value : {
"left": pos => position.addOffset(pos, 0, -this.dialogConfig.gap),
"right": pos => position.addOffset(pos, 0, this.dialogConfig.gap),
"top": pos => position.addOffset(pos, -this.dialogConfig.gap),
"bottom": pos => position.addOffset(pos, this.dialogConfig.gap),
"left-bottom": pos => position.addOffset(pos, 0, -this.dialogConfig.gap),
"right-bottom": pos => position.addOffset(pos, 0, this.dialogConfig.gap)
}
|
Inherited from
Dialog
|
Defined in
Dialog:65
|
Handles offsetting the |
Protected animationFrameSubscription |
Default value : new Subscription()
|
Inherited from
Dialog
|
Defined in
Dialog:59
|
Public data |
Type : object
|
Default value : {}
|
Inherited from
Dialog
|
Defined in
Dialog:50
|
Stores the data received from |
dialog |
Type : ElementRef
|
Decorators :
@ViewChild('dialog')
|
Inherited from
Dialog
|
Defined in
Dialog:45
|
Maintains a reference to the view DOM element of the |
Public placement |
Type : string
|
Inherited from
Dialog
|
Defined in
Dialog:55
|
The placement of the |
Protected placements |
Type : Positions
|
Default value : {}
|
Inherited from
Dialog
|
Defined in
Dialog:77
|
Extra placements. Child classes can add to this for use in |
Protected visibilitySubscription |
Default value : new Subscription()
|
Inherited from
Dialog
|
Defined in
Dialog:57
|
import {
Component,
HostListener,
ElementRef,
AfterViewInit,
Optional
} from "@angular/core";
import { Dialog } from "../dialog.component";
import { position } from "@carbon/utils-position";
import { isFocusInLastItem, isFocusInFirstItem } from "carbon-components-angular/common";
import { I18n } from "carbon-components-angular/i18n";
import { ExperimentalService } from "carbon-components-angular/experimental";
import { AnimationFrameService, ElementService } from "carbon-components-angular/utils";
import { CloseReasons } from "../dialog-config.interface";
import { closestAttr } from "carbon-components-angular/utils";
/**
* Extend the `Dialog` component to create an overflow menu.
*
* Not used directly. See overflow-menu.component and overflow-menu.directive for more
*/
@Component({
selector: "cds-overflow-menu-pane, ibm-overflow-menu-pane",
template: `
<ul
[attr.id]="dialogConfig.compID"
[attr.aria-label]="dialogConfig.menuLabel"
[attr.data-floating-menu-direction]="placement ? placement : null"
[ngClass]="{'cds--overflow-menu--flip': dialogConfig.flip}"
role="menu"
#dialog
class="cds--overflow-menu-options cds--overflow-menu-options--open"
(click)="onClose($event)"
[attr.aria-label]="dialogConfig.menuLabel">
<ng-template
[ngTemplateOutlet]="dialogConfig.content"
[ngTemplateOutletContext]="{overflowMenu: this}">
</ng-template>
</ul>
`
})
export class OverflowMenuPane extends Dialog implements AfterViewInit {
constructor(
protected elementRef: ElementRef,
protected i18n: I18n,
protected experimental: ExperimentalService,
@Optional() protected animationFrameService: AnimationFrameService = null,
// mark `elementService` as optional since making it mandatory would be a breaking change
@Optional() protected elementService: ElementService = null) {
super(elementRef, elementService, animationFrameService);
}
onDialogInit() {
const positionOverflowMenu = pos => {
let offset;
/*
* 20 is half the width of the overflow menu trigger element.
* we also move the element by half of it's own width, since
* position service will try and center everything
*/
const closestRel = closestAttr("position", ["relative", "fixed", "absolute"], this.elementRef.nativeElement);
const topFix = closestRel ? closestRel.getBoundingClientRect().top * -1 : 0;
const leftFix = closestRel ? closestRel.getBoundingClientRect().left * -1 : 0;
offset = Math.round(this.dialog.nativeElement.offsetWidth / 2) - 20;
if (this.dialogConfig.flip) {
return position.addOffset(pos, topFix, (-offset + leftFix));
}
return position.addOffset(pos, topFix, (offset + leftFix));
};
this.addGap["bottom"] = positionOverflowMenu;
this.addGap["top"] = positionOverflowMenu;
if (!this.dialogConfig.menuLabel) {
this.dialogConfig.menuLabel = this.i18n.get().OVERFLOW_MENU.OVERFLOW;
}
}
@HostListener("keydown", ["$event"])
hostkeys(event: KeyboardEvent) {
const listItems = this.listItems();
switch (event.key) {
case "ArrowDown":
event.preventDefault();
if (!isFocusInLastItem(event, listItems)) {
const index = listItems.findIndex(item => item === event.target);
listItems[index + 1].focus();
} else {
listItems[0].focus();
}
break;
case "ArrowUp":
event.preventDefault();
if (!isFocusInFirstItem(event, listItems)) {
const index = listItems.findIndex(item => item === event.target);
listItems[index - 1].focus();
} else {
listItems[listItems.length - 1].focus();
}
break;
case "Home":
event.preventDefault();
listItems[0].focus();
break;
case "End":
event.preventDefault();
listItems[listItems.length - 1].focus();
break;
case "Escape":
case "Tab":
event.stopImmediatePropagation();
this.doClose({
reason: CloseReasons.interaction,
target: event.target
});
break;
default: break;
}
}
onClose(event) {
this.doClose({
reason: CloseReasons.interaction,
target: event.target
});
}
afterDialogViewInit() {
const focusElementList = this.listItems();
focusElementList.forEach(button => {
// Allows user to set tabindex to 0.
if (button.getAttribute("tabindex") === null) {
button.tabIndex = -1;
}
});
if (focusElementList[0]) {
focusElementList[0].tabIndex = 0;
focusElementList[0].focus();
}
}
protected listItems() {
const selector = ".cds--overflow-menu-options__option:not([disabled]) .cds--overflow-menu-options__btn";
return Array.from<HTMLElement>(this.elementRef.nativeElement.querySelectorAll(selector));
}
}