<nav class="languages ">
<button type="button" class="languages__trigger" aria-label="Toggle language menu" aria-expanded="false">
eng
<svg class="icon languages__chevron">
<use xlink:href="../../inc/svg/global.bc9cdd731ad718497c5d8f03d08908d4.svg#chevron-bottom"></use>
</svg>
</button>
<ul class="languages__list">
<li class="languages__item ">
<a href="#" class="languages__link" aria-label="Estonian ">est</a>
</li>
<li class="languages__item is-current">
<a href="#" class="languages__link" aria-label="English - current language">eng</a>
</li>
<li class="languages__item ">
<a href="#" class="languages__link" aria-label="Russian ">rus</a>
</li>
</ul>
</nav>
<nav class="languages {{ modifier }} {{ class }}">
{% for item in data.items %}
{% if item.current %}
<button type="button" class="languages__trigger" aria-label="{{ data.label }}" aria-expanded="false">
{{ item.shortName }}
{% include '@icon' with { name: 'chevron-bottom', class: 'languages__chevron' } %}
</button>
{% endif %}
{% endfor %}
{% if data.items %}
<ul class="languages__list">
{% for item in data.items %}
<li class="languages__item {% if item.current %}is-current{% endif %}">
<a href="{{ item.link }}" class="languages__link" aria-label="{{ item.fullName }} {% if item.current and data.currentLabel %}{{ '- ' ~ data.currentLabel }}{% endif %}">{{ item.shortName }}</a>
</li>
{% endfor %}
</ul>
{% endif %}
</nav>
{
"language": "en-US",
"data": {
"label": "Toggle language menu",
"currentLabel": "current language",
"items": [
{
"link": "#",
"shortName": "est",
"fullName": "Estonian"
},
{
"link": "#",
"shortName": "eng",
"fullName": "English",
"current": "true"
},
{
"link": "#",
"shortName": "rus",
"fullName": "Russian"
}
]
}
}
.languages {
position: relative;
display: inline-block;
text-transform: uppercase;
z-index: map-get($zindex, 'languages');
overflow: hidden;
&.is-active {
overflow: visible;
}
}
.languages__trigger {
appearance: none;
text-align: center;
background: transparent;
border: none;
text-transform: uppercase;
margin: 0;
padding: 12px 50px 12px 24px;
align-items: center;
cursor: pointer;
color: $color-text-01;
}
.languages__link {
display: block;
color: $color-text-01;
text-decoration: none;
padding: 12px 16px;
&:hover {
background-color: $color-ui-03;
}
}
.languages__chevron {
position: absolute;
top: 0;
bottom: 0;
right: 24px;
font-size: 24px;
margin: auto 0 auto 4px;
pointer-events: none;
@include bp(md-min) {
margin: auto 0;
}
.languages.is-active & {
transform: rotate(180deg);
}
}
.languages__list {
position: absolute;
top: 100%;
right: 0;
z-index: map-get($zindex, 'default');
background-color: $color-ui-01;
border-radius: $border-radius-base;
box-shadow: $elevation-05;
padding: 4px 0;
display: inline-block;
opacity: 0;
visibility: hidden;
transition: visibility $transition-duration $transition-easing, opacity $transition-duration $transition-easing;
.languages.to-top & {
top: auto;
bottom: 100%;
}
.languages.is-active & {
opacity: 1;
visibility: visible;
}
}
import Component from '../component/component';
import './languages.scss';
interface ILanguageSettings {
activeClass: string;
topClass: string;
}
export default class Languages extends Component {
static initSelector: string = '.languages';
public trigger: JQuery;
settings: ILanguageSettings;
constructor(target: HTMLElement) {
super(target);
this.trigger = this.element.find('.languages__trigger');
this.documentClickHandler = this.documentClickHandler.bind(this);
this.settings = {
activeClass: 'is-active',
topClass: 'to-top',
};
this.init();
}
init(): void {
this.trigger.on('click', this.toggleHandler.bind(this));
this.element.on('keyup.languages', this.keyboardHandler.bind(this));
}
addEventListeners(): void {
$(document).on('click.languages', this.documentClickHandler);
}
documentClickHandler(event: JQuery.TriggeredEvent): void {
if ($(event.target).closest(this.element).length === 0) {
this.close();
}
}
toggleHandler(event: Event): void {
event.preventDefault();
if (this.element.hasClass(this.settings.activeClass)) {
this.close();
} else {
this.open();
}
}
keyboardHandler(event: KeyboardEvent): void {
if (event.key === 'Escape') {
this.close();
this.trigger.focus();
}
}
open(): void {
if (this.getListDirection() === 'top') {
this.element.addClass(this.settings.topClass);
} else {
this.element.removeClass(this.settings.topClass);
}
this.element.addClass(this.settings.activeClass);
this.trigger.attr('aria-expanded', 'true');
this.addEventListeners();
}
close(): void {
this.element.removeClass(this.settings.activeClass);
this.trigger.attr('aria-expanded', 'false');
this.destroy();
}
getListDirection(): 'top' | 'bottom' {
const elemTop: number = this.element.offset().top;
const windowTop: number = $(window).scrollTop();
const windowHeight: number = $(window).height();
const elemHeight: number = this.element.outerHeight();
const ddHeight: number = this.element.find('.languages__list').outerHeight();
if ((elemTop - windowTop + elemHeight + ddHeight) > windowHeight) {
return 'top';
} else {
return 'bottom';
}
}
destroy(): void {
$(document).off('click.languages', this.documentClickHandler);
}
}