This repository has been archived by the owner on Oct 18, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.ts
129 lines (109 loc) · 3.65 KB
/
index.ts
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import { CSSResultGroup, LitElement, PropertyValueMap, html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { WebComponentsBase } from '../base';
import { dropdownStyle } from './index.style';
const WebComponentsBaseElement = WebComponentsBase(LitElement);
const styles: CSSResultGroup[] = [WebComponentsBaseElement.styles, dropdownStyle];
@customElement('superviz-dropdown')
export class Dropdown extends WebComponentsBaseElement {
static styles = styles;
declare open: boolean;
declare disabled: boolean;
declare align: 'left' | 'right';
declare position: 'bottom-left' | 'bottom-center' | 'bottom-right';
declare options: object[];
declare label: string;
declare returnTo: string;
declare active: string | object;
static properties = {
open: { type: Boolean },
disabled: { type: Boolean },
align: { type: String },
position: { type: String },
options: { type: Array },
label: { type: String },
returnTo: { type: String },
active: { type: [String, Object] },
};
protected updated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {
if (_changedProperties.has('open')) {
if (this.open) {
document.addEventListener('click', this.onClickOutDropdown);
}
if (!this.open) {
document.removeEventListener('click', this.onClickOutDropdown);
this.close();
}
}
}
private onClickOutDropdown = (event: Event) => {
event.stopPropagation();
if (!this.open) return;
const elements = event.composedPath();
const dropdownContent = this.shadowRoot.querySelector('.dropdown-content');
const dropdownList = this.shadowRoot.querySelector('.dropdown-list');
const slotDropdown = this.shadowRoot.querySelector('slot[name="dropdown"]') as HTMLSlotElement;
const dropdownCta = slotDropdown.assignedElements()[0];
const hasDropdownContent = elements.includes(dropdownContent);
const hasDropdownList = elements.includes(dropdownList);
const hasDropdownCta = elements.includes(dropdownCta);
if (!(hasDropdownContent || hasDropdownList || hasDropdownCta)) {
this.open = false;
}
};
private close = () => {
this.emitEvent('close', {
bubbles: false,
composed: false,
});
};
private callbackSelected = (option: any) => {
this.open = false;
const returnTo = this.returnTo
? option[this.returnTo]
: option;
this.emitEvent(
'selected',
returnTo,
{
bubbles: false,
composed: false,
},
);
};
protected render() {
const menuClasses = {
menu: true,
'menu--bottom-left': this.position === 'bottom-left',
'menu--bottom-center': this.position === 'bottom-center',
'menu--bottom-right': this.position === 'bottom-right',
'menu-open': this.open,
'menu-left': this.align === 'left',
'menu-right': this.align === 'right',
};
const options = this.options.map((option: any) => {
const liClasses = {
text: true,
'text-bold': true,
active: this.active === option?.[this.returnTo],
};
return html`<li @click=${() => this.callbackSelected(option)} class=${classMap(liClasses)}>${option[this.label]}</li>`;
});
const toggle = () => {
this.open = !this.open;
};
return html`
<div class="dropdown">
<div class="dropdown-content" @click=${() => toggle()}>
<slot name="dropdown"></slot>
</div>
</div>
<div class="dropdown-list">
<ul class=${classMap(menuClasses)}>
${options}
</ul>
</div>
`;
}
}