admin-lte 4.0.4 → 4.2.0

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 (59) hide show
  1. package/CHANGELOG.md +41 -1
  2. package/README.md +6 -6
  3. package/dist/css/adminlte-docs.css +878 -0
  4. package/dist/css/adminlte-docs.css.map +1 -0
  5. package/dist/css/adminlte-docs.min.css +7 -0
  6. package/dist/css/adminlte-docs.min.css.map +1 -0
  7. package/dist/css/adminlte-docs.rtl.css +877 -0
  8. package/dist/css/adminlte-docs.rtl.css.map +1 -0
  9. package/dist/css/adminlte-docs.rtl.min.css +7 -0
  10. package/dist/css/adminlte-docs.rtl.min.css.map +1 -0
  11. package/dist/css/adminlte.css +132 -912
  12. package/dist/css/adminlte.css.map +1 -1
  13. package/dist/css/adminlte.min.css +2 -2
  14. package/dist/css/adminlte.min.css.map +1 -1
  15. package/dist/css/adminlte.rtl.css +132 -912
  16. package/dist/css/adminlte.rtl.css.map +1 -1
  17. package/dist/css/adminlte.rtl.min.css +2 -2
  18. package/dist/css/adminlte.rtl.min.css.map +1 -1
  19. package/dist/js/adminlte.esm.js +1406 -0
  20. package/dist/js/adminlte.esm.js.map +1 -0
  21. package/dist/js/adminlte.esm.min.js +7 -0
  22. package/dist/js/adminlte.esm.min.js.map +1 -0
  23. package/dist/js/adminlte.js +449 -215
  24. package/dist/js/adminlte.js.map +1 -1
  25. package/dist/js/adminlte.min.js +2 -2
  26. package/dist/js/adminlte.min.js.map +1 -1
  27. package/dist/js/types/accessibility.d.ts +46 -0
  28. package/dist/js/types/adminlte.d.ts +10 -0
  29. package/dist/js/types/base-component.d.ts +60 -0
  30. package/dist/js/types/card-widget.d.ts +30 -0
  31. package/dist/js/types/color-mode.d.ts +74 -0
  32. package/dist/js/types/direct-chat.d.ts +19 -0
  33. package/dist/js/types/fullscreen.d.ts +21 -0
  34. package/dist/js/types/layout.d.ts +19 -0
  35. package/dist/js/types/push-menu.d.ts +123 -0
  36. package/dist/js/types/treeview.d.ts +27 -0
  37. package/dist/js/types/util/index.d.ts +79 -0
  38. package/package.json +52 -25
  39. package/src/scss/_app-header.scss +3 -1
  40. package/src/scss/_app-main.scss +4 -0
  41. package/src/scss/_app-sidebar.scss +3 -1
  42. package/src/scss/_bootstrap-overrides.scss +60 -0
  43. package/src/scss/_info-box.scss +3 -1
  44. package/src/scss/_progress-bars.scss +3 -1
  45. package/src/scss/_table.scss +4 -2
  46. package/src/scss/adminlte-docs.scss +25 -0
  47. package/src/scss/adminlte.scss +5 -4
  48. package/src/scss/pages/_login_and_register.scss +3 -1
  49. package/src/ts/accessibility.ts +6 -2
  50. package/src/ts/adminlte.ts +7 -3
  51. package/src/ts/base-component.ts +111 -0
  52. package/src/ts/card-widget.ts +124 -100
  53. package/src/ts/color-mode.ts +254 -0
  54. package/src/ts/direct-chat.ts +38 -32
  55. package/src/ts/fullscreen.ts +32 -23
  56. package/src/ts/push-menu.ts +106 -43
  57. package/src/ts/treeview.ts +84 -50
  58. package/src/ts/util/index.ts +80 -16
  59. package/src/scss/_bootstrap-variables.scss +0 -1766
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * AdminLTE v4.0.4 (https://adminlte.io)
2
+ * AdminLTE v4.2.0 (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
  */
@@ -12,7 +12,8 @@
12
12
  const lifecycleCallbacks = [];
13
13
  const lifecycleState = {
14
14
  controller: new AbortController(),
15
- hasInitialized: false
15
+ hasInitialized: false,
16
+ isReplaying: false
16
17
  };
17
18
  const getLifecycleSignal = () => lifecycleState.controller.signal;
18
19
  const runLifecycleCallbacks = () => {
@@ -20,8 +21,14 @@
20
21
  return;
21
22
  }
22
23
  lifecycleState.hasInitialized = true;
23
- for (const callback of lifecycleCallbacks) {
24
- callback();
24
+ lifecycleState.isReplaying = true;
25
+ try {
26
+ for (const callback of lifecycleCallbacks) {
27
+ callback();
28
+ }
29
+ }
30
+ finally {
31
+ lifecycleState.isReplaying = false;
25
32
  }
26
33
  };
27
34
  const onDOMContentLoaded = (callback) => {
@@ -30,17 +37,25 @@
30
37
  callback();
31
38
  }
32
39
  };
40
+ const teardown = () => {
41
+ lifecycleState.controller.abort();
42
+ lifecycleState.controller = new AbortController();
43
+ lifecycleState.hasInitialized = false;
44
+ };
45
+ const initialize = () => {
46
+ if (lifecycleState.isReplaying) {
47
+ return;
48
+ }
49
+ teardown();
50
+ runLifecycleCallbacks();
51
+ };
33
52
  if (document.readyState === 'loading') {
34
- document.addEventListener('DOMContentLoaded', runLifecycleCallbacks, { once: true });
53
+ document.addEventListener('DOMContentLoaded', initialize, { once: true });
35
54
  }
36
55
  else {
37
56
  runLifecycleCallbacks();
38
57
  }
39
- document.addEventListener('turbo:before-render', () => {
40
- lifecycleState.controller.abort();
41
- lifecycleState.controller = new AbortController();
42
- lifecycleState.hasInitialized = false;
43
- });
58
+ document.addEventListener('turbo:before-render', teardown);
44
59
  document.addEventListener('turbo:load', runLifecycleCallbacks);
45
60
  const slideTimers = new WeakMap();
46
61
  const cancelSlide = (target) => {
@@ -144,13 +159,55 @@
144
159
  }, 400);
145
160
  });
146
161
 
147
- const DATA_KEY$4 = 'lte.card-widget';
148
- const EVENT_KEY$4 = `.${DATA_KEY$4}`;
149
- const EVENT_COLLAPSED$2 = `collapsed${EVENT_KEY$4}`;
150
- const EVENT_EXPANDED$2 = `expanded${EVENT_KEY$4}`;
151
- const EVENT_REMOVE = `remove${EVENT_KEY$4}`;
152
- const EVENT_MAXIMIZED$1 = `maximized${EVENT_KEY$4}`;
153
- const EVENT_MINIMIZED$1 = `minimized${EVENT_KEY$4}`;
162
+ const componentRegistry = new WeakMap();
163
+ class BaseComponent {
164
+ static get NAME() {
165
+ throw new Error('Component subclasses must override the static NAME getter.');
166
+ }
167
+ static get DATA_KEY() {
168
+ return `lte.${this.NAME}`;
169
+ }
170
+ static _getInstance(element) {
171
+ if (!element) {
172
+ return null;
173
+ }
174
+ return componentRegistry.get(element)?.get(this.DATA_KEY) ?? null;
175
+ }
176
+ _element;
177
+ constructor(element) {
178
+ this._element = element;
179
+ const instances = componentRegistry.get(element) ?? new Map();
180
+ componentRegistry.set(element, instances);
181
+ instances.set(this.constructor.DATA_KEY, this);
182
+ }
183
+ dispose() {
184
+ const instances = componentRegistry.get(this._element);
185
+ instances?.delete(this.constructor.DATA_KEY);
186
+ if (instances?.size === 0) {
187
+ componentRegistry.delete(this._element);
188
+ }
189
+ }
190
+ }
191
+ const dispatchCustomEvent = (element, name, options = {}) => {
192
+ const event = new CustomEvent(name, {
193
+ bubbles: true,
194
+ cancelable: options.cancelable ?? false,
195
+ detail: options.detail
196
+ });
197
+ element.dispatchEvent(event);
198
+ return event;
199
+ };
200
+
201
+ const NAME$4 = 'card-widget';
202
+ const EVENT_KEY$5 = `.lte.${NAME$4}`;
203
+ const EVENT_COLLAPSE$2 = `collapse${EVENT_KEY$5}`;
204
+ const EVENT_EXPAND$1 = `expand${EVENT_KEY$5}`;
205
+ const EVENT_REMOVE = `remove${EVENT_KEY$5}`;
206
+ const EVENT_COLLAPSED$3 = `collapsed${EVENT_KEY$5}`;
207
+ const EVENT_EXPANDED$2 = `expanded${EVENT_KEY$5}`;
208
+ const EVENT_REMOVED = `removed${EVENT_KEY$5}`;
209
+ const EVENT_MAXIMIZED$1 = `maximized${EVENT_KEY$5}`;
210
+ const EVENT_MINIMIZED$1 = `minimized${EVENT_KEY$5}`;
154
211
  const CLASS_NAME_CARD = 'card';
155
212
  const CLASS_NAME_COLLAPSED = 'collapsed-card';
156
213
  const CLASS_NAME_COLLAPSING = 'collapsing-card';
@@ -169,13 +226,20 @@
169
226
  removeTrigger: SELECTOR_DATA_REMOVE,
170
227
  maximizeTrigger: SELECTOR_DATA_MAXIMIZE
171
228
  };
172
- class CardWidget {
173
- _element;
229
+ class CardWidget extends BaseComponent {
230
+ static get NAME() {
231
+ return NAME$4;
232
+ }
233
+ static getInstance(element) {
234
+ return this._getInstance(element);
235
+ }
236
+ static getOrCreateInstance(element, config = {}) {
237
+ return this.getInstance(element) ?? new this(element, config);
238
+ }
174
239
  _parent;
175
- _clone;
176
240
  _config;
177
- constructor(element, config) {
178
- this._element = element;
241
+ constructor(element, config = {}) {
242
+ super(element);
179
243
  this._parent = element.closest(SELECTOR_CARD);
180
244
  if (element.classList.contains(CLASS_NAME_CARD)) {
181
245
  this._parent = element;
@@ -183,54 +247,64 @@
183
247
  this._config = { ...Default$1, ...config };
184
248
  }
185
249
  collapse() {
186
- const event = new Event(EVENT_COLLAPSED$2);
187
- if (this._parent) {
188
- this._parent.classList.add(CLASS_NAME_COLLAPSING);
189
- this._parent.classList.remove(CLASS_NAME_EXPANDING);
190
- const elm = this._parent?.querySelectorAll(`:scope > ${SELECTOR_CARD_BODY}, :scope > ${SELECTOR_CARD_FOOTER}`);
191
- elm.forEach(el => {
192
- if (el instanceof HTMLElement) {
193
- slideUp(el, this._config.animationSpeed);
194
- }
195
- });
196
- setTimeout(() => {
197
- if (this._parent?.classList.contains(CLASS_NAME_COLLAPSING)) {
198
- this._parent.classList.add(CLASS_NAME_COLLAPSED);
199
- this._parent.classList.remove(CLASS_NAME_COLLAPSING);
200
- }
201
- }, this._config.animationSpeed);
250
+ if (!this._parent) {
251
+ return;
252
+ }
253
+ if (dispatchCustomEvent(this._parent, EVENT_COLLAPSE$2, { cancelable: true }).defaultPrevented) {
254
+ return;
202
255
  }
203
- this._element?.dispatchEvent(event);
256
+ this._parent.classList.add(CLASS_NAME_COLLAPSING);
257
+ this._parent.classList.remove(CLASS_NAME_EXPANDING);
258
+ const elm = this._parent.querySelectorAll(`:scope > ${SELECTOR_CARD_BODY}, :scope > ${SELECTOR_CARD_FOOTER}`);
259
+ elm.forEach(el => {
260
+ if (el instanceof HTMLElement) {
261
+ slideUp(el, this._config.animationSpeed);
262
+ }
263
+ });
264
+ setTimeout(() => {
265
+ if (this._parent?.classList.contains(CLASS_NAME_COLLAPSING)) {
266
+ this._parent.classList.add(CLASS_NAME_COLLAPSED);
267
+ this._parent.classList.remove(CLASS_NAME_COLLAPSING);
268
+ dispatchCustomEvent(this._parent, EVENT_COLLAPSED$3);
269
+ }
270
+ }, this._config.animationSpeed);
204
271
  }
205
272
  expand() {
206
- const event = new Event(EVENT_EXPANDED$2);
207
- if (this._parent) {
208
- this._parent.classList.add(CLASS_NAME_EXPANDING);
209
- this._parent.classList.remove(CLASS_NAME_COLLAPSING, CLASS_NAME_COLLAPSED);
210
- const elm = this._parent?.querySelectorAll(`:scope > ${SELECTOR_CARD_BODY}, :scope > ${SELECTOR_CARD_FOOTER}`);
211
- elm.forEach(el => {
212
- if (el instanceof HTMLElement) {
213
- slideDown(el, this._config.animationSpeed);
214
- }
215
- });
216
- setTimeout(() => {
217
- if (this._parent?.classList.contains(CLASS_NAME_EXPANDING)) {
218
- this._parent.classList.remove(CLASS_NAME_EXPANDING);
219
- }
220
- }, this._config.animationSpeed);
273
+ if (!this._parent) {
274
+ return;
275
+ }
276
+ if (dispatchCustomEvent(this._parent, EVENT_EXPAND$1, { cancelable: true }).defaultPrevented) {
277
+ return;
221
278
  }
222
- this._element?.dispatchEvent(event);
279
+ this._parent.classList.add(CLASS_NAME_EXPANDING);
280
+ this._parent.classList.remove(CLASS_NAME_COLLAPSING, CLASS_NAME_COLLAPSED);
281
+ const elm = this._parent.querySelectorAll(`:scope > ${SELECTOR_CARD_BODY}, :scope > ${SELECTOR_CARD_FOOTER}`);
282
+ elm.forEach(el => {
283
+ if (el instanceof HTMLElement) {
284
+ slideDown(el, this._config.animationSpeed);
285
+ }
286
+ });
287
+ setTimeout(() => {
288
+ if (this._parent?.classList.contains(CLASS_NAME_EXPANDING)) {
289
+ this._parent.classList.remove(CLASS_NAME_EXPANDING);
290
+ dispatchCustomEvent(this._parent, EVENT_EXPANDED$2);
291
+ }
292
+ }, this._config.animationSpeed);
223
293
  }
224
294
  remove() {
225
- const event = new Event(EVENT_REMOVE);
226
- if (this._parent) {
227
- const parent = this._parent;
228
- slideUp(parent, this._config.animationSpeed);
229
- setTimeout(() => {
230
- parent.remove();
231
- }, this._config.animationSpeed);
295
+ if (!this._parent) {
296
+ return;
297
+ }
298
+ if (dispatchCustomEvent(this._parent, EVENT_REMOVE, { cancelable: true }).defaultPrevented) {
299
+ return;
232
300
  }
233
- this._element?.dispatchEvent(event);
301
+ const parent = this._parent;
302
+ slideUp(parent, this._config.animationSpeed);
303
+ setTimeout(() => {
304
+ dispatchCustomEvent(parent, EVENT_REMOVED);
305
+ parent.remove();
306
+ this.dispose();
307
+ }, this._config.animationSpeed);
234
308
  }
235
309
  toggle() {
236
310
  if (this._parent?.classList.contains(CLASS_NAME_COLLAPSED) || this._parent?.classList.contains(CLASS_NAME_COLLAPSING)) {
@@ -240,7 +314,6 @@
240
314
  this.collapse();
241
315
  }
242
316
  maximize() {
243
- const event = new Event(EVENT_MAXIMIZED$1);
244
317
  if (this._parent) {
245
318
  this._parent.style.height = `${this._parent.offsetHeight}px`;
246
319
  this._parent.style.width = `${this._parent.offsetWidth}px`;
@@ -255,13 +328,12 @@
255
328
  if (this._parent.classList.contains(CLASS_NAME_COLLAPSED)) {
256
329
  this._parent.classList.add(CLASS_NAME_WAS_COLLAPSED);
257
330
  }
331
+ dispatchCustomEvent(this._parent, EVENT_MAXIMIZED$1);
258
332
  }
259
333
  }, 150);
260
334
  }
261
- this._element?.dispatchEvent(event);
262
335
  }
263
336
  minimize() {
264
- const event = new Event(EVENT_MINIMIZED$1);
265
337
  if (this._parent) {
266
338
  this._parent.style.height = 'auto';
267
339
  this._parent.style.width = 'auto';
@@ -276,6 +348,7 @@
276
348
  if (this._parent?.classList.contains(CLASS_NAME_WAS_COLLAPSED)) {
277
349
  this._parent.classList.remove(CLASS_NAME_WAS_COLLAPSED);
278
350
  }
351
+ dispatchCustomEvent(this._parent, EVENT_MINIMIZED$1);
279
352
  setTimeout(() => {
280
353
  this._parent?.style.removeProperty('height');
281
354
  this._parent?.style.removeProperty('width');
@@ -284,7 +357,6 @@
284
357
  }
285
358
  }, 10);
286
359
  }
287
- this._element?.dispatchEvent(event);
288
360
  }
289
361
  toggleMaximize() {
290
362
  if (this._parent?.classList.contains(CLASS_NAME_MAXIMIZED)) {
@@ -294,41 +366,42 @@
294
366
  this.maximize();
295
367
  }
296
368
  }
297
- onDOMContentLoaded(() => {
298
- const collapseBtn = document.querySelectorAll(SELECTOR_DATA_COLLAPSE);
299
- collapseBtn.forEach(btn => {
300
- btn.addEventListener('click', event => {
301
- event.preventDefault();
302
- const target = event.currentTarget;
303
- const data = new CardWidget(target, Default$1);
304
- data.toggle();
305
- });
306
- });
307
- const removeBtn = document.querySelectorAll(SELECTOR_DATA_REMOVE);
308
- removeBtn.forEach(btn => {
309
- btn.addEventListener('click', event => {
310
- event.preventDefault();
311
- const target = event.currentTarget;
312
- const data = new CardWidget(target, Default$1);
313
- data.remove();
314
- });
315
- });
316
- const maxBtn = document.querySelectorAll(SELECTOR_DATA_MAXIMIZE);
317
- maxBtn.forEach(btn => {
318
- btn.addEventListener('click', event => {
319
- event.preventDefault();
320
- const target = event.currentTarget;
321
- const data = new CardWidget(target, Default$1);
322
- data.toggleMaximize();
323
- });
324
- });
369
+ document.addEventListener('click', event => {
370
+ const target = event.target;
371
+ if (!(target instanceof Element)) {
372
+ return;
373
+ }
374
+ const collapseTrigger = target.closest(SELECTOR_DATA_COLLAPSE);
375
+ const removeTrigger = target.closest(SELECTOR_DATA_REMOVE);
376
+ const maximizeTrigger = target.closest(SELECTOR_DATA_MAXIMIZE);
377
+ const trigger = collapseTrigger ?? removeTrigger ?? maximizeTrigger;
378
+ if (!trigger) {
379
+ return;
380
+ }
381
+ event.preventDefault();
382
+ const card = trigger.closest(SELECTOR_CARD);
383
+ if (!card) {
384
+ return;
385
+ }
386
+ const widget = CardWidget.getOrCreateInstance(card);
387
+ if (collapseTrigger) {
388
+ widget.toggle();
389
+ }
390
+ else if (removeTrigger) {
391
+ widget.remove();
392
+ }
393
+ else {
394
+ widget.toggleMaximize();
395
+ }
325
396
  });
326
397
 
327
- const DATA_KEY$3 = 'lte.treeview';
328
- const EVENT_KEY$3 = `.${DATA_KEY$3}`;
329
- const EVENT_EXPANDED$1 = `expanded${EVENT_KEY$3}`;
330
- const EVENT_COLLAPSED$1 = `collapsed${EVENT_KEY$3}`;
331
- const EVENT_LOAD_DATA_API = `load${EVENT_KEY$3}`;
398
+ const NAME$3 = 'treeview';
399
+ const EVENT_KEY$4 = `.lte.${NAME$3}`;
400
+ const EVENT_EXPAND = `expand${EVENT_KEY$4}`;
401
+ const EVENT_COLLAPSE$1 = `collapse${EVENT_KEY$4}`;
402
+ const EVENT_EXPANDED$1 = `expanded${EVENT_KEY$4}`;
403
+ const EVENT_COLLAPSED$2 = `collapsed${EVENT_KEY$4}`;
404
+ const EVENT_LOAD_DATA_API = `load${EVENT_KEY$4}`;
332
405
  const CLASS_NAME_MENU_OPEN = 'menu-open';
333
406
  const SELECTOR_NAV_ITEM = '.nav-item';
334
407
  const SELECTOR_NAV_LINK = '.nav-link';
@@ -342,15 +415,25 @@
342
415
  const link = navItem.querySelector(`:scope > ${SELECTOR_NAV_LINK}`);
343
416
  link?.setAttribute('aria-expanded', String(expanded));
344
417
  };
345
- class Treeview {
346
- _element;
418
+ class Treeview extends BaseComponent {
419
+ static get NAME() {
420
+ return NAME$3;
421
+ }
422
+ static getInstance(element) {
423
+ return this._getInstance(element);
424
+ }
425
+ static getOrCreateInstance(element, config = {}) {
426
+ return this.getInstance(element) ?? new this(element, config);
427
+ }
347
428
  _config;
348
- constructor(element, config) {
349
- this._element = element;
429
+ constructor(element, config = {}) {
430
+ super(element);
350
431
  this._config = { ...Default, ...config };
351
432
  }
352
433
  open() {
353
- const event = new Event(EVENT_EXPANDED$1);
434
+ if (dispatchCustomEvent(this._element, EVENT_EXPAND, { cancelable: true }).defaultPrevented) {
435
+ return;
436
+ }
354
437
  if (this._config.accordion) {
355
438
  const openMenuList = this._element.parentElement?.querySelectorAll(`${SELECTOR_NAV_ITEM}.${CLASS_NAME_MENU_OPEN}`);
356
439
  openMenuList?.forEach(openMenu => {
@@ -366,21 +449,31 @@
366
449
  }
367
450
  this._element.classList.add(CLASS_NAME_MENU_OPEN);
368
451
  setAriaExpanded(this._element, true);
369
- const childElement = this._element?.querySelector(SELECTOR_TREEVIEW_MENU);
452
+ const childElement = this._element.querySelector(SELECTOR_TREEVIEW_MENU);
370
453
  if (childElement) {
371
454
  slideDown(childElement, this._config.animationSpeed);
372
455
  }
373
- this._element.dispatchEvent(event);
456
+ setTimeout(() => {
457
+ if (this._element.classList.contains(CLASS_NAME_MENU_OPEN)) {
458
+ dispatchCustomEvent(this._element, EVENT_EXPANDED$1);
459
+ }
460
+ }, this._config.animationSpeed);
374
461
  }
375
462
  close() {
376
- const event = new Event(EVENT_COLLAPSED$1);
463
+ if (dispatchCustomEvent(this._element, EVENT_COLLAPSE$1, { cancelable: true }).defaultPrevented) {
464
+ return;
465
+ }
377
466
  this._element.classList.remove(CLASS_NAME_MENU_OPEN);
378
467
  setAriaExpanded(this._element, false);
379
- const childElement = this._element?.querySelector(SELECTOR_TREEVIEW_MENU);
468
+ const childElement = this._element.querySelector(SELECTOR_TREEVIEW_MENU);
380
469
  if (childElement) {
381
470
  slideUp(childElement, this._config.animationSpeed);
382
471
  }
383
- this._element.dispatchEvent(event);
472
+ setTimeout(() => {
473
+ if (!this._element.classList.contains(CLASS_NAME_MENU_OPEN)) {
474
+ dispatchCustomEvent(this._element, EVENT_COLLAPSED$2);
475
+ }
476
+ }, this._config.animationSpeed);
384
477
  }
385
478
  toggle() {
386
479
  if (this._element.classList.contains(CLASS_NAME_MENU_OPEN)) {
@@ -391,6 +484,31 @@
391
484
  }
392
485
  }
393
486
  }
487
+ document.addEventListener('click', event => {
488
+ const target = event.target;
489
+ if (!(target instanceof Element)) {
490
+ return;
491
+ }
492
+ const toggleRoot = target.closest(SELECTOR_DATA_TOGGLE$1);
493
+ if (!toggleRoot) {
494
+ return;
495
+ }
496
+ const targetItem = target.closest(SELECTOR_NAV_ITEM);
497
+ const targetLink = target.closest(SELECTOR_NAV_LINK);
498
+ if (!targetItem?.querySelector(SELECTOR_TREEVIEW_MENU)) {
499
+ return;
500
+ }
501
+ if (target.getAttribute('href') === '#' || targetLink?.getAttribute('href') === '#') {
502
+ event.preventDefault();
503
+ }
504
+ const accordionAttr = toggleRoot.dataset.accordion;
505
+ const animationSpeedAttr = toggleRoot.dataset.animationSpeed;
506
+ const config = {
507
+ accordion: accordionAttr === undefined ? Default.accordion : accordionAttr === 'true',
508
+ animationSpeed: animationSpeedAttr === undefined ? Default.animationSpeed : Number(animationSpeedAttr)
509
+ };
510
+ Treeview.getOrCreateInstance(targetItem, config).toggle();
511
+ });
394
512
  onDOMContentLoaded(() => {
395
513
  const openMenuItems = document.querySelectorAll(`${SELECTOR_NAV_ITEM}.${CLASS_NAME_MENU_OPEN}`);
396
514
  openMenuItems.forEach(menuItem => {
@@ -408,78 +526,56 @@
408
526
  }
409
527
  });
410
528
  });
411
- const button = document.querySelectorAll(SELECTOR_DATA_TOGGLE$1);
412
- button.forEach(btn => {
413
- btn.addEventListener('click', event => {
414
- const target = event.target;
415
- const targetItem = target.closest(SELECTOR_NAV_ITEM);
416
- const targetLink = target.closest(SELECTOR_NAV_LINK);
417
- const targetTreeviewMenu = targetItem?.querySelector(SELECTOR_TREEVIEW_MENU);
418
- const lteToggleElement = event.currentTarget;
419
- if (!targetTreeviewMenu) {
420
- return;
421
- }
422
- if (target?.getAttribute('href') === '#' || targetLink?.getAttribute('href') === '#') {
423
- event.preventDefault();
424
- }
425
- if (targetItem) {
426
- const accordionAttr = lteToggleElement.dataset.accordion;
427
- const animationSpeedAttr = lteToggleElement.dataset.animationSpeed;
428
- const config = {
429
- accordion: accordionAttr === undefined ? Default.accordion : accordionAttr === 'true',
430
- animationSpeed: animationSpeedAttr === undefined ? Default.animationSpeed : Number(animationSpeedAttr)
431
- };
432
- const data = new Treeview(targetItem, config);
433
- data.toggle();
434
- }
435
- });
436
- });
437
529
  });
438
530
 
439
- const DATA_KEY$2 = 'lte.direct-chat';
440
- const EVENT_KEY$2 = `.${DATA_KEY$2}`;
441
- const EVENT_EXPANDED = `expanded${EVENT_KEY$2}`;
442
- const EVENT_COLLAPSED = `collapsed${EVENT_KEY$2}`;
531
+ const NAME$2 = 'direct-chat';
532
+ const EVENT_KEY$3 = `.lte.${NAME$2}`;
533
+ const EVENT_EXPANDED = `expanded${EVENT_KEY$3}`;
534
+ const EVENT_COLLAPSED$1 = `collapsed${EVENT_KEY$3}`;
443
535
  const SELECTOR_DATA_TOGGLE = '[data-lte-toggle="chat-pane"]';
444
536
  const SELECTOR_DIRECT_CHAT = '.direct-chat';
445
537
  const CLASS_NAME_DIRECT_CHAT_OPEN = 'direct-chat-contacts-open';
446
- class DirectChat {
447
- _element;
448
- constructor(element) {
449
- this._element = element;
538
+ class DirectChat extends BaseComponent {
539
+ static get NAME() {
540
+ return NAME$2;
541
+ }
542
+ static getInstance(element) {
543
+ return this._getInstance(element);
544
+ }
545
+ static getOrCreateInstance(element) {
546
+ return this.getInstance(element) ?? new this(element);
450
547
  }
451
548
  toggle() {
452
549
  if (this._element.classList.contains(CLASS_NAME_DIRECT_CHAT_OPEN)) {
453
- const event = new Event(EVENT_COLLAPSED);
454
550
  this._element.classList.remove(CLASS_NAME_DIRECT_CHAT_OPEN);
455
- this._element.dispatchEvent(event);
551
+ dispatchCustomEvent(this._element, EVENT_COLLAPSED$1);
456
552
  }
457
553
  else {
458
- const event = new Event(EVENT_EXPANDED);
459
554
  this._element.classList.add(CLASS_NAME_DIRECT_CHAT_OPEN);
460
- this._element.dispatchEvent(event);
555
+ dispatchCustomEvent(this._element, EVENT_EXPANDED);
461
556
  }
462
557
  }
463
558
  }
464
- onDOMContentLoaded(() => {
465
- const button = document.querySelectorAll(SELECTOR_DATA_TOGGLE);
466
- button.forEach(btn => {
467
- btn.addEventListener('click', event => {
468
- event.preventDefault();
469
- const target = event.target;
470
- const chatPane = target.closest(SELECTOR_DIRECT_CHAT);
471
- if (chatPane) {
472
- const data = new DirectChat(chatPane);
473
- data.toggle();
474
- }
475
- });
476
- });
559
+ document.addEventListener('click', event => {
560
+ const target = event.target;
561
+ if (!(target instanceof Element)) {
562
+ return;
563
+ }
564
+ const trigger = target.closest(SELECTOR_DATA_TOGGLE);
565
+ if (!trigger) {
566
+ return;
567
+ }
568
+ event.preventDefault();
569
+ const chatPane = trigger.closest(SELECTOR_DIRECT_CHAT);
570
+ if (chatPane) {
571
+ DirectChat.getOrCreateInstance(chatPane).toggle();
572
+ }
477
573
  });
478
574
 
479
- const DATA_KEY$1 = 'lte.fullscreen';
480
- const EVENT_KEY$1 = `.${DATA_KEY$1}`;
481
- const EVENT_MAXIMIZED = `maximized${EVENT_KEY$1}`;
482
- const EVENT_MINIMIZED = `minimized${EVENT_KEY$1}`;
575
+ const NAME$1 = 'fullscreen';
576
+ const EVENT_KEY$2 = `.lte.${NAME$1}`;
577
+ const EVENT_MAXIMIZED = `maximized${EVENT_KEY$2}`;
578
+ const EVENT_MINIMIZED = `minimized${EVENT_KEY$2}`;
483
579
  const SELECTOR_FULLSCREEN_TOGGLE = '[data-lte-toggle="fullscreen"]';
484
580
  const SELECTOR_MAXIMIZE_ICON = '[data-lte-icon="maximize"]';
485
581
  const SELECTOR_MINIMIZE_ICON = '[data-lte-icon="minimize"]';
@@ -491,15 +587,18 @@
491
587
  iconMinimize?.classList.toggle('d-none', !isFullScreen);
492
588
  const eventName = isFullScreen ? EVENT_MAXIMIZED : EVENT_MINIMIZED;
493
589
  document.querySelectorAll(SELECTOR_FULLSCREEN_TOGGLE).forEach(button => {
494
- button.dispatchEvent(new Event(eventName));
590
+ dispatchCustomEvent(button, eventName);
495
591
  });
496
592
  }
497
- class FullScreen {
498
- _element;
499
- _config;
500
- constructor(element, config) {
501
- this._element = element;
502
- this._config = config;
593
+ class FullScreen extends BaseComponent {
594
+ static get NAME() {
595
+ return NAME$1;
596
+ }
597
+ static getInstance(element) {
598
+ return this._getInstance(element);
599
+ }
600
+ static getOrCreateInstance(element) {
601
+ return this.getInstance(element) ?? new this(element);
503
602
  }
504
603
  inFullScreen() {
505
604
  void document.documentElement.requestFullscreen().catch(() => {
@@ -521,26 +620,28 @@
521
620
  }
522
621
  }
523
622
  }
623
+ document.addEventListener('click', event => {
624
+ const target = event.target;
625
+ if (!(target instanceof Element)) {
626
+ return;
627
+ }
628
+ const button = target.closest(SELECTOR_FULLSCREEN_TOGGLE);
629
+ if (!button) {
630
+ return;
631
+ }
632
+ event.preventDefault();
633
+ FullScreen.getOrCreateInstance(button).toggleFullScreen();
634
+ });
524
635
  onDOMContentLoaded(() => {
525
636
  document.addEventListener('fullscreenchange', syncFullScreenState, { signal: getLifecycleSignal() });
526
- const buttons = document.querySelectorAll(SELECTOR_FULLSCREEN_TOGGLE);
527
- buttons.forEach(btn => {
528
- btn.addEventListener('click', event => {
529
- event.preventDefault();
530
- const target = event.target;
531
- const button = target.closest(SELECTOR_FULLSCREEN_TOGGLE);
532
- if (button) {
533
- const data = new FullScreen(button, undefined);
534
- data.toggleFullScreen();
535
- }
536
- });
537
- });
538
637
  });
539
638
 
540
- const DATA_KEY = 'lte.push-menu';
541
- const EVENT_KEY = `.${DATA_KEY}`;
542
- const EVENT_OPEN = `open${EVENT_KEY}`;
543
- const EVENT_COLLAPSE = `collapse${EVENT_KEY}`;
639
+ const NAME = 'push-menu';
640
+ const EVENT_KEY$1 = `.lte.${NAME}`;
641
+ const EVENT_OPEN = `open${EVENT_KEY$1}`;
642
+ const EVENT_COLLAPSE = `collapse${EVENT_KEY$1}`;
643
+ const EVENT_OPENED = `opened${EVENT_KEY$1}`;
644
+ const EVENT_COLLAPSED = `collapsed${EVENT_KEY$1}`;
544
645
  const CLASS_NAME_SIDEBAR_MINI = 'sidebar-mini';
545
646
  const CLASS_NAME_SIDEBAR_EXPAND = 'sidebar-expand';
546
647
  const CLASS_NAME_SIDEBAR_OVERLAY = 'sidebar-overlay';
@@ -555,11 +656,19 @@
555
656
  sidebarBreakpoint: 991.98,
556
657
  enablePersistence: false
557
658
  };
558
- class PushMenu {
559
- _element;
659
+ class PushMenu extends BaseComponent {
660
+ static get NAME() {
661
+ return NAME;
662
+ }
663
+ static getInstance(element) {
664
+ return this._getInstance(element);
665
+ }
666
+ static getOrCreateInstance(element, config = {}) {
667
+ return this.getInstance(element) ?? new this(element, config);
668
+ }
560
669
  _config;
561
- constructor(element, config) {
562
- this._element = element;
670
+ constructor(element, config = {}) {
671
+ super(element);
563
672
  this._config = { ...Defaults, ...config };
564
673
  }
565
674
  isCollapsed() {
@@ -575,16 +684,22 @@
575
684
  return globalThis.innerWidth <= this._config.sidebarBreakpoint;
576
685
  }
577
686
  expand() {
687
+ if (dispatchCustomEvent(this._element, EVENT_OPEN, { cancelable: true }).defaultPrevented) {
688
+ return;
689
+ }
578
690
  document.body.classList.remove(CLASS_NAME_SIDEBAR_COLLAPSE);
579
691
  if (this.isMobileSize()) {
580
692
  document.body.classList.add(CLASS_NAME_SIDEBAR_OPEN);
581
693
  }
582
- this._element.dispatchEvent(new Event(EVENT_OPEN));
694
+ dispatchCustomEvent(this._element, EVENT_OPENED);
583
695
  }
584
696
  collapse() {
697
+ if (dispatchCustomEvent(this._element, EVENT_COLLAPSE, { cancelable: true }).defaultPrevented) {
698
+ return;
699
+ }
585
700
  document.body.classList.remove(CLASS_NAME_SIDEBAR_OPEN);
586
701
  document.body.classList.add(CLASS_NAME_SIDEBAR_COLLAPSE);
587
- this._element.dispatchEvent(new Event(EVENT_COLLAPSE));
702
+ dispatchCustomEvent(this._element, EVENT_COLLAPSED);
588
703
  }
589
704
  toggle() {
590
705
  const isCollapsed = this.isCollapsed();
@@ -674,13 +789,28 @@
674
789
  if (this._config.enablePersistence && !this.isMobileSize()) {
675
790
  this.loadSidebarState();
676
791
  }
677
- else {
792
+ else if (!this.isCollapsed()) {
678
793
  this.updateStateByResponsiveLogic();
679
794
  }
680
795
  }
681
796
  }
797
+ document.addEventListener('click', event => {
798
+ const target = event.target;
799
+ if (!(target instanceof Element)) {
800
+ return;
801
+ }
802
+ const button = target.closest(SELECTOR_SIDEBAR_TOGGLE);
803
+ if (!button) {
804
+ return;
805
+ }
806
+ event.preventDefault();
807
+ const sidebar = document.querySelector(SELECTOR_APP_SIDEBAR);
808
+ if (sidebar) {
809
+ PushMenu.getOrCreateInstance(sidebar).toggle();
810
+ }
811
+ });
682
812
  onDOMContentLoaded(() => {
683
- const sidebar = document?.querySelector(SELECTOR_APP_SIDEBAR);
813
+ const sidebar = document.querySelector(SELECTOR_APP_SIDEBAR);
684
814
  if (!sidebar) {
685
815
  return;
686
816
  }
@@ -694,7 +824,7 @@
694
824
  Defaults.enablePersistence :
695
825
  enablePersistenceAttr === 'true'
696
826
  };
697
- const pushMenu = new PushMenu(sidebar, config);
827
+ const pushMenu = PushMenu.getOrCreateInstance(sidebar, config);
698
828
  pushMenu.init();
699
829
  const breakpointQuery = globalThis.matchMedia(`(max-width: ${pushMenu._config.sidebarBreakpoint}px)`);
700
830
  breakpointQuery.addEventListener('change', () => {
@@ -707,38 +837,139 @@
707
837
  sidebarOverlay.className = CLASS_NAME_SIDEBAR_OVERLAY;
708
838
  appWrapper?.append(sidebarOverlay);
709
839
  }
840
+ const overlaySignal = getLifecycleSignal();
710
841
  let overlayTouchMoved = false;
711
842
  sidebarOverlay.addEventListener('touchstart', () => {
712
843
  overlayTouchMoved = false;
713
- }, { passive: true });
844
+ }, { passive: true, signal: overlaySignal });
714
845
  sidebarOverlay.addEventListener('touchmove', () => {
715
846
  overlayTouchMoved = true;
716
- }, { passive: true });
847
+ }, { passive: true, signal: overlaySignal });
717
848
  sidebarOverlay.addEventListener('touchend', event => {
718
849
  if (!overlayTouchMoved) {
719
850
  event.preventDefault();
720
851
  pushMenu.collapse();
721
852
  }
722
853
  overlayTouchMoved = false;
723
- }, { passive: false });
854
+ }, { passive: false, signal: overlaySignal });
724
855
  sidebarOverlay.addEventListener('click', event => {
725
856
  event.preventDefault();
726
857
  pushMenu.collapse();
727
- });
728
- const fullBtn = document.querySelectorAll(SELECTOR_SIDEBAR_TOGGLE);
729
- fullBtn.forEach(btn => {
730
- btn.addEventListener('click', event => {
731
- event.preventDefault();
732
- let button = event.currentTarget;
733
- if (button?.dataset.lteToggle !== 'sidebar') {
734
- button = button?.closest(SELECTOR_SIDEBAR_TOGGLE);
735
- }
736
- if (button) {
737
- event?.preventDefault();
738
- pushMenu.toggle();
739
- }
858
+ }, { signal: overlaySignal });
859
+ });
860
+
861
+ const DATA_KEY = 'lte.color-mode';
862
+ const EVENT_KEY = `.${DATA_KEY}`;
863
+ const EVENT_CHANGED = `changed${EVENT_KEY}`;
864
+ const STORAGE_KEY = 'lte-theme';
865
+ const ATTRIBUTE_THEME = 'data-bs-theme';
866
+ const ATTRIBUTE_TOGGLE = 'data-bs-theme-value';
867
+ const ATTRIBUTE_DISABLED = 'data-lte-color-mode';
868
+ const ATTRIBUTE_RESOLVED = 'data-lte-theme-resolved';
869
+ const SELECTOR_TOGGLE = `[${ATTRIBUTE_TOGGLE}]`;
870
+ const SELECTOR_ICON = '[data-lte-theme-icon]';
871
+ const THEMES = new Set(['light', 'dark', 'auto']);
872
+ const isValidTheme = (value) => THEMES.has(value);
873
+ const isDisabled = () => document.documentElement.getAttribute(ATTRIBUTE_DISABLED) === 'off';
874
+ const readMarkupTheme = () => {
875
+ const { documentElement } = document;
876
+ if (documentElement.hasAttribute(ATTRIBUTE_RESOLVED)) {
877
+ return null;
878
+ }
879
+ const declared = documentElement.getAttribute(ATTRIBUTE_THEME);
880
+ return declared && isValidTheme(declared) ? declared : null;
881
+ };
882
+ const MARKUP_THEME = readMarkupTheme();
883
+ class ColorMode {
884
+ getStoredTheme() {
885
+ try {
886
+ const stored = localStorage.getItem(STORAGE_KEY);
887
+ return stored && isValidTheme(stored) ? stored : null;
888
+ }
889
+ catch {
890
+ return null;
891
+ }
892
+ }
893
+ getMarkupTheme() {
894
+ return MARKUP_THEME;
895
+ }
896
+ getPreferredTheme() {
897
+ const preferred = this.getStoredTheme() ?? this.getMarkupTheme();
898
+ if (preferred) {
899
+ return preferred;
900
+ }
901
+ return this._prefersDark() ? 'dark' : 'light';
902
+ }
903
+ resolveTheme(theme) {
904
+ if (theme === 'auto') {
905
+ return this._prefersDark() ? 'dark' : 'light';
906
+ }
907
+ return theme;
908
+ }
909
+ setTheme(theme) {
910
+ try {
911
+ localStorage.setItem(STORAGE_KEY, theme);
912
+ }
913
+ catch {
914
+ }
915
+ this._applyTheme(theme);
916
+ this._showActiveTheme(theme);
917
+ document.dispatchEvent(new CustomEvent(EVENT_CHANGED, {
918
+ detail: { theme, resolved: this.resolveTheme(theme) }
919
+ }));
920
+ }
921
+ _applyTheme(theme) {
922
+ const resolved = this.resolveTheme(theme);
923
+ document.documentElement.setAttribute(ATTRIBUTE_THEME, resolved);
924
+ document.documentElement.style.colorScheme = resolved;
925
+ }
926
+ _prefersDark() {
927
+ return globalThis.matchMedia('(prefers-color-scheme: dark)').matches;
928
+ }
929
+ _showActiveTheme(theme) {
930
+ document.querySelectorAll(SELECTOR_TOGGLE).forEach(toggle => {
931
+ const isActive = toggle.getAttribute(ATTRIBUTE_TOGGLE) === theme;
932
+ toggle.classList.toggle('active', isActive);
933
+ toggle.setAttribute('aria-pressed', String(isActive));
934
+ toggle.querySelector('.bi-check-lg')?.classList.toggle('d-none', !isActive);
740
935
  });
741
- });
936
+ document.querySelectorAll(SELECTOR_ICON).forEach(icon => {
937
+ icon.classList.toggle('d-none', icon.dataset.lteThemeIcon !== theme);
938
+ });
939
+ }
940
+ init() {
941
+ if (isDisabled()) {
942
+ return;
943
+ }
944
+ const theme = this.getPreferredTheme();
945
+ this._applyTheme(theme);
946
+ this._showActiveTheme(theme);
947
+ }
948
+ }
949
+ document.addEventListener('click', event => {
950
+ const target = event.target;
951
+ if (!(target instanceof Element) || isDisabled()) {
952
+ return;
953
+ }
954
+ const toggle = target.closest(SELECTOR_TOGGLE);
955
+ const theme = toggle?.getAttribute(ATTRIBUTE_TOGGLE);
956
+ if (theme && isValidTheme(theme)) {
957
+ new ColorMode().setTheme(theme);
958
+ }
959
+ });
960
+ onDOMContentLoaded(() => {
961
+ const colorMode = new ColorMode();
962
+ colorMode.init();
963
+ globalThis.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
964
+ if (isDisabled()) {
965
+ return;
966
+ }
967
+ const preferred = colorMode.getStoredTheme() ?? colorMode.getMarkupTheme();
968
+ if (!preferred || preferred === 'auto') {
969
+ colorMode._applyTheme('auto');
970
+ colorMode._showActiveTheme(preferred ?? 'auto');
971
+ }
972
+ }, { signal: getLifecycleSignal() });
742
973
  });
743
974
 
744
975
  class AccessibilityManager {
@@ -991,7 +1222,7 @@
991
1222
  if (!htmlInput.classList.contains('disable-adminlte-validations')) {
992
1223
  htmlInput.addEventListener('invalid', () => {
993
1224
  this.handleFormError(htmlInput);
994
- });
1225
+ }, { signal: this.signal });
995
1226
  }
996
1227
  });
997
1228
  }
@@ -1178,12 +1409,15 @@
1178
1409
  });
1179
1410
 
1180
1411
  exports.CardWidget = CardWidget;
1412
+ exports.ColorMode = ColorMode;
1181
1413
  exports.DirectChat = DirectChat;
1182
1414
  exports.FullScreen = FullScreen;
1183
1415
  exports.Layout = Layout;
1184
1416
  exports.PushMenu = PushMenu;
1185
1417
  exports.Treeview = Treeview;
1186
1418
  exports.initAccessibility = initAccessibility;
1419
+ exports.initialize = initialize;
1420
+ exports.teardown = teardown;
1187
1421
 
1188
1422
  }));
1189
1423
  //# sourceMappingURL=adminlte.js.map