Newer
Older
Markus Kalijärvi
committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import {Component, Element, Prop, Host, Listen, Event, h, EventEmitter} from '@stencil/core';
import {MenuItemVariants} from '../../utils/utils';
@Component({
tag: 'hy-menu-item',
styleUrl: 'menu-item.scss',
shadow: true
})
export class MenuItem {
@Element() el: HTMLElement;
@Prop() variant: MenuItemVariants = MenuItemVariants.default;
@Prop() inActiveTrail: boolean = false;
@Prop() isActive: boolean = false;
@Prop() isHeading: boolean = false;
@Prop() menuItemAlternative: boolean = false;
@Prop() menuLinkId: string = '';
@Prop({mutable: true}) url: string = '';
@Prop({mutable: true}) label: string = '';
@Prop({mutable: true}) ariaExpanded: boolean = false;
@Prop({mutable: true, reflect: true}) depth: number = 0;
@Prop({mutable: true}) hasChildren: boolean = null;
@Prop({mutable: true, reflect: true}) parentExpanded: boolean = false;
@Prop({mutable: true}) parentAsHeading: string = '';
@Event() routeClicked: EventEmitter;
@Event() menuContainerToggled: EventEmitter;
@Event() menuContainerActiveTrail: EventEmitter;
@Event() addBreadcrumb: EventEmitter;
@Listen('handleClick', {capture: true}) handleClick() {
this.menuContainerToggled.emit({triggerItem: this.menuLinkId});
const currentParent = this.el.parentNode;
this.addBreadcrumb.emit({
url: this.url,
label: currentParent.parentElement.getAttribute('label'),
bid: this.menuLinkId
});
}
componentWillLoad() {
// Notify breadcrumbs if item is in active trail.
if (this.inActiveTrail && !this.isActive) {
const currentParent = this.el.parentNode;
this.addBreadcrumb.emit({
url: this.url,
label: currentParent.parentElement.getAttribute('label'),
bid: this.menuLinkId
});
}
// Trigger all parent menuLevelContainer elements in the same active-trail
// to open the menu.
if (this.isActive) {
const getParents = (elem) => {
let parents = [];
while (elem.parentNode && elem.parentNode.nodeName.toLowerCase() != 'hy-menu-mobile') {
elem = elem.parentNode;
parents.push(elem);
}
return parents;
};
const parents = getParents(this.el);
parents.forEach((element) => {
if (element.tagName.toLowerCase() === 'hy-menu-item') {
this.menuContainerActiveTrail.emit({triggerItem: element.getAttribute('menu-link-id')});
}
});
}
}
componentWillRender() {
this.hasChildren = !!this.el.hasChildNodes();
let parentMenu = this.el.closest('hy-menu-item');
let nextParentMenu;
this.depth = 0;
while (parentMenu) {
nextParentMenu = parentMenu.parentElement.closest('hy-menu-item');
if (nextParentMenu === parentMenu) {
break;
} else {
if (nextParentMenu !== null) {
this.parentAsHeading = nextParentMenu;
}
parentMenu = nextParentMenu;
this.depth = this.depth + 1;
}
}
}
render() {
return (
<Host
class={{
'is-active': this.isActive,
'menu-item--alternative': this.menuItemAlternative,
'hy-menu-item': true
}}
>
<a
aria-current={this.isHeading.toString()}
href={this.url}
class={{
'is-active': this.isActive,
'in-active-trail': this.inActiveTrail,
'is-heading': this.isHeading
}}
>
<span class={'hy-menu-item__label'}>{this.label}</span>
</a>
{this.hasChildren && (
<button
// TODO: Fix aria-label translation.
Markus Kalijärvi
committed
aria-label={`Open submenu for ${this.label}`}
onClick={() => this.handleClick()}
class={'hy-menu-item__button'}
>
<hy-icon icon={'hy-icon-caret-right'} size={12} />
</button>
)}
{this.hasChildren && <slot />}
</Host>
);
}
}