admin-lte 4.0.0-beta3 → 4.0.0-rc3

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 (76) hide show
  1. package/.browserslistrc +9 -4
  2. package/ACCESSIBILITY-COMPLIANCE.md +369 -0
  3. package/CHANGELOG.md +460 -0
  4. package/README.md +50 -7
  5. package/dist/{pages/UI → UI}/general.html +79 -28
  6. package/dist/{pages/UI → UI}/icons.html +76 -25
  7. package/dist/{pages/UI → UI}/timeline.html +80 -29
  8. package/dist/css/adminlte.css +516 -332
  9. package/dist/css/adminlte.css.map +1 -1
  10. package/dist/css/adminlte.min.css +1 -1
  11. package/dist/css/adminlte.min.css.map +1 -1
  12. package/dist/css/adminlte.rtl.css +516 -332
  13. package/dist/css/adminlte.rtl.css.map +1 -1
  14. package/dist/css/adminlte.rtl.min.css +1 -1
  15. package/dist/css/adminlte.rtl.min.css.map +1 -1
  16. package/dist/{pages/docs → docs}/browser-support.html +77 -44
  17. package/dist/{pages/docs → docs}/color-mode.html +82 -50
  18. package/dist/{pages/docs → docs}/components/main-header.html +82 -49
  19. package/dist/{pages/docs → docs}/components/main-sidebar.html +78 -46
  20. package/dist/{pages/docs → docs}/faq.html +76 -42
  21. package/dist/{pages/docs → docs}/how-to-contribute.html +77 -44
  22. package/dist/{pages/docs → docs}/introduction.html +82 -54
  23. package/dist/{pages/docs → docs}/javascript/treeview.html +77 -44
  24. package/dist/{pages/docs → docs}/layout.html +76 -25
  25. package/dist/{pages/docs → docs}/license.html +76 -42
  26. package/dist/{pages/examples → examples}/lockscreen.html +49 -18
  27. package/dist/{pages/examples → examples}/login-v2.html +47 -16
  28. package/dist/{pages/examples → examples}/login.html +47 -16
  29. package/dist/{pages/examples → examples}/register-v2.html +47 -16
  30. package/dist/{pages/examples → examples}/register.html +47 -16
  31. package/dist/{pages/forms → forms}/general.html +76 -25
  32. package/dist/{pages/generate → generate}/theme.html +193 -24
  33. package/dist/{pages/index.html → index.html} +90 -57
  34. package/dist/{pages/index2.html → index2.html} +99 -48
  35. package/dist/{pages/index3.html → index3.html} +80 -29
  36. package/dist/js/adminlte.js +795 -345
  37. package/dist/js/adminlte.js.map +1 -1
  38. package/dist/js/adminlte.min.js +3 -3
  39. package/dist/js/adminlte.min.js.map +1 -1
  40. package/dist/{pages/layout → layout}/collapsed-sidebar.html +75 -24
  41. package/dist/layout/fixed-complete.html +883 -0
  42. package/dist/layout/fixed-footer.html +880 -0
  43. package/dist/layout/fixed-header.html +880 -0
  44. package/dist/{pages/layout → layout}/fixed-sidebar.html +76 -25
  45. package/dist/{pages/layout → layout}/layout-custom-area.html +76 -25
  46. package/dist/{pages/layout → layout}/layout-rtl.html +76 -25
  47. package/dist/{pages/layout → layout}/logo-switch.html +55 -24
  48. package/dist/{pages/layout → layout}/sidebar-mini.html +75 -24
  49. package/dist/{pages/layout → layout}/unfixed-sidebar.html +76 -25
  50. package/dist/{pages/tables → tables}/simple.html +76 -25
  51. package/dist/{pages/widgets → widgets}/cards.html +76 -25
  52. package/dist/{pages/widgets → widgets}/info-box.html +76 -25
  53. package/dist/{pages/widgets → widgets}/small-box.html +76 -25
  54. package/eslint.config.js +82 -0
  55. package/package.json +42 -37
  56. package/src/scss/_accessibility.scss +292 -0
  57. package/src/scss/_app-footer.scss +8 -0
  58. package/src/scss/_app-header.scss +8 -0
  59. package/src/scss/_app-sidebar.scss +12 -0
  60. package/src/scss/_table.scss +1 -9
  61. package/src/scss/_variables.scss +2 -1
  62. package/src/scss/adminlte.scss +3 -0
  63. package/src/ts/accessibility.ts +533 -0
  64. package/src/ts/adminlte.ts +48 -9
  65. package/src/ts/card-widget.ts +1 -2
  66. package/src/ts/push-menu.ts +1 -2
  67. package/src/ts/treeview.ts +13 -2
  68. package/src/ts/util/index.ts +39 -7
  69. package/.astro/content-assets.mjs +0 -1
  70. package/.astro/content-modules.mjs +0 -1
  71. package/.astro/content.d.ts +0 -166
  72. package/.astro/data-store.json +0 -1
  73. package/.astro/settings.json +0 -5
  74. package/.astro/types.d.ts +0 -2
  75. package/adminlte-v4.0.0-beta1-with-dist.zip +0 -0
  76. package/adminlte-v4.0.0-beta3.zip +0 -0
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * AdminLTE v4.0.0-beta3 (https://adminlte.io)
3
- * Copyright 2014-2024 Colorlib <https://colorlib.com>
2
+ * AdminLTE v4.0.0-rc3 (https://adminlte.io)
3
+ * Copyright 2014-2025 Colorlib <https://colorlib.com>
4
4
  * Licensed under MIT (https://github.com/ColorlibHQ/AdminLTE/blob/master/LICENSE)
5
5
  */
6
6
  (function (global, factory) {
@@ -33,14 +33,14 @@
33
33
  target.style.boxSizing = 'border-box';
34
34
  target.style.height = `${target.offsetHeight}px`;
35
35
  target.style.overflow = 'hidden';
36
- window.setTimeout(() => {
36
+ globalThis.setTimeout(() => {
37
37
  target.style.height = '0';
38
38
  target.style.paddingTop = '0';
39
39
  target.style.paddingBottom = '0';
40
40
  target.style.marginTop = '0';
41
41
  target.style.marginBottom = '0';
42
42
  }, 1);
43
- window.setTimeout(() => {
43
+ globalThis.setTimeout(() => {
44
44
  target.style.display = 'none';
45
45
  target.style.removeProperty('height');
46
46
  target.style.removeProperty('padding-top');
@@ -55,7 +55,7 @@
55
55
  /* SLIDE DOWN */
56
56
  const slideDown = (target, duration = 500) => {
57
57
  target.style.removeProperty('display');
58
- let { display } = window.getComputedStyle(target);
58
+ let { display } = globalThis.getComputedStyle(target);
59
59
  if (display === 'none') {
60
60
  display = 'block';
61
61
  }
@@ -67,7 +67,7 @@
67
67
  target.style.paddingBottom = '0';
68
68
  target.style.marginTop = '0';
69
69
  target.style.marginBottom = '0';
70
- window.setTimeout(() => {
70
+ globalThis.setTimeout(() => {
71
71
  target.style.boxSizing = 'border-box';
72
72
  target.style.transitionProperty = 'height, margin, padding';
73
73
  target.style.transitionDuration = `${duration}ms`;
@@ -77,7 +77,7 @@
77
77
  target.style.removeProperty('margin-top');
78
78
  target.style.removeProperty('margin-bottom');
79
79
  }, 1);
80
- window.setTimeout(() => {
80
+ globalThis.setTimeout(() => {
81
81
  target.style.removeProperty('height');
82
82
  target.style.removeProperty('overflow');
83
83
  target.style.removeProperty('transition-duration');
@@ -104,6 +104,7 @@
104
104
  * ====================================================
105
105
  */
106
106
  class Layout {
107
+ _element;
107
108
  constructor(element) {
108
109
  this._element = element;
109
110
  }
@@ -128,146 +129,185 @@
128
129
 
129
130
  /**
130
131
  * --------------------------------------------
131
- * @file AdminLTE push-menu.ts
132
- * @description Push menu for AdminLTE.
132
+ * @file AdminLTE card-widget.ts
133
+ * @description Card widget for AdminLTE.
133
134
  * @license MIT
134
135
  * --------------------------------------------
135
136
  */
136
137
  /**
137
- * ------------------------------------------------------------------------
138
138
  * Constants
139
- * ------------------------------------------------------------------------
139
+ * ====================================================
140
140
  */
141
- const DATA_KEY$4 = 'lte.push-menu';
141
+ const DATA_KEY$4 = 'lte.card-widget';
142
142
  const EVENT_KEY$4 = `.${DATA_KEY$4}`;
143
- const EVENT_OPEN = `open${EVENT_KEY$4}`;
144
- const EVENT_COLLAPSE = `collapse${EVENT_KEY$4}`;
145
- const CLASS_NAME_SIDEBAR_MINI = 'sidebar-mini';
146
- const CLASS_NAME_SIDEBAR_COLLAPSE = 'sidebar-collapse';
147
- const CLASS_NAME_SIDEBAR_OPEN = 'sidebar-open';
148
- const CLASS_NAME_SIDEBAR_EXPAND = 'sidebar-expand';
149
- const CLASS_NAME_SIDEBAR_OVERLAY = 'sidebar-overlay';
150
- const CLASS_NAME_MENU_OPEN$1 = 'menu-open';
151
- const SELECTOR_APP_SIDEBAR = '.app-sidebar';
152
- const SELECTOR_SIDEBAR_MENU = '.sidebar-menu';
153
- const SELECTOR_NAV_ITEM$1 = '.nav-item';
154
- const SELECTOR_NAV_TREEVIEW = '.nav-treeview';
155
- const SELECTOR_APP_WRAPPER = '.app-wrapper';
156
- const SELECTOR_SIDEBAR_EXPAND = `[class*="${CLASS_NAME_SIDEBAR_EXPAND}"]`;
157
- const SELECTOR_SIDEBAR_TOGGLE = '[data-lte-toggle="sidebar"]';
158
- const Defaults = {
159
- sidebarBreakpoint: 992
143
+ const EVENT_COLLAPSED$2 = `collapsed${EVENT_KEY$4}`;
144
+ const EVENT_EXPANDED$2 = `expanded${EVENT_KEY$4}`;
145
+ const EVENT_REMOVE = `remove${EVENT_KEY$4}`;
146
+ const EVENT_MAXIMIZED$1 = `maximized${EVENT_KEY$4}`;
147
+ const EVENT_MINIMIZED$1 = `minimized${EVENT_KEY$4}`;
148
+ const CLASS_NAME_CARD = 'card';
149
+ const CLASS_NAME_COLLAPSED = 'collapsed-card';
150
+ const CLASS_NAME_COLLAPSING = 'collapsing-card';
151
+ const CLASS_NAME_EXPANDING = 'expanding-card';
152
+ const CLASS_NAME_WAS_COLLAPSED = 'was-collapsed';
153
+ const CLASS_NAME_MAXIMIZED = 'maximized-card';
154
+ const SELECTOR_DATA_REMOVE = '[data-lte-toggle="card-remove"]';
155
+ const SELECTOR_DATA_COLLAPSE = '[data-lte-toggle="card-collapse"]';
156
+ const SELECTOR_DATA_MAXIMIZE = '[data-lte-toggle="card-maximize"]';
157
+ const SELECTOR_CARD = `.${CLASS_NAME_CARD}`;
158
+ const SELECTOR_CARD_BODY = '.card-body';
159
+ const SELECTOR_CARD_FOOTER = '.card-footer';
160
+ const Default$1 = {
161
+ animationSpeed: 500,
162
+ collapseTrigger: SELECTOR_DATA_COLLAPSE,
163
+ removeTrigger: SELECTOR_DATA_REMOVE,
164
+ maximizeTrigger: SELECTOR_DATA_MAXIMIZE
160
165
  };
161
- /**
162
- * Class Definition
163
- * ====================================================
164
- */
165
- class PushMenu {
166
+ class CardWidget {
167
+ _element;
168
+ _parent;
169
+ _clone;
170
+ _config;
166
171
  constructor(element, config) {
167
172
  this._element = element;
168
- this._config = Object.assign(Object.assign({}, Defaults), config);
173
+ this._parent = element.closest(SELECTOR_CARD);
174
+ if (element.classList.contains(CLASS_NAME_CARD)) {
175
+ this._parent = element;
176
+ }
177
+ this._config = { ...Default$1, ...config };
169
178
  }
170
- // TODO
171
- menusClose() {
172
- const navTreeview = document.querySelectorAll(SELECTOR_NAV_TREEVIEW);
173
- navTreeview.forEach(navTree => {
174
- navTree.style.removeProperty('display');
175
- navTree.style.removeProperty('height');
176
- });
177
- const navSidebar = document.querySelector(SELECTOR_SIDEBAR_MENU);
178
- const navItem = navSidebar === null || navSidebar === void 0 ? void 0 : navSidebar.querySelectorAll(SELECTOR_NAV_ITEM$1);
179
- if (navItem) {
180
- navItem.forEach(navI => {
181
- navI.classList.remove(CLASS_NAME_MENU_OPEN$1);
179
+ collapse() {
180
+ const event = new Event(EVENT_COLLAPSED$2);
181
+ if (this._parent) {
182
+ this._parent.classList.add(CLASS_NAME_COLLAPSING);
183
+ const elm = this._parent?.querySelectorAll(`${SELECTOR_CARD_BODY}, ${SELECTOR_CARD_FOOTER}`);
184
+ elm.forEach(el => {
185
+ if (el instanceof HTMLElement) {
186
+ slideUp(el, this._config.animationSpeed);
187
+ }
182
188
  });
189
+ setTimeout(() => {
190
+ if (this._parent) {
191
+ this._parent.classList.add(CLASS_NAME_COLLAPSED);
192
+ this._parent.classList.remove(CLASS_NAME_COLLAPSING);
193
+ }
194
+ }, this._config.animationSpeed);
183
195
  }
196
+ this._element?.dispatchEvent(event);
184
197
  }
185
198
  expand() {
186
- const event = new Event(EVENT_OPEN);
187
- document.body.classList.remove(CLASS_NAME_SIDEBAR_COLLAPSE);
188
- document.body.classList.add(CLASS_NAME_SIDEBAR_OPEN);
189
- this._element.dispatchEvent(event);
190
- }
191
- collapse() {
192
- const event = new Event(EVENT_COLLAPSE);
193
- document.body.classList.remove(CLASS_NAME_SIDEBAR_OPEN);
194
- document.body.classList.add(CLASS_NAME_SIDEBAR_COLLAPSE);
195
- this._element.dispatchEvent(event);
196
- }
197
- addSidebarBreakPoint() {
198
- var _a, _b, _c;
199
- const sidebarExpandList = (_b = (_a = document.querySelector(SELECTOR_SIDEBAR_EXPAND)) === null || _a === void 0 ? void 0 : _a.classList) !== null && _b !== void 0 ? _b : [];
200
- const sidebarExpand = (_c = Array.from(sidebarExpandList).find(className => className.startsWith(CLASS_NAME_SIDEBAR_EXPAND))) !== null && _c !== void 0 ? _c : '';
201
- const sidebar = document.getElementsByClassName(sidebarExpand)[0];
202
- const sidebarContent = window.getComputedStyle(sidebar, '::before').getPropertyValue('content');
203
- this._config = Object.assign(Object.assign({}, this._config), { sidebarBreakpoint: Number(sidebarContent.replace(/[^\d.-]/g, '')) });
204
- if (window.innerWidth <= this._config.sidebarBreakpoint) {
205
- this.collapse();
199
+ const event = new Event(EVENT_EXPANDED$2);
200
+ if (this._parent) {
201
+ this._parent.classList.add(CLASS_NAME_EXPANDING);
202
+ const elm = this._parent?.querySelectorAll(`${SELECTOR_CARD_BODY}, ${SELECTOR_CARD_FOOTER}`);
203
+ elm.forEach(el => {
204
+ if (el instanceof HTMLElement) {
205
+ slideDown(el, this._config.animationSpeed);
206
+ }
207
+ });
208
+ setTimeout(() => {
209
+ if (this._parent) {
210
+ this._parent.classList.remove(CLASS_NAME_COLLAPSED, CLASS_NAME_EXPANDING);
211
+ }
212
+ }, this._config.animationSpeed);
206
213
  }
207
- else {
208
- if (!document.body.classList.contains(CLASS_NAME_SIDEBAR_MINI)) {
209
- this.expand();
210
- }
211
- if (document.body.classList.contains(CLASS_NAME_SIDEBAR_MINI) && document.body.classList.contains(CLASS_NAME_SIDEBAR_COLLAPSE)) {
212
- this.collapse();
213
- }
214
+ this._element?.dispatchEvent(event);
215
+ }
216
+ remove() {
217
+ const event = new Event(EVENT_REMOVE);
218
+ if (this._parent) {
219
+ slideUp(this._parent, this._config.animationSpeed);
214
220
  }
221
+ this._element?.dispatchEvent(event);
215
222
  }
216
223
  toggle() {
217
- if (document.body.classList.contains(CLASS_NAME_SIDEBAR_COLLAPSE)) {
224
+ if (this._parent?.classList.contains(CLASS_NAME_COLLAPSED)) {
218
225
  this.expand();
226
+ return;
219
227
  }
220
- else {
221
- this.collapse();
228
+ this.collapse();
229
+ }
230
+ maximize() {
231
+ const event = new Event(EVENT_MAXIMIZED$1);
232
+ if (this._parent) {
233
+ this._parent.style.height = `${this._parent.offsetHeight}px`;
234
+ this._parent.style.width = `${this._parent.offsetWidth}px`;
235
+ this._parent.style.transition = 'all .15s';
236
+ setTimeout(() => {
237
+ const htmlTag = document.querySelector('html');
238
+ if (htmlTag) {
239
+ htmlTag.classList.add(CLASS_NAME_MAXIMIZED);
240
+ }
241
+ if (this._parent) {
242
+ this._parent.classList.add(CLASS_NAME_MAXIMIZED);
243
+ if (this._parent.classList.contains(CLASS_NAME_COLLAPSED)) {
244
+ this._parent.classList.add(CLASS_NAME_WAS_COLLAPSED);
245
+ }
246
+ }
247
+ }, 150);
222
248
  }
249
+ this._element?.dispatchEvent(event);
223
250
  }
224
- init() {
225
- this.addSidebarBreakPoint();
251
+ minimize() {
252
+ const event = new Event(EVENT_MINIMIZED$1);
253
+ if (this._parent) {
254
+ this._parent.style.height = 'auto';
255
+ this._parent.style.width = 'auto';
256
+ this._parent.style.transition = 'all .15s';
257
+ setTimeout(() => {
258
+ const htmlTag = document.querySelector('html');
259
+ if (htmlTag) {
260
+ htmlTag.classList.remove(CLASS_NAME_MAXIMIZED);
261
+ }
262
+ if (this._parent) {
263
+ this._parent.classList.remove(CLASS_NAME_MAXIMIZED);
264
+ if (this._parent?.classList.contains(CLASS_NAME_WAS_COLLAPSED)) {
265
+ this._parent.classList.remove(CLASS_NAME_WAS_COLLAPSED);
266
+ }
267
+ }
268
+ }, 10);
269
+ }
270
+ this._element?.dispatchEvent(event);
271
+ }
272
+ toggleMaximize() {
273
+ if (this._parent?.classList.contains(CLASS_NAME_MAXIMIZED)) {
274
+ this.minimize();
275
+ return;
276
+ }
277
+ this.maximize();
226
278
  }
227
279
  }
228
280
  /**
229
- * ------------------------------------------------------------------------
281
+ *
230
282
  * Data Api implementation
231
- * ------------------------------------------------------------------------
283
+ * ====================================================
232
284
  */
233
285
  onDOMContentLoaded(() => {
234
- var _a;
235
- const sidebar = document === null || document === void 0 ? void 0 : document.querySelector(SELECTOR_APP_SIDEBAR);
236
- if (sidebar) {
237
- const data = new PushMenu(sidebar, Defaults);
238
- data.init();
239
- window.addEventListener('resize', () => {
240
- data.init();
286
+ const collapseBtn = document.querySelectorAll(SELECTOR_DATA_COLLAPSE);
287
+ collapseBtn.forEach(btn => {
288
+ btn.addEventListener('click', event => {
289
+ event.preventDefault();
290
+ const target = event.target;
291
+ const data = new CardWidget(target, Default$1);
292
+ data.toggle();
241
293
  });
242
- }
243
- const sidebarOverlay = document.createElement('div');
244
- sidebarOverlay.className = CLASS_NAME_SIDEBAR_OVERLAY;
245
- (_a = document.querySelector(SELECTOR_APP_WRAPPER)) === null || _a === void 0 ? void 0 : _a.append(sidebarOverlay);
246
- sidebarOverlay.addEventListener('touchstart', event => {
247
- event.preventDefault();
248
- const target = event.currentTarget;
249
- const data = new PushMenu(target, Defaults);
250
- data.collapse();
251
- }, { passive: true });
252
- sidebarOverlay.addEventListener('click', event => {
253
- event.preventDefault();
254
- const target = event.currentTarget;
255
- const data = new PushMenu(target, Defaults);
256
- data.collapse();
257
294
  });
258
- const fullBtn = document.querySelectorAll(SELECTOR_SIDEBAR_TOGGLE);
259
- fullBtn.forEach(btn => {
295
+ const removeBtn = document.querySelectorAll(SELECTOR_DATA_REMOVE);
296
+ removeBtn.forEach(btn => {
260
297
  btn.addEventListener('click', event => {
261
298
  event.preventDefault();
262
- let button = event.currentTarget;
263
- if ((button === null || button === void 0 ? void 0 : button.dataset.lteToggle) !== 'sidebar') {
264
- button = button === null || button === void 0 ? void 0 : button.closest(SELECTOR_SIDEBAR_TOGGLE);
265
- }
266
- if (button) {
267
- event === null || event === void 0 ? void 0 : event.preventDefault();
268
- const data = new PushMenu(button, Defaults);
269
- data.toggle();
270
- }
299
+ const target = event.target;
300
+ const data = new CardWidget(target, Default$1);
301
+ data.remove();
302
+ });
303
+ });
304
+ const maxBtn = document.querySelectorAll(SELECTOR_DATA_MAXIMIZE);
305
+ maxBtn.forEach(btn => {
306
+ btn.addEventListener('click', event => {
307
+ event.preventDefault();
308
+ const target = event.target;
309
+ const data = new CardWidget(target, Default$1);
310
+ data.toggleMaximize();
271
311
  });
272
312
  });
273
313
  });
@@ -287,15 +327,15 @@
287
327
  // const NAME = 'Treeview'
288
328
  const DATA_KEY$3 = 'lte.treeview';
289
329
  const EVENT_KEY$3 = `.${DATA_KEY$3}`;
290
- const EVENT_EXPANDED$2 = `expanded${EVENT_KEY$3}`;
291
- const EVENT_COLLAPSED$2 = `collapsed${EVENT_KEY$3}`;
330
+ const EVENT_EXPANDED$1 = `expanded${EVENT_KEY$3}`;
331
+ const EVENT_COLLAPSED$1 = `collapsed${EVENT_KEY$3}`;
292
332
  // const EVENT_LOAD_DATA_API = `load${EVENT_KEY}`
293
- const CLASS_NAME_MENU_OPEN = 'menu-open';
294
- const SELECTOR_NAV_ITEM = '.nav-item';
333
+ const CLASS_NAME_MENU_OPEN$1 = 'menu-open';
334
+ const SELECTOR_NAV_ITEM$1 = '.nav-item';
295
335
  const SELECTOR_NAV_LINK = '.nav-link';
296
336
  const SELECTOR_TREEVIEW_MENU = '.nav-treeview';
297
337
  const SELECTOR_DATA_TOGGLE$1 = '[data-lte-toggle="treeview"]';
298
- const Default$1 = {
338
+ const Default = {
299
339
  animationSpeed: 300,
300
340
  accordion: true
301
341
  };
@@ -304,44 +344,44 @@
304
344
  * ====================================================
305
345
  */
306
346
  class Treeview {
347
+ _element;
348
+ _config;
307
349
  constructor(element, config) {
308
350
  this._element = element;
309
- this._config = Object.assign(Object.assign({}, Default$1), config);
351
+ this._config = { ...Default, ...config };
310
352
  }
311
353
  open() {
312
- var _a, _b;
313
- const event = new Event(EVENT_EXPANDED$2);
354
+ const event = new Event(EVENT_EXPANDED$1);
314
355
  if (this._config.accordion) {
315
- const openMenuList = (_a = this._element.parentElement) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`${SELECTOR_NAV_ITEM}.${CLASS_NAME_MENU_OPEN}`);
316
- openMenuList === null || openMenuList === void 0 ? void 0 : openMenuList.forEach(openMenu => {
356
+ const openMenuList = this._element.parentElement?.querySelectorAll(`${SELECTOR_NAV_ITEM$1}.${CLASS_NAME_MENU_OPEN$1}`);
357
+ openMenuList?.forEach(openMenu => {
317
358
  if (openMenu !== this._element.parentElement) {
318
- openMenu.classList.remove(CLASS_NAME_MENU_OPEN);
319
- const childElement = openMenu === null || openMenu === void 0 ? void 0 : openMenu.querySelector(SELECTOR_TREEVIEW_MENU);
359
+ openMenu.classList.remove(CLASS_NAME_MENU_OPEN$1);
360
+ const childElement = openMenu?.querySelector(SELECTOR_TREEVIEW_MENU);
320
361
  if (childElement) {
321
362
  slideUp(childElement, this._config.animationSpeed);
322
363
  }
323
364
  }
324
365
  });
325
366
  }
326
- this._element.classList.add(CLASS_NAME_MENU_OPEN);
327
- const childElement = (_b = this._element) === null || _b === void 0 ? void 0 : _b.querySelector(SELECTOR_TREEVIEW_MENU);
367
+ this._element.classList.add(CLASS_NAME_MENU_OPEN$1);
368
+ const childElement = this._element?.querySelector(SELECTOR_TREEVIEW_MENU);
328
369
  if (childElement) {
329
370
  slideDown(childElement, this._config.animationSpeed);
330
371
  }
331
372
  this._element.dispatchEvent(event);
332
373
  }
333
374
  close() {
334
- var _a;
335
- const event = new Event(EVENT_COLLAPSED$2);
336
- this._element.classList.remove(CLASS_NAME_MENU_OPEN);
337
- const childElement = (_a = this._element) === null || _a === void 0 ? void 0 : _a.querySelector(SELECTOR_TREEVIEW_MENU);
375
+ const event = new Event(EVENT_COLLAPSED$1);
376
+ this._element.classList.remove(CLASS_NAME_MENU_OPEN$1);
377
+ const childElement = this._element?.querySelector(SELECTOR_TREEVIEW_MENU);
338
378
  if (childElement) {
339
379
  slideUp(childElement, this._config.animationSpeed);
340
380
  }
341
381
  this._element.dispatchEvent(event);
342
382
  }
343
383
  toggle() {
344
- if (this._element.classList.contains(CLASS_NAME_MENU_OPEN)) {
384
+ if (this._element.classList.contains(CLASS_NAME_MENU_OPEN$1)) {
345
385
  this.close();
346
386
  }
347
387
  else {
@@ -359,13 +399,22 @@
359
399
  button.forEach(btn => {
360
400
  btn.addEventListener('click', event => {
361
401
  const target = event.target;
362
- const targetItem = target.closest(SELECTOR_NAV_ITEM);
402
+ const targetItem = target.closest(SELECTOR_NAV_ITEM$1);
363
403
  const targetLink = target.closest(SELECTOR_NAV_LINK);
364
- if ((target === null || target === void 0 ? void 0 : target.getAttribute('href')) === '#' || (targetLink === null || targetLink === void 0 ? void 0 : targetLink.getAttribute('href')) === '#') {
404
+ const lteToggleElement = event.currentTarget;
405
+ if (target?.getAttribute('href') === '#' || targetLink?.getAttribute('href') === '#') {
365
406
  event.preventDefault();
366
407
  }
367
408
  if (targetItem) {
368
- const data = new Treeview(targetItem, Default$1);
409
+ // Read data attributes
410
+ const accordionAttr = lteToggleElement.dataset.accordion;
411
+ const animationSpeedAttr = lteToggleElement.dataset.animationSpeed;
412
+ // Build config from data attributes, fallback to Default
413
+ const config = {
414
+ accordion: accordionAttr === undefined ? Default.accordion : accordionAttr === 'true',
415
+ animationSpeed: animationSpeedAttr === undefined ? Default.animationSpeed : Number(animationSpeedAttr)
416
+ };
417
+ const data = new Treeview(targetItem, config);
369
418
  data.toggle();
370
419
  }
371
420
  });
@@ -385,8 +434,8 @@
385
434
  */
386
435
  const DATA_KEY$2 = 'lte.direct-chat';
387
436
  const EVENT_KEY$2 = `.${DATA_KEY$2}`;
388
- const EVENT_EXPANDED$1 = `expanded${EVENT_KEY$2}`;
389
- const EVENT_COLLAPSED$1 = `collapsed${EVENT_KEY$2}`;
437
+ const EVENT_EXPANDED = `expanded${EVENT_KEY$2}`;
438
+ const EVENT_COLLAPSED = `collapsed${EVENT_KEY$2}`;
390
439
  const SELECTOR_DATA_TOGGLE = '[data-lte-toggle="chat-pane"]';
391
440
  const SELECTOR_DIRECT_CHAT = '.direct-chat';
392
441
  const CLASS_NAME_DIRECT_CHAT_OPEN = 'direct-chat-contacts-open';
@@ -395,17 +444,18 @@
395
444
  * ====================================================
396
445
  */
397
446
  class DirectChat {
447
+ _element;
398
448
  constructor(element) {
399
449
  this._element = element;
400
450
  }
401
451
  toggle() {
402
452
  if (this._element.classList.contains(CLASS_NAME_DIRECT_CHAT_OPEN)) {
403
- const event = new Event(EVENT_COLLAPSED$1);
453
+ const event = new Event(EVENT_COLLAPSED);
404
454
  this._element.classList.remove(CLASS_NAME_DIRECT_CHAT_OPEN);
405
455
  this._element.dispatchEvent(event);
406
456
  }
407
457
  else {
408
- const event = new Event(EVENT_EXPANDED$1);
458
+ const event = new Event(EVENT_EXPANDED);
409
459
  this._element.classList.add(CLASS_NAME_DIRECT_CHAT_OPEN);
410
460
  this._element.dispatchEvent(event);
411
461
  }
@@ -433,220 +483,32 @@
433
483
 
434
484
  /**
435
485
  * --------------------------------------------
436
- * @file AdminLTE card-widget.ts
437
- * @description Card widget for AdminLTE.
486
+ * @file AdminLTE fullscreen.ts
487
+ * @description Fullscreen plugin for AdminLTE.
438
488
  * @license MIT
439
489
  * --------------------------------------------
440
490
  */
441
491
  /**
442
492
  * Constants
443
- * ====================================================
493
+ * ============================================================================
444
494
  */
445
- const DATA_KEY$1 = 'lte.card-widget';
495
+ const DATA_KEY$1 = 'lte.fullscreen';
446
496
  const EVENT_KEY$1 = `.${DATA_KEY$1}`;
447
- const EVENT_COLLAPSED = `collapsed${EVENT_KEY$1}`;
448
- const EVENT_EXPANDED = `expanded${EVENT_KEY$1}`;
449
- const EVENT_REMOVE = `remove${EVENT_KEY$1}`;
450
- const EVENT_MAXIMIZED$1 = `maximized${EVENT_KEY$1}`;
451
- const EVENT_MINIMIZED$1 = `minimized${EVENT_KEY$1}`;
452
- const CLASS_NAME_CARD = 'card';
453
- const CLASS_NAME_COLLAPSED = 'collapsed-card';
454
- const CLASS_NAME_COLLAPSING = 'collapsing-card';
455
- const CLASS_NAME_EXPANDING = 'expanding-card';
456
- const CLASS_NAME_WAS_COLLAPSED = 'was-collapsed';
457
- const CLASS_NAME_MAXIMIZED = 'maximized-card';
458
- const SELECTOR_DATA_REMOVE = '[data-lte-toggle="card-remove"]';
459
- const SELECTOR_DATA_COLLAPSE = '[data-lte-toggle="card-collapse"]';
460
- const SELECTOR_DATA_MAXIMIZE = '[data-lte-toggle="card-maximize"]';
461
- const SELECTOR_CARD = `.${CLASS_NAME_CARD}`;
462
- const SELECTOR_CARD_BODY = '.card-body';
463
- const SELECTOR_CARD_FOOTER = '.card-footer';
464
- const Default = {
465
- animationSpeed: 500,
466
- collapseTrigger: SELECTOR_DATA_COLLAPSE,
467
- removeTrigger: SELECTOR_DATA_REMOVE,
468
- maximizeTrigger: SELECTOR_DATA_MAXIMIZE
469
- };
470
- class CardWidget {
497
+ const EVENT_MAXIMIZED = `maximized${EVENT_KEY$1}`;
498
+ const EVENT_MINIMIZED = `minimized${EVENT_KEY$1}`;
499
+ const SELECTOR_FULLSCREEN_TOGGLE = '[data-lte-toggle="fullscreen"]';
500
+ const SELECTOR_MAXIMIZE_ICON = '[data-lte-icon="maximize"]';
501
+ const SELECTOR_MINIMIZE_ICON = '[data-lte-icon="minimize"]';
502
+ /**
503
+ * Class Definition.
504
+ * ============================================================================
505
+ */
506
+ class FullScreen {
507
+ _element;
508
+ _config;
471
509
  constructor(element, config) {
472
510
  this._element = element;
473
- this._parent = element.closest(SELECTOR_CARD);
474
- if (element.classList.contains(CLASS_NAME_CARD)) {
475
- this._parent = element;
476
- }
477
- this._config = Object.assign(Object.assign({}, Default), config);
478
- }
479
- collapse() {
480
- var _a, _b;
481
- const event = new Event(EVENT_COLLAPSED);
482
- if (this._parent) {
483
- this._parent.classList.add(CLASS_NAME_COLLAPSING);
484
- const elm = (_a = this._parent) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`${SELECTOR_CARD_BODY}, ${SELECTOR_CARD_FOOTER}`);
485
- elm.forEach(el => {
486
- if (el instanceof HTMLElement) {
487
- slideUp(el, this._config.animationSpeed);
488
- }
489
- });
490
- setTimeout(() => {
491
- if (this._parent) {
492
- this._parent.classList.add(CLASS_NAME_COLLAPSED);
493
- this._parent.classList.remove(CLASS_NAME_COLLAPSING);
494
- }
495
- }, this._config.animationSpeed);
496
- }
497
- (_b = this._element) === null || _b === void 0 ? void 0 : _b.dispatchEvent(event);
498
- }
499
- expand() {
500
- var _a, _b;
501
- const event = new Event(EVENT_EXPANDED);
502
- if (this._parent) {
503
- this._parent.classList.add(CLASS_NAME_EXPANDING);
504
- const elm = (_a = this._parent) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`${SELECTOR_CARD_BODY}, ${SELECTOR_CARD_FOOTER}`);
505
- elm.forEach(el => {
506
- if (el instanceof HTMLElement) {
507
- slideDown(el, this._config.animationSpeed);
508
- }
509
- });
510
- setTimeout(() => {
511
- if (this._parent) {
512
- this._parent.classList.remove(CLASS_NAME_COLLAPSED);
513
- this._parent.classList.remove(CLASS_NAME_EXPANDING);
514
- }
515
- }, this._config.animationSpeed);
516
- }
517
- (_b = this._element) === null || _b === void 0 ? void 0 : _b.dispatchEvent(event);
518
- }
519
- remove() {
520
- var _a;
521
- const event = new Event(EVENT_REMOVE);
522
- if (this._parent) {
523
- slideUp(this._parent, this._config.animationSpeed);
524
- }
525
- (_a = this._element) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);
526
- }
527
- toggle() {
528
- var _a;
529
- if ((_a = this._parent) === null || _a === void 0 ? void 0 : _a.classList.contains(CLASS_NAME_COLLAPSED)) {
530
- this.expand();
531
- return;
532
- }
533
- this.collapse();
534
- }
535
- maximize() {
536
- var _a;
537
- const event = new Event(EVENT_MAXIMIZED$1);
538
- if (this._parent) {
539
- this._parent.style.height = `${this._parent.offsetHeight}px`;
540
- this._parent.style.width = `${this._parent.offsetWidth}px`;
541
- this._parent.style.transition = 'all .15s';
542
- setTimeout(() => {
543
- const htmlTag = document.querySelector('html');
544
- if (htmlTag) {
545
- htmlTag.classList.add(CLASS_NAME_MAXIMIZED);
546
- }
547
- if (this._parent) {
548
- this._parent.classList.add(CLASS_NAME_MAXIMIZED);
549
- if (this._parent.classList.contains(CLASS_NAME_COLLAPSED)) {
550
- this._parent.classList.add(CLASS_NAME_WAS_COLLAPSED);
551
- }
552
- }
553
- }, 150);
554
- }
555
- (_a = this._element) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);
556
- }
557
- minimize() {
558
- var _a;
559
- const event = new Event(EVENT_MINIMIZED$1);
560
- if (this._parent) {
561
- this._parent.style.height = 'auto';
562
- this._parent.style.width = 'auto';
563
- this._parent.style.transition = 'all .15s';
564
- setTimeout(() => {
565
- var _a;
566
- const htmlTag = document.querySelector('html');
567
- if (htmlTag) {
568
- htmlTag.classList.remove(CLASS_NAME_MAXIMIZED);
569
- }
570
- if (this._parent) {
571
- this._parent.classList.remove(CLASS_NAME_MAXIMIZED);
572
- if ((_a = this._parent) === null || _a === void 0 ? void 0 : _a.classList.contains(CLASS_NAME_WAS_COLLAPSED)) {
573
- this._parent.classList.remove(CLASS_NAME_WAS_COLLAPSED);
574
- }
575
- }
576
- }, 10);
577
- }
578
- (_a = this._element) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);
579
- }
580
- toggleMaximize() {
581
- var _a;
582
- if ((_a = this._parent) === null || _a === void 0 ? void 0 : _a.classList.contains(CLASS_NAME_MAXIMIZED)) {
583
- this.minimize();
584
- return;
585
- }
586
- this.maximize();
587
- }
588
- }
589
- /**
590
- *
591
- * Data Api implementation
592
- * ====================================================
593
- */
594
- onDOMContentLoaded(() => {
595
- const collapseBtn = document.querySelectorAll(SELECTOR_DATA_COLLAPSE);
596
- collapseBtn.forEach(btn => {
597
- btn.addEventListener('click', event => {
598
- event.preventDefault();
599
- const target = event.target;
600
- const data = new CardWidget(target, Default);
601
- data.toggle();
602
- });
603
- });
604
- const removeBtn = document.querySelectorAll(SELECTOR_DATA_REMOVE);
605
- removeBtn.forEach(btn => {
606
- btn.addEventListener('click', event => {
607
- event.preventDefault();
608
- const target = event.target;
609
- const data = new CardWidget(target, Default);
610
- data.remove();
611
- });
612
- });
613
- const maxBtn = document.querySelectorAll(SELECTOR_DATA_MAXIMIZE);
614
- maxBtn.forEach(btn => {
615
- btn.addEventListener('click', event => {
616
- event.preventDefault();
617
- const target = event.target;
618
- const data = new CardWidget(target, Default);
619
- data.toggleMaximize();
620
- });
621
- });
622
- });
623
-
624
- /**
625
- * --------------------------------------------
626
- * @file AdminLTE fullscreen.ts
627
- * @description Fullscreen plugin for AdminLTE.
628
- * @license MIT
629
- * --------------------------------------------
630
- */
631
- /**
632
- * Constants
633
- * ============================================================================
634
- */
635
- const DATA_KEY = 'lte.fullscreen';
636
- const EVENT_KEY = `.${DATA_KEY}`;
637
- const EVENT_MAXIMIZED = `maximized${EVENT_KEY}`;
638
- const EVENT_MINIMIZED = `minimized${EVENT_KEY}`;
639
- const SELECTOR_FULLSCREEN_TOGGLE = '[data-lte-toggle="fullscreen"]';
640
- const SELECTOR_MAXIMIZE_ICON = '[data-lte-icon="maximize"]';
641
- const SELECTOR_MINIMIZE_ICON = '[data-lte-icon="minimize"]';
642
- /**
643
- * Class Definition.
644
- * ============================================================================
645
- */
646
- class FullScreen {
647
- constructor(element, config) {
648
- this._element = element;
649
- this._config = config;
511
+ this._config = config;
650
512
  }
651
513
  inFullScreen() {
652
514
  const event = new Event(EVENT_MAXIMIZED);
@@ -704,12 +566,600 @@
704
566
  });
705
567
  });
706
568
 
569
+ /**
570
+ * --------------------------------------------
571
+ * @file AdminLTE push-menu.ts
572
+ * @description Push menu for AdminLTE.
573
+ * @license MIT
574
+ * --------------------------------------------
575
+ */
576
+ /**
577
+ * ------------------------------------------------------------------------
578
+ * Constants
579
+ * ------------------------------------------------------------------------
580
+ */
581
+ const DATA_KEY = 'lte.push-menu';
582
+ const EVENT_KEY = `.${DATA_KEY}`;
583
+ const EVENT_OPEN = `open${EVENT_KEY}`;
584
+ const EVENT_COLLAPSE = `collapse${EVENT_KEY}`;
585
+ const CLASS_NAME_SIDEBAR_MINI = 'sidebar-mini';
586
+ const CLASS_NAME_SIDEBAR_COLLAPSE = 'sidebar-collapse';
587
+ const CLASS_NAME_SIDEBAR_OPEN = 'sidebar-open';
588
+ const CLASS_NAME_SIDEBAR_EXPAND = 'sidebar-expand';
589
+ const CLASS_NAME_SIDEBAR_OVERLAY = 'sidebar-overlay';
590
+ const CLASS_NAME_MENU_OPEN = 'menu-open';
591
+ const SELECTOR_APP_SIDEBAR = '.app-sidebar';
592
+ const SELECTOR_SIDEBAR_MENU = '.sidebar-menu';
593
+ const SELECTOR_NAV_ITEM = '.nav-item';
594
+ const SELECTOR_NAV_TREEVIEW = '.nav-treeview';
595
+ const SELECTOR_APP_WRAPPER = '.app-wrapper';
596
+ const SELECTOR_SIDEBAR_EXPAND = `[class*="${CLASS_NAME_SIDEBAR_EXPAND}"]`;
597
+ const SELECTOR_SIDEBAR_TOGGLE = '[data-lte-toggle="sidebar"]';
598
+ const Defaults = {
599
+ sidebarBreakpoint: 992
600
+ };
601
+ /**
602
+ * Class Definition
603
+ * ====================================================
604
+ */
605
+ class PushMenu {
606
+ _element;
607
+ _config;
608
+ constructor(element, config) {
609
+ this._element = element;
610
+ this._config = { ...Defaults, ...config };
611
+ }
612
+ menusClose() {
613
+ const navTreeview = document.querySelectorAll(SELECTOR_NAV_TREEVIEW);
614
+ navTreeview.forEach(navTree => {
615
+ navTree.style.removeProperty('display');
616
+ navTree.style.removeProperty('height');
617
+ });
618
+ const navSidebar = document.querySelector(SELECTOR_SIDEBAR_MENU);
619
+ const navItem = navSidebar?.querySelectorAll(SELECTOR_NAV_ITEM);
620
+ if (navItem) {
621
+ navItem.forEach(navI => {
622
+ navI.classList.remove(CLASS_NAME_MENU_OPEN);
623
+ });
624
+ }
625
+ }
626
+ expand() {
627
+ const event = new Event(EVENT_OPEN);
628
+ document.body.classList.remove(CLASS_NAME_SIDEBAR_COLLAPSE);
629
+ document.body.classList.add(CLASS_NAME_SIDEBAR_OPEN);
630
+ this._element.dispatchEvent(event);
631
+ }
632
+ collapse() {
633
+ const event = new Event(EVENT_COLLAPSE);
634
+ document.body.classList.remove(CLASS_NAME_SIDEBAR_OPEN);
635
+ document.body.classList.add(CLASS_NAME_SIDEBAR_COLLAPSE);
636
+ this._element.dispatchEvent(event);
637
+ }
638
+ addSidebarBreakPoint() {
639
+ const sidebarExpandList = document.querySelector(SELECTOR_SIDEBAR_EXPAND)?.classList ?? [];
640
+ const sidebarExpand = Array.from(sidebarExpandList).find(className => className.startsWith(CLASS_NAME_SIDEBAR_EXPAND)) ?? '';
641
+ const sidebar = document.getElementsByClassName(sidebarExpand)[0];
642
+ const sidebarContent = globalThis.getComputedStyle(sidebar, '::before').getPropertyValue('content');
643
+ this._config = { ...this._config, sidebarBreakpoint: Number(sidebarContent.replace(/[^\d.-]/g, '')) };
644
+ if (window.innerWidth <= this._config.sidebarBreakpoint) {
645
+ this.collapse();
646
+ }
647
+ else {
648
+ if (!document.body.classList.contains(CLASS_NAME_SIDEBAR_MINI)) {
649
+ this.expand();
650
+ }
651
+ if (document.body.classList.contains(CLASS_NAME_SIDEBAR_MINI) && document.body.classList.contains(CLASS_NAME_SIDEBAR_COLLAPSE)) {
652
+ this.collapse();
653
+ }
654
+ }
655
+ }
656
+ toggle() {
657
+ if (document.body.classList.contains(CLASS_NAME_SIDEBAR_COLLAPSE)) {
658
+ this.expand();
659
+ }
660
+ else {
661
+ this.collapse();
662
+ }
663
+ }
664
+ init() {
665
+ this.addSidebarBreakPoint();
666
+ }
667
+ }
668
+ /**
669
+ * ------------------------------------------------------------------------
670
+ * Data Api implementation
671
+ * ------------------------------------------------------------------------
672
+ */
673
+ onDOMContentLoaded(() => {
674
+ const sidebar = document?.querySelector(SELECTOR_APP_SIDEBAR);
675
+ if (sidebar) {
676
+ const data = new PushMenu(sidebar, Defaults);
677
+ data.init();
678
+ window.addEventListener('resize', () => {
679
+ data.init();
680
+ });
681
+ }
682
+ const sidebarOverlay = document.createElement('div');
683
+ sidebarOverlay.className = CLASS_NAME_SIDEBAR_OVERLAY;
684
+ document.querySelector(SELECTOR_APP_WRAPPER)?.append(sidebarOverlay);
685
+ sidebarOverlay.addEventListener('touchstart', event => {
686
+ event.preventDefault();
687
+ const target = event.currentTarget;
688
+ const data = new PushMenu(target, Defaults);
689
+ data.collapse();
690
+ }, { passive: true });
691
+ sidebarOverlay.addEventListener('click', event => {
692
+ event.preventDefault();
693
+ const target = event.currentTarget;
694
+ const data = new PushMenu(target, Defaults);
695
+ data.collapse();
696
+ });
697
+ const fullBtn = document.querySelectorAll(SELECTOR_SIDEBAR_TOGGLE);
698
+ fullBtn.forEach(btn => {
699
+ btn.addEventListener('click', event => {
700
+ event.preventDefault();
701
+ let button = event.currentTarget;
702
+ if (button?.dataset.lteToggle !== 'sidebar') {
703
+ button = button?.closest(SELECTOR_SIDEBAR_TOGGLE);
704
+ }
705
+ if (button) {
706
+ event?.preventDefault();
707
+ const data = new PushMenu(button, Defaults);
708
+ data.toggle();
709
+ }
710
+ });
711
+ });
712
+ });
713
+
714
+ /**
715
+ * AdminLTE Accessibility Module
716
+ * WCAG 2.1 AA Compliance Features
717
+ */
718
+ class AccessibilityManager {
719
+ config;
720
+ liveRegion = null;
721
+ focusHistory = [];
722
+ constructor(config = {}) {
723
+ this.config = {
724
+ announcements: true,
725
+ skipLinks: true,
726
+ focusManagement: true,
727
+ keyboardNavigation: true,
728
+ reducedMotion: true,
729
+ ...config
730
+ };
731
+ this.init();
732
+ }
733
+ init() {
734
+ if (this.config.announcements) {
735
+ this.createLiveRegion();
736
+ }
737
+ if (this.config.skipLinks) {
738
+ this.addSkipLinks();
739
+ }
740
+ if (this.config.focusManagement) {
741
+ this.initFocusManagement();
742
+ }
743
+ if (this.config.keyboardNavigation) {
744
+ this.initKeyboardNavigation();
745
+ }
746
+ if (this.config.reducedMotion) {
747
+ this.respectReducedMotion();
748
+ }
749
+ this.initErrorAnnouncements();
750
+ this.initTableAccessibility();
751
+ this.initFormAccessibility();
752
+ }
753
+ // WCAG 4.1.3: Status Messages
754
+ createLiveRegion() {
755
+ if (this.liveRegion)
756
+ return;
757
+ this.liveRegion = document.createElement('div');
758
+ this.liveRegion.id = 'live-region';
759
+ this.liveRegion.className = 'live-region';
760
+ this.liveRegion.setAttribute('aria-live', 'polite');
761
+ this.liveRegion.setAttribute('aria-atomic', 'true');
762
+ this.liveRegion.setAttribute('role', 'status');
763
+ document.body.append(this.liveRegion);
764
+ }
765
+ // WCAG 2.4.1: Bypass Blocks
766
+ addSkipLinks() {
767
+ const skipLinksContainer = document.createElement('div');
768
+ skipLinksContainer.className = 'skip-links';
769
+ const skipToMain = document.createElement('a');
770
+ skipToMain.href = '#main';
771
+ skipToMain.className = 'skip-link';
772
+ skipToMain.textContent = 'Skip to main content';
773
+ const skipToNav = document.createElement('a');
774
+ skipToNav.href = '#navigation';
775
+ skipToNav.className = 'skip-link';
776
+ skipToNav.textContent = 'Skip to navigation';
777
+ skipLinksContainer.append(skipToMain);
778
+ skipLinksContainer.append(skipToNav);
779
+ document.body.insertBefore(skipLinksContainer, document.body.firstChild);
780
+ // Ensure targets exist and are focusable
781
+ this.ensureSkipTargets();
782
+ }
783
+ ensureSkipTargets() {
784
+ const main = document.querySelector('#main, main, [role="main"]');
785
+ if (main && !main.id) {
786
+ main.id = 'main';
787
+ }
788
+ if (main && !main.hasAttribute('tabindex')) {
789
+ main.setAttribute('tabindex', '-1');
790
+ }
791
+ const nav = document.querySelector('#navigation, nav, [role="navigation"]');
792
+ if (nav && !nav.id) {
793
+ nav.id = 'navigation';
794
+ }
795
+ if (nav && !nav.hasAttribute('tabindex')) {
796
+ nav.setAttribute('tabindex', '-1');
797
+ }
798
+ }
799
+ // WCAG 2.4.3: Focus Order & 2.4.7: Focus Visible
800
+ initFocusManagement() {
801
+ document.addEventListener('keydown', (event) => {
802
+ if (event.key === 'Tab') {
803
+ this.handleTabNavigation(event);
804
+ }
805
+ if (event.key === 'Escape') {
806
+ this.handleEscapeKey(event);
807
+ }
808
+ });
809
+ // Focus management for modals and dropdowns
810
+ this.initModalFocusManagement();
811
+ this.initDropdownFocusManagement();
812
+ }
813
+ handleTabNavigation(event) {
814
+ const focusableElements = this.getFocusableElements();
815
+ const currentIndex = focusableElements.indexOf(document.activeElement);
816
+ if (event.shiftKey) {
817
+ // Shift+Tab (backward)
818
+ if (currentIndex <= 0) {
819
+ event.preventDefault();
820
+ focusableElements.at(-1)?.focus();
821
+ }
822
+ }
823
+ else if (currentIndex >= focusableElements.length - 1) {
824
+ // Tab (forward)
825
+ event.preventDefault();
826
+ focusableElements[0]?.focus();
827
+ }
828
+ }
829
+ getFocusableElements() {
830
+ const selector = [
831
+ 'a[href]',
832
+ 'button:not([disabled])',
833
+ 'input:not([disabled])',
834
+ 'select:not([disabled])',
835
+ 'textarea:not([disabled])',
836
+ '[tabindex]:not([tabindex="-1"])',
837
+ '[contenteditable="true"]'
838
+ ].join(', ');
839
+ return Array.from(document.querySelectorAll(selector));
840
+ }
841
+ handleEscapeKey(event) {
842
+ // Close modals, dropdowns, etc.
843
+ const activeModal = document.querySelector('.modal.show');
844
+ const activeDropdown = document.querySelector('.dropdown-menu.show');
845
+ if (activeModal) {
846
+ const closeButton = activeModal.querySelector('[data-bs-dismiss="modal"]');
847
+ closeButton?.click();
848
+ event.preventDefault();
849
+ }
850
+ else if (activeDropdown) {
851
+ const toggleButton = document.querySelector('[data-bs-toggle="dropdown"][aria-expanded="true"]');
852
+ toggleButton?.click();
853
+ event.preventDefault();
854
+ }
855
+ }
856
+ // WCAG 2.1.1: Keyboard Access
857
+ initKeyboardNavigation() {
858
+ // Add keyboard support for custom components
859
+ document.addEventListener('keydown', (event) => {
860
+ const target = event.target;
861
+ // Handle arrow key navigation for menus
862
+ if (target.closest('.nav, .navbar-nav, .dropdown-menu')) {
863
+ this.handleMenuNavigation(event);
864
+ }
865
+ // Handle Enter and Space for custom buttons
866
+ if ((event.key === 'Enter' || event.key === ' ') && target.hasAttribute('role') && target.getAttribute('role') === 'button' && !target.matches('button, input[type="button"], input[type="submit"]')) {
867
+ event.preventDefault();
868
+ target.click();
869
+ }
870
+ });
871
+ }
872
+ handleMenuNavigation(event) {
873
+ if (!['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) {
874
+ return;
875
+ }
876
+ const currentElement = event.target;
877
+ const menuItems = Array.from(currentElement.closest('.nav, .navbar-nav, .dropdown-menu')?.querySelectorAll('a, button') || []);
878
+ const currentIndex = menuItems.indexOf(currentElement);
879
+ let nextIndex;
880
+ switch (event.key) {
881
+ case 'ArrowDown':
882
+ case 'ArrowRight': {
883
+ nextIndex = currentIndex < menuItems.length - 1 ? currentIndex + 1 : 0;
884
+ break;
885
+ }
886
+ case 'ArrowUp':
887
+ case 'ArrowLeft': {
888
+ nextIndex = currentIndex > 0 ? currentIndex - 1 : menuItems.length - 1;
889
+ break;
890
+ }
891
+ case 'Home': {
892
+ nextIndex = 0;
893
+ break;
894
+ }
895
+ case 'End': {
896
+ nextIndex = menuItems.length - 1;
897
+ break;
898
+ }
899
+ default: {
900
+ return;
901
+ }
902
+ }
903
+ event.preventDefault();
904
+ menuItems[nextIndex]?.focus();
905
+ }
906
+ // WCAG 2.3.3: Animation from Interactions
907
+ respectReducedMotion() {
908
+ const prefersReducedMotion = globalThis.matchMedia('(prefers-reduced-motion: reduce)').matches;
909
+ if (prefersReducedMotion) {
910
+ document.body.classList.add('reduce-motion');
911
+ // Disable smooth scrolling
912
+ document.documentElement.style.scrollBehavior = 'auto';
913
+ // Reduce animation duration
914
+ const style = document.createElement('style');
915
+ style.textContent = `
916
+ *, *::before, *::after {
917
+ animation-duration: 0.01ms !important;
918
+ animation-iteration-count: 1 !important;
919
+ transition-duration: 0.01ms !important;
920
+ }
921
+ `;
922
+ document.head.append(style);
923
+ }
924
+ }
925
+ // WCAG 3.3.1: Error Identification
926
+ initErrorAnnouncements() {
927
+ const observer = new MutationObserver((mutations) => {
928
+ mutations.forEach((mutation) => {
929
+ mutation.addedNodes.forEach((node) => {
930
+ if (node.nodeType === Node.ELEMENT_NODE) {
931
+ const element = node;
932
+ // Check for error messages
933
+ if (element.matches('.alert-danger, .invalid-feedback, .error')) {
934
+ this.announce(element.textContent || 'Error occurred', 'assertive');
935
+ }
936
+ // Check for success messages
937
+ if (element.matches('.alert-success, .success')) {
938
+ this.announce(element.textContent || 'Success', 'polite');
939
+ }
940
+ }
941
+ });
942
+ });
943
+ });
944
+ observer.observe(document.body, {
945
+ childList: true,
946
+ subtree: true
947
+ });
948
+ }
949
+ // WCAG 1.3.1: Info and Relationships
950
+ initTableAccessibility() {
951
+ document.querySelectorAll('table').forEach((table) => {
952
+ // Add table role if missing
953
+ if (!table.hasAttribute('role')) {
954
+ table.setAttribute('role', 'table');
955
+ }
956
+ // Ensure headers have proper scope
957
+ table.querySelectorAll('th').forEach((th) => {
958
+ if (!th.hasAttribute('scope')) {
959
+ const isInThead = th.closest('thead');
960
+ const isFirstColumn = th.cellIndex === 0;
961
+ if (isInThead) {
962
+ th.setAttribute('scope', 'col');
963
+ }
964
+ else if (isFirstColumn) {
965
+ th.setAttribute('scope', 'row');
966
+ }
967
+ }
968
+ });
969
+ // Add caption if missing but title exists
970
+ if (!table.querySelector('caption') && table.hasAttribute('title')) {
971
+ const caption = document.createElement('caption');
972
+ caption.textContent = table.getAttribute('title') || '';
973
+ table.insertBefore(caption, table.firstChild);
974
+ }
975
+ });
976
+ }
977
+ // WCAG 3.3.2: Labels or Instructions
978
+ initFormAccessibility() {
979
+ document.querySelectorAll('input, select, textarea').forEach((input) => {
980
+ const htmlInput = input;
981
+ // Ensure all inputs have labels
982
+ if (!htmlInput.labels?.length && !htmlInput.hasAttribute('aria-label') && !htmlInput.hasAttribute('aria-labelledby')) {
983
+ const placeholder = htmlInput.getAttribute('placeholder');
984
+ if (placeholder) {
985
+ htmlInput.setAttribute('aria-label', placeholder);
986
+ }
987
+ }
988
+ // Add required indicators
989
+ if (htmlInput.hasAttribute('required')) {
990
+ const label = htmlInput.labels?.[0];
991
+ if (label && !label.querySelector('.required-indicator')) {
992
+ const indicator = document.createElement('span');
993
+ indicator.className = 'required-indicator sr-only';
994
+ indicator.textContent = ' (required)';
995
+ label.append(indicator);
996
+ }
997
+ }
998
+ // Handle invalid states
999
+ htmlInput.addEventListener('invalid', () => {
1000
+ this.handleFormError(htmlInput);
1001
+ });
1002
+ });
1003
+ }
1004
+ handleFormError(input) {
1005
+ const errorId = `${input.id || input.name}-error`;
1006
+ let errorElement = document.getElementById(errorId);
1007
+ if (!errorElement) {
1008
+ errorElement = document.createElement('div');
1009
+ errorElement.id = errorId;
1010
+ errorElement.className = 'invalid-feedback';
1011
+ errorElement.setAttribute('role', 'alert');
1012
+ input.parentNode?.insertBefore(errorElement, input.nextSibling);
1013
+ }
1014
+ errorElement.textContent = input.validationMessage;
1015
+ input.setAttribute('aria-describedby', errorId);
1016
+ input.classList.add('is-invalid');
1017
+ this.announce(`Error in ${input.labels?.[0]?.textContent || input.name}: ${input.validationMessage}`, 'assertive');
1018
+ }
1019
+ // Modal focus management
1020
+ initModalFocusManagement() {
1021
+ document.addEventListener('shown.bs.modal', (event) => {
1022
+ const modal = event.target;
1023
+ const focusableElements = modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
1024
+ if (focusableElements.length > 0) {
1025
+ focusableElements[0].focus();
1026
+ }
1027
+ // Store previous focus
1028
+ this.focusHistory.push(document.activeElement);
1029
+ });
1030
+ document.addEventListener('hidden.bs.modal', () => {
1031
+ // Restore previous focus
1032
+ const previousElement = this.focusHistory.pop();
1033
+ if (previousElement) {
1034
+ previousElement.focus();
1035
+ }
1036
+ });
1037
+ }
1038
+ // Dropdown focus management
1039
+ initDropdownFocusManagement() {
1040
+ document.addEventListener('shown.bs.dropdown', (event) => {
1041
+ const dropdown = event.target;
1042
+ const menu = dropdown.querySelector('.dropdown-menu');
1043
+ const firstItem = menu?.querySelector('a, button');
1044
+ if (firstItem) {
1045
+ firstItem.focus();
1046
+ }
1047
+ });
1048
+ }
1049
+ // Public API methods
1050
+ announce(message, priority = 'polite') {
1051
+ if (!this.liveRegion) {
1052
+ this.createLiveRegion();
1053
+ }
1054
+ if (this.liveRegion) {
1055
+ this.liveRegion.setAttribute('aria-live', priority);
1056
+ this.liveRegion.textContent = message;
1057
+ // Clear after announcement
1058
+ setTimeout(() => {
1059
+ if (this.liveRegion) {
1060
+ this.liveRegion.textContent = '';
1061
+ }
1062
+ }, 1000);
1063
+ }
1064
+ }
1065
+ focusElement(selector) {
1066
+ const element = document.querySelector(selector);
1067
+ if (element) {
1068
+ element.focus();
1069
+ // Ensure element is visible
1070
+ element.scrollIntoView({ behavior: 'smooth', block: 'center' });
1071
+ }
1072
+ }
1073
+ trapFocus(container) {
1074
+ const focusableElements = container.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
1075
+ const focusableArray = Array.from(focusableElements);
1076
+ const firstElement = focusableArray[0];
1077
+ const lastElement = focusableArray.at(-1);
1078
+ container.addEventListener('keydown', (event) => {
1079
+ if (event.key === 'Tab') {
1080
+ if (event.shiftKey) {
1081
+ if (document.activeElement === firstElement) {
1082
+ lastElement?.focus();
1083
+ event.preventDefault();
1084
+ }
1085
+ }
1086
+ else if (document.activeElement === lastElement) {
1087
+ firstElement.focus();
1088
+ event.preventDefault();
1089
+ }
1090
+ }
1091
+ });
1092
+ }
1093
+ addLandmarks() {
1094
+ // Add main landmark if missing
1095
+ const main = document.querySelector('main');
1096
+ if (!main) {
1097
+ const appMain = document.querySelector('.app-main');
1098
+ if (appMain) {
1099
+ appMain.setAttribute('role', 'main');
1100
+ appMain.id = 'main';
1101
+ }
1102
+ }
1103
+ // Add navigation landmarks
1104
+ document.querySelectorAll('.navbar-nav, .nav').forEach((nav, index) => {
1105
+ if (!nav.hasAttribute('role')) {
1106
+ nav.setAttribute('role', 'navigation');
1107
+ }
1108
+ if (!nav.hasAttribute('aria-label')) {
1109
+ nav.setAttribute('aria-label', `Navigation ${index + 1}`);
1110
+ }
1111
+ });
1112
+ // Add search landmark
1113
+ const searchForm = document.querySelector('form[role="search"], .navbar-search');
1114
+ if (searchForm && !searchForm.hasAttribute('role')) {
1115
+ searchForm.setAttribute('role', 'search');
1116
+ }
1117
+ }
1118
+ }
1119
+ // Initialize accessibility when DOM is ready
1120
+ const initAccessibility = (config) => {
1121
+ return new AccessibilityManager(config);
1122
+ };
1123
+
1124
+ /**
1125
+ * AdminLTE v4.0.0-rc1
1126
+ * Author: Colorlib
1127
+ * Website: AdminLTE.io <https://adminlte.io>
1128
+ * License: Open source - MIT <https://opensource.org/licenses/MIT>
1129
+ */
1130
+ onDOMContentLoaded(() => {
1131
+ /**
1132
+ * Initialize AdminLTE Core Components
1133
+ * -------------------------------
1134
+ */
1135
+ const layout = new Layout(document.body);
1136
+ layout.holdTransition();
1137
+ /**
1138
+ * Initialize Accessibility Features - WCAG 2.1 AA Compliance
1139
+ * --------------------------------------------------------
1140
+ */
1141
+ const accessibilityManager = initAccessibility({
1142
+ announcements: true,
1143
+ skipLinks: true,
1144
+ focusManagement: true,
1145
+ keyboardNavigation: true,
1146
+ reducedMotion: true
1147
+ });
1148
+ // Add semantic landmarks
1149
+ accessibilityManager.addLandmarks();
1150
+ // Mark app as loaded after initialization
1151
+ setTimeout(() => {
1152
+ document.body.classList.add('app-loaded');
1153
+ }, 400);
1154
+ });
1155
+
707
1156
  exports.CardWidget = CardWidget;
708
1157
  exports.DirectChat = DirectChat;
709
1158
  exports.FullScreen = FullScreen;
710
1159
  exports.Layout = Layout;
711
1160
  exports.PushMenu = PushMenu;
712
1161
  exports.Treeview = Treeview;
1162
+ exports.initAccessibility = initAccessibility;
713
1163
 
714
1164
  }));
715
1165
  //# sourceMappingURL=adminlte.js.map