admin-lte 4.1.0 → 4.3.1

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 (57) hide show
  1. package/CHANGELOG.md +57 -1
  2. package/README.md +23 -7
  3. package/dist/css/adminlte-docs.css +1 -1
  4. package/dist/css/adminlte-docs.css.map +1 -1
  5. package/dist/css/adminlte-docs.min.css +1 -1
  6. package/dist/css/adminlte-docs.min.css.map +1 -1
  7. package/dist/css/adminlte-docs.rtl.css +1 -1
  8. package/dist/css/adminlte-docs.rtl.css.map +1 -1
  9. package/dist/css/adminlte-docs.rtl.min.css +1 -1
  10. package/dist/css/adminlte-docs.rtl.min.css.map +1 -1
  11. package/dist/css/adminlte-select2.css +329 -0
  12. package/dist/css/adminlte-select2.css.map +1 -0
  13. package/dist/css/adminlte-select2.min.css +12 -0
  14. package/dist/css/adminlte-select2.min.css.map +1 -0
  15. package/dist/css/adminlte-select2.rtl.css +328 -0
  16. package/dist/css/adminlte-select2.rtl.css.map +1 -0
  17. package/dist/css/adminlte-select2.rtl.min.css +12 -0
  18. package/dist/css/adminlte-select2.rtl.min.css.map +1 -0
  19. package/dist/css/adminlte.css +332 -131
  20. package/dist/css/adminlte.css.map +1 -1
  21. package/dist/css/adminlte.min.css +2 -2
  22. package/dist/css/adminlte.min.css.map +1 -1
  23. package/dist/css/adminlte.rtl.css +332 -131
  24. package/dist/css/adminlte.rtl.css.map +1 -1
  25. package/dist/css/adminlte.rtl.min.css +2 -2
  26. package/dist/css/adminlte.rtl.min.css.map +1 -1
  27. package/dist/js/adminlte.esm.js +300 -109
  28. package/dist/js/adminlte.esm.js.map +1 -1
  29. package/dist/js/adminlte.esm.min.js +2 -2
  30. package/dist/js/adminlte.esm.min.js.map +1 -1
  31. package/dist/js/adminlte.js +302 -108
  32. package/dist/js/adminlte.js.map +1 -1
  33. package/dist/js/adminlte.min.js +2 -2
  34. package/dist/js/adminlte.min.js.map +1 -1
  35. package/dist/js/types/adminlte.d.ts +3 -1
  36. package/dist/js/types/base-component.d.ts +24 -0
  37. package/dist/js/types/color-mode.d.ts +24 -6
  38. package/dist/js/types/push-menu.d.ts +21 -0
  39. package/dist/js/types/sidebar-search.d.ts +46 -0
  40. package/dist/js/types/util/index.d.ts +38 -1
  41. package/package.json +24 -23
  42. package/src/scss/_app-sidebar.scss +12 -0
  43. package/src/scss/_ribbon.scss +75 -0
  44. package/src/scss/_variables.scss +28 -0
  45. package/src/scss/_widgets.scss +192 -0
  46. package/src/scss/adminlte-docs.scss +1 -1
  47. package/src/scss/adminlte-select2.scss +31 -0
  48. package/src/scss/adminlte.scss +1 -1
  49. package/src/scss/compat/_select2.scss +476 -0
  50. package/src/scss/parts/_extra-components.scss +2 -0
  51. package/src/ts/accessibility.ts +31 -15
  52. package/src/ts/adminlte.ts +7 -3
  53. package/src/ts/base-component.ts +30 -3
  54. package/src/ts/color-mode.ts +100 -20
  55. package/src/ts/push-menu.ts +37 -7
  56. package/src/ts/sidebar-search.ts +252 -0
  57. package/src/ts/util/index.ts +79 -15
@@ -1,12 +1,13 @@
1
1
  /*!
2
- * AdminLTE v4.1.0 (https://adminlte.io)
2
+ * AdminLTE v4.3.1 (https://adminlte.io)
3
3
  * Copyright 2014-2026 Colorlib <https://colorlib.com>
4
4
  * Licensed under MIT (https://github.com/ColorlibHQ/AdminLTE/blob/master/LICENSE)
5
5
  */
6
6
  const lifecycleCallbacks = [];
7
7
  const lifecycleState = {
8
8
  controller: new AbortController(),
9
- hasInitialized: false
9
+ hasInitialized: false,
10
+ isReplaying: false
10
11
  };
11
12
  const getLifecycleSignal = () => lifecycleState.controller.signal;
12
13
  const runLifecycleCallbacks = () => {
@@ -14,8 +15,14 @@ const runLifecycleCallbacks = () => {
14
15
  return;
15
16
  }
16
17
  lifecycleState.hasInitialized = true;
17
- for (const callback of lifecycleCallbacks) {
18
- callback();
18
+ lifecycleState.isReplaying = true;
19
+ try {
20
+ for (const callback of lifecycleCallbacks) {
21
+ callback();
22
+ }
23
+ }
24
+ finally {
25
+ lifecycleState.isReplaying = false;
19
26
  }
20
27
  };
21
28
  const onDOMContentLoaded = (callback) => {
@@ -24,17 +31,25 @@ const onDOMContentLoaded = (callback) => {
24
31
  callback();
25
32
  }
26
33
  };
34
+ const teardown = () => {
35
+ lifecycleState.controller.abort();
36
+ lifecycleState.controller = new AbortController();
37
+ lifecycleState.hasInitialized = false;
38
+ };
39
+ const initialize = () => {
40
+ if (lifecycleState.isReplaying) {
41
+ return;
42
+ }
43
+ teardown();
44
+ runLifecycleCallbacks();
45
+ };
27
46
  if (document.readyState === 'loading') {
28
- document.addEventListener('DOMContentLoaded', runLifecycleCallbacks, { once: true });
47
+ document.addEventListener('DOMContentLoaded', initialize, { once: true });
29
48
  }
30
49
  else {
31
50
  runLifecycleCallbacks();
32
51
  }
33
- document.addEventListener('turbo:before-render', () => {
34
- lifecycleState.controller.abort();
35
- lifecycleState.controller = new AbortController();
36
- lifecycleState.hasInitialized = false;
37
- });
52
+ document.addEventListener('turbo:before-render', teardown);
38
53
  document.addEventListener('turbo:load', runLifecycleCallbacks);
39
54
  const slideTimers = new WeakMap();
40
55
  const cancelSlide = (target) => {
@@ -177,16 +192,16 @@ const dispatchCustomEvent = (element, name, options = {}) => {
177
192
  return event;
178
193
  };
179
194
 
180
- const NAME$4 = 'card-widget';
181
- const EVENT_KEY$5 = `.lte.${NAME$4}`;
182
- const EVENT_COLLAPSE$2 = `collapse${EVENT_KEY$5}`;
183
- const EVENT_EXPAND$1 = `expand${EVENT_KEY$5}`;
184
- const EVENT_REMOVE = `remove${EVENT_KEY$5}`;
185
- const EVENT_COLLAPSED$3 = `collapsed${EVENT_KEY$5}`;
186
- const EVENT_EXPANDED$2 = `expanded${EVENT_KEY$5}`;
187
- const EVENT_REMOVED = `removed${EVENT_KEY$5}`;
188
- const EVENT_MAXIMIZED$1 = `maximized${EVENT_KEY$5}`;
189
- const EVENT_MINIMIZED$1 = `minimized${EVENT_KEY$5}`;
195
+ const NAME$5 = 'card-widget';
196
+ const EVENT_KEY$6 = `.lte.${NAME$5}`;
197
+ const EVENT_COLLAPSE$2 = `collapse${EVENT_KEY$6}`;
198
+ const EVENT_EXPAND$1 = `expand${EVENT_KEY$6}`;
199
+ const EVENT_REMOVE = `remove${EVENT_KEY$6}`;
200
+ const EVENT_COLLAPSED$3 = `collapsed${EVENT_KEY$6}`;
201
+ const EVENT_EXPANDED$2 = `expanded${EVENT_KEY$6}`;
202
+ const EVENT_REMOVED = `removed${EVENT_KEY$6}`;
203
+ const EVENT_MAXIMIZED$1 = `maximized${EVENT_KEY$6}`;
204
+ const EVENT_MINIMIZED$1 = `minimized${EVENT_KEY$6}`;
190
205
  const CLASS_NAME_CARD = 'card';
191
206
  const CLASS_NAME_COLLAPSED = 'collapsed-card';
192
207
  const CLASS_NAME_COLLAPSING = 'collapsing-card';
@@ -207,7 +222,7 @@ const Default$1 = {
207
222
  };
208
223
  class CardWidget extends BaseComponent {
209
224
  static get NAME() {
210
- return NAME$4;
225
+ return NAME$5;
211
226
  }
212
227
  static getInstance(element) {
213
228
  return this._getInstance(element);
@@ -374,29 +389,29 @@ document.addEventListener('click', event => {
374
389
  }
375
390
  });
376
391
 
377
- const NAME$3 = 'treeview';
378
- const EVENT_KEY$4 = `.lte.${NAME$3}`;
379
- const EVENT_EXPAND = `expand${EVENT_KEY$4}`;
380
- const EVENT_COLLAPSE$1 = `collapse${EVENT_KEY$4}`;
381
- const EVENT_EXPANDED$1 = `expanded${EVENT_KEY$4}`;
382
- const EVENT_COLLAPSED$2 = `collapsed${EVENT_KEY$4}`;
383
- const EVENT_LOAD_DATA_API = `load${EVENT_KEY$4}`;
384
- const CLASS_NAME_MENU_OPEN = 'menu-open';
385
- const SELECTOR_NAV_ITEM = '.nav-item';
386
- const SELECTOR_NAV_LINK = '.nav-link';
387
- const SELECTOR_TREEVIEW_MENU = '.nav-treeview';
388
- const SELECTOR_DATA_TOGGLE$1 = '[data-lte-toggle="treeview"]';
392
+ const NAME$4 = 'treeview';
393
+ const EVENT_KEY$5 = `.lte.${NAME$4}`;
394
+ const EVENT_EXPAND = `expand${EVENT_KEY$5}`;
395
+ const EVENT_COLLAPSE$1 = `collapse${EVENT_KEY$5}`;
396
+ const EVENT_EXPANDED$1 = `expanded${EVENT_KEY$5}`;
397
+ const EVENT_COLLAPSED$2 = `collapsed${EVENT_KEY$5}`;
398
+ const EVENT_LOAD_DATA_API = `load${EVENT_KEY$5}`;
399
+ const CLASS_NAME_MENU_OPEN$1 = 'menu-open';
400
+ const SELECTOR_NAV_ITEM$1 = '.nav-item';
401
+ const SELECTOR_NAV_LINK$1 = '.nav-link';
402
+ const SELECTOR_TREEVIEW_MENU$1 = '.nav-treeview';
403
+ const SELECTOR_DATA_TOGGLE$2 = '[data-lte-toggle="treeview"]';
389
404
  const Default = {
390
405
  animationSpeed: 300,
391
406
  accordion: true
392
407
  };
393
408
  const setAriaExpanded = (navItem, expanded) => {
394
- const link = navItem.querySelector(`:scope > ${SELECTOR_NAV_LINK}`);
409
+ const link = navItem.querySelector(`:scope > ${SELECTOR_NAV_LINK$1}`);
395
410
  link?.setAttribute('aria-expanded', String(expanded));
396
411
  };
397
412
  class Treeview extends BaseComponent {
398
413
  static get NAME() {
399
- return NAME$3;
414
+ return NAME$4;
400
415
  }
401
416
  static getInstance(element) {
402
417
  return this._getInstance(element);
@@ -414,26 +429,26 @@ class Treeview extends BaseComponent {
414
429
  return;
415
430
  }
416
431
  if (this._config.accordion) {
417
- const openMenuList = this._element.parentElement?.querySelectorAll(`${SELECTOR_NAV_ITEM}.${CLASS_NAME_MENU_OPEN}`);
432
+ const openMenuList = this._element.parentElement?.querySelectorAll(`${SELECTOR_NAV_ITEM$1}.${CLASS_NAME_MENU_OPEN$1}`);
418
433
  openMenuList?.forEach(openMenu => {
419
434
  if (!this._element.contains(openMenu)) {
420
- openMenu.classList.remove(CLASS_NAME_MENU_OPEN);
435
+ openMenu.classList.remove(CLASS_NAME_MENU_OPEN$1);
421
436
  setAriaExpanded(openMenu, false);
422
- const childElement = openMenu?.querySelector(SELECTOR_TREEVIEW_MENU);
437
+ const childElement = openMenu?.querySelector(SELECTOR_TREEVIEW_MENU$1);
423
438
  if (childElement) {
424
439
  slideUp(childElement, this._config.animationSpeed);
425
440
  }
426
441
  }
427
442
  });
428
443
  }
429
- this._element.classList.add(CLASS_NAME_MENU_OPEN);
444
+ this._element.classList.add(CLASS_NAME_MENU_OPEN$1);
430
445
  setAriaExpanded(this._element, true);
431
- const childElement = this._element.querySelector(SELECTOR_TREEVIEW_MENU);
446
+ const childElement = this._element.querySelector(SELECTOR_TREEVIEW_MENU$1);
432
447
  if (childElement) {
433
448
  slideDown(childElement, this._config.animationSpeed);
434
449
  }
435
450
  setTimeout(() => {
436
- if (this._element.classList.contains(CLASS_NAME_MENU_OPEN)) {
451
+ if (this._element.classList.contains(CLASS_NAME_MENU_OPEN$1)) {
437
452
  dispatchCustomEvent(this._element, EVENT_EXPANDED$1);
438
453
  }
439
454
  }, this._config.animationSpeed);
@@ -442,20 +457,20 @@ class Treeview extends BaseComponent {
442
457
  if (dispatchCustomEvent(this._element, EVENT_COLLAPSE$1, { cancelable: true }).defaultPrevented) {
443
458
  return;
444
459
  }
445
- this._element.classList.remove(CLASS_NAME_MENU_OPEN);
460
+ this._element.classList.remove(CLASS_NAME_MENU_OPEN$1);
446
461
  setAriaExpanded(this._element, false);
447
- const childElement = this._element.querySelector(SELECTOR_TREEVIEW_MENU);
462
+ const childElement = this._element.querySelector(SELECTOR_TREEVIEW_MENU$1);
448
463
  if (childElement) {
449
464
  slideUp(childElement, this._config.animationSpeed);
450
465
  }
451
466
  setTimeout(() => {
452
- if (!this._element.classList.contains(CLASS_NAME_MENU_OPEN)) {
467
+ if (!this._element.classList.contains(CLASS_NAME_MENU_OPEN$1)) {
453
468
  dispatchCustomEvent(this._element, EVENT_COLLAPSED$2);
454
469
  }
455
470
  }, this._config.animationSpeed);
456
471
  }
457
472
  toggle() {
458
- if (this._element.classList.contains(CLASS_NAME_MENU_OPEN)) {
473
+ if (this._element.classList.contains(CLASS_NAME_MENU_OPEN$1)) {
459
474
  this.close();
460
475
  }
461
476
  else {
@@ -468,13 +483,13 @@ document.addEventListener('click', event => {
468
483
  if (!(target instanceof Element)) {
469
484
  return;
470
485
  }
471
- const toggleRoot = target.closest(SELECTOR_DATA_TOGGLE$1);
486
+ const toggleRoot = target.closest(SELECTOR_DATA_TOGGLE$2);
472
487
  if (!toggleRoot) {
473
488
  return;
474
489
  }
475
- const targetItem = target.closest(SELECTOR_NAV_ITEM);
476
- const targetLink = target.closest(SELECTOR_NAV_LINK);
477
- if (!targetItem?.querySelector(SELECTOR_TREEVIEW_MENU)) {
490
+ const targetItem = target.closest(SELECTOR_NAV_ITEM$1);
491
+ const targetLink = target.closest(SELECTOR_NAV_LINK$1);
492
+ if (!targetItem?.querySelector(SELECTOR_TREEVIEW_MENU$1)) {
478
493
  return;
479
494
  }
480
495
  if (target.getAttribute('href') === '#' || targetLink?.getAttribute('href') === '#') {
@@ -489,34 +504,34 @@ document.addEventListener('click', event => {
489
504
  Treeview.getOrCreateInstance(targetItem, config).toggle();
490
505
  });
491
506
  onDOMContentLoaded(() => {
492
- const openMenuItems = document.querySelectorAll(`${SELECTOR_NAV_ITEM}.${CLASS_NAME_MENU_OPEN}`);
507
+ const openMenuItems = document.querySelectorAll(`${SELECTOR_NAV_ITEM$1}.${CLASS_NAME_MENU_OPEN$1}`);
493
508
  openMenuItems.forEach(menuItem => {
494
- const childElement = menuItem.querySelector(SELECTOR_TREEVIEW_MENU);
509
+ const childElement = menuItem.querySelector(SELECTOR_TREEVIEW_MENU$1);
495
510
  if (childElement) {
496
511
  slideDown(childElement, 0);
497
512
  const event = new Event(EVENT_LOAD_DATA_API);
498
513
  menuItem.dispatchEvent(event);
499
514
  }
500
515
  });
501
- document.querySelectorAll(SELECTOR_DATA_TOGGLE$1).forEach(root => {
502
- root.querySelectorAll(SELECTOR_NAV_ITEM).forEach(item => {
503
- if (item.querySelector(`:scope > ${SELECTOR_TREEVIEW_MENU}`)) {
504
- setAriaExpanded(item, item.classList.contains(CLASS_NAME_MENU_OPEN));
516
+ document.querySelectorAll(SELECTOR_DATA_TOGGLE$2).forEach(root => {
517
+ root.querySelectorAll(SELECTOR_NAV_ITEM$1).forEach(item => {
518
+ if (item.querySelector(`:scope > ${SELECTOR_TREEVIEW_MENU$1}`)) {
519
+ setAriaExpanded(item, item.classList.contains(CLASS_NAME_MENU_OPEN$1));
505
520
  }
506
521
  });
507
522
  });
508
523
  });
509
524
 
510
- const NAME$2 = 'direct-chat';
511
- const EVENT_KEY$3 = `.lte.${NAME$2}`;
512
- const EVENT_EXPANDED = `expanded${EVENT_KEY$3}`;
513
- const EVENT_COLLAPSED$1 = `collapsed${EVENT_KEY$3}`;
514
- const SELECTOR_DATA_TOGGLE = '[data-lte-toggle="chat-pane"]';
525
+ const NAME$3 = 'direct-chat';
526
+ const EVENT_KEY$4 = `.lte.${NAME$3}`;
527
+ const EVENT_EXPANDED = `expanded${EVENT_KEY$4}`;
528
+ const EVENT_COLLAPSED$1 = `collapsed${EVENT_KEY$4}`;
529
+ const SELECTOR_DATA_TOGGLE$1 = '[data-lte-toggle="chat-pane"]';
515
530
  const SELECTOR_DIRECT_CHAT = '.direct-chat';
516
531
  const CLASS_NAME_DIRECT_CHAT_OPEN = 'direct-chat-contacts-open';
517
532
  class DirectChat extends BaseComponent {
518
533
  static get NAME() {
519
- return NAME$2;
534
+ return NAME$3;
520
535
  }
521
536
  static getInstance(element) {
522
537
  return this._getInstance(element);
@@ -540,7 +555,7 @@ document.addEventListener('click', event => {
540
555
  if (!(target instanceof Element)) {
541
556
  return;
542
557
  }
543
- const trigger = target.closest(SELECTOR_DATA_TOGGLE);
558
+ const trigger = target.closest(SELECTOR_DATA_TOGGLE$1);
544
559
  if (!trigger) {
545
560
  return;
546
561
  }
@@ -551,10 +566,10 @@ document.addEventListener('click', event => {
551
566
  }
552
567
  });
553
568
 
554
- const NAME$1 = 'fullscreen';
555
- const EVENT_KEY$2 = `.lte.${NAME$1}`;
556
- const EVENT_MAXIMIZED = `maximized${EVENT_KEY$2}`;
557
- const EVENT_MINIMIZED = `minimized${EVENT_KEY$2}`;
569
+ const NAME$2 = 'fullscreen';
570
+ const EVENT_KEY$3 = `.lte.${NAME$2}`;
571
+ const EVENT_MAXIMIZED = `maximized${EVENT_KEY$3}`;
572
+ const EVENT_MINIMIZED = `minimized${EVENT_KEY$3}`;
558
573
  const SELECTOR_FULLSCREEN_TOGGLE = '[data-lte-toggle="fullscreen"]';
559
574
  const SELECTOR_MAXIMIZE_ICON = '[data-lte-icon="maximize"]';
560
575
  const SELECTOR_MINIMIZE_ICON = '[data-lte-icon="minimize"]';
@@ -571,7 +586,7 @@ function syncFullScreenState() {
571
586
  }
572
587
  class FullScreen extends BaseComponent {
573
588
  static get NAME() {
574
- return NAME$1;
589
+ return NAME$2;
575
590
  }
576
591
  static getInstance(element) {
577
592
  return this._getInstance(element);
@@ -615,12 +630,12 @@ onDOMContentLoaded(() => {
615
630
  document.addEventListener('fullscreenchange', syncFullScreenState, { signal: getLifecycleSignal() });
616
631
  });
617
632
 
618
- const NAME = 'push-menu';
619
- const EVENT_KEY$1 = `.lte.${NAME}`;
620
- const EVENT_OPEN = `open${EVENT_KEY$1}`;
621
- const EVENT_COLLAPSE = `collapse${EVENT_KEY$1}`;
622
- const EVENT_OPENED = `opened${EVENT_KEY$1}`;
623
- const EVENT_COLLAPSED = `collapsed${EVENT_KEY$1}`;
633
+ const NAME$1 = 'push-menu';
634
+ const EVENT_KEY$2 = `.lte.${NAME$1}`;
635
+ const EVENT_OPEN = `open${EVENT_KEY$2}`;
636
+ const EVENT_COLLAPSE = `collapse${EVENT_KEY$2}`;
637
+ const EVENT_OPENED = `opened${EVENT_KEY$2}`;
638
+ const EVENT_COLLAPSED = `collapsed${EVENT_KEY$2}`;
624
639
  const CLASS_NAME_SIDEBAR_MINI = 'sidebar-mini';
625
640
  const CLASS_NAME_SIDEBAR_EXPAND = 'sidebar-expand';
626
641
  const CLASS_NAME_SIDEBAR_OVERLAY = 'sidebar-overlay';
@@ -637,7 +652,7 @@ const Defaults = {
637
652
  };
638
653
  class PushMenu extends BaseComponent {
639
654
  static get NAME() {
640
- return NAME;
655
+ return NAME$1;
641
656
  }
642
657
  static getInstance(element) {
643
658
  return this._getInstance(element);
@@ -768,7 +783,7 @@ class PushMenu extends BaseComponent {
768
783
  if (this._config.enablePersistence && !this.isMobileSize()) {
769
784
  this.loadSidebarState();
770
785
  }
771
- else {
786
+ else if (!this.isCollapsed()) {
772
787
  this.updateStateByResponsiveLogic();
773
788
  }
774
789
  }
@@ -816,46 +831,66 @@ onDOMContentLoaded(() => {
816
831
  sidebarOverlay.className = CLASS_NAME_SIDEBAR_OVERLAY;
817
832
  appWrapper?.append(sidebarOverlay);
818
833
  }
834
+ const overlaySignal = getLifecycleSignal();
819
835
  let overlayTouchMoved = false;
820
836
  sidebarOverlay.addEventListener('touchstart', () => {
821
837
  overlayTouchMoved = false;
822
- }, { passive: true });
838
+ }, { passive: true, signal: overlaySignal });
823
839
  sidebarOverlay.addEventListener('touchmove', () => {
824
840
  overlayTouchMoved = true;
825
- }, { passive: true });
841
+ }, { passive: true, signal: overlaySignal });
826
842
  sidebarOverlay.addEventListener('touchend', event => {
827
843
  if (!overlayTouchMoved) {
828
844
  event.preventDefault();
829
845
  pushMenu.collapse();
830
846
  }
831
847
  overlayTouchMoved = false;
832
- }, { passive: false });
848
+ }, { passive: false, signal: overlaySignal });
833
849
  sidebarOverlay.addEventListener('click', event => {
834
850
  event.preventDefault();
835
851
  pushMenu.collapse();
836
- });
852
+ }, { signal: overlaySignal });
837
853
  });
838
854
 
839
855
  const DATA_KEY = 'lte.color-mode';
840
- const EVENT_KEY = `.${DATA_KEY}`;
841
- const EVENT_CHANGED = `changed${EVENT_KEY}`;
856
+ const EVENT_KEY$1 = `.${DATA_KEY}`;
857
+ const EVENT_CHANGED = `changed${EVENT_KEY$1}`;
842
858
  const STORAGE_KEY = 'lte-theme';
843
- const SELECTOR_TOGGLE = '[data-bs-theme-value]';
859
+ const ATTRIBUTE_THEME = 'data-bs-theme';
860
+ const ATTRIBUTE_TOGGLE = 'data-bs-theme-value';
861
+ const ATTRIBUTE_DISABLED = 'data-lte-color-mode';
862
+ const ATTRIBUTE_RESOLVED = 'data-lte-theme-resolved';
863
+ const SELECTOR_TOGGLE = `[${ATTRIBUTE_TOGGLE}]`;
844
864
  const SELECTOR_ICON = '[data-lte-theme-icon]';
865
+ const THEMES = new Set(['light', 'dark', 'auto']);
866
+ const isValidTheme = (value) => THEMES.has(value);
867
+ const isDisabled = () => document.documentElement.getAttribute(ATTRIBUTE_DISABLED) === 'off';
868
+ const readMarkupTheme = () => {
869
+ const { documentElement } = document;
870
+ if (documentElement.hasAttribute(ATTRIBUTE_RESOLVED)) {
871
+ return null;
872
+ }
873
+ const declared = documentElement.getAttribute(ATTRIBUTE_THEME);
874
+ return declared && isValidTheme(declared) ? declared : null;
875
+ };
876
+ const MARKUP_THEME = readMarkupTheme();
845
877
  class ColorMode {
846
878
  getStoredTheme() {
847
879
  try {
848
880
  const stored = localStorage.getItem(STORAGE_KEY);
849
- return stored && ['light', 'dark', 'auto'].includes(stored) ? stored : null;
881
+ return stored && isValidTheme(stored) ? stored : null;
850
882
  }
851
883
  catch {
852
884
  return null;
853
885
  }
854
886
  }
887
+ getMarkupTheme() {
888
+ return MARKUP_THEME;
889
+ }
855
890
  getPreferredTheme() {
856
- const stored = this.getStoredTheme();
857
- if (stored) {
858
- return stored;
891
+ const preferred = this.getStoredTheme() ?? this.getMarkupTheme();
892
+ if (preferred) {
893
+ return preferred;
859
894
  }
860
895
  return this._prefersDark() ? 'dark' : 'light';
861
896
  }
@@ -879,7 +914,7 @@ class ColorMode {
879
914
  }
880
915
  _applyTheme(theme) {
881
916
  const resolved = this.resolveTheme(theme);
882
- document.documentElement.setAttribute('data-bs-theme', resolved);
917
+ document.documentElement.setAttribute(ATTRIBUTE_THEME, resolved);
883
918
  document.documentElement.style.colorScheme = resolved;
884
919
  }
885
920
  _prefersDark() {
@@ -887,7 +922,7 @@ class ColorMode {
887
922
  }
888
923
  _showActiveTheme(theme) {
889
924
  document.querySelectorAll(SELECTOR_TOGGLE).forEach(toggle => {
890
- const isActive = toggle.getAttribute('data-bs-theme-value') === theme;
925
+ const isActive = toggle.getAttribute(ATTRIBUTE_TOGGLE) === theme;
891
926
  toggle.classList.toggle('active', isActive);
892
927
  toggle.setAttribute('aria-pressed', String(isActive));
893
928
  toggle.querySelector('.bi-check-lg')?.classList.toggle('d-none', !isActive);
@@ -897,6 +932,9 @@ class ColorMode {
897
932
  });
898
933
  }
899
934
  init() {
935
+ if (isDisabled()) {
936
+ return;
937
+ }
900
938
  const theme = this.getPreferredTheme();
901
939
  this._applyTheme(theme);
902
940
  this._showActiveTheme(theme);
@@ -904,12 +942,12 @@ class ColorMode {
904
942
  }
905
943
  document.addEventListener('click', event => {
906
944
  const target = event.target;
907
- if (!(target instanceof Element)) {
945
+ if (!(target instanceof Element) || isDisabled()) {
908
946
  return;
909
947
  }
910
948
  const toggle = target.closest(SELECTOR_TOGGLE);
911
- const theme = toggle?.getAttribute('data-bs-theme-value');
912
- if (theme) {
949
+ const theme = toggle?.getAttribute(ATTRIBUTE_TOGGLE);
950
+ if (theme && isValidTheme(theme)) {
913
951
  new ColorMode().setTheme(theme);
914
952
  }
915
953
  });
@@ -917,14 +955,165 @@ onDOMContentLoaded(() => {
917
955
  const colorMode = new ColorMode();
918
956
  colorMode.init();
919
957
  globalThis.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
920
- const stored = colorMode.getStoredTheme();
921
- if (!stored || stored === 'auto') {
958
+ if (isDisabled()) {
959
+ return;
960
+ }
961
+ const preferred = colorMode.getStoredTheme() ?? colorMode.getMarkupTheme();
962
+ if (!preferred || preferred === 'auto') {
922
963
  colorMode._applyTheme('auto');
923
- colorMode._showActiveTheme(stored ?? 'auto');
964
+ colorMode._showActiveTheme(preferred ?? 'auto');
924
965
  }
925
966
  }, { signal: getLifecycleSignal() });
926
967
  });
927
968
 
969
+ const NAME = 'sidebar-search';
970
+ const EVENT_KEY = `.lte.${NAME}`;
971
+ const EVENT_FILTERED = `filtered${EVENT_KEY}`;
972
+ const CLASS_NAME_MENU_OPEN = 'menu-open';
973
+ const SELECTOR_DATA_TOGGLE = '[data-lte-toggle="sidebar-search"]';
974
+ const SELECTOR_SIDEBAR = '.app-sidebar';
975
+ const SELECTOR_MENU = '.sidebar-menu';
976
+ const SELECTOR_NAV_ITEM = '.nav-item';
977
+ const SELECTOR_NAV_HEADER = '.nav-header';
978
+ const SELECTOR_NAV_LINK = ':scope > .nav-link';
979
+ const SELECTOR_TREEVIEW_MENU = ':scope > .nav-treeview';
980
+ const SELECTOR_EMPTY_STATE = '[data-lte-search-empty]';
981
+ const submenuOf = (item) => item.querySelector(SELECTOR_TREEVIEW_MENU);
982
+ const setOpen = (item, submenu, open, display) => {
983
+ item.classList.toggle(CLASS_NAME_MENU_OPEN, open);
984
+ item.querySelector(SELECTOR_NAV_LINK)?.setAttribute('aria-expanded', String(open));
985
+ submenu.style.display = display;
986
+ };
987
+ class SidebarSearch extends BaseComponent {
988
+ static get NAME() {
989
+ return NAME;
990
+ }
991
+ static getInstance(element) {
992
+ return this._getInstance(element);
993
+ }
994
+ static getOrCreateInstance(element) {
995
+ return this.getInstance(element) ?? new this(element);
996
+ }
997
+ _menu;
998
+ _emptyState;
999
+ _snapshot = null;
1000
+ constructor(element) {
1001
+ super(element);
1002
+ const target = element.dataset.lteTarget;
1003
+ const scope = element.closest(SELECTOR_SIDEBAR) ?? document;
1004
+ this._menu = target ?
1005
+ document.querySelector(target) :
1006
+ scope.querySelector(SELECTOR_MENU);
1007
+ this._emptyState = scope.querySelector(SELECTOR_EMPTY_STATE);
1008
+ }
1009
+ search(term) {
1010
+ const menu = this._menu;
1011
+ if (!menu) {
1012
+ return;
1013
+ }
1014
+ const query = term.trim().toLowerCase();
1015
+ if (!query) {
1016
+ this.clear();
1017
+ return;
1018
+ }
1019
+ this._snapshot ??= this._takeSnapshot(menu);
1020
+ const items = [...menu.querySelectorAll(SELECTOR_NAV_ITEM)];
1021
+ const matched = new Set();
1022
+ for (const item of items) {
1023
+ const label = item.querySelector(SELECTOR_NAV_LINK)?.textContent?.replace(/\s+/g, ' ').trim().toLowerCase();
1024
+ if (label?.includes(query)) {
1025
+ matched.add(item);
1026
+ }
1027
+ }
1028
+ for (let index = items.length - 1; index >= 0; index--) {
1029
+ const item = items[index];
1030
+ item.hidden = !(matched.has(item) || item.querySelector(`${SELECTOR_NAV_ITEM}:not([hidden])`));
1031
+ }
1032
+ for (const item of matched) {
1033
+ for (const descendant of item.querySelectorAll(SELECTOR_NAV_ITEM)) {
1034
+ descendant.hidden = false;
1035
+ }
1036
+ }
1037
+ let visible = 0;
1038
+ for (const item of items) {
1039
+ if (!item.hidden) {
1040
+ visible++;
1041
+ }
1042
+ const submenu = submenuOf(item);
1043
+ if (submenu) {
1044
+ const expand = !item.hidden && Boolean(item.querySelector(`${SELECTOR_NAV_ITEM}:not([hidden])`));
1045
+ setOpen(item, submenu, expand, expand ? 'block' : 'none');
1046
+ }
1047
+ }
1048
+ for (const header of menu.querySelectorAll(SELECTOR_NAV_HEADER)) {
1049
+ header.hidden = true;
1050
+ }
1051
+ if (this._emptyState) {
1052
+ this._emptyState.hidden = visible > 0;
1053
+ }
1054
+ dispatchCustomEvent(this._element, EVENT_FILTERED, { detail: { query, matches: visible } });
1055
+ }
1056
+ clear() {
1057
+ const menu = this._menu;
1058
+ if (!menu) {
1059
+ return;
1060
+ }
1061
+ for (const item of menu.querySelectorAll(`${SELECTOR_NAV_ITEM}, ${SELECTOR_NAV_HEADER}`)) {
1062
+ item.hidden = false;
1063
+ }
1064
+ if (this._snapshot) {
1065
+ for (const [item, state] of this._snapshot) {
1066
+ const submenu = submenuOf(item);
1067
+ if (submenu) {
1068
+ setOpen(item, submenu, state.open, state.display);
1069
+ }
1070
+ }
1071
+ this._snapshot = null;
1072
+ }
1073
+ if (this._emptyState) {
1074
+ this._emptyState.hidden = true;
1075
+ }
1076
+ dispatchCustomEvent(this._element, EVENT_FILTERED, { detail: { query: '', matches: -1 } });
1077
+ }
1078
+ dispose() {
1079
+ this.clear();
1080
+ super.dispose();
1081
+ }
1082
+ _takeSnapshot(menu) {
1083
+ const snapshot = new Map();
1084
+ for (const item of menu.querySelectorAll(SELECTOR_NAV_ITEM)) {
1085
+ const submenu = submenuOf(item);
1086
+ if (submenu) {
1087
+ snapshot.set(item, {
1088
+ open: item.classList.contains(CLASS_NAME_MENU_OPEN),
1089
+ display: submenu.style.display
1090
+ });
1091
+ }
1092
+ }
1093
+ return snapshot;
1094
+ }
1095
+ }
1096
+ document.addEventListener('input', event => {
1097
+ const target = event.target;
1098
+ if (target instanceof HTMLInputElement && target.matches(SELECTOR_DATA_TOGGLE)) {
1099
+ SidebarSearch.getOrCreateInstance(target).search(target.value);
1100
+ }
1101
+ });
1102
+ document.addEventListener('keydown', event => {
1103
+ const target = event.target;
1104
+ if (event.key === 'Escape' && target instanceof HTMLInputElement && target.matches(SELECTOR_DATA_TOGGLE)) {
1105
+ target.value = '';
1106
+ SidebarSearch.getOrCreateInstance(target).clear();
1107
+ }
1108
+ });
1109
+ onDOMContentLoaded(() => {
1110
+ document.querySelectorAll(SELECTOR_DATA_TOGGLE).forEach(input => {
1111
+ if (input.value) {
1112
+ SidebarSearch.getOrCreateInstance(input).search(input.value);
1113
+ }
1114
+ });
1115
+ });
1116
+
928
1117
  class AccessibilityManager {
929
1118
  config;
930
1119
  liveRegion = null;
@@ -998,19 +1187,21 @@ class AccessibilityManager {
998
1187
  this.ensureSkipTargets();
999
1188
  }
1000
1189
  ensureSkipTargets() {
1001
- const main = document.querySelector('#main, main, [role="main"]');
1002
- if (main && !main.id) {
1003
- main.id = 'main';
1004
- }
1005
- if (main && !main.hasAttribute('tabindex')) {
1006
- main.setAttribute('tabindex', '-1');
1007
- }
1008
- const nav = document.querySelector('#navigation, nav, [role="navigation"]');
1009
- if (nav && !nav.id) {
1010
- nav.id = 'navigation';
1011
- }
1012
- if (nav && !nav.hasAttribute('tabindex')) {
1013
- nav.setAttribute('tabindex', '-1');
1190
+ const targets = [
1191
+ ['main', 'main, [role="main"]'],
1192
+ ['navigation', 'nav, [role="navigation"]']
1193
+ ];
1194
+ for (const [id, fallbackSelector] of targets) {
1195
+ const target = document.getElementById(id) ?? document.querySelector(fallbackSelector);
1196
+ if (!target) {
1197
+ continue;
1198
+ }
1199
+ if (!target.id) {
1200
+ target.id = id;
1201
+ }
1202
+ if (!target.hasAttribute('tabindex')) {
1203
+ target.setAttribute('tabindex', '-1');
1204
+ }
1014
1205
  }
1015
1206
  }
1016
1207
  initFocusManagement() {
@@ -1175,7 +1366,7 @@ class AccessibilityManager {
1175
1366
  if (!htmlInput.classList.contains('disable-adminlte-validations')) {
1176
1367
  htmlInput.addEventListener('invalid', () => {
1177
1368
  this.handleFormError(htmlInput);
1178
- });
1369
+ }, { signal: this.signal });
1179
1370
  }
1180
1371
  });
1181
1372
  }
@@ -1361,5 +1552,5 @@ onDOMContentLoaded(() => {
1361
1552
  accessibilityManager.addLandmarks();
1362
1553
  });
1363
1554
 
1364
- export { CardWidget, ColorMode, DirectChat, FullScreen, Layout, PushMenu, Treeview, initAccessibility };
1555
+ export { CardWidget, ColorMode, DirectChat, FullScreen, Layout, PushMenu, SidebarSearch, Treeview, initAccessibility, initialize, teardown };
1365
1556
  //# sourceMappingURL=adminlte.esm.js.map