@kupola/kupola 1.6.3 → 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/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
 
@@ -208,7 +208,6 @@ class Dropdown {
208
208
  if (!this.autoPosition) {return;}
209
209
 
210
210
  const triggerRect = this.element.getBoundingClientRect();
211
- const menuRect = this.menu.getBoundingClientRect();
212
211
  const viewportHeight = window.innerHeight;
213
212
  const viewportWidth = window.innerWidth;
214
213
 
@@ -216,7 +215,8 @@ class Dropdown {
216
215
  this.menu.classList.remove('ds-dropdown--top', 'ds-dropdown--right', 'ds-dropdown--dropup');
217
216
 
218
217
  if (this.appendToBody) {
219
- this.menu.style.width = `${Math.max(triggerRect.width, menuRect.width)}px`;
218
+ this.menu.style.width = `${triggerRect.width}px`;
219
+ const menuRect = this.menu.getBoundingClientRect();
220
220
 
221
221
  const spaceBelow = viewportHeight - triggerRect.bottom;
222
222
  const spaceAbove = triggerRect.top;
@@ -230,7 +230,7 @@ class Dropdown {
230
230
  }
231
231
 
232
232
  if (triggerRect.left + menuRect.width > viewportWidth) {
233
- this.menu.style.left = `${triggerRect.right - Math.max(triggerRect.width, menuRect.width)}px`;
233
+ this.menu.style.left = `${triggerRect.right - menuRect.width}px`;
234
234
  this.menu.style.right = 'auto';
235
235
  } else {
236
236
  this.menu.style.left = `${triggerRect.left}px`;
@@ -307,9 +307,12 @@ class Dropdown {
307
307
  this._originalWidth = this.menu.style.width;
308
308
  this._originalTransform = this.menu.style.transform;
309
309
  this._originalZIndex = this.menu.style.zIndex;
310
+ this._originalDisplay = this.menu.style.display;
310
311
 
312
+ const triggerRect = this.element.getBoundingClientRect();
311
313
  const zIndex = getZIndexConfig().dropdown;
312
314
  this.menu.style.position = 'fixed';
315
+ this.menu.style.width = `${triggerRect.width}px`;
313
316
  this.menu.style.zIndex = zIndex;
314
317
  this.menu.style.transform = 'translateZ(0)';
315
318
  document.body.appendChild(this.menu);
@@ -327,7 +330,9 @@ class Dropdown {
327
330
  this.menu.style.width = this._originalWidth || '';
328
331
  this.menu.style.zIndex = this._originalZIndex || '';
329
332
  this.menu.style.transform = this._originalTransform || '';
333
+ this.menu.style.display = this._originalDisplay || '';
330
334
  this._originalParent = null;
335
+ console.log('[Dropdown] Menu restored from body');
331
336
  }
332
337
 
333
338
  _addScrollListener() {
@@ -365,6 +370,33 @@ class Dropdown {
365
370
 
366
371
  // Update menu items dynamically
367
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
+
368
400
  // Remove old item listeners
369
401
  this.menu.querySelectorAll('.ds-dropdown__item').forEach(item => {
370
402
  if (item._dropdownItemClickHandler) {
@@ -374,7 +406,7 @@ class Dropdown {
374
406
 
375
407
  // Rebuild menu content
376
408
  this.menu.innerHTML = '';
377
- items.forEach(item => {
409
+ items.forEach((item, index) => {
378
410
  if (item.type === 'divider') {
379
411
  const divider = document.createElement('div');
380
412
  divider.className = 'ds-dropdown__divider';
@@ -445,6 +477,9 @@ class Dropdown {
445
477
  }
446
478
 
447
479
  function initDropdown(element, options) {
480
+ if (element._kupolaDropdown) {
481
+ element._kupolaDropdown.destroy();
482
+ }
448
483
  const dropdown = new Dropdown(element, options);
449
484
  dropdown.init();
450
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
- if (className.includes(cls)) {
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
- if (className.includes(cls)) {
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
@@ -234,6 +234,23 @@ class Select {
234
234
  }
235
235
 
236
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
+
237
254
  this.optionsEl.querySelectorAll('.ds-select__option, .ds-select__item').forEach(opt => {
238
255
  if (opt._selectOptionClickHandler) {
239
256
  opt.removeEventListener('click', opt._selectOptionClickHandler);
@@ -503,8 +520,10 @@ class Select {
503
520
  this._originalTransform = this.optionsEl.style.transform;
504
521
  this._originalZIndex = this.optionsEl.style.zIndex;
505
522
 
523
+ const triggerRect = this.element.getBoundingClientRect();
506
524
  const zIndex = getZIndexConfig().dropdown;
507
525
  this.optionsEl.style.position = 'fixed';
526
+ this.optionsEl.style.width = `${triggerRect.width}px`;
508
527
  this.optionsEl.style.zIndex = zIndex;
509
528
  this.optionsEl.style.transform = 'translateZ(0)';
510
529
  document.body.appendChild(this.optionsEl);
@@ -527,11 +546,11 @@ class Select {
527
546
  if (!this.appendToBody || !this.optionsEl) return;
528
547
 
529
548
  const triggerRect = this.element.getBoundingClientRect();
530
- const optionsRect = this.optionsEl.getBoundingClientRect();
531
549
  const viewportHeight = window.innerHeight;
532
550
  const viewportWidth = window.innerWidth;
533
551
 
534
- this.optionsEl.style.width = `${Math.max(triggerRect.width, optionsRect.width)}px`;
552
+ this.optionsEl.style.width = `${triggerRect.width}px`;
553
+ const optionsRect = this.optionsEl.getBoundingClientRect();
535
554
 
536
555
  const spaceBelow = viewportHeight - triggerRect.bottom;
537
556
  const spaceAbove = triggerRect.top;
@@ -543,7 +562,7 @@ class Select {
543
562
  }
544
563
 
545
564
  if (triggerRect.left + optionsRect.width > viewportWidth) {
546
- this.optionsEl.style.left = `${triggerRect.right - Math.max(triggerRect.width, optionsRect.width)}px`;
565
+ this.optionsEl.style.left = `${triggerRect.right - optionsRect.width}px`;
547
566
  } else {
548
567
  this.optionsEl.style.left = `${triggerRect.left}px`;
549
568
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kupola/kupola",
3
- "version": "1.6.3",
3
+ "version": "1.6.4",
4
4
  "description": "A lightweight UI toolkit for any web project. No heavy frontend frameworks required.",
5
5
  "main": "dist/kupola.cjs.js",
6
6
  "module": "dist/kupola.esm.js",