admin-lte 4.0.0-beta2 → 4.0.0-rc2

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 (69) hide show
  1. package/.browserslistrc +9 -4
  2. package/.prettierrc +6 -0
  3. package/ACCESSIBILITY-COMPLIANCE.md +369 -0
  4. package/CHANGELOG.md +314 -0
  5. package/README.md +43 -7
  6. package/dist/css/adminlte.css +1417 -1269
  7. package/dist/css/adminlte.css.map +1 -1
  8. package/dist/css/adminlte.min.css +2 -2
  9. package/dist/css/adminlte.min.css.map +1 -1
  10. package/dist/css/adminlte.rtl.css +1437 -1263
  11. package/dist/css/adminlte.rtl.css.map +1 -1
  12. package/dist/css/adminlte.rtl.min.css +2 -2
  13. package/dist/css/adminlte.rtl.min.css.map +1 -1
  14. package/dist/js/adminlte.js +786 -345
  15. package/dist/js/adminlte.js.map +1 -1
  16. package/dist/js/adminlte.min.js +3 -3
  17. package/dist/js/adminlte.min.js.map +1 -1
  18. package/dist/pages/UI/general.html +1918 -889
  19. package/dist/pages/UI/icons.html +848 -450
  20. package/dist/pages/UI/timeline.html +926 -496
  21. package/dist/pages/docs/browser-support.html +855 -442
  22. package/dist/pages/docs/color-mode.html +1002 -549
  23. package/dist/pages/docs/components/main-header.html +1032 -543
  24. package/dist/pages/docs/components/main-sidebar.html +848 -441
  25. package/dist/pages/docs/faq.html +846 -438
  26. package/dist/pages/docs/how-to-contribute.html +918 -478
  27. package/dist/pages/docs/introduction.html +900 -465
  28. package/dist/pages/docs/javascript/treeview.html +853 -451
  29. package/dist/pages/docs/layout.html +867 -479
  30. package/dist/pages/docs/license.html +843 -440
  31. package/dist/pages/examples/lockscreen.html +141 -66
  32. package/dist/pages/examples/login-v2.html +169 -85
  33. package/dist/pages/examples/login.html +159 -80
  34. package/dist/pages/examples/register-v2.html +179 -88
  35. package/dist/pages/examples/register.html +164 -81
  36. package/dist/pages/forms/general.html +1255 -605
  37. package/dist/pages/generate/theme.html +861 -386
  38. package/dist/pages/index.html +1417 -801
  39. package/dist/pages/index2.html +1884 -1057
  40. package/dist/pages/index3.html +1215 -690
  41. package/dist/pages/layout/collapsed-sidebar.html +861 -446
  42. package/dist/pages/layout/fixed-complete.html +862 -0
  43. package/dist/pages/layout/fixed-footer.html +861 -0
  44. package/dist/pages/layout/fixed-header.html +861 -0
  45. package/dist/pages/layout/fixed-sidebar.html +861 -446
  46. package/dist/pages/layout/layout-custom-area.html +891 -464
  47. package/dist/pages/layout/layout-rtl.html +861 -446
  48. package/dist/pages/layout/logo-switch.html +498 -233
  49. package/dist/pages/layout/sidebar-mini.html +861 -446
  50. package/dist/pages/layout/unfixed-sidebar.html +859 -445
  51. package/dist/pages/tables/simple.html +1111 -692
  52. package/dist/pages/widgets/cards.html +1066 -550
  53. package/dist/pages/widgets/info-box.html +1084 -577
  54. package/dist/pages/widgets/small-box.html +946 -480
  55. package/eslint.config.js +81 -0
  56. package/package.json +40 -36
  57. package/src/scss/_accessibility.scss +292 -0
  58. package/src/scss/_app-footer.scss +8 -0
  59. package/src/scss/_app-header.scss +8 -0
  60. package/src/scss/_bootstrap-variables.scss +11 -9
  61. package/src/scss/_table.scss +1 -9
  62. package/src/scss/_variables.scss +2 -1
  63. package/src/scss/adminlte.scss +4 -1
  64. package/src/ts/accessibility.ts +533 -0
  65. package/src/ts/adminlte.ts +48 -9
  66. package/src/ts/card-widget.ts +1 -2
  67. package/src/ts/push-menu.ts +1 -2
  68. package/src/ts/util/index.ts +39 -7
  69. package/.astro/settings.json +0 -5
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * AdminLTE v4.0.0-beta2 (https://adminlte.io)
3
- * Copyright 2014-2024 Colorlib <https://colorlib.com>
2
+ * AdminLTE v4.0.0-rc2 (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,13 @@
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
+ if (target?.getAttribute('href') === '#' || targetLink?.getAttribute('href') === '#') {
365
405
  event.preventDefault();
366
406
  }
367
407
  if (targetItem) {
368
- const data = new Treeview(targetItem, Default$1);
408
+ const data = new Treeview(targetItem, Default);
369
409
  data.toggle();
370
410
  }
371
411
  });
@@ -385,8 +425,8 @@
385
425
  */
386
426
  const DATA_KEY$2 = 'lte.direct-chat';
387
427
  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}`;
428
+ const EVENT_EXPANDED = `expanded${EVENT_KEY$2}`;
429
+ const EVENT_COLLAPSED = `collapsed${EVENT_KEY$2}`;
390
430
  const SELECTOR_DATA_TOGGLE = '[data-lte-toggle="chat-pane"]';
391
431
  const SELECTOR_DIRECT_CHAT = '.direct-chat';
392
432
  const CLASS_NAME_DIRECT_CHAT_OPEN = 'direct-chat-contacts-open';
@@ -395,17 +435,18 @@
395
435
  * ====================================================
396
436
  */
397
437
  class DirectChat {
438
+ _element;
398
439
  constructor(element) {
399
440
  this._element = element;
400
441
  }
401
442
  toggle() {
402
443
  if (this._element.classList.contains(CLASS_NAME_DIRECT_CHAT_OPEN)) {
403
- const event = new Event(EVENT_COLLAPSED$1);
444
+ const event = new Event(EVENT_COLLAPSED);
404
445
  this._element.classList.remove(CLASS_NAME_DIRECT_CHAT_OPEN);
405
446
  this._element.dispatchEvent(event);
406
447
  }
407
448
  else {
408
- const event = new Event(EVENT_EXPANDED$1);
449
+ const event = new Event(EVENT_EXPANDED);
409
450
  this._element.classList.add(CLASS_NAME_DIRECT_CHAT_OPEN);
410
451
  this._element.dispatchEvent(event);
411
452
  }
@@ -433,220 +474,32 @@
433
474
 
434
475
  /**
435
476
  * --------------------------------------------
436
- * @file AdminLTE card-widget.ts
437
- * @description Card widget for AdminLTE.
477
+ * @file AdminLTE fullscreen.ts
478
+ * @description Fullscreen plugin for AdminLTE.
438
479
  * @license MIT
439
480
  * --------------------------------------------
440
481
  */
441
482
  /**
442
483
  * Constants
443
- * ====================================================
484
+ * ============================================================================
444
485
  */
445
- const DATA_KEY$1 = 'lte.card-widget';
486
+ const DATA_KEY$1 = 'lte.fullscreen';
446
487
  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 {
488
+ const EVENT_MAXIMIZED = `maximized${EVENT_KEY$1}`;
489
+ const EVENT_MINIMIZED = `minimized${EVENT_KEY$1}`;
490
+ const SELECTOR_FULLSCREEN_TOGGLE = '[data-lte-toggle="fullscreen"]';
491
+ const SELECTOR_MAXIMIZE_ICON = '[data-lte-icon="maximize"]';
492
+ const SELECTOR_MINIMIZE_ICON = '[data-lte-icon="minimize"]';
493
+ /**
494
+ * Class Definition.
495
+ * ============================================================================
496
+ */
497
+ class FullScreen {
498
+ _element;
499
+ _config;
471
500
  constructor(element, config) {
472
501
  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;
502
+ this._config = config;
650
503
  }
651
504
  inFullScreen() {
652
505
  const event = new Event(EVENT_MAXIMIZED);
@@ -704,12 +557,600 @@
704
557
  });
705
558
  });
706
559
 
560
+ /**
561
+ * --------------------------------------------
562
+ * @file AdminLTE push-menu.ts
563
+ * @description Push menu for AdminLTE.
564
+ * @license MIT
565
+ * --------------------------------------------
566
+ */
567
+ /**
568
+ * ------------------------------------------------------------------------
569
+ * Constants
570
+ * ------------------------------------------------------------------------
571
+ */
572
+ const DATA_KEY = 'lte.push-menu';
573
+ const EVENT_KEY = `.${DATA_KEY}`;
574
+ const EVENT_OPEN = `open${EVENT_KEY}`;
575
+ const EVENT_COLLAPSE = `collapse${EVENT_KEY}`;
576
+ const CLASS_NAME_SIDEBAR_MINI = 'sidebar-mini';
577
+ const CLASS_NAME_SIDEBAR_COLLAPSE = 'sidebar-collapse';
578
+ const CLASS_NAME_SIDEBAR_OPEN = 'sidebar-open';
579
+ const CLASS_NAME_SIDEBAR_EXPAND = 'sidebar-expand';
580
+ const CLASS_NAME_SIDEBAR_OVERLAY = 'sidebar-overlay';
581
+ const CLASS_NAME_MENU_OPEN = 'menu-open';
582
+ const SELECTOR_APP_SIDEBAR = '.app-sidebar';
583
+ const SELECTOR_SIDEBAR_MENU = '.sidebar-menu';
584
+ const SELECTOR_NAV_ITEM = '.nav-item';
585
+ const SELECTOR_NAV_TREEVIEW = '.nav-treeview';
586
+ const SELECTOR_APP_WRAPPER = '.app-wrapper';
587
+ const SELECTOR_SIDEBAR_EXPAND = `[class*="${CLASS_NAME_SIDEBAR_EXPAND}"]`;
588
+ const SELECTOR_SIDEBAR_TOGGLE = '[data-lte-toggle="sidebar"]';
589
+ const Defaults = {
590
+ sidebarBreakpoint: 992
591
+ };
592
+ /**
593
+ * Class Definition
594
+ * ====================================================
595
+ */
596
+ class PushMenu {
597
+ _element;
598
+ _config;
599
+ constructor(element, config) {
600
+ this._element = element;
601
+ this._config = { ...Defaults, ...config };
602
+ }
603
+ menusClose() {
604
+ const navTreeview = document.querySelectorAll(SELECTOR_NAV_TREEVIEW);
605
+ navTreeview.forEach(navTree => {
606
+ navTree.style.removeProperty('display');
607
+ navTree.style.removeProperty('height');
608
+ });
609
+ const navSidebar = document.querySelector(SELECTOR_SIDEBAR_MENU);
610
+ const navItem = navSidebar?.querySelectorAll(SELECTOR_NAV_ITEM);
611
+ if (navItem) {
612
+ navItem.forEach(navI => {
613
+ navI.classList.remove(CLASS_NAME_MENU_OPEN);
614
+ });
615
+ }
616
+ }
617
+ expand() {
618
+ const event = new Event(EVENT_OPEN);
619
+ document.body.classList.remove(CLASS_NAME_SIDEBAR_COLLAPSE);
620
+ document.body.classList.add(CLASS_NAME_SIDEBAR_OPEN);
621
+ this._element.dispatchEvent(event);
622
+ }
623
+ collapse() {
624
+ const event = new Event(EVENT_COLLAPSE);
625
+ document.body.classList.remove(CLASS_NAME_SIDEBAR_OPEN);
626
+ document.body.classList.add(CLASS_NAME_SIDEBAR_COLLAPSE);
627
+ this._element.dispatchEvent(event);
628
+ }
629
+ addSidebarBreakPoint() {
630
+ const sidebarExpandList = document.querySelector(SELECTOR_SIDEBAR_EXPAND)?.classList ?? [];
631
+ const sidebarExpand = Array.from(sidebarExpandList).find(className => className.startsWith(CLASS_NAME_SIDEBAR_EXPAND)) ?? '';
632
+ const sidebar = document.getElementsByClassName(sidebarExpand)[0];
633
+ const sidebarContent = globalThis.getComputedStyle(sidebar, '::before').getPropertyValue('content');
634
+ this._config = { ...this._config, sidebarBreakpoint: Number(sidebarContent.replace(/[^\d.-]/g, '')) };
635
+ if (window.innerWidth <= this._config.sidebarBreakpoint) {
636
+ this.collapse();
637
+ }
638
+ else {
639
+ if (!document.body.classList.contains(CLASS_NAME_SIDEBAR_MINI)) {
640
+ this.expand();
641
+ }
642
+ if (document.body.classList.contains(CLASS_NAME_SIDEBAR_MINI) && document.body.classList.contains(CLASS_NAME_SIDEBAR_COLLAPSE)) {
643
+ this.collapse();
644
+ }
645
+ }
646
+ }
647
+ toggle() {
648
+ if (document.body.classList.contains(CLASS_NAME_SIDEBAR_COLLAPSE)) {
649
+ this.expand();
650
+ }
651
+ else {
652
+ this.collapse();
653
+ }
654
+ }
655
+ init() {
656
+ this.addSidebarBreakPoint();
657
+ }
658
+ }
659
+ /**
660
+ * ------------------------------------------------------------------------
661
+ * Data Api implementation
662
+ * ------------------------------------------------------------------------
663
+ */
664
+ onDOMContentLoaded(() => {
665
+ const sidebar = document?.querySelector(SELECTOR_APP_SIDEBAR);
666
+ if (sidebar) {
667
+ const data = new PushMenu(sidebar, Defaults);
668
+ data.init();
669
+ window.addEventListener('resize', () => {
670
+ data.init();
671
+ });
672
+ }
673
+ const sidebarOverlay = document.createElement('div');
674
+ sidebarOverlay.className = CLASS_NAME_SIDEBAR_OVERLAY;
675
+ document.querySelector(SELECTOR_APP_WRAPPER)?.append(sidebarOverlay);
676
+ sidebarOverlay.addEventListener('touchstart', event => {
677
+ event.preventDefault();
678
+ const target = event.currentTarget;
679
+ const data = new PushMenu(target, Defaults);
680
+ data.collapse();
681
+ }, { passive: true });
682
+ sidebarOverlay.addEventListener('click', event => {
683
+ event.preventDefault();
684
+ const target = event.currentTarget;
685
+ const data = new PushMenu(target, Defaults);
686
+ data.collapse();
687
+ });
688
+ const fullBtn = document.querySelectorAll(SELECTOR_SIDEBAR_TOGGLE);
689
+ fullBtn.forEach(btn => {
690
+ btn.addEventListener('click', event => {
691
+ event.preventDefault();
692
+ let button = event.currentTarget;
693
+ if (button?.dataset.lteToggle !== 'sidebar') {
694
+ button = button?.closest(SELECTOR_SIDEBAR_TOGGLE);
695
+ }
696
+ if (button) {
697
+ event?.preventDefault();
698
+ const data = new PushMenu(button, Defaults);
699
+ data.toggle();
700
+ }
701
+ });
702
+ });
703
+ });
704
+
705
+ /**
706
+ * AdminLTE Accessibility Module
707
+ * WCAG 2.1 AA Compliance Features
708
+ */
709
+ class AccessibilityManager {
710
+ config;
711
+ liveRegion = null;
712
+ focusHistory = [];
713
+ constructor(config = {}) {
714
+ this.config = {
715
+ announcements: true,
716
+ skipLinks: true,
717
+ focusManagement: true,
718
+ keyboardNavigation: true,
719
+ reducedMotion: true,
720
+ ...config
721
+ };
722
+ this.init();
723
+ }
724
+ init() {
725
+ if (this.config.announcements) {
726
+ this.createLiveRegion();
727
+ }
728
+ if (this.config.skipLinks) {
729
+ this.addSkipLinks();
730
+ }
731
+ if (this.config.focusManagement) {
732
+ this.initFocusManagement();
733
+ }
734
+ if (this.config.keyboardNavigation) {
735
+ this.initKeyboardNavigation();
736
+ }
737
+ if (this.config.reducedMotion) {
738
+ this.respectReducedMotion();
739
+ }
740
+ this.initErrorAnnouncements();
741
+ this.initTableAccessibility();
742
+ this.initFormAccessibility();
743
+ }
744
+ // WCAG 4.1.3: Status Messages
745
+ createLiveRegion() {
746
+ if (this.liveRegion)
747
+ return;
748
+ this.liveRegion = document.createElement('div');
749
+ this.liveRegion.id = 'live-region';
750
+ this.liveRegion.className = 'live-region';
751
+ this.liveRegion.setAttribute('aria-live', 'polite');
752
+ this.liveRegion.setAttribute('aria-atomic', 'true');
753
+ this.liveRegion.setAttribute('role', 'status');
754
+ document.body.append(this.liveRegion);
755
+ }
756
+ // WCAG 2.4.1: Bypass Blocks
757
+ addSkipLinks() {
758
+ const skipLinksContainer = document.createElement('div');
759
+ skipLinksContainer.className = 'skip-links';
760
+ const skipToMain = document.createElement('a');
761
+ skipToMain.href = '#main';
762
+ skipToMain.className = 'skip-link';
763
+ skipToMain.textContent = 'Skip to main content';
764
+ const skipToNav = document.createElement('a');
765
+ skipToNav.href = '#navigation';
766
+ skipToNav.className = 'skip-link';
767
+ skipToNav.textContent = 'Skip to navigation';
768
+ skipLinksContainer.append(skipToMain);
769
+ skipLinksContainer.append(skipToNav);
770
+ document.body.insertBefore(skipLinksContainer, document.body.firstChild);
771
+ // Ensure targets exist and are focusable
772
+ this.ensureSkipTargets();
773
+ }
774
+ ensureSkipTargets() {
775
+ const main = document.querySelector('#main, main, [role="main"]');
776
+ if (main && !main.id) {
777
+ main.id = 'main';
778
+ }
779
+ if (main && !main.hasAttribute('tabindex')) {
780
+ main.setAttribute('tabindex', '-1');
781
+ }
782
+ const nav = document.querySelector('#navigation, nav, [role="navigation"]');
783
+ if (nav && !nav.id) {
784
+ nav.id = 'navigation';
785
+ }
786
+ if (nav && !nav.hasAttribute('tabindex')) {
787
+ nav.setAttribute('tabindex', '-1');
788
+ }
789
+ }
790
+ // WCAG 2.4.3: Focus Order & 2.4.7: Focus Visible
791
+ initFocusManagement() {
792
+ document.addEventListener('keydown', (event) => {
793
+ if (event.key === 'Tab') {
794
+ this.handleTabNavigation(event);
795
+ }
796
+ if (event.key === 'Escape') {
797
+ this.handleEscapeKey(event);
798
+ }
799
+ });
800
+ // Focus management for modals and dropdowns
801
+ this.initModalFocusManagement();
802
+ this.initDropdownFocusManagement();
803
+ }
804
+ handleTabNavigation(event) {
805
+ const focusableElements = this.getFocusableElements();
806
+ const currentIndex = focusableElements.indexOf(document.activeElement);
807
+ if (event.shiftKey) {
808
+ // Shift+Tab (backward)
809
+ if (currentIndex <= 0) {
810
+ event.preventDefault();
811
+ focusableElements.at(-1)?.focus();
812
+ }
813
+ }
814
+ else if (currentIndex >= focusableElements.length - 1) {
815
+ // Tab (forward)
816
+ event.preventDefault();
817
+ focusableElements[0]?.focus();
818
+ }
819
+ }
820
+ getFocusableElements() {
821
+ const selector = [
822
+ 'a[href]',
823
+ 'button:not([disabled])',
824
+ 'input:not([disabled])',
825
+ 'select:not([disabled])',
826
+ 'textarea:not([disabled])',
827
+ '[tabindex]:not([tabindex="-1"])',
828
+ '[contenteditable="true"]'
829
+ ].join(', ');
830
+ return Array.from(document.querySelectorAll(selector));
831
+ }
832
+ handleEscapeKey(event) {
833
+ // Close modals, dropdowns, etc.
834
+ const activeModal = document.querySelector('.modal.show');
835
+ const activeDropdown = document.querySelector('.dropdown-menu.show');
836
+ if (activeModal) {
837
+ const closeButton = activeModal.querySelector('[data-bs-dismiss="modal"]');
838
+ closeButton?.click();
839
+ event.preventDefault();
840
+ }
841
+ else if (activeDropdown) {
842
+ const toggleButton = document.querySelector('[data-bs-toggle="dropdown"][aria-expanded="true"]');
843
+ toggleButton?.click();
844
+ event.preventDefault();
845
+ }
846
+ }
847
+ // WCAG 2.1.1: Keyboard Access
848
+ initKeyboardNavigation() {
849
+ // Add keyboard support for custom components
850
+ document.addEventListener('keydown', (event) => {
851
+ const target = event.target;
852
+ // Handle arrow key navigation for menus
853
+ if (target.closest('.nav, .navbar-nav, .dropdown-menu')) {
854
+ this.handleMenuNavigation(event);
855
+ }
856
+ // Handle Enter and Space for custom buttons
857
+ if ((event.key === 'Enter' || event.key === ' ') && target.hasAttribute('role') && target.getAttribute('role') === 'button' && !target.matches('button, input[type="button"], input[type="submit"]')) {
858
+ event.preventDefault();
859
+ target.click();
860
+ }
861
+ });
862
+ }
863
+ handleMenuNavigation(event) {
864
+ if (!['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) {
865
+ return;
866
+ }
867
+ const currentElement = event.target;
868
+ const menuItems = Array.from(currentElement.closest('.nav, .navbar-nav, .dropdown-menu')?.querySelectorAll('a, button') || []);
869
+ const currentIndex = menuItems.indexOf(currentElement);
870
+ let nextIndex;
871
+ switch (event.key) {
872
+ case 'ArrowDown':
873
+ case 'ArrowRight': {
874
+ nextIndex = currentIndex < menuItems.length - 1 ? currentIndex + 1 : 0;
875
+ break;
876
+ }
877
+ case 'ArrowUp':
878
+ case 'ArrowLeft': {
879
+ nextIndex = currentIndex > 0 ? currentIndex - 1 : menuItems.length - 1;
880
+ break;
881
+ }
882
+ case 'Home': {
883
+ nextIndex = 0;
884
+ break;
885
+ }
886
+ case 'End': {
887
+ nextIndex = menuItems.length - 1;
888
+ break;
889
+ }
890
+ default: {
891
+ return;
892
+ }
893
+ }
894
+ event.preventDefault();
895
+ menuItems[nextIndex]?.focus();
896
+ }
897
+ // WCAG 2.3.3: Animation from Interactions
898
+ respectReducedMotion() {
899
+ const prefersReducedMotion = globalThis.matchMedia('(prefers-reduced-motion: reduce)').matches;
900
+ if (prefersReducedMotion) {
901
+ document.body.classList.add('reduce-motion');
902
+ // Disable smooth scrolling
903
+ document.documentElement.style.scrollBehavior = 'auto';
904
+ // Reduce animation duration
905
+ const style = document.createElement('style');
906
+ style.textContent = `
907
+ *, *::before, *::after {
908
+ animation-duration: 0.01ms !important;
909
+ animation-iteration-count: 1 !important;
910
+ transition-duration: 0.01ms !important;
911
+ }
912
+ `;
913
+ document.head.append(style);
914
+ }
915
+ }
916
+ // WCAG 3.3.1: Error Identification
917
+ initErrorAnnouncements() {
918
+ const observer = new MutationObserver((mutations) => {
919
+ mutations.forEach((mutation) => {
920
+ mutation.addedNodes.forEach((node) => {
921
+ if (node.nodeType === Node.ELEMENT_NODE) {
922
+ const element = node;
923
+ // Check for error messages
924
+ if (element.matches('.alert-danger, .invalid-feedback, .error')) {
925
+ this.announce(element.textContent || 'Error occurred', 'assertive');
926
+ }
927
+ // Check for success messages
928
+ if (element.matches('.alert-success, .success')) {
929
+ this.announce(element.textContent || 'Success', 'polite');
930
+ }
931
+ }
932
+ });
933
+ });
934
+ });
935
+ observer.observe(document.body, {
936
+ childList: true,
937
+ subtree: true
938
+ });
939
+ }
940
+ // WCAG 1.3.1: Info and Relationships
941
+ initTableAccessibility() {
942
+ document.querySelectorAll('table').forEach((table) => {
943
+ // Add table role if missing
944
+ if (!table.hasAttribute('role')) {
945
+ table.setAttribute('role', 'table');
946
+ }
947
+ // Ensure headers have proper scope
948
+ table.querySelectorAll('th').forEach((th) => {
949
+ if (!th.hasAttribute('scope')) {
950
+ const isInThead = th.closest('thead');
951
+ const isFirstColumn = th.cellIndex === 0;
952
+ if (isInThead) {
953
+ th.setAttribute('scope', 'col');
954
+ }
955
+ else if (isFirstColumn) {
956
+ th.setAttribute('scope', 'row');
957
+ }
958
+ }
959
+ });
960
+ // Add caption if missing but title exists
961
+ if (!table.querySelector('caption') && table.hasAttribute('title')) {
962
+ const caption = document.createElement('caption');
963
+ caption.textContent = table.getAttribute('title') || '';
964
+ table.insertBefore(caption, table.firstChild);
965
+ }
966
+ });
967
+ }
968
+ // WCAG 3.3.2: Labels or Instructions
969
+ initFormAccessibility() {
970
+ document.querySelectorAll('input, select, textarea').forEach((input) => {
971
+ const htmlInput = input;
972
+ // Ensure all inputs have labels
973
+ if (!htmlInput.labels?.length && !htmlInput.hasAttribute('aria-label') && !htmlInput.hasAttribute('aria-labelledby')) {
974
+ const placeholder = htmlInput.getAttribute('placeholder');
975
+ if (placeholder) {
976
+ htmlInput.setAttribute('aria-label', placeholder);
977
+ }
978
+ }
979
+ // Add required indicators
980
+ if (htmlInput.hasAttribute('required')) {
981
+ const label = htmlInput.labels?.[0];
982
+ if (label && !label.querySelector('.required-indicator')) {
983
+ const indicator = document.createElement('span');
984
+ indicator.className = 'required-indicator sr-only';
985
+ indicator.textContent = ' (required)';
986
+ label.append(indicator);
987
+ }
988
+ }
989
+ // Handle invalid states
990
+ htmlInput.addEventListener('invalid', () => {
991
+ this.handleFormError(htmlInput);
992
+ });
993
+ });
994
+ }
995
+ handleFormError(input) {
996
+ const errorId = `${input.id || input.name}-error`;
997
+ let errorElement = document.getElementById(errorId);
998
+ if (!errorElement) {
999
+ errorElement = document.createElement('div');
1000
+ errorElement.id = errorId;
1001
+ errorElement.className = 'invalid-feedback';
1002
+ errorElement.setAttribute('role', 'alert');
1003
+ input.parentNode?.insertBefore(errorElement, input.nextSibling);
1004
+ }
1005
+ errorElement.textContent = input.validationMessage;
1006
+ input.setAttribute('aria-describedby', errorId);
1007
+ input.classList.add('is-invalid');
1008
+ this.announce(`Error in ${input.labels?.[0]?.textContent || input.name}: ${input.validationMessage}`, 'assertive');
1009
+ }
1010
+ // Modal focus management
1011
+ initModalFocusManagement() {
1012
+ document.addEventListener('shown.bs.modal', (event) => {
1013
+ const modal = event.target;
1014
+ const focusableElements = modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
1015
+ if (focusableElements.length > 0) {
1016
+ focusableElements[0].focus();
1017
+ }
1018
+ // Store previous focus
1019
+ this.focusHistory.push(document.activeElement);
1020
+ });
1021
+ document.addEventListener('hidden.bs.modal', () => {
1022
+ // Restore previous focus
1023
+ const previousElement = this.focusHistory.pop();
1024
+ if (previousElement) {
1025
+ previousElement.focus();
1026
+ }
1027
+ });
1028
+ }
1029
+ // Dropdown focus management
1030
+ initDropdownFocusManagement() {
1031
+ document.addEventListener('shown.bs.dropdown', (event) => {
1032
+ const dropdown = event.target;
1033
+ const menu = dropdown.querySelector('.dropdown-menu');
1034
+ const firstItem = menu?.querySelector('a, button');
1035
+ if (firstItem) {
1036
+ firstItem.focus();
1037
+ }
1038
+ });
1039
+ }
1040
+ // Public API methods
1041
+ announce(message, priority = 'polite') {
1042
+ if (!this.liveRegion) {
1043
+ this.createLiveRegion();
1044
+ }
1045
+ if (this.liveRegion) {
1046
+ this.liveRegion.setAttribute('aria-live', priority);
1047
+ this.liveRegion.textContent = message;
1048
+ // Clear after announcement
1049
+ setTimeout(() => {
1050
+ if (this.liveRegion) {
1051
+ this.liveRegion.textContent = '';
1052
+ }
1053
+ }, 1000);
1054
+ }
1055
+ }
1056
+ focusElement(selector) {
1057
+ const element = document.querySelector(selector);
1058
+ if (element) {
1059
+ element.focus();
1060
+ // Ensure element is visible
1061
+ element.scrollIntoView({ behavior: 'smooth', block: 'center' });
1062
+ }
1063
+ }
1064
+ trapFocus(container) {
1065
+ const focusableElements = container.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
1066
+ const focusableArray = Array.from(focusableElements);
1067
+ const firstElement = focusableArray[0];
1068
+ const lastElement = focusableArray.at(-1);
1069
+ container.addEventListener('keydown', (event) => {
1070
+ if (event.key === 'Tab') {
1071
+ if (event.shiftKey) {
1072
+ if (document.activeElement === firstElement) {
1073
+ lastElement?.focus();
1074
+ event.preventDefault();
1075
+ }
1076
+ }
1077
+ else if (document.activeElement === lastElement) {
1078
+ firstElement.focus();
1079
+ event.preventDefault();
1080
+ }
1081
+ }
1082
+ });
1083
+ }
1084
+ addLandmarks() {
1085
+ // Add main landmark if missing
1086
+ const main = document.querySelector('main');
1087
+ if (!main) {
1088
+ const appMain = document.querySelector('.app-main');
1089
+ if (appMain) {
1090
+ appMain.setAttribute('role', 'main');
1091
+ appMain.id = 'main';
1092
+ }
1093
+ }
1094
+ // Add navigation landmarks
1095
+ document.querySelectorAll('.navbar-nav, .nav').forEach((nav, index) => {
1096
+ if (!nav.hasAttribute('role')) {
1097
+ nav.setAttribute('role', 'navigation');
1098
+ }
1099
+ if (!nav.hasAttribute('aria-label')) {
1100
+ nav.setAttribute('aria-label', `Navigation ${index + 1}`);
1101
+ }
1102
+ });
1103
+ // Add search landmark
1104
+ const searchForm = document.querySelector('form[role="search"], .navbar-search');
1105
+ if (searchForm && !searchForm.hasAttribute('role')) {
1106
+ searchForm.setAttribute('role', 'search');
1107
+ }
1108
+ }
1109
+ }
1110
+ // Initialize accessibility when DOM is ready
1111
+ const initAccessibility = (config) => {
1112
+ return new AccessibilityManager(config);
1113
+ };
1114
+
1115
+ /**
1116
+ * AdminLTE v4.0.0-rc1
1117
+ * Author: Colorlib
1118
+ * Website: AdminLTE.io <https://adminlte.io>
1119
+ * License: Open source - MIT <https://opensource.org/licenses/MIT>
1120
+ */
1121
+ onDOMContentLoaded(() => {
1122
+ /**
1123
+ * Initialize AdminLTE Core Components
1124
+ * -------------------------------
1125
+ */
1126
+ const layout = new Layout(document.body);
1127
+ layout.holdTransition();
1128
+ /**
1129
+ * Initialize Accessibility Features - WCAG 2.1 AA Compliance
1130
+ * --------------------------------------------------------
1131
+ */
1132
+ const accessibilityManager = initAccessibility({
1133
+ announcements: true,
1134
+ skipLinks: true,
1135
+ focusManagement: true,
1136
+ keyboardNavigation: true,
1137
+ reducedMotion: true
1138
+ });
1139
+ // Add semantic landmarks
1140
+ accessibilityManager.addLandmarks();
1141
+ // Mark app as loaded after initialization
1142
+ setTimeout(() => {
1143
+ document.body.classList.add('app-loaded');
1144
+ }, 400);
1145
+ });
1146
+
707
1147
  exports.CardWidget = CardWidget;
708
1148
  exports.DirectChat = DirectChat;
709
1149
  exports.FullScreen = FullScreen;
710
1150
  exports.Layout = Layout;
711
1151
  exports.PushMenu = PushMenu;
712
1152
  exports.Treeview = Treeview;
1153
+ exports.initAccessibility = initAccessibility;
713
1154
 
714
1155
  }));
715
1156
  //# sourceMappingURL=adminlte.js.map