File

src/context-menu/context-menu-item.component.ts

Implements

OnInit AfterContentInit OnDestroy

Metadata

Index

Properties
Methods
Inputs
Outputs
HostBindings
HostListeners
Accessors

Constructor

constructor(elementRef: ElementRef, contextMenuSelectionService: ContextMenuSelectionService)
Parameters :
Name Type Optional
elementRef ElementRef No
contextMenuSelectionService ContextMenuSelectionService No

Inputs

checked
Type : boolean
Default value : false
danger
Type : boolean
Default value : false
disabled
Type : boolean
Default value : false
icon
Type : string
Default value : ""
info
Type : string
Default value : ""
label
Type : string
Default value : ""
type
Type : null | "checkbox" | "radio"
Default value : null
value
Type : string
Default value : ""

Outputs

checkedChange
Type : EventEmitter
itemClick
Type : EventEmitter

HostBindings

attr.aria-checked
Type : boolean
attr.aria-disabled
Type : boolean
attr.aria-expanded
Type : any
Default value : null
attr.aria-haspopup
Type : any
Default value : null
attr.role
Type : string
Default value : "menuitem"
attr.tabindex
Type : number
Default value : -1
class.cds--menu-item
Type : boolean
Default value : true

HostListeners

blur
blur()
click
Arguments : '$event'
click(event)
focus
focus()
keydown.enter
Arguments : '$event'
keydown.enter(event)
keydown.space
Arguments : '$event'
keydown.space(event)
mouseout
mouseout()
mouseover
mouseover()

Methods

closeSubMenu
closeSubMenu()
Returns : void
focusItem
focusItem()
Returns : void
handleBlur
handleBlur()
Decorators :
@HostListener('blur')
Returns : void
handleClick
handleClick(event)
Decorators :
@HostListener('keydown.enter', ['$event'])
@HostListener('keydown.space', ['$event'])
@HostListener('click', ['$event'])
Parameters :
Name Optional
event No
Returns : void
handleFocus
handleFocus()
Decorators :
@HostListener('focus')
Returns : void
handleMouseOut
handleMouseOut()
Decorators :
@HostListener('mouseout')
Returns : void
handleMouseOver
handleMouseOver()
Decorators :
@HostListener('mouseover')
Returns : void
handleSelection
handleSelection(selected: boolean)
Parameters :
Name Type Optional
selected boolean No
Returns : void
ngAfterContentInit
ngAfterContentInit()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
openSubMenu
openSubMenu()
Returns : void

Properties

ariaExpanded
Type : null
Default value : null
Decorators :
@HostBinding('attr.aria-expanded')
ariaHasPopup
Type : null
Default value : null
Decorators :
@HostBinding('attr.aria-haspopup')
childContextMenu
Type : ContextMenuComponent
Decorators :
@ContentChild(ContextMenuComponent, {static: true})
hasChildren
Default value : false
optionClass
Default value : true
Decorators :
@HostBinding('class.cds--menu-item')
role
Type : string
Default value : "menuitem"
Decorators :
@HostBinding('attr.role')
selectable
Default value : false
Private subscriptions
Default value : new Subscription()
tabindex
Default value : -1
Decorators :
@HostBinding('attr.tabindex')

Accessors

ariaChecked
getariaChecked()
ariaDisabled
getariaDisabled()
import {
	Component,
	HostBinding,
	Input,
	Output,
	EventEmitter,
	ElementRef,
	HostListener,
	ContentChild,
	Optional,
	OnInit,
	AfterContentInit,
	OnDestroy
} from "@angular/core";
import { Subscription } from "rxjs";
import { ContextMenuSelectionService } from "./context-menu-selection.service";
import { ContextMenuComponent } from "./context-menu.component";
import { ItemClickEvent } from "./context-menu.types";

@Component({
	selector: "cds-menu-item, cds-context-menu-item, ibm-context-menu-item",
	template: `
		<div class="cds--menu-item__icon">
			<svg *ngIf="selectable && checked" cdsIcon="checkmark" size="16"></svg>
			<svg *ngIf="!selectable && icon" [cdsIcon]="icon" size="16"></svg>
		</div>
		<div class="cds--menu-item__label" [title]="label">{{label}}</div>
		<div class="cds--menu-item__shortcut">
			<ng-container *ngIf="info">{{info}}</ng-container>
			<svg *ngIf="hasChildren" cdsIcon="caret--right" size="16"></svg>
		</div>
		<ng-content></ng-content>
	`,
	styles: [`
		:host {
			grid-template-columns: 1rem 1fr max-content;
		}
	`]
})
export class ContextMenuItemComponent implements OnInit, AfterContentInit, OnDestroy {
	@HostBinding("class.cds--menu-item") optionClass = true;
	@HostBinding("attr.role") role = "menuitem";
	@HostBinding("attr.tabindex") tabindex = -1;
	@HostBinding("attr.aria-haspopup") ariaHasPopup = null;
	@HostBinding("attr.aria-expanded") ariaExpanded = null;
	@HostBinding("attr.aria-checked") get ariaChecked() {
		return this.type === "checkbox" ?
			(this.checked ? true : false) : null;
	}
	@HostBinding("attr.aria-disabled") get ariaDisabled() {
		return this.disabled;
	}
	@Input() @HostBinding("class.cds--menu-item--disabled") disabled = false;
	@Input() @HostBinding("class.cds--menu-item--danger") danger = false;
	@Input() label = "";
	@Input() info = "";
	@Input() type: null | "checkbox" | "radio" = null;
	@Input() checked = false;
	@Input() icon = "";
	@Input() value = "";
	@Output() checkedChange = new EventEmitter<boolean>();
	@Output() itemClick = new EventEmitter<ItemClickEvent>();

	hasChildren = false;
	selectable = false;

	@ContentChild(ContextMenuComponent, { static: true }) childContextMenu: ContextMenuComponent;
	private subscriptions = new Subscription();

	constructor(
		protected elementRef: ElementRef,
		@Optional() protected contextMenuSelectionService: ContextMenuSelectionService
	) {}

	ngOnInit() {
		switch (this.type) {
			case "checkbox": {
				this.role = "menuitemcheckbox";
				this.selectable = true;
				break;
			}
			case "radio": {
				this.role = "menuitemradio";
				this.selectable = true;
				break;
			}
			default: {
				this.role = "menuitem";
			}
		}

		if (this.type && this.contextMenuSelectionService && this.value) {
			const { selectionObservable } = this.contextMenuSelectionService;
			const subscription = selectionObservable.subscribe((value) => {
				if (this.type === "radio") {
					this.handleSelection(value === this.value);
				}

				if (this.type === "checkbox") {
					this.handleSelection(value.includes(this.value));
				}
			});
			this.subscriptions.add(subscription);
		}
	}

	ngAfterContentInit() {
		if (this.childContextMenu) {
			this.hasChildren = true;
			this.ariaHasPopup = true;
			this.ariaExpanded = false;
		}
	}

	@HostListener("keydown.enter", ["$event"])
	@HostListener("keydown.space", ["$event"])
	@HostListener("click", ["$event"])
	handleClick(event: MouseEvent & KeyboardEvent) {
		event.stopPropagation();
		if (this.hasChildren) {
			this.openSubMenu();
			this.childContextMenu.focusMenu();
		}

		if (this.type) {
			this.handleSelection(!this.checked);
		}

		if (this.contextMenuSelectionService) {
			if (this.type === "radio") {
				this.contextMenuSelectionService.selectRadio(this.value);
			}

			if (this.type === "checkbox") {
				this.contextMenuSelectionService.selectCheckbox(this.value);
			}
		}

		if (!this.disabled) {
			this.itemClick.emit({
				event,
				label: this.label,
				info: this.info,
				value: this.value,
				type: this.type
			});
		}
	}

	handleSelection(selected: boolean) {
		this.checked = selected;
		this.checkedChange.emit(this.checked);
	}

	openSubMenu() {
		if (this.childContextMenu) {
			this.childContextMenu.open = true;
			this.ariaExpanded = true;
			const dimensions = this.elementRef.nativeElement.getBoundingClientRect();
			this.childContextMenu.position.left = dimensions.left + dimensions.width;
			// subtract 4px to account for margins
			this.childContextMenu.position.top = dimensions.top - 4;
		}
	}

	closeSubMenu() {
		if (this.childContextMenu) {
			this.childContextMenu.open = false;
			this.ariaExpanded = false;
		}
	}

	@HostListener("mouseover")
	handleMouseOver() {
		this.openSubMenu();
	}

	@HostListener("mouseout")
	handleMouseOut() {
		this.closeSubMenu();
	}

	@HostListener("focus")
	handleFocus() {
		this.tabindex = 0;
		if (this.hasChildren && this.ariaExpanded) {
			this.closeSubMenu();
		}
	}

	@HostListener("blur")
	handleBlur() {
		this.tabindex = -1;
	}

	focusItem() {
		this.elementRef.nativeElement.focus();
	}

	ngOnDestroy() {
		this.subscriptions.unsubscribe();
	}
}

		:host {
			grid-template-columns: 1rem 1fr max-content;
		}
	
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""