@kupola/kupola 1.6.2 → 1.6.4
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/dist/kupola.cjs.js +4 -4
- package/dist/kupola.cjs.js.map +1 -1
- package/dist/kupola.esm.js +57 -42
- package/dist/kupola.esm.js.map +1 -1
- package/dist/kupola.umd.js +8 -8
- package/dist/kupola.umd.js.map +1 -1
- package/js/dropdown.js +50 -10
- package/js/initializer.js +4 -2
- package/js/select.js +28 -6
- package/package.json +1 -1
package/js/dropdown.js
CHANGED
|
@@ -65,9 +65,9 @@ class Dropdown {
|
|
|
65
65
|
this.onSelect({ item, value: item.getAttribute('data-value'), text: item.textContent.trim() });
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
if (this.closeOnClick) {
|
|
68
|
+
if (this.closeOnClick !== false) {
|
|
69
69
|
this.hideMenu();
|
|
70
|
-
this.trigger.focus();
|
|
70
|
+
if (this.trigger) {this.trigger.focus();}
|
|
71
71
|
}
|
|
72
72
|
};
|
|
73
73
|
|
|
@@ -170,7 +170,10 @@ class Dropdown {
|
|
|
170
170
|
|
|
171
171
|
// Document click to close
|
|
172
172
|
this._documentClickHandler = (e) => {
|
|
173
|
-
if (!this.
|
|
173
|
+
if (!this.isOpen) return;
|
|
174
|
+
const isInElement = this.element.contains(e.target);
|
|
175
|
+
const isInMenu = this.menu && this.menu.contains(e.target);
|
|
176
|
+
if (!isInElement && !isInMenu) {
|
|
174
177
|
this.hideMenu();
|
|
175
178
|
}
|
|
176
179
|
};
|
|
@@ -183,8 +186,8 @@ class Dropdown {
|
|
|
183
186
|
|
|
184
187
|
_bindMenuItems() {
|
|
185
188
|
this.menu.querySelectorAll('.ds-dropdown__item').forEach(item => {
|
|
186
|
-
item.addEventListener('click', (e) => this._itemClickHandler(e));
|
|
187
189
|
item._dropdownItemClickHandler = (e) => this._itemClickHandler(e);
|
|
190
|
+
item.addEventListener('click', item._dropdownItemClickHandler);
|
|
188
191
|
});
|
|
189
192
|
}
|
|
190
193
|
|
|
@@ -205,7 +208,6 @@ class Dropdown {
|
|
|
205
208
|
if (!this.autoPosition) {return;}
|
|
206
209
|
|
|
207
210
|
const triggerRect = this.element.getBoundingClientRect();
|
|
208
|
-
const menuRect = this.menu.getBoundingClientRect();
|
|
209
211
|
const viewportHeight = window.innerHeight;
|
|
210
212
|
const viewportWidth = window.innerWidth;
|
|
211
213
|
|
|
@@ -213,7 +215,8 @@ class Dropdown {
|
|
|
213
215
|
this.menu.classList.remove('ds-dropdown--top', 'ds-dropdown--right', 'ds-dropdown--dropup');
|
|
214
216
|
|
|
215
217
|
if (this.appendToBody) {
|
|
216
|
-
this.menu.style.width = `${
|
|
218
|
+
this.menu.style.width = `${triggerRect.width}px`;
|
|
219
|
+
const menuRect = this.menu.getBoundingClientRect();
|
|
217
220
|
|
|
218
221
|
const spaceBelow = viewportHeight - triggerRect.bottom;
|
|
219
222
|
const spaceAbove = triggerRect.top;
|
|
@@ -227,7 +230,7 @@ class Dropdown {
|
|
|
227
230
|
}
|
|
228
231
|
|
|
229
232
|
if (triggerRect.left + menuRect.width > viewportWidth) {
|
|
230
|
-
this.menu.style.left = `${triggerRect.right -
|
|
233
|
+
this.menu.style.left = `${triggerRect.right - menuRect.width}px`;
|
|
231
234
|
this.menu.style.right = 'auto';
|
|
232
235
|
} else {
|
|
233
236
|
this.menu.style.left = `${triggerRect.left}px`;
|
|
@@ -304,9 +307,12 @@ class Dropdown {
|
|
|
304
307
|
this._originalWidth = this.menu.style.width;
|
|
305
308
|
this._originalTransform = this.menu.style.transform;
|
|
306
309
|
this._originalZIndex = this.menu.style.zIndex;
|
|
310
|
+
this._originalDisplay = this.menu.style.display;
|
|
307
311
|
|
|
312
|
+
const triggerRect = this.element.getBoundingClientRect();
|
|
308
313
|
const zIndex = getZIndexConfig().dropdown;
|
|
309
314
|
this.menu.style.position = 'fixed';
|
|
315
|
+
this.menu.style.width = `${triggerRect.width}px`;
|
|
310
316
|
this.menu.style.zIndex = zIndex;
|
|
311
317
|
this.menu.style.transform = 'translateZ(0)';
|
|
312
318
|
document.body.appendChild(this.menu);
|
|
@@ -324,7 +330,9 @@ class Dropdown {
|
|
|
324
330
|
this.menu.style.width = this._originalWidth || '';
|
|
325
331
|
this.menu.style.zIndex = this._originalZIndex || '';
|
|
326
332
|
this.menu.style.transform = this._originalTransform || '';
|
|
333
|
+
this.menu.style.display = this._originalDisplay || '';
|
|
327
334
|
this._originalParent = null;
|
|
335
|
+
console.log('[Dropdown] Menu restored from body');
|
|
328
336
|
}
|
|
329
337
|
|
|
330
338
|
_addScrollListener() {
|
|
@@ -362,6 +370,33 @@ class Dropdown {
|
|
|
362
370
|
|
|
363
371
|
// Update menu items dynamically
|
|
364
372
|
setItems(items) {
|
|
373
|
+
// Ensure _itemClickHandler is defined
|
|
374
|
+
if (!this._itemClickHandler) {
|
|
375
|
+
this._itemClickHandler = (e) => {
|
|
376
|
+
e.stopPropagation();
|
|
377
|
+
const item = e.currentTarget;
|
|
378
|
+
if (item.classList.contains('is-disabled') || item.classList.contains('ds-dropdown__divider')) {return;}
|
|
379
|
+
|
|
380
|
+
this.menu.querySelectorAll('.ds-dropdown__item').forEach(i => i.classList.remove('is-selected'));
|
|
381
|
+
item.classList.add('is-selected');
|
|
382
|
+
|
|
383
|
+
if (this.triggerText && !item.hasAttribute('data-no-update-trigger')) {
|
|
384
|
+
this.triggerText.textContent = item.textContent.trim();
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
this.element.setAttribute('data-value', item.getAttribute('data-value') || '');
|
|
388
|
+
|
|
389
|
+
if (this.onSelect) {
|
|
390
|
+
this.onSelect({ item, value: item.getAttribute('data-value'), text: item.textContent.trim() });
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (this.closeOnClick !== false) {
|
|
394
|
+
this.hideMenu();
|
|
395
|
+
if (this.trigger) {this.trigger.focus();}
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
|
|
365
400
|
// Remove old item listeners
|
|
366
401
|
this.menu.querySelectorAll('.ds-dropdown__item').forEach(item => {
|
|
367
402
|
if (item._dropdownItemClickHandler) {
|
|
@@ -371,7 +406,7 @@ class Dropdown {
|
|
|
371
406
|
|
|
372
407
|
// Rebuild menu content
|
|
373
408
|
this.menu.innerHTML = '';
|
|
374
|
-
items.forEach(item => {
|
|
409
|
+
items.forEach((item, index) => {
|
|
375
410
|
if (item.type === 'divider') {
|
|
376
411
|
const divider = document.createElement('div');
|
|
377
412
|
divider.className = 'ds-dropdown__divider';
|
|
@@ -383,11 +418,13 @@ class Dropdown {
|
|
|
383
418
|
if (item.value !== undefined) {el.setAttribute('data-value', item.value);}
|
|
384
419
|
if (item.icon) {el.innerHTML = item.icon + el.innerHTML;}
|
|
385
420
|
if (item.disabled) {el.classList.add('is-disabled');}
|
|
421
|
+
|
|
422
|
+
el._dropdownItemClickHandler = (e) => this._itemClickHandler(e);
|
|
423
|
+
el.addEventListener('click', el._dropdownItemClickHandler);
|
|
424
|
+
|
|
386
425
|
this.menu.appendChild(el);
|
|
387
426
|
}
|
|
388
427
|
});
|
|
389
|
-
|
|
390
|
-
this._bindMenuItems();
|
|
391
428
|
}
|
|
392
429
|
|
|
393
430
|
destroy() {
|
|
@@ -440,6 +477,9 @@ class Dropdown {
|
|
|
440
477
|
}
|
|
441
478
|
|
|
442
479
|
function initDropdown(element, options) {
|
|
480
|
+
if (element._kupolaDropdown) {
|
|
481
|
+
element._kupolaDropdown.destroy();
|
|
482
|
+
}
|
|
443
483
|
const dropdown = new Dropdown(element, options);
|
|
444
484
|
dropdown.init();
|
|
445
485
|
element._kupolaDropdown = dropdown;
|
package/js/initializer.js
CHANGED
|
@@ -86,7 +86,8 @@ class ComponentInitializerRegistry {
|
|
|
86
86
|
const className = element.className;
|
|
87
87
|
if (typeof className === 'string') {
|
|
88
88
|
for (const cls of this._cssClasses) {
|
|
89
|
-
|
|
89
|
+
const regex = new RegExp(`(^|\\s)${cls}(\\s|$)`);
|
|
90
|
+
if (regex.test(className)) {
|
|
90
91
|
const name = cls.replace('ds-', '');
|
|
91
92
|
const initFn = this.initializers.get(name) || this.initializers.get(cls);
|
|
92
93
|
if (initFn) {
|
|
@@ -127,7 +128,8 @@ class ComponentInitializerRegistry {
|
|
|
127
128
|
const className = element.className;
|
|
128
129
|
if (typeof className === 'string') {
|
|
129
130
|
for (const cls of this._cssClasses) {
|
|
130
|
-
|
|
131
|
+
const regex = new RegExp(`(^|\\s)${cls}(\\s|$)`);
|
|
132
|
+
if (regex.test(className)) {
|
|
131
133
|
const name = cls.replace('ds-', '');
|
|
132
134
|
const cleanupFn = this.cleanupFunctions.get(name) || this.cleanupFunctions.get(cls);
|
|
133
135
|
if (cleanupFn) {
|
package/js/select.js
CHANGED
|
@@ -133,7 +133,10 @@ class Select {
|
|
|
133
133
|
|
|
134
134
|
// Document click to close
|
|
135
135
|
this._documentClickHandler = (e) => {
|
|
136
|
-
if (!this.
|
|
136
|
+
if (!this.isOpen) return;
|
|
137
|
+
const isInElement = this.element.contains(e.target);
|
|
138
|
+
const isInOptions = this.optionsEl && this.optionsEl.contains(e.target);
|
|
139
|
+
if (!isInElement && !isInOptions) {
|
|
137
140
|
this.hideOptions();
|
|
138
141
|
}
|
|
139
142
|
};
|
|
@@ -231,6 +234,23 @@ class Select {
|
|
|
231
234
|
}
|
|
232
235
|
|
|
233
236
|
_renderRemoteOptions(options) {
|
|
237
|
+
// Ensure _optionClickHandler is defined
|
|
238
|
+
if (!this._optionClickHandler) {
|
|
239
|
+
this._optionClickHandler = (e) => {
|
|
240
|
+
e.stopPropagation();
|
|
241
|
+
const option = e.currentTarget;
|
|
242
|
+
if (option.classList.contains('is-disabled')) return;
|
|
243
|
+
|
|
244
|
+
const value = option.getAttribute('data-value');
|
|
245
|
+
|
|
246
|
+
if (this.multiple) {
|
|
247
|
+
this._toggleMultiOption(value, option);
|
|
248
|
+
} else {
|
|
249
|
+
this._selectSingleOption(value, option);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
234
254
|
this.optionsEl.querySelectorAll('.ds-select__option, .ds-select__item').forEach(opt => {
|
|
235
255
|
if (opt._selectOptionClickHandler) {
|
|
236
256
|
opt.removeEventListener('click', opt._selectOptionClickHandler);
|
|
@@ -246,8 +266,8 @@ class Select {
|
|
|
246
266
|
if (opt.disabled) el.classList.add('is-disabled');
|
|
247
267
|
if (this.selectedValues.has(opt.value)) el.classList.add('is-selected');
|
|
248
268
|
|
|
249
|
-
el.addEventListener('click', (e) => this._optionClickHandler(e));
|
|
250
269
|
el._selectOptionClickHandler = (e) => this._optionClickHandler(e);
|
|
270
|
+
el.addEventListener('click', el._selectOptionClickHandler);
|
|
251
271
|
|
|
252
272
|
this.optionsEl.appendChild(el);
|
|
253
273
|
});
|
|
@@ -408,8 +428,8 @@ class Select {
|
|
|
408
428
|
|
|
409
429
|
_bindOptionClicks() {
|
|
410
430
|
this.optionsEl.querySelectorAll('.ds-select__option, .ds-select__item').forEach(option => {
|
|
411
|
-
option.addEventListener('click', (e) => this._optionClickHandler(e));
|
|
412
431
|
option._selectOptionClickHandler = (e) => this._optionClickHandler(e);
|
|
432
|
+
option.addEventListener('click', option._selectOptionClickHandler);
|
|
413
433
|
});
|
|
414
434
|
}
|
|
415
435
|
|
|
@@ -500,8 +520,10 @@ class Select {
|
|
|
500
520
|
this._originalTransform = this.optionsEl.style.transform;
|
|
501
521
|
this._originalZIndex = this.optionsEl.style.zIndex;
|
|
502
522
|
|
|
523
|
+
const triggerRect = this.element.getBoundingClientRect();
|
|
503
524
|
const zIndex = getZIndexConfig().dropdown;
|
|
504
525
|
this.optionsEl.style.position = 'fixed';
|
|
526
|
+
this.optionsEl.style.width = `${triggerRect.width}px`;
|
|
505
527
|
this.optionsEl.style.zIndex = zIndex;
|
|
506
528
|
this.optionsEl.style.transform = 'translateZ(0)';
|
|
507
529
|
document.body.appendChild(this.optionsEl);
|
|
@@ -524,11 +546,11 @@ class Select {
|
|
|
524
546
|
if (!this.appendToBody || !this.optionsEl) return;
|
|
525
547
|
|
|
526
548
|
const triggerRect = this.element.getBoundingClientRect();
|
|
527
|
-
const optionsRect = this.optionsEl.getBoundingClientRect();
|
|
528
549
|
const viewportHeight = window.innerHeight;
|
|
529
550
|
const viewportWidth = window.innerWidth;
|
|
530
551
|
|
|
531
|
-
this.optionsEl.style.width = `${
|
|
552
|
+
this.optionsEl.style.width = `${triggerRect.width}px`;
|
|
553
|
+
const optionsRect = this.optionsEl.getBoundingClientRect();
|
|
532
554
|
|
|
533
555
|
const spaceBelow = viewportHeight - triggerRect.bottom;
|
|
534
556
|
const spaceAbove = triggerRect.top;
|
|
@@ -540,7 +562,7 @@ class Select {
|
|
|
540
562
|
}
|
|
541
563
|
|
|
542
564
|
if (triggerRect.left + optionsRect.width > viewportWidth) {
|
|
543
|
-
this.optionsEl.style.left = `${triggerRect.right -
|
|
565
|
+
this.optionsEl.style.left = `${triggerRect.right - optionsRect.width}px`;
|
|
544
566
|
} else {
|
|
545
567
|
this.optionsEl.style.left = `${triggerRect.left}px`;
|
|
546
568
|
}
|
package/package.json
CHANGED