@dodlhuat/basix 1.2.0 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +266 -6
- package/css/accordion.scss +86 -87
- package/css/alert.scss +137 -137
- package/css/button.scss +48 -0
- package/css/calendar.scss +957 -0
- package/css/card.scss +65 -65
- package/css/chart.scss +270 -157
- package/css/chat-bubbles.scss +134 -68
- package/css/chips.scss +109 -19
- package/css/colors.scss +32 -32
- package/css/datepicker.scss +336 -336
- package/css/defaults.scss +90 -90
- package/css/docs.scss +529 -0
- package/css/editor.scss +36 -0
- package/css/file-uploader.scss +1 -1
- package/css/flyout-menu.scss +361 -361
- package/css/form.scss +0 -15
- package/css/gallery.scss +65 -6
- package/css/grid.scss +41 -40
- package/css/group-picker.scss +345 -0
- package/css/guitar-chords.css +250 -250
- package/css/icons.scss +330 -330
- package/css/parameters.scss +3 -3
- package/css/placeholder.scss +33 -33
- package/css/popover.scss +206 -0
- package/css/progress.scss +76 -32
- package/css/properties.scss +51 -36
- package/css/push-menu.scss +302 -174
- package/css/reset.scss +39 -39
- package/css/scrollbar.scss +62 -5
- package/css/sidebar-nav.scss +92 -0
- package/css/spinner.scss +65 -65
- package/css/stepper.scss +48 -12
- package/css/style.css +3155 -254
- package/css/style.css.map +1 -1
- package/css/style.min.css +1 -1
- package/css/style.scss +51 -45
- package/css/table.scss +199 -199
- package/css/tabs.scss +154 -123
- package/css/timeline.scss +83 -38
- package/css/timepicker.scss +100 -5
- package/css/toast.scss +81 -81
- package/css/virtual-dropdown.scss +35 -29
- package/js/calendar.js +532 -0
- package/js/calendar.ts +706 -0
- package/js/chart.js +573 -257
- package/js/chart.ts +692 -0
- package/js/code-viewer.js +10 -10
- package/js/code-viewer.ts +188 -188
- package/js/datepicker.ts +627 -627
- package/js/docs-nav.js +204 -0
- package/js/dropdown.ts +179 -179
- package/js/editor.js +50 -6
- package/js/editor.ts +483 -444
- package/js/file-uploader.js +1 -0
- package/js/file-uploader.ts +1 -0
- package/js/flyout-menu.js +14 -14
- package/js/flyout-menu.ts +249 -249
- package/js/form-builder.js +106 -106
- package/js/gallery.js +14 -8
- package/js/gallery.ts +245 -236
- package/js/group-picker.js +342 -0
- package/js/group-picker.ts +447 -0
- package/js/guitar-chords.js +268 -268
- package/js/lazy-loader.js +121 -121
- package/js/modal.ts +166 -166
- package/js/popover.js +163 -0
- package/js/popover.ts +219 -0
- package/js/position.js +108 -0
- package/js/position.ts +111 -0
- package/js/push-menu.js +113 -0
- package/js/push-menu.ts +284 -145
- package/js/request.js +50 -50
- package/js/scroll.ts +47 -47
- package/js/scrollbar.js +13 -0
- package/js/scrollbar.ts +324 -307
- package/js/select.ts +216 -216
- package/js/sidebar-nav.js +41 -0
- package/js/sidebar-nav.ts +66 -0
- package/js/table.ts +452 -452
- package/js/tabs.ts +279 -279
- package/js/theme.js +17 -6
- package/js/theme.ts +234 -224
- package/js/toast.ts +137 -137
- package/js/tooltip.js +6 -60
- package/js/tooltip.ts +184 -251
- package/js/tsconfig.json +18 -18
- package/js/utils.ts +83 -83
- package/js/virtual-dropdown.js +25 -25
- package/js/virtual-dropdown.ts +365 -365
- package/package.json +37 -39
- package/js/index.js +0 -816
- package/js/index.ts +0 -987
package/js/select.ts
CHANGED
|
@@ -1,217 +1,217 @@
|
|
|
1
|
-
class Select {
|
|
2
|
-
private readonly element: HTMLSelectElement;
|
|
3
|
-
private readonly isMultiselect: boolean;
|
|
4
|
-
|
|
5
|
-
constructor(elementOrSelector: string | HTMLSelectElement) {
|
|
6
|
-
const element = typeof elementOrSelector === 'string'
|
|
7
|
-
? document.querySelector<HTMLSelectElement>(elementOrSelector)
|
|
8
|
-
: elementOrSelector;
|
|
9
|
-
|
|
10
|
-
if (!element) {
|
|
11
|
-
throw new Error(`Select: Element not found for selector "${elementOrSelector}"`);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
this.element = element;
|
|
15
|
-
const result = Select.initElement(element);
|
|
16
|
-
|
|
17
|
-
if (result === null) {
|
|
18
|
-
throw new Error(`Select: Failed to initialize select for "${elementOrSelector}"`);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
this.isMultiselect = result;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public value(): string | string[] | undefined {
|
|
25
|
-
if (!this.element) {
|
|
26
|
-
return undefined;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const selectedValues = Array.from(this.element.options)
|
|
30
|
-
.filter(option => option.selected)
|
|
31
|
-
.map(option => option.value);
|
|
32
|
-
|
|
33
|
-
return this.isMultiselect ? selectedValues : selectedValues[0];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
public static init(elementOrSelector: string | HTMLSelectElement): boolean | null {
|
|
37
|
-
const element = typeof elementOrSelector === 'string'
|
|
38
|
-
? document.querySelector<HTMLSelectElement>(elementOrSelector)
|
|
39
|
-
: elementOrSelector;
|
|
40
|
-
|
|
41
|
-
if (!element) {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return Select.initElement(element);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
private static initElement(element: HTMLSelectElement): boolean | null {
|
|
49
|
-
if (!Select.transformSelect(element)) {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const selectGroup = element.closest('.select-group');
|
|
54
|
-
if (!selectGroup) {
|
|
55
|
-
throw new Error(`Select: Parent .select-group not found for "${element}"`);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const dropdown = selectGroup.querySelector('.dropdown') as HTMLElement | null;
|
|
59
|
-
if (!dropdown) {
|
|
60
|
-
throw new Error(`Select: Dropdown element not found for "${element}"`);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const selected = dropdown.querySelector('.dropdown-selected') as HTMLElement | null;
|
|
64
|
-
const options = dropdown.querySelector('.dropdown-options') as HTMLElement | null;
|
|
65
|
-
|
|
66
|
-
if (!selected || !options) {
|
|
67
|
-
throw new Error(`Select: Required dropdown elements not found for "${element}"`);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const isMulti = dropdown.dataset.multi === 'true';
|
|
71
|
-
|
|
72
|
-
// Toggle dropdown on selected element click
|
|
73
|
-
selected.addEventListener('click', () => {
|
|
74
|
-
Select.closeAllDropdowns(dropdown);
|
|
75
|
-
dropdown.classList.toggle('open');
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
// Handle option selection
|
|
79
|
-
options.addEventListener('click', (e: Event) => {
|
|
80
|
-
const target = e.target as HTMLElement;
|
|
81
|
-
|
|
82
|
-
if (!target.classList.contains('dropdown-option')) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (isMulti) {
|
|
87
|
-
Select.handleMultiSelect(target, options, selected, element);
|
|
88
|
-
} else {
|
|
89
|
-
Select.handleSingleSelect(target, options, selected, dropdown, element);
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
// Close dropdown when clicking the close icon
|
|
94
|
-
const closeIcon = options.querySelector('.dropdown-options-icon') as HTMLElement | null;
|
|
95
|
-
if (closeIcon) {
|
|
96
|
-
closeIcon.addEventListener('click', () => {
|
|
97
|
-
dropdown.classList.remove('open');
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Close dropdown when clicking outside
|
|
102
|
-
document.addEventListener('click', (e: Event) => {
|
|
103
|
-
if (!dropdown.contains(e.target as Node)) {
|
|
104
|
-
dropdown.classList.remove('open');
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
return isMulti;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
private static closeAllDropdowns(exceptDropdown?: HTMLElement): void {
|
|
112
|
-
document.querySelectorAll('.dropdown').forEach(dropdown => {
|
|
113
|
-
if (dropdown !== exceptDropdown) {
|
|
114
|
-
dropdown.classList.remove('open');
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
private static handleMultiSelect(
|
|
120
|
-
option: HTMLElement,
|
|
121
|
-
optionsContainer: HTMLElement,
|
|
122
|
-
selected: HTMLElement,
|
|
123
|
-
selectElement: HTMLSelectElement
|
|
124
|
-
): void {
|
|
125
|
-
option.classList.toggle('selected');
|
|
126
|
-
|
|
127
|
-
const selectedOptions = Array.from(
|
|
128
|
-
optionsContainer.querySelectorAll('.dropdown-option.selected')
|
|
129
|
-
) as HTMLElement[];
|
|
130
|
-
|
|
131
|
-
const values = selectedOptions.map(opt => opt.textContent?.trim() || '');
|
|
132
|
-
selected.textContent = values.length ? values.join(', ') : 'Select options';
|
|
133
|
-
|
|
134
|
-
const selectedValues = selectedOptions.map(opt => opt.dataset.value || '');
|
|
135
|
-
Array.from(selectElement.options).forEach(opt => {
|
|
136
|
-
opt.selected = selectedValues.includes(opt.value);
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
private static handleSingleSelect(
|
|
141
|
-
option: HTMLElement,
|
|
142
|
-
optionsContainer: HTMLElement,
|
|
143
|
-
selected: HTMLElement,
|
|
144
|
-
dropdown: HTMLElement,
|
|
145
|
-
selectElement: HTMLSelectElement
|
|
146
|
-
): void {
|
|
147
|
-
optionsContainer.querySelectorAll('.dropdown-option').forEach(opt => {
|
|
148
|
-
opt.classList.remove('selected');
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
option.classList.add('selected');
|
|
152
|
-
selected.textContent = option.textContent?.trim() || '';
|
|
153
|
-
dropdown.classList.remove('open');
|
|
154
|
-
selectElement.value = option.dataset.value || '';
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
private static transformSelect(select: HTMLSelectElement): boolean {
|
|
158
|
-
const parent = select.closest('.select-group') as HTMLElement | null;
|
|
159
|
-
|
|
160
|
-
if (!parent) {
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const label = parent.querySelector('label');
|
|
165
|
-
const isMulti = select.hasAttribute('multiple');
|
|
166
|
-
const labelText = label?.textContent?.trim() || 'Select';
|
|
167
|
-
|
|
168
|
-
// Create hidden wrapper for original select
|
|
169
|
-
const hiddenWrapper = document.createElement('div');
|
|
170
|
-
hiddenWrapper.classList.add('hidden');
|
|
171
|
-
|
|
172
|
-
if (label) {
|
|
173
|
-
hiddenWrapper.appendChild(label);
|
|
174
|
-
}
|
|
175
|
-
hiddenWrapper.appendChild(select);
|
|
176
|
-
|
|
177
|
-
// Create dropdown structure
|
|
178
|
-
const dropdown = document.createElement('div');
|
|
179
|
-
dropdown.className = 'dropdown';
|
|
180
|
-
dropdown.dataset.multi = String(isMulti);
|
|
181
|
-
|
|
182
|
-
const dropdownSelected = document.createElement('div');
|
|
183
|
-
dropdownSelected.className = 'dropdown-selected';
|
|
184
|
-
dropdownSelected.textContent = labelText;
|
|
185
|
-
|
|
186
|
-
const dropdownOptions = document.createElement('div');
|
|
187
|
-
dropdownOptions.className = 'dropdown-options';
|
|
188
|
-
|
|
189
|
-
// Add mobile menu
|
|
190
|
-
const optionsMenu = document.createElement('div');
|
|
191
|
-
optionsMenu.className = 'dropdown-options-menu hidden';
|
|
192
|
-
optionsMenu.innerHTML = 'Select options<span class="dropdown-options-icon icon icon-close"></span>';
|
|
193
|
-
dropdownOptions.appendChild(optionsMenu);
|
|
194
|
-
|
|
195
|
-
// Create option elements
|
|
196
|
-
Array.from(select.options).forEach(opt => {
|
|
197
|
-
const optDiv = document.createElement('div');
|
|
198
|
-
optDiv.className = 'dropdown-option';
|
|
199
|
-
optDiv.dataset.value = opt.value;
|
|
200
|
-
optDiv.textContent = opt.textContent;
|
|
201
|
-
dropdownOptions.appendChild(optDiv);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
// Assemble dropdown
|
|
205
|
-
dropdown.appendChild(dropdownSelected);
|
|
206
|
-
dropdown.appendChild(dropdownOptions);
|
|
207
|
-
|
|
208
|
-
// Replace original content
|
|
209
|
-
parent.innerHTML = '';
|
|
210
|
-
parent.appendChild(hiddenWrapper);
|
|
211
|
-
parent.appendChild(dropdown);
|
|
212
|
-
|
|
213
|
-
return true;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
1
|
+
class Select {
|
|
2
|
+
private readonly element: HTMLSelectElement;
|
|
3
|
+
private readonly isMultiselect: boolean;
|
|
4
|
+
|
|
5
|
+
constructor(elementOrSelector: string | HTMLSelectElement) {
|
|
6
|
+
const element = typeof elementOrSelector === 'string'
|
|
7
|
+
? document.querySelector<HTMLSelectElement>(elementOrSelector)
|
|
8
|
+
: elementOrSelector;
|
|
9
|
+
|
|
10
|
+
if (!element) {
|
|
11
|
+
throw new Error(`Select: Element not found for selector "${elementOrSelector}"`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
this.element = element;
|
|
15
|
+
const result = Select.initElement(element);
|
|
16
|
+
|
|
17
|
+
if (result === null) {
|
|
18
|
+
throw new Error(`Select: Failed to initialize select for "${elementOrSelector}"`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
this.isMultiselect = result;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public value(): string | string[] | undefined {
|
|
25
|
+
if (!this.element) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const selectedValues = Array.from(this.element.options)
|
|
30
|
+
.filter(option => option.selected)
|
|
31
|
+
.map(option => option.value);
|
|
32
|
+
|
|
33
|
+
return this.isMultiselect ? selectedValues : selectedValues[0];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public static init(elementOrSelector: string | HTMLSelectElement): boolean | null {
|
|
37
|
+
const element = typeof elementOrSelector === 'string'
|
|
38
|
+
? document.querySelector<HTMLSelectElement>(elementOrSelector)
|
|
39
|
+
: elementOrSelector;
|
|
40
|
+
|
|
41
|
+
if (!element) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return Select.initElement(element);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private static initElement(element: HTMLSelectElement): boolean | null {
|
|
49
|
+
if (!Select.transformSelect(element)) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const selectGroup = element.closest('.select-group');
|
|
54
|
+
if (!selectGroup) {
|
|
55
|
+
throw new Error(`Select: Parent .select-group not found for "${element}"`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const dropdown = selectGroup.querySelector('.dropdown') as HTMLElement | null;
|
|
59
|
+
if (!dropdown) {
|
|
60
|
+
throw new Error(`Select: Dropdown element not found for "${element}"`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const selected = dropdown.querySelector('.dropdown-selected') as HTMLElement | null;
|
|
64
|
+
const options = dropdown.querySelector('.dropdown-options') as HTMLElement | null;
|
|
65
|
+
|
|
66
|
+
if (!selected || !options) {
|
|
67
|
+
throw new Error(`Select: Required dropdown elements not found for "${element}"`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const isMulti = dropdown.dataset.multi === 'true';
|
|
71
|
+
|
|
72
|
+
// Toggle dropdown on selected element click
|
|
73
|
+
selected.addEventListener('click', () => {
|
|
74
|
+
Select.closeAllDropdowns(dropdown);
|
|
75
|
+
dropdown.classList.toggle('open');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Handle option selection
|
|
79
|
+
options.addEventListener('click', (e: Event) => {
|
|
80
|
+
const target = e.target as HTMLElement;
|
|
81
|
+
|
|
82
|
+
if (!target.classList.contains('dropdown-option')) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (isMulti) {
|
|
87
|
+
Select.handleMultiSelect(target, options, selected, element);
|
|
88
|
+
} else {
|
|
89
|
+
Select.handleSingleSelect(target, options, selected, dropdown, element);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Close dropdown when clicking the close icon
|
|
94
|
+
const closeIcon = options.querySelector('.dropdown-options-icon') as HTMLElement | null;
|
|
95
|
+
if (closeIcon) {
|
|
96
|
+
closeIcon.addEventListener('click', () => {
|
|
97
|
+
dropdown.classList.remove('open');
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Close dropdown when clicking outside
|
|
102
|
+
document.addEventListener('click', (e: Event) => {
|
|
103
|
+
if (!dropdown.contains(e.target as Node)) {
|
|
104
|
+
dropdown.classList.remove('open');
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return isMulti;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private static closeAllDropdowns(exceptDropdown?: HTMLElement): void {
|
|
112
|
+
document.querySelectorAll('.dropdown').forEach(dropdown => {
|
|
113
|
+
if (dropdown !== exceptDropdown) {
|
|
114
|
+
dropdown.classList.remove('open');
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private static handleMultiSelect(
|
|
120
|
+
option: HTMLElement,
|
|
121
|
+
optionsContainer: HTMLElement,
|
|
122
|
+
selected: HTMLElement,
|
|
123
|
+
selectElement: HTMLSelectElement
|
|
124
|
+
): void {
|
|
125
|
+
option.classList.toggle('selected');
|
|
126
|
+
|
|
127
|
+
const selectedOptions = Array.from(
|
|
128
|
+
optionsContainer.querySelectorAll('.dropdown-option.selected')
|
|
129
|
+
) as HTMLElement[];
|
|
130
|
+
|
|
131
|
+
const values = selectedOptions.map(opt => opt.textContent?.trim() || '');
|
|
132
|
+
selected.textContent = values.length ? values.join(', ') : 'Select options';
|
|
133
|
+
|
|
134
|
+
const selectedValues = selectedOptions.map(opt => opt.dataset.value || '');
|
|
135
|
+
Array.from(selectElement.options).forEach(opt => {
|
|
136
|
+
opt.selected = selectedValues.includes(opt.value);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private static handleSingleSelect(
|
|
141
|
+
option: HTMLElement,
|
|
142
|
+
optionsContainer: HTMLElement,
|
|
143
|
+
selected: HTMLElement,
|
|
144
|
+
dropdown: HTMLElement,
|
|
145
|
+
selectElement: HTMLSelectElement
|
|
146
|
+
): void {
|
|
147
|
+
optionsContainer.querySelectorAll('.dropdown-option').forEach(opt => {
|
|
148
|
+
opt.classList.remove('selected');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
option.classList.add('selected');
|
|
152
|
+
selected.textContent = option.textContent?.trim() || '';
|
|
153
|
+
dropdown.classList.remove('open');
|
|
154
|
+
selectElement.value = option.dataset.value || '';
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private static transformSelect(select: HTMLSelectElement): boolean {
|
|
158
|
+
const parent = select.closest('.select-group') as HTMLElement | null;
|
|
159
|
+
|
|
160
|
+
if (!parent) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const label = parent.querySelector('label');
|
|
165
|
+
const isMulti = select.hasAttribute('multiple');
|
|
166
|
+
const labelText = label?.textContent?.trim() || 'Select';
|
|
167
|
+
|
|
168
|
+
// Create hidden wrapper for original select
|
|
169
|
+
const hiddenWrapper = document.createElement('div');
|
|
170
|
+
hiddenWrapper.classList.add('hidden');
|
|
171
|
+
|
|
172
|
+
if (label) {
|
|
173
|
+
hiddenWrapper.appendChild(label);
|
|
174
|
+
}
|
|
175
|
+
hiddenWrapper.appendChild(select);
|
|
176
|
+
|
|
177
|
+
// Create dropdown structure
|
|
178
|
+
const dropdown = document.createElement('div');
|
|
179
|
+
dropdown.className = 'dropdown';
|
|
180
|
+
dropdown.dataset.multi = String(isMulti);
|
|
181
|
+
|
|
182
|
+
const dropdownSelected = document.createElement('div');
|
|
183
|
+
dropdownSelected.className = 'dropdown-selected';
|
|
184
|
+
dropdownSelected.textContent = labelText;
|
|
185
|
+
|
|
186
|
+
const dropdownOptions = document.createElement('div');
|
|
187
|
+
dropdownOptions.className = 'dropdown-options';
|
|
188
|
+
|
|
189
|
+
// Add mobile menu
|
|
190
|
+
const optionsMenu = document.createElement('div');
|
|
191
|
+
optionsMenu.className = 'dropdown-options-menu hidden';
|
|
192
|
+
optionsMenu.innerHTML = 'Select options<span class="dropdown-options-icon icon icon-close"></span>';
|
|
193
|
+
dropdownOptions.appendChild(optionsMenu);
|
|
194
|
+
|
|
195
|
+
// Create option elements
|
|
196
|
+
Array.from(select.options).forEach(opt => {
|
|
197
|
+
const optDiv = document.createElement('div');
|
|
198
|
+
optDiv.className = 'dropdown-option';
|
|
199
|
+
optDiv.dataset.value = opt.value;
|
|
200
|
+
optDiv.textContent = opt.textContent;
|
|
201
|
+
dropdownOptions.appendChild(optDiv);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Assemble dropdown
|
|
205
|
+
dropdown.appendChild(dropdownSelected);
|
|
206
|
+
dropdown.appendChild(dropdownOptions);
|
|
207
|
+
|
|
208
|
+
// Replace original content
|
|
209
|
+
parent.innerHTML = '';
|
|
210
|
+
parent.appendChild(hiddenWrapper);
|
|
211
|
+
parent.appendChild(dropdown);
|
|
212
|
+
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
217
|
export { Select };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
class SidebarNav {
|
|
2
|
+
constructor(containerOrSelector, options = {}) {
|
|
3
|
+
const container = typeof containerOrSelector === 'string'
|
|
4
|
+
? document.querySelector(containerOrSelector)
|
|
5
|
+
: containerOrSelector;
|
|
6
|
+
this.opts = {
|
|
7
|
+
toggleSelector: options.toggleSelector ?? '.sidebar-toggle',
|
|
8
|
+
breakpoint: options.breakpoint ?? 768,
|
|
9
|
+
};
|
|
10
|
+
this.nav = container?.querySelector('.sidebar-nav') ?? null;
|
|
11
|
+
this.backdrop = container?.querySelector('.sidebar-backdrop') ?? null;
|
|
12
|
+
this.toggleBtn = document.querySelector(this.opts.toggleSelector);
|
|
13
|
+
this._onToggle = () => this.toggle();
|
|
14
|
+
this._onBackdrop = () => this.close();
|
|
15
|
+
this._onResize = () => { if (window.innerWidth > this.opts.breakpoint)
|
|
16
|
+
this.close(); };
|
|
17
|
+
this.toggleBtn?.addEventListener('click', this._onToggle);
|
|
18
|
+
this.backdrop?.addEventListener('click', this._onBackdrop);
|
|
19
|
+
window.addEventListener('resize', this._onResize);
|
|
20
|
+
}
|
|
21
|
+
open() {
|
|
22
|
+
this.nav?.classList.add('is-open');
|
|
23
|
+
this.backdrop?.classList.add('is-visible');
|
|
24
|
+
}
|
|
25
|
+
close() {
|
|
26
|
+
this.nav?.classList.remove('is-open');
|
|
27
|
+
this.backdrop?.classList.remove('is-visible');
|
|
28
|
+
}
|
|
29
|
+
toggle() {
|
|
30
|
+
this.nav?.classList.contains('is-open') ? this.close() : this.open();
|
|
31
|
+
}
|
|
32
|
+
isOpen() {
|
|
33
|
+
return this.nav?.classList.contains('is-open') ?? false;
|
|
34
|
+
}
|
|
35
|
+
destroy() {
|
|
36
|
+
this.toggleBtn?.removeEventListener('click', this._onToggle);
|
|
37
|
+
this.backdrop?.removeEventListener('click', this._onBackdrop);
|
|
38
|
+
window.removeEventListener('resize', this._onResize);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export { SidebarNav };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
interface SidebarNavOptions {
|
|
2
|
+
/** Selector for the toggle button. Default: '.sidebar-toggle' */
|
|
3
|
+
toggleSelector?: string;
|
|
4
|
+
/** Breakpoint (px) above which the sidebar is always visible. Default: 768 */
|
|
5
|
+
breakpoint?: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
class SidebarNav {
|
|
9
|
+
private nav: HTMLElement | null;
|
|
10
|
+
private backdrop: HTMLElement | null;
|
|
11
|
+
private toggleBtn: HTMLElement | null;
|
|
12
|
+
private opts: Required<SidebarNavOptions>;
|
|
13
|
+
private _onToggle: () => void;
|
|
14
|
+
private _onBackdrop: () => void;
|
|
15
|
+
private _onResize: () => void;
|
|
16
|
+
|
|
17
|
+
constructor(containerOrSelector: string | HTMLElement, options: SidebarNavOptions = {}) {
|
|
18
|
+
const container: HTMLElement | null =
|
|
19
|
+
typeof containerOrSelector === 'string'
|
|
20
|
+
? (document.querySelector(containerOrSelector) as HTMLElement | null)
|
|
21
|
+
: containerOrSelector;
|
|
22
|
+
|
|
23
|
+
this.opts = {
|
|
24
|
+
toggleSelector: options.toggleSelector ?? '.sidebar-toggle',
|
|
25
|
+
breakpoint: options.breakpoint ?? 768,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
this.nav = container?.querySelector('.sidebar-nav') ?? null;
|
|
29
|
+
this.backdrop = container?.querySelector('.sidebar-backdrop') ?? null;
|
|
30
|
+
this.toggleBtn = document.querySelector(this.opts.toggleSelector);
|
|
31
|
+
|
|
32
|
+
this._onToggle = () => this.toggle();
|
|
33
|
+
this._onBackdrop = () => this.close();
|
|
34
|
+
this._onResize = () => { if (window.innerWidth > this.opts.breakpoint) this.close(); };
|
|
35
|
+
|
|
36
|
+
this.toggleBtn?.addEventListener('click', this._onToggle);
|
|
37
|
+
this.backdrop?.addEventListener('click', this._onBackdrop);
|
|
38
|
+
window.addEventListener('resize', this._onResize);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
open(): void {
|
|
42
|
+
this.nav?.classList.add('is-open');
|
|
43
|
+
this.backdrop?.classList.add('is-visible');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
close(): void {
|
|
47
|
+
this.nav?.classList.remove('is-open');
|
|
48
|
+
this.backdrop?.classList.remove('is-visible');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
toggle(): void {
|
|
52
|
+
this.nav?.classList.contains('is-open') ? this.close() : this.open();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
isOpen(): boolean {
|
|
56
|
+
return this.nav?.classList.contains('is-open') ?? false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
destroy(): void {
|
|
60
|
+
this.toggleBtn?.removeEventListener('click', this._onToggle);
|
|
61
|
+
this.backdrop?.removeEventListener('click', this._onBackdrop);
|
|
62
|
+
window.removeEventListener('resize', this._onResize);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export { SidebarNav, SidebarNavOptions };
|