@keenthemes/ktui 1.1.2 → 1.1.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.
Files changed (56) hide show
  1. package/dist/ktui.js +532 -59
  2. package/dist/ktui.min.js +1 -1
  3. package/dist/ktui.min.js.map +1 -1
  4. package/dist/styles.css +51 -0
  5. package/lib/cjs/components/component.js +22 -0
  6. package/lib/cjs/components/component.js.map +1 -1
  7. package/lib/cjs/components/datatable/datatable.js +26 -7
  8. package/lib/cjs/components/datatable/datatable.js.map +1 -1
  9. package/lib/cjs/components/drawer/drawer.js +255 -9
  10. package/lib/cjs/components/drawer/drawer.js.map +1 -1
  11. package/lib/cjs/components/dropdown/dropdown.js +55 -8
  12. package/lib/cjs/components/dropdown/dropdown.js.map +1 -1
  13. package/lib/cjs/components/select/search.js +17 -7
  14. package/lib/cjs/components/select/search.js.map +1 -1
  15. package/lib/cjs/components/select/select.js +92 -14
  16. package/lib/cjs/components/select/select.js.map +1 -1
  17. package/lib/cjs/components/sticky/sticky.js +44 -5
  18. package/lib/cjs/components/sticky/sticky.js.map +1 -1
  19. package/lib/cjs/helpers/data.js +8 -0
  20. package/lib/cjs/helpers/data.js.map +1 -1
  21. package/lib/cjs/helpers/event-handler.js +6 -5
  22. package/lib/cjs/helpers/event-handler.js.map +1 -1
  23. package/lib/cjs/index.js.map +1 -1
  24. package/lib/esm/components/component.js +22 -0
  25. package/lib/esm/components/component.js.map +1 -1
  26. package/lib/esm/components/datatable/datatable.js +26 -7
  27. package/lib/esm/components/datatable/datatable.js.map +1 -1
  28. package/lib/esm/components/drawer/drawer.js +255 -9
  29. package/lib/esm/components/drawer/drawer.js.map +1 -1
  30. package/lib/esm/components/dropdown/dropdown.js +55 -8
  31. package/lib/esm/components/dropdown/dropdown.js.map +1 -1
  32. package/lib/esm/components/select/search.js +17 -7
  33. package/lib/esm/components/select/search.js.map +1 -1
  34. package/lib/esm/components/select/select.js +92 -14
  35. package/lib/esm/components/select/select.js.map +1 -1
  36. package/lib/esm/components/sticky/sticky.js +44 -5
  37. package/lib/esm/components/sticky/sticky.js.map +1 -1
  38. package/lib/esm/helpers/data.js +8 -0
  39. package/lib/esm/helpers/data.js.map +1 -1
  40. package/lib/esm/helpers/event-handler.js +6 -5
  41. package/lib/esm/helpers/event-handler.js.map +1 -1
  42. package/lib/esm/index.js.map +1 -1
  43. package/package.json +4 -2
  44. package/src/components/component.ts +26 -0
  45. package/src/components/datatable/__tests__/race-conditions.test.ts +2 -2
  46. package/src/components/datatable/datatable.ts +32 -7
  47. package/src/components/drawer/drawer.ts +266 -10
  48. package/src/components/dropdown/dropdown.ts +63 -8
  49. package/src/components/select/__tests__/ux-behaviors.test.ts +382 -4
  50. package/src/components/select/search.ts +16 -7
  51. package/src/components/select/select.css +7 -2
  52. package/src/components/select/select.ts +112 -20
  53. package/src/components/sticky/sticky.ts +55 -5
  54. package/src/helpers/data.ts +10 -0
  55. package/src/helpers/event-handler.ts +7 -6
  56. package/src/index.ts +2 -0
package/dist/ktui.js CHANGED
@@ -173,6 +173,15 @@ var __extends = (this && this.__extends) || (function () {
173
173
  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
174
174
  };
175
175
  })();
176
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
177
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
178
+ if (ar || !(i in from)) {
179
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
180
+ ar[i] = from[i];
181
+ }
182
+ }
183
+ return to.concat(ar || Array.prototype.slice.call(from));
184
+ };
176
185
  Object.defineProperty(exports, "__esModule", ({ value: true }));
177
186
  exports.KTDrawer = void 0;
178
187
  var data_1 = __webpack_require__(8716);
@@ -205,8 +214,9 @@ var KTDrawer = /** @class */ (function (_super) {
205
214
  _this._isTransitioning = false;
206
215
  _this._backdropElement = null;
207
216
  _this._relatedTarget = null;
208
- if (data_1.default.has(element, _this._name))
217
+ if (data_1.default.has(element, _this._name)) {
209
218
  return _this;
219
+ }
210
220
  _this._init(element);
211
221
  _this._buildConfig(config);
212
222
  _this._handleClose();
@@ -248,6 +258,27 @@ var KTDrawer = /** @class */ (function (_super) {
248
258
  return;
249
259
  }
250
260
  KTDrawer.hide();
261
+ // If drawer needs to be in front of backdrop, ensure it's in body (for proper z-index stacking)
262
+ // This ensures the drawer and backdrop are in the same stacking context
263
+ if (this._getOption('container') === 'body' && this._element.parentElement !== document.body) {
264
+ // Store original parent for restoration when hiding
265
+ if (!this._element.hasAttribute('data-kt-drawer-original-parent-id')) {
266
+ var originalParent = this._element.parentElement;
267
+ if (originalParent && originalParent !== document.body) {
268
+ this._element.setAttribute('data-kt-drawer-original-parent-id', originalParent.id || '');
269
+ // Store a reference to find the parent later (using closest to find Livewire component or header)
270
+ var livewireComponent = originalParent.closest('[wire\\:id]');
271
+ var header = originalParent.closest('header#header');
272
+ if (livewireComponent) {
273
+ this._element.setAttribute('data-kt-drawer-original-wire-id', livewireComponent.getAttribute('wire:id') || '');
274
+ }
275
+ if (header) {
276
+ this._element.setAttribute('data-kt-drawer-original-in-header', 'true');
277
+ }
278
+ }
279
+ }
280
+ document.body.appendChild(this._element);
281
+ }
251
282
  if (this._getOption('backdrop') === true)
252
283
  this._createBackdrop();
253
284
  if (relatedTarget)
@@ -312,6 +343,9 @@ var KTDrawer = /** @class */ (function (_super) {
312
343
  _this._element.classList.add(_this._getOption('hiddenClass'));
313
344
  _this._element.classList.remove(_this._getOption('shownClass'));
314
345
  _this._element.style.zIndex = '';
346
+ // Note: We don't move drawer back to original location here
347
+ // Livewire will handle DOM structure on next navigation, and drawer will be reinitialized
348
+ // in its original location from the persisted component HTML
315
349
  _this._fireEvent('hidden');
316
350
  _this._dispatchEvent('hidden');
317
351
  });
@@ -331,7 +365,25 @@ var KTDrawer = /** @class */ (function (_super) {
331
365
  var _a;
332
366
  if (this._getOption('container')) {
333
367
  if (this._getOption('container') === 'body') {
334
- document.body.appendChild(this._element);
368
+ // Check if drawer is in a persisted Livewire component (like header with @persist)
369
+ // If so, don't move it to body - keep it in place so Livewire can preserve it
370
+ // This follows the same pattern as dropdowns/menus which work with wire:navigate
371
+ var originalParent = this._element.parentNode;
372
+ var isInPersistedComponent = originalParent &&
373
+ (originalParent.closest('[wire\\:id]') !== null ||
374
+ originalParent.closest('header#header') !== null);
375
+ if (isInPersistedComponent) {
376
+ // Don't move to body - keep in original location for Livewire persistence
377
+ // Use fixed positioning to achieve the same visual effect
378
+ // Ensure drawer has fixed positioning to work from its current location
379
+ if (!this._element.style.position || this._element.style.position === 'static') {
380
+ this._element.style.position = 'fixed';
381
+ }
382
+ }
383
+ else {
384
+ // Not in persisted component - safe to move to body (follows original behavior)
385
+ document.body.appendChild(this._element);
386
+ }
335
387
  }
336
388
  else {
337
389
  (_a = document
@@ -402,14 +454,117 @@ var KTDrawer = /** @class */ (function (_super) {
402
454
  KTDrawer.prototype.isEnabled = function () {
403
455
  return this._isEnabled();
404
456
  };
457
+ KTDrawer.getElement = function (reference) {
458
+ if (reference && reference.hasAttribute('data-kt-drawer-initialized'))
459
+ return reference;
460
+ var findElement = reference &&
461
+ reference.closest('[data-kt-drawer-initialized]');
462
+ if (findElement)
463
+ return findElement;
464
+ // Fallback: look for parent with data-kt-drawer attribute
465
+ if (reference) {
466
+ var drawerContainer = reference.closest('[data-kt-drawer]');
467
+ if (drawerContainer)
468
+ return drawerContainer;
469
+ }
470
+ // If reference is a toggle button with a selector, find the drawer by selector
471
+ // This handles cases where the toggle button is not a child of the drawer
472
+ if (reference && reference.hasAttribute('data-kt-drawer-toggle')) {
473
+ var selector = reference.getAttribute('data-kt-drawer-toggle');
474
+ if (selector) {
475
+ // Check both document and body (drawers with container="body" are moved to body)
476
+ var drawerElInDoc = document.querySelector(selector);
477
+ var drawerElInBody = document.body.querySelector(selector);
478
+ var drawerEl = drawerElInDoc || drawerElInBody;
479
+ if (drawerEl)
480
+ return drawerEl;
481
+ }
482
+ }
483
+ return null;
484
+ };
485
+ /**
486
+ * Wait for an element to appear in the DOM using polling with MutationObserver fallback
487
+ * Useful for persisted Livewire components that may not be in DOM immediately
488
+ */
489
+ KTDrawer.waitForElement = function (selector, timeout) {
490
+ if (timeout === void 0) { timeout = 2000; }
491
+ return new Promise(function (resolve) {
492
+ var resolved = false;
493
+ var doResolve = function (element) {
494
+ if (!resolved) {
495
+ resolved = true;
496
+ resolve(element);
497
+ }
498
+ };
499
+ // Check if element already exists
500
+ var existing = document.querySelector(selector) || document.body.querySelector(selector);
501
+ if (existing) {
502
+ doResolve(existing);
503
+ return;
504
+ }
505
+ // Use polling for faster detection (check every 50ms)
506
+ var attempts = 0;
507
+ var maxAttempts = timeout / 50;
508
+ var pollInterval = setInterval(function () {
509
+ if (resolved) {
510
+ clearInterval(pollInterval);
511
+ return;
512
+ }
513
+ attempts++;
514
+ var element = document.querySelector(selector) || document.body.querySelector(selector);
515
+ if (element) {
516
+ clearInterval(pollInterval);
517
+ doResolve(element);
518
+ return;
519
+ }
520
+ if (attempts >= maxAttempts) {
521
+ clearInterval(pollInterval);
522
+ doResolve(null);
523
+ }
524
+ }, 50);
525
+ // Also use MutationObserver as backup for immediate detection
526
+ var observer = new MutationObserver(function () {
527
+ if (resolved) {
528
+ observer.disconnect();
529
+ return;
530
+ }
531
+ var element = document.querySelector(selector) || document.body.querySelector(selector);
532
+ if (element) {
533
+ clearInterval(pollInterval);
534
+ observer.disconnect();
535
+ doResolve(element);
536
+ }
537
+ });
538
+ observer.observe(document.body, {
539
+ childList: true,
540
+ subtree: true,
541
+ });
542
+ // Cleanup on timeout
543
+ setTimeout(function () {
544
+ if (!resolved) {
545
+ clearInterval(pollInterval);
546
+ observer.disconnect();
547
+ doResolve(null);
548
+ }
549
+ }, timeout);
550
+ });
551
+ };
405
552
  KTDrawer.getInstance = function (element) {
406
553
  if (!element)
407
554
  return null;
408
- if (data_1.default.has(element, 'drawer')) {
409
- return data_1.default.get(element, 'drawer');
555
+ var drawerElement = KTDrawer.getElement(element);
556
+ if (!drawerElement) {
557
+ // If element is a toggle button and drawer element wasn't found, return null
558
+ // The handleToggle() will handle waiting for the element to appear
559
+ if (element.hasAttribute('data-kt-drawer-toggle')) {
560
+ }
561
+ return null;
562
+ }
563
+ if (data_1.default.has(drawerElement, 'drawer')) {
564
+ return data_1.default.get(drawerElement, 'drawer');
410
565
  }
411
- if (element.getAttribute('data-kt-drawer-initialized') === 'true') {
412
- return new KTDrawer(element);
566
+ if (drawerElement.getAttribute('data-kt-drawer-initialized') === 'true') {
567
+ return new KTDrawer(drawerElement);
413
568
  }
414
569
  return null;
415
570
  };
@@ -442,16 +597,62 @@ var KTDrawer = /** @class */ (function (_super) {
442
597
  });
443
598
  };
444
599
  KTDrawer.handleToggle = function () {
600
+ // Add raw click listener to document.body to track all clicks
601
+ document.body.addEventListener('click', function (rawEvent) {
602
+ var target = rawEvent.target;
603
+ if (target && target.hasAttribute('data-kt-drawer-toggle')) {
604
+ }
605
+ }, true); // Use capture phase to catch before any stopPropagation
445
606
  event_handler_1.default.on(document.body, '[data-kt-drawer-toggle]', 'click', function (event, target) {
607
+ var _a;
446
608
  event.stopPropagation();
447
609
  var selector = target.getAttribute('data-kt-drawer-toggle');
448
610
  if (!selector)
449
611
  return;
450
- var drawerEl = document.querySelector(selector);
451
- var drawer = KTDrawer.getInstance(drawerEl);
612
+ // Try to get instance immediately
613
+ var drawer = KTDrawer.getInstance(target);
452
614
  if (drawer) {
453
615
  drawer.toggle();
454
616
  }
617
+ else {
618
+ // Drawer element not found - wait for it to appear (handles persisted Livewire components)
619
+ // Check if drawer exists in persisted components (might be in header that's persisted)
620
+ var persistedHeader = ((_a = document.querySelector('[wire\\:id]')) === null || _a === void 0 ? void 0 : _a.closest('[wire\\:id]')) || document.querySelector('header#header');
621
+ var drawerInPersisted = persistedHeader ? persistedHeader.querySelector(selector) : null;
622
+ // Wait longer for persisted components that may take time to render
623
+ // Also check if drawer exists in persisted header component
624
+ KTDrawer.waitForElement(selector, 5000).then(function (drawerElement) {
625
+ if (drawerElement) {
626
+ // Initialize the drawer if not already initialized
627
+ if (!data_1.default.has(drawerElement, 'drawer')) {
628
+ new KTDrawer(drawerElement);
629
+ }
630
+ // Get instance and toggle
631
+ var drawerInstance = KTDrawer.getInstance(drawerElement);
632
+ if (drawerInstance) {
633
+ drawerInstance.toggle();
634
+ }
635
+ }
636
+ else {
637
+ // Drawer never appeared - trigger a reinit to see if it helps
638
+ // This handles cases where drawers are in persisted components that haven't rendered yet
639
+ setTimeout(function () {
640
+ KTDrawer.reinit();
641
+ // Try one more time after reinit
642
+ var drawerAfterReinit = document.querySelector(selector) || document.body.querySelector(selector);
643
+ if (drawerAfterReinit) {
644
+ if (!data_1.default.has(drawerAfterReinit, 'drawer')) {
645
+ new KTDrawer(drawerAfterReinit);
646
+ }
647
+ var drawerInstance = KTDrawer.getInstance(drawerAfterReinit);
648
+ if (drawerInstance) {
649
+ drawerInstance.toggle();
650
+ }
651
+ }
652
+ }, 500);
653
+ }
654
+ });
655
+ }
455
656
  });
456
657
  };
457
658
  KTDrawer.handleDismiss = function () {
@@ -503,7 +704,12 @@ var KTDrawer = /** @class */ (function (_super) {
503
704
  });
504
705
  };
505
706
  KTDrawer.createInstances = function () {
506
- var elements = document.querySelectorAll('[data-kt-drawer]');
707
+ // Find all drawer elements - check both document and body (drawers with container="body" are moved there)
708
+ var elementsInDoc = document.querySelectorAll('[data-kt-drawer]');
709
+ var elementsInBody = document.body.querySelectorAll('[data-kt-drawer]');
710
+ // Combine and deduplicate
711
+ var allElements = new Set(__spreadArray(__spreadArray([], Array.from(elementsInDoc), true), Array.from(elementsInBody), true));
712
+ var elements = Array.from(allElements);
507
713
  elements.forEach(function (element) {
508
714
  new KTDrawer(element);
509
715
  });
@@ -519,6 +725,46 @@ var KTDrawer = /** @class */ (function (_super) {
519
725
  window.KT_DRAWER_INITIALIZED = true;
520
726
  }
521
727
  };
728
+ /**
729
+ * Force reinitialization of drawers by clearing KTData entries.
730
+ * Useful for Livewire wire:navigate where persisted elements need reinitialization.
731
+ */
732
+ KTDrawer.reinit = function () {
733
+ // Follow the same simple pattern as KTDropdown.reinit()
734
+ // Find all drawer elements - check both document and body (some may be moved to body)
735
+ var elementsInDoc = document.querySelectorAll('[data-kt-drawer]');
736
+ var elementsInBody = document.body.querySelectorAll('[data-kt-drawer]');
737
+ // Combine and deduplicate
738
+ var allElements = new Set(__spreadArray(__spreadArray([], Array.from(elementsInDoc), true), Array.from(elementsInBody), true));
739
+ var elements = Array.from(allElements);
740
+ // Clean up existing instances
741
+ elements.forEach(function (element) {
742
+ try {
743
+ // Get existing instance to clean up
744
+ var instance = KTDrawer.getInstance(element);
745
+ if (instance && typeof instance.hide === 'function') {
746
+ instance.hide(); // This will clean up backdrop and state
747
+ }
748
+ // Clear KTData entries
749
+ var hadDrawer = data_1.default.has(element, 'drawer');
750
+ data_1.default.remove(element, 'drawer');
751
+ // Remove initialization attribute to allow fresh initialization
752
+ element.removeAttribute('data-kt-drawer-initialized');
753
+ }
754
+ catch (e) {
755
+ // Ignore errors for individual elements
756
+ }
757
+ });
758
+ // Now create fresh instances
759
+ KTDrawer.createInstances();
760
+ // Always ensure handlers are set up (similar to KTMenu.init() behavior)
761
+ // Event handlers use delegation so they persist, but we ensure they're attached
762
+ KTDrawer.handleToggle();
763
+ KTDrawer.handleDismiss();
764
+ KTDrawer.handleResize();
765
+ KTDrawer.handleClickAway();
766
+ KTDrawer.handleKeyword();
767
+ };
522
768
  return KTDrawer;
523
769
  }(component_1.default));
524
770
  exports.KTDrawer = KTDrawer;
@@ -1929,6 +2175,28 @@ var KTComponent = /** @class */ (function () {
1929
2175
  this._uid = null;
1930
2176
  this._element = null;
1931
2177
  }
2178
+ /**
2179
+ * Check if component should skip initialization
2180
+ * Returns true if element already has an instance and is still connected to DOM
2181
+ * Returns false if element should be initialized (no instance or disconnected)
2182
+ * @param element The element to check
2183
+ * @returns true if initialization should be skipped, false otherwise
2184
+ */
2185
+ KTComponent.prototype._shouldSkipInit = function (element) {
2186
+ if (!data_1.default.has(element, this._name)) {
2187
+ return false;
2188
+ }
2189
+ var existingInstance = data_1.default.get(element, this._name);
2190
+ // If element is not connected to DOM, dispose old instance and allow reinitialization
2191
+ if (element.isConnected === false) {
2192
+ if (existingInstance && typeof existingInstance.dispose === 'function') {
2193
+ existingInstance.dispose();
2194
+ }
2195
+ return false;
2196
+ }
2197
+ // Element is connected and has instance, skip initialization
2198
+ return true;
2199
+ };
1932
2200
  KTComponent.prototype._init = function (element) {
1933
2201
  element = dom_1.default.getElement(element);
1934
2202
  if (!element) {
@@ -2307,8 +2575,12 @@ var KTSticky = /** @class */ (function (_super) {
2307
2575
  };
2308
2576
  _this._config = _this._defaultConfig;
2309
2577
  _this._targetElement = null;
2310
- if (data_1.default.has(element, _this._name))
2578
+ _this._resizeHandler = null;
2579
+ _this._scrollHandler = null;
2580
+ // Check if element already has an instance and is still connected
2581
+ if (_this._shouldSkipInit(element)) {
2311
2582
  return _this;
2583
+ }
2312
2584
  _this._init(element);
2313
2585
  _this._buildConfig(config);
2314
2586
  _this._releaseElement = dom_1.default.getElement(_this._getOption('release'));
@@ -2334,15 +2606,26 @@ var KTSticky = /** @class */ (function (_super) {
2334
2606
  };
2335
2607
  KTSticky.prototype._handlers = function () {
2336
2608
  var _this = this;
2337
- window.addEventListener('resize', function () {
2609
+ // Store resize handler reference for cleanup
2610
+ this._resizeHandler = function () {
2338
2611
  var timer;
2339
2612
  utils_1.default.throttle(timer, function () {
2340
2613
  _this._update();
2341
2614
  }, 200);
2342
- });
2343
- this._targetElement.addEventListener('scroll', function () {
2615
+ };
2616
+ window.addEventListener('resize', this._resizeHandler);
2617
+ // Store scroll handler reference for cleanup
2618
+ this._scrollHandler = function () {
2344
2619
  _this._process();
2345
- });
2620
+ };
2621
+ if (this._targetElement) {
2622
+ if (this._targetElement === document) {
2623
+ window.addEventListener('scroll', this._scrollHandler);
2624
+ }
2625
+ else {
2626
+ this._targetElement.addEventListener('scroll', this._scrollHandler);
2627
+ }
2628
+ }
2346
2629
  };
2347
2630
  KTSticky.prototype._process = function () {
2348
2631
  var reverse = this._getOption('reverse');
@@ -2583,6 +2866,30 @@ var KTSticky = /** @class */ (function (_super) {
2583
2866
  KTSticky.prototype.isActive = function () {
2584
2867
  return this._isActive();
2585
2868
  };
2869
+ KTSticky.prototype.dispose = function () {
2870
+ // Remove resize event listener
2871
+ if (this._resizeHandler) {
2872
+ window.removeEventListener('resize', this._resizeHandler);
2873
+ this._resizeHandler = null;
2874
+ }
2875
+ // Remove scroll event listener
2876
+ if (this._scrollHandler) {
2877
+ if (this._targetElement === document) {
2878
+ window.removeEventListener('scroll', this._scrollHandler);
2879
+ }
2880
+ else if (this._targetElement) {
2881
+ this._targetElement.removeEventListener('scroll', this._scrollHandler);
2882
+ }
2883
+ this._scrollHandler = null;
2884
+ }
2885
+ // Clean up state
2886
+ this._disable();
2887
+ if (this._attributeRoot && document.body.hasAttribute(this._attributeRoot)) {
2888
+ document.body.removeAttribute(this._attributeRoot);
2889
+ }
2890
+ // Call parent dispose to clean up data attributes and KTData
2891
+ _super.prototype.dispose.call(this);
2892
+ };
2586
2893
  KTSticky.getInstance = function (element) {
2587
2894
  if (!element)
2588
2895
  return null;
@@ -5743,13 +6050,14 @@ var KTEventHandler = {
5743
6050
  }
5744
6051
  var eventId = utils_1.default.geUID('event');
5745
6052
  KTDelegatedEventHandlers[eventId] = function (event) {
5746
- var targets = element.querySelectorAll(selector);
6053
+ // Fix: Check selector dynamically instead of pre-computing targets
6054
+ // This allows event delegation to work with dynamically added elements
5747
6055
  var target = event.target;
5748
6056
  while (target && target !== element) {
5749
- for (var i = 0, j = targets.length; i < j; i++) {
5750
- if (target === targets[i]) {
5751
- handler.call(_this, event, target);
5752
- }
6057
+ // Check if current target matches the selector
6058
+ if (target.matches && target.matches(selector)) {
6059
+ handler.call(_this, event, target);
6060
+ return; // Stop bubbling once we've handled it
5753
6061
  }
5754
6062
  target = target.parentNode;
5755
6063
  }
@@ -7213,9 +7521,13 @@ var KTDataTable = /** @class */ (function (_super) {
7213
7521
  var originalDataAttributes = [];
7214
7522
  this._storeOriginalClasses();
7215
7523
  var rows = this._tbodyElement.querySelectorAll('tr');
7216
- var ths = this._theadElement
7524
+ // Filter th elements to only include those with data-kt-datatable-column attribute
7525
+ var allThs = this._theadElement
7217
7526
  ? this._theadElement.querySelectorAll('th')
7218
7527
  : [];
7528
+ var ths = Array.from(allThs).filter(function (th) {
7529
+ return th.hasAttribute('data-kt-datatable-column');
7530
+ });
7219
7531
  rows.forEach(function (row) {
7220
7532
  var dataRow = {};
7221
7533
  var dataRowAttribute = {};
@@ -7243,9 +7555,13 @@ var KTDataTable = /** @class */ (function (_super) {
7243
7555
  */
7244
7556
  KTDataTable.prototype._localTableHeaderInvalidate = function () {
7245
7557
  var originalData = this.getState().originalData;
7246
- var currentTableHeaders = this._theadElement
7247
- ? this._theadElement.querySelectorAll('th').length
7248
- : 0;
7558
+ // Count only th elements with data-kt-datatable-column attribute
7559
+ var allThs = this._theadElement
7560
+ ? this._theadElement.querySelectorAll('th')
7561
+ : [];
7562
+ var currentTableHeaders = Array.from(allThs).filter(function (th) {
7563
+ return th.hasAttribute('data-kt-datatable-column');
7564
+ }).length;
7249
7565
  var totalColumns = originalData.length
7250
7566
  ? Object.keys(originalData[0]).length
7251
7567
  : 0;
@@ -7495,9 +7811,14 @@ var KTDataTable = /** @class */ (function (_super) {
7495
7811
  this._noticeOnTable(this._config.infoEmpty || '');
7496
7812
  return tbodyElement;
7497
7813
  }
7498
- var ths = this._theadElement
7814
+ // Filter th elements to only include those with data-kt-datatable-column attribute
7815
+ // This prevents creating blank td elements for merged header cells (colspan/rowspan)
7816
+ var allThs = this._theadElement
7499
7817
  ? this._theadElement.querySelectorAll('th')
7500
7818
  : [];
7819
+ var ths = Array.from(allThs).filter(function (th) {
7820
+ return th.hasAttribute('data-kt-datatable-column');
7821
+ });
7501
7822
  this._data.forEach(function (item, rowIndex) {
7502
7823
  var row = document.createElement('tr');
7503
7824
  // Apply original tr class if available
@@ -7508,7 +7829,7 @@ var KTDataTable = /** @class */ (function (_super) {
7508
7829
  var dataRowAttributes_1 = _this.getState().originalDataAttributes
7509
7830
  ? _this.getState().originalDataAttributes[rowIndex]
7510
7831
  : null;
7511
- // Use the order of <th> elements to render <td>s in the correct order
7832
+ // Use the order of <th> elements with data-kt-datatable-column to render <td>s in the correct order
7512
7833
  ths.forEach(function (th, colIndex) {
7513
7834
  var colName = th.getAttribute('data-kt-datatable-column');
7514
7835
  var td = document.createElement('td');
@@ -8090,7 +8411,13 @@ var KTDataTable = /** @class */ (function (_super) {
8090
8411
  * @returns The KTDataTable instance or undefined if not found
8091
8412
  */
8092
8413
  KTDataTable.getInstance = function (element) {
8093
- return this._instances.get(element);
8414
+ // First check the static Map (for instances created via createInstances)
8415
+ var instanceFromMap = this._instances.get(element);
8416
+ if (instanceFromMap) {
8417
+ return instanceFromMap;
8418
+ }
8419
+ // Fallback to element's instance property (for manually created instances)
8420
+ return element.instance;
8094
8421
  };
8095
8422
  /**
8096
8423
  * Initializes all KTDataTable instances on the page.
@@ -9391,6 +9718,7 @@ var KTSelectSearch = /** @class */ (function () {
9391
9718
  * Handles keydown events on the search input for navigation and actions.
9392
9719
  */
9393
9720
  KTSelectSearch.prototype._handleSearchKeyDown = function (event) {
9721
+ var _this = this;
9394
9722
  var key = event.key;
9395
9723
  switch (key) {
9396
9724
  case ' ': // Spacebar
@@ -9408,19 +9736,28 @@ var KTSelectSearch = /** @class */ (function () {
9408
9736
  break;
9409
9737
  case 'Enter':
9410
9738
  event.preventDefault();
9411
- // Always attempt to select the first available option in the list.
9412
- // focusFirst() finds, focuses, and returns the first visible, non-disabled option.
9413
9739
  var firstAvailableOption = this._focusManager.focusFirst();
9414
9740
  if (firstAvailableOption) {
9415
9741
  var optionValue = firstAvailableOption.getAttribute('data-value');
9416
9742
  if (optionValue) {
9417
- // toggleSelection() already handles closing the dropdown based on closeOnEnter config
9418
- // for single-select mode, so we don't need to call closeDropdown() here
9419
- this._select.toggleSelection(optionValue);
9420
- // If closeOnEnter is false, dropdown remains open for additional selections
9743
+ var config = this._select.getConfig();
9744
+ var isAlreadySelected = !config.multiple && this._select.getSelectedOptions().includes(optionValue);
9745
+ var shouldClose = !config.multiple && config.closeOnEnter !== false;
9746
+ if (isAlreadySelected && shouldClose) {
9747
+ this._select.closeDropdown();
9748
+ }
9749
+ else {
9750
+ this._select.toggleSelection(optionValue);
9751
+ }
9752
+ // Focus display element after closing so user can press Enter again
9753
+ if (shouldClose) {
9754
+ setTimeout(function () {
9755
+ var _a;
9756
+ (_a = _this._select.getDisplayElement()) === null || _a === void 0 ? void 0 : _a.focus();
9757
+ }, 0);
9758
+ }
9421
9759
  }
9422
9760
  }
9423
- // If no available option, do nothing (dropdown remains open)
9424
9761
  break;
9425
9762
  case 'Escape':
9426
9763
  event.preventDefault();
@@ -9790,21 +10127,29 @@ var KTSelect = /** @class */ (function (_super) {
9790
10127
  // Also dispatch on document if configured
9791
10128
  var dispatchGlobalEvents = this._config.dispatchGlobalEvents !== false; // Default to true
9792
10129
  if (dispatchGlobalEvents) {
9793
- // Create namespaced event name for document dispatch
10130
+ // Create event detail structure
10131
+ var eventDetail = {
10132
+ payload: payload,
10133
+ instance: this, // Include component instance reference
10134
+ element: this._element, // Include element reference
10135
+ };
10136
+ // Dispatch non-namespaced event on document (for jQuery compatibility: $(document).on('show', ...))
10137
+ var nonNamespacedEvent = new CustomEvent(eventType, {
10138
+ detail: eventDetail,
10139
+ bubbles: true,
10140
+ cancelable: true,
10141
+ composed: true, // Allow event to cross shadow DOM boundaries
10142
+ });
10143
+ document.dispatchEvent(nonNamespacedEvent);
10144
+ // Also dispatch namespaced event on document (for namespaced listeners: $(document).on('kt-select:show', ...))
9794
10145
  var namespacedEventType = "kt-select:".concat(eventType);
9795
- // Create event with same detail structure
9796
- var globalEvent = new CustomEvent(namespacedEventType, {
9797
- detail: {
9798
- payload: payload,
9799
- instance: this, // Include component instance reference
9800
- element: this._element, // Include element reference
9801
- },
10146
+ var namespacedEvent = new CustomEvent(namespacedEventType, {
10147
+ detail: eventDetail,
9802
10148
  bubbles: true,
9803
10149
  cancelable: true,
9804
10150
  composed: true, // Allow event to cross shadow DOM boundaries
9805
10151
  });
9806
- // Dispatch on document
9807
- document.dispatchEvent(globalEvent);
10152
+ document.dispatchEvent(namespacedEvent);
9808
10153
  }
9809
10154
  };
9810
10155
  /**
@@ -10494,7 +10839,23 @@ var KTSelect = /** @class */ (function (_super) {
10494
10839
  // Update select all button state
10495
10840
  this.updateSelectAllButtonState();
10496
10841
  // Focus the first selected option or first option if nothing selected
10497
- this._focusSelectedOption();
10842
+ // BUT: Skip this if search autofocus is enabled, as we want search input to get focus
10843
+ if (!(this._config.enableSearch && this._config.searchAutofocus)) {
10844
+ this._focusSelectedOption();
10845
+ }
10846
+ // Dispatch dropdown.show event on the wrapper element for search module
10847
+ // Use requestAnimationFrame to ensure dropdown is visible and transition has started
10848
+ requestAnimationFrame(function () {
10849
+ requestAnimationFrame(function () {
10850
+ if (_this._wrapperElement) {
10851
+ var dropdownShowEvent_1 = new CustomEvent('dropdown.show', {
10852
+ bubbles: true,
10853
+ cancelable: true,
10854
+ });
10855
+ _this._wrapperElement.dispatchEvent(dropdownShowEvent_1);
10856
+ }
10857
+ });
10858
+ });
10498
10859
  };
10499
10860
  /**
10500
10861
  * Close the dropdown
@@ -10523,7 +10884,7 @@ var KTSelect = /** @class */ (function (_super) {
10523
10884
  if (this._focusManager) {
10524
10885
  this._focusManager.resetFocus();
10525
10886
  }
10526
- // Dispatch custom events
10887
+ // Dispatch custom events on the select element
10527
10888
  this._dispatchEvent('close');
10528
10889
  this._fireEvent('close');
10529
10890
  // Dispatch dropdown.close event on wrapper for search module
@@ -10670,14 +11031,17 @@ var KTSelect = /** @class */ (function (_super) {
10670
11031
  }
10671
11032
  else {
10672
11033
  // Tags are not enabled AND options are selected: render normal text display.
10673
- var content = '';
11034
+ // Wrap content in .kt-select-option-text so long text truncates in single-select (see Asana #1212821478465094).
11035
+ var wrapper = document.createElement('div');
11036
+ wrapper.className = 'kt-select-option-text';
11037
+ wrapper.setAttribute('data-kt-text-container', 'true');
10674
11038
  if (this._config.displayTemplate) {
10675
- content = this.renderDisplayTemplateForSelected(this.getSelectedOptions());
11039
+ wrapper.innerHTML = this.renderDisplayTemplateForSelected(this.getSelectedOptions());
10676
11040
  }
10677
11041
  else {
10678
- content = this.getSelectedOptionsText();
11042
+ wrapper.textContent = this.getSelectedOptionsText();
10679
11043
  }
10680
- valueDisplayEl.innerHTML = content;
11044
+ valueDisplayEl.replaceChildren(wrapper);
10681
11045
  }
10682
11046
  }
10683
11047
  }
@@ -10747,6 +11111,55 @@ var KTSelect = /** @class */ (function (_super) {
10747
11111
  this._dispatchEvent('change');
10748
11112
  this._fireEvent('change');
10749
11113
  };
11114
+ /**
11115
+ * Deselect a specific option by value
11116
+ * @param value The value of the option to deselect
11117
+ * @public
11118
+ */
11119
+ KTSelect.prototype.deselectOption = function (value) {
11120
+ // Check if the option is currently selected
11121
+ if (!this._state.isSelected(value)) {
11122
+ return; // Already deselected
11123
+ }
11124
+ // For single-select mode, check if clearing is allowed
11125
+ if (!this._config.multiple && !this._config.allowClear) {
11126
+ return; // Cannot deselect in single-select mode unless allowClear is true
11127
+ }
11128
+ // Remove from selected options
11129
+ if (this._config.multiple) {
11130
+ // For multiple select, just toggle it off
11131
+ this._state.toggleSelectedOptions(value);
11132
+ }
11133
+ else {
11134
+ // For single select, clear all selections
11135
+ this._state.setSelectedOptions([]);
11136
+ }
11137
+ // Update the native select element
11138
+ var optionEl = Array.from(this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
11139
+ if (optionEl) {
11140
+ optionEl.selected = false;
11141
+ }
11142
+ // For single select, clear the native select value
11143
+ if (!this._config.multiple) {
11144
+ this._element.value = '';
11145
+ }
11146
+ // Update the display
11147
+ this.updateSelectedOptionDisplay();
11148
+ this._updateSelectedOptionClass();
11149
+ // Update select all button state
11150
+ this.updateSelectAllButtonState();
11151
+ // Dispatch change event
11152
+ this._dispatchEvent('change', {
11153
+ value: value,
11154
+ selected: false,
11155
+ selectedOptions: this.getSelectedOptions(),
11156
+ });
11157
+ this._fireEvent('change', {
11158
+ value: value,
11159
+ selected: false,
11160
+ selectedOptions: this.getSelectedOptions(),
11161
+ });
11162
+ };
10750
11163
  /**
10751
11164
  * Set selected options programmatically
10752
11165
  */
@@ -10948,9 +11361,14 @@ var KTSelect = /** @class */ (function (_super) {
10948
11361
  }
10949
11362
  // Get current selection state
10950
11363
  var isSelected = this._state.isSelected(value);
10951
- // If already selected in single select mode, do nothing (can't deselect in single select)
11364
+ // If already selected in single select mode, allow deselecting only if allowClear is true
10952
11365
  if (isSelected && !this._config.multiple) {
10953
- return;
11366
+ if (this._config.allowClear) {
11367
+ // Use the deselectOption method to handle clearing
11368
+ this.deselectOption(value);
11369
+ return;
11370
+ }
11371
+ return; // Can't deselect in single select mode when allowClear is false
10954
11372
  }
10955
11373
  // Ensure any search input is cleared when selection changes
10956
11374
  if (this._searchModule) {
@@ -12019,16 +12437,19 @@ var KTDropdown = /** @class */ (function (_super) {
12019
12437
  _this._disabled = false;
12020
12438
  _this._isTransitioning = false;
12021
12439
  _this._isOpen = false;
12022
- if (data_1.default.has(element, _this._name))
12440
+ if (data_1.default.has(element, _this._name)) {
12023
12441
  return _this;
12442
+ }
12024
12443
  _this._init(element);
12025
12444
  _this._buildConfig(config);
12026
12445
  _this._toggleElement = _this._element.querySelector('[data-kt-dropdown-toggle]');
12027
- if (!_this._toggleElement)
12446
+ if (!_this._toggleElement) {
12028
12447
  return _this;
12448
+ }
12029
12449
  _this._menuElement = _this._element.querySelector('[data-kt-dropdown-menu]');
12030
- if (!_this._menuElement)
12450
+ if (!_this._menuElement) {
12031
12451
  return _this;
12452
+ }
12032
12453
  data_1.default.set(_this._menuElement, 'dropdownElement', _this._element);
12033
12454
  _this._setupNestedDropdowns();
12034
12455
  _this._handleContainer();
@@ -12061,10 +12482,12 @@ var KTDropdown = /** @class */ (function (_super) {
12061
12482
  KTDropdown.prototype._click = function (event) {
12062
12483
  event.preventDefault();
12063
12484
  event.stopPropagation();
12064
- if (this._disabled)
12485
+ if (this._disabled) {
12065
12486
  return;
12066
- if (this._getOption('trigger') !== 'click')
12487
+ }
12488
+ if (this._getOption('trigger') !== 'click') {
12067
12489
  return;
12490
+ }
12068
12491
  this._toggle();
12069
12492
  };
12070
12493
  KTDropdown.prototype._mouseover = function (event) {
@@ -12107,8 +12530,9 @@ var KTDropdown = /** @class */ (function (_super) {
12107
12530
  };
12108
12531
  KTDropdown.prototype._show = function () {
12109
12532
  var _this = this;
12110
- if (this._isOpen || this._isTransitioning)
12533
+ if (this._isOpen || this._isTransitioning) {
12111
12534
  return;
12535
+ }
12112
12536
  var payload = { cancel: false };
12113
12537
  this._fireEvent('show', payload);
12114
12538
  this._dispatchEvent('show', payload);
@@ -12281,6 +12705,12 @@ var KTDropdown = /** @class */ (function (_super) {
12281
12705
  reference.closest('[data-kt-dropdown-initialized]');
12282
12706
  if (findElement)
12283
12707
  return findElement;
12708
+ // Fallback: look for parent with data-kt-dropdown attribute
12709
+ if (reference) {
12710
+ var dropdownContainer = reference.closest('[data-kt-dropdown]');
12711
+ if (dropdownContainer)
12712
+ return dropdownContainer;
12713
+ }
12284
12714
  if (reference &&
12285
12715
  reference.hasAttribute('data-kt-dropdown-menu') &&
12286
12716
  data_1.default.has(reference, 'dropdownElement')) {
@@ -12290,10 +12720,12 @@ var KTDropdown = /** @class */ (function (_super) {
12290
12720
  };
12291
12721
  KTDropdown.getInstance = function (element) {
12292
12722
  element = this.getElement(element);
12293
- if (!element)
12723
+ if (!element) {
12294
12724
  return null;
12725
+ }
12295
12726
  if (data_1.default.has(element, 'dropdown')) {
12296
- return data_1.default.get(element, 'dropdown');
12727
+ var instance = data_1.default.get(element, 'dropdown');
12728
+ return instance;
12297
12729
  }
12298
12730
  if (element.getAttribute('data-kt-dropdown-initialized') === 'true') {
12299
12731
  return new KTDropdown(element);
@@ -12408,6 +12840,39 @@ var KTDropdown = /** @class */ (function (_super) {
12408
12840
  window.KT_DROPDOWN_INITIALIZED = true;
12409
12841
  }
12410
12842
  };
12843
+ /**
12844
+ * Force reinitialization of dropdowns by clearing KTData entries.
12845
+ * Useful for Livewire wire:navigate where persisted elements need reinitialization.
12846
+ */
12847
+ KTDropdown.reinit = function () {
12848
+ var elements = document.querySelectorAll('[data-kt-dropdown]');
12849
+ elements.forEach(function (element) {
12850
+ try {
12851
+ // Get existing instance to clean up Popper
12852
+ var instance = KTDropdown.getInstance(element);
12853
+ if (instance && typeof instance.hide === 'function') {
12854
+ instance.hide(); // This will destroy Popper
12855
+ }
12856
+ // Clear KTData entries
12857
+ data_1.default.remove(element, 'dropdown');
12858
+ data_1.default.remove(element, 'popper');
12859
+ // Remove initialization attribute to allow fresh initialization
12860
+ element.removeAttribute('data-kt-dropdown-initialized');
12861
+ var menu = element.querySelector('[data-kt-dropdown-menu]');
12862
+ if (menu) {
12863
+ data_1.default.remove(menu, 'dropdownElement');
12864
+ }
12865
+ }
12866
+ catch (e) {
12867
+ // Ignore errors for individual elements
12868
+ }
12869
+ });
12870
+ // Now create fresh instances
12871
+ KTDropdown.createInstances();
12872
+ // Always ensure handlers are set up (similar to KTMenu.init() behavior)
12873
+ // Event handlers use delegation so they persist, but we ensure they're attached
12874
+ KTDropdown.initHandlers();
12875
+ };
12411
12876
  return KTDropdown;
12412
12877
  }(component_1.default));
12413
12878
  exports.KTDropdown = KTDropdown;
@@ -12471,7 +12936,15 @@ var KTData = {
12471
12936
  KTElementMap.delete(element);
12472
12937
  }
12473
12938
  },
12939
+ // Clear all data for a specific element (useful for reinitialization)
12940
+ clear: function (element) {
12941
+ KTElementMap.delete(element);
12942
+ },
12474
12943
  };
12944
+ // Expose KTData on window for external access (useful for Livewire wire:navigate)
12945
+ if (typeof window !== 'undefined') {
12946
+ window.KTData = KTData;
12947
+ }
12475
12948
  exports["default"] = KTData;
12476
12949
 
12477
12950