admin-lte 4.0.4 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/dist/css/adminlte-docs.css +878 -0
- package/dist/css/adminlte-docs.css.map +1 -0
- package/dist/css/adminlte-docs.min.css +7 -0
- package/dist/css/adminlte-docs.min.css.map +1 -0
- package/dist/css/adminlte-docs.rtl.css +877 -0
- package/dist/css/adminlte-docs.rtl.css.map +1 -0
- package/dist/css/adminlte-docs.rtl.min.css +7 -0
- package/dist/css/adminlte-docs.rtl.min.css.map +1 -0
- package/dist/css/adminlte.css +2 -782
- package/dist/css/adminlte.css.map +1 -1
- package/dist/css/adminlte.min.css +2 -2
- package/dist/css/adminlte.min.css.map +1 -1
- package/dist/css/adminlte.rtl.css +2 -782
- package/dist/css/adminlte.rtl.css.map +1 -1
- package/dist/css/adminlte.rtl.min.css +2 -2
- package/dist/css/adminlte.rtl.min.css.map +1 -1
- package/dist/js/adminlte.esm.js +1365 -0
- package/dist/js/adminlte.esm.js.map +1 -0
- package/dist/js/adminlte.esm.min.js +7 -0
- package/dist/js/adminlte.esm.min.js.map +1 -0
- package/dist/js/adminlte.js +391 -200
- package/dist/js/adminlte.js.map +1 -1
- package/dist/js/adminlte.min.js +2 -2
- package/dist/js/adminlte.min.js.map +1 -1
- package/dist/js/types/accessibility.d.ts +46 -0
- package/dist/js/types/adminlte.d.ts +9 -0
- package/dist/js/types/base-component.d.ts +36 -0
- package/dist/js/types/card-widget.d.ts +30 -0
- package/dist/js/types/color-mode.d.ts +56 -0
- package/dist/js/types/direct-chat.d.ts +19 -0
- package/dist/js/types/fullscreen.d.ts +21 -0
- package/dist/js/types/layout.d.ts +19 -0
- package/dist/js/types/push-menu.d.ts +102 -0
- package/dist/js/types/treeview.d.ts +27 -0
- package/dist/js/types/util/index.d.ts +42 -0
- package/package.json +32 -6
- package/src/scss/_app-header.scss +3 -1
- package/src/scss/_app-main.scss +4 -0
- package/src/scss/_app-sidebar.scss +3 -1
- package/src/scss/_bootstrap-overrides.scss +60 -0
- package/src/scss/_info-box.scss +3 -1
- package/src/scss/_progress-bars.scss +3 -1
- package/src/scss/_table.scss +4 -2
- package/src/scss/adminlte-docs.scss +25 -0
- package/src/scss/adminlte.scss +5 -4
- package/src/scss/pages/_login_and_register.scss +3 -1
- package/src/ts/adminlte.ts +3 -1
- package/src/ts/base-component.ts +84 -0
- package/src/ts/card-widget.ts +124 -100
- package/src/ts/color-mode.ts +174 -0
- package/src/ts/direct-chat.ts +38 -32
- package/src/ts/fullscreen.ts +32 -23
- package/src/ts/push-menu.ts +69 -36
- package/src/ts/treeview.ts +84 -50
- package/src/ts/util/index.ts +1 -1
- package/src/scss/_bootstrap-variables.scss +0 -1766
package/src/ts/fullscreen.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* --------------------------------------------
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { BaseComponent, dispatchCustomEvent } from './base-component'
|
|
9
10
|
import {
|
|
10
11
|
getLifecycleSignal,
|
|
11
12
|
onDOMContentLoaded
|
|
@@ -15,8 +16,8 @@ import {
|
|
|
15
16
|
* Constants
|
|
16
17
|
* ============================================================================
|
|
17
18
|
*/
|
|
18
|
-
const
|
|
19
|
-
const EVENT_KEY =
|
|
19
|
+
const NAME = 'fullscreen'
|
|
20
|
+
const EVENT_KEY = `.lte.${NAME}`
|
|
20
21
|
const EVENT_MAXIMIZED = `maximized${EVENT_KEY}`
|
|
21
22
|
const EVENT_MINIMIZED = `minimized${EVENT_KEY}`
|
|
22
23
|
|
|
@@ -48,7 +49,7 @@ function syncFullScreenState(): void {
|
|
|
48
49
|
const eventName = isFullScreen ? EVENT_MAXIMIZED : EVENT_MINIMIZED
|
|
49
50
|
|
|
50
51
|
document.querySelectorAll(SELECTOR_FULLSCREEN_TOGGLE).forEach(button => {
|
|
51
|
-
button
|
|
52
|
+
dispatchCustomEvent(button, eventName)
|
|
52
53
|
})
|
|
53
54
|
}
|
|
54
55
|
|
|
@@ -56,13 +57,17 @@ function syncFullScreenState(): void {
|
|
|
56
57
|
* Class Definition.
|
|
57
58
|
* ============================================================================
|
|
58
59
|
*/
|
|
59
|
-
class FullScreen {
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
class FullScreen extends BaseComponent {
|
|
61
|
+
static get NAME(): string {
|
|
62
|
+
return NAME
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static getInstance(element: Element | null | undefined): FullScreen | null {
|
|
66
|
+
return this._getInstance(element) as FullScreen | null
|
|
67
|
+
}
|
|
62
68
|
|
|
63
|
-
|
|
64
|
-
this.
|
|
65
|
-
this._config = config
|
|
69
|
+
static getOrCreateInstance(element: HTMLElement): FullScreen {
|
|
70
|
+
return this.getInstance(element) ?? new this(element)
|
|
66
71
|
}
|
|
67
72
|
|
|
68
73
|
inFullScreen(): void {
|
|
@@ -96,25 +101,29 @@ class FullScreen {
|
|
|
96
101
|
/**
|
|
97
102
|
* Data Api implementation
|
|
98
103
|
* ============================================================================
|
|
104
|
+
* Toggle clicks are delegated on `document`; the fullscreenchange listener is
|
|
105
|
+
* re-registered per page load with the lifecycle signal.
|
|
99
106
|
*/
|
|
100
|
-
onDOMContentLoaded(() => {
|
|
101
|
-
document.addEventListener('fullscreenchange', syncFullScreenState, { signal: getLifecycleSignal() })
|
|
102
107
|
|
|
103
|
-
|
|
108
|
+
document.addEventListener('click', event => {
|
|
109
|
+
const target = event.target
|
|
104
110
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
111
|
+
if (!(target instanceof Element)) {
|
|
112
|
+
return
|
|
113
|
+
}
|
|
108
114
|
|
|
109
|
-
|
|
110
|
-
const button = target.closest(SELECTOR_FULLSCREEN_TOGGLE) as HTMLElement | undefined
|
|
115
|
+
const button = target.closest(SELECTOR_FULLSCREEN_TOGGLE) as HTMLElement | null
|
|
111
116
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
if (!button) {
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
event.preventDefault()
|
|
122
|
+
FullScreen.getOrCreateInstance(button).toggleFullScreen()
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
onDOMContentLoaded(() => {
|
|
126
|
+
document.addEventListener('fullscreenchange', syncFullScreenState, { signal: getLifecycleSignal() })
|
|
118
127
|
})
|
|
119
128
|
|
|
120
129
|
export default FullScreen
|
package/src/ts/push-menu.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* ----------------------------------------------------------------------------
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { BaseComponent, dispatchCustomEvent } from './base-component'
|
|
9
10
|
import {
|
|
10
11
|
getLifecycleSignal,
|
|
11
12
|
onDOMContentLoaded
|
|
@@ -17,11 +18,17 @@ import {
|
|
|
17
18
|
* ----------------------------------------------------------------------------
|
|
18
19
|
*/
|
|
19
20
|
|
|
20
|
-
const
|
|
21
|
-
const EVENT_KEY =
|
|
21
|
+
const NAME = 'push-menu'
|
|
22
|
+
const EVENT_KEY = `.lte.${NAME}`
|
|
23
|
+
|
|
24
|
+
// Cancelable "before" events: preventDefault() aborts the state change.
|
|
22
25
|
const EVENT_OPEN = `open${EVENT_KEY}`
|
|
23
26
|
const EVENT_COLLAPSE = `collapse${EVENT_KEY}`
|
|
24
27
|
|
|
28
|
+
// "After" events, dispatched once the classes have been applied.
|
|
29
|
+
const EVENT_OPENED = `opened${EVENT_KEY}`
|
|
30
|
+
const EVENT_COLLAPSED = `collapsed${EVENT_KEY}`
|
|
31
|
+
|
|
25
32
|
const CLASS_NAME_SIDEBAR_MINI = 'sidebar-mini'
|
|
26
33
|
const CLASS_NAME_SIDEBAR_EXPAND = 'sidebar-expand'
|
|
27
34
|
const CLASS_NAME_SIDEBAR_OVERLAY = 'sidebar-overlay'
|
|
@@ -68,12 +75,23 @@ const Defaults: Config = {
|
|
|
68
75
|
* ----------------------------------------------------------------------------
|
|
69
76
|
*/
|
|
70
77
|
|
|
71
|
-
class PushMenu {
|
|
72
|
-
|
|
78
|
+
class PushMenu extends BaseComponent {
|
|
79
|
+
static get NAME(): string {
|
|
80
|
+
return NAME
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static getInstance(element: Element | null | undefined): PushMenu | null {
|
|
84
|
+
return this._getInstance(element) as PushMenu | null
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
static getOrCreateInstance(element: HTMLElement, config: Partial<Config> = {}): PushMenu {
|
|
88
|
+
return this.getInstance(element) ?? new this(element, config)
|
|
89
|
+
}
|
|
90
|
+
|
|
73
91
|
_config: Config
|
|
74
92
|
|
|
75
|
-
constructor(element: HTMLElement, config: Config) {
|
|
76
|
-
|
|
93
|
+
constructor(element: HTMLElement, config: Partial<Config> = {}) {
|
|
94
|
+
super(element)
|
|
77
95
|
this._config = { ...Defaults, ...config }
|
|
78
96
|
}
|
|
79
97
|
|
|
@@ -118,6 +136,12 @@ class PushMenu {
|
|
|
118
136
|
* Expand the sidebar menu.
|
|
119
137
|
*/
|
|
120
138
|
expand(): void {
|
|
139
|
+
// The "open" event is cancelable: preventDefault() keeps the sidebar
|
|
140
|
+
// in its current state.
|
|
141
|
+
if (dispatchCustomEvent(this._element, EVENT_OPEN, { cancelable: true }).defaultPrevented) {
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
|
|
121
145
|
// Remove the sidebar-collapse class. Only on mobile, add the sidebar-open
|
|
122
146
|
// class to indicate the sidebar is explicitly open.
|
|
123
147
|
|
|
@@ -127,24 +151,24 @@ class PushMenu {
|
|
|
127
151
|
document.body.classList.add(CLASS_NAME_SIDEBAR_OPEN)
|
|
128
152
|
}
|
|
129
153
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
this._element.dispatchEvent(new Event(EVENT_OPEN))
|
|
154
|
+
dispatchCustomEvent(this._element, EVENT_OPENED)
|
|
133
155
|
}
|
|
134
156
|
|
|
135
157
|
/**
|
|
136
158
|
* Collapse the sidebar menu.
|
|
137
159
|
*/
|
|
138
160
|
collapse(): void {
|
|
161
|
+
if (dispatchCustomEvent(this._element, EVENT_COLLAPSE, { cancelable: true }).defaultPrevented) {
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
|
|
139
165
|
// Remove the sidebar-open class (if present), and add the sidebar-collapse
|
|
140
166
|
// class.
|
|
141
167
|
|
|
142
168
|
document.body.classList.remove(CLASS_NAME_SIDEBAR_OPEN)
|
|
143
169
|
document.body.classList.add(CLASS_NAME_SIDEBAR_COLLAPSE)
|
|
144
170
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
this._element.dispatchEvent(new Event(EVENT_COLLAPSE))
|
|
171
|
+
dispatchCustomEvent(this._element, EVENT_COLLAPSED)
|
|
148
172
|
}
|
|
149
173
|
|
|
150
174
|
/**
|
|
@@ -332,12 +356,40 @@ class PushMenu {
|
|
|
332
356
|
* ----------------------------------------------------------------------------
|
|
333
357
|
* Data Api implementation
|
|
334
358
|
* ----------------------------------------------------------------------------
|
|
359
|
+
* Toggle clicks are handled by one delegated listener on `document`, so
|
|
360
|
+
* toggle buttons added later work and the listener survives Turbo's <body>
|
|
361
|
+
* swaps. The instance itself is created per page load below and can be
|
|
362
|
+
* retrieved anywhere with:
|
|
363
|
+
*
|
|
364
|
+
* PushMenu.getInstance(document.querySelector('.app-sidebar'))
|
|
335
365
|
*/
|
|
336
366
|
|
|
367
|
+
document.addEventListener('click', event => {
|
|
368
|
+
const target = event.target
|
|
369
|
+
|
|
370
|
+
if (!(target instanceof Element)) {
|
|
371
|
+
return
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const button = target.closest(SELECTOR_SIDEBAR_TOGGLE)
|
|
375
|
+
|
|
376
|
+
if (!button) {
|
|
377
|
+
return
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
event.preventDefault()
|
|
381
|
+
|
|
382
|
+
const sidebar = document.querySelector(SELECTOR_APP_SIDEBAR) as HTMLElement | null
|
|
383
|
+
|
|
384
|
+
if (sidebar) {
|
|
385
|
+
PushMenu.getOrCreateInstance(sidebar).toggle()
|
|
386
|
+
}
|
|
387
|
+
})
|
|
388
|
+
|
|
337
389
|
onDOMContentLoaded(() => {
|
|
338
390
|
// Find the sidebar element in the DOM.
|
|
339
391
|
|
|
340
|
-
const sidebar = document
|
|
392
|
+
const sidebar = document.querySelector(SELECTOR_APP_SIDEBAR) as HTMLElement | null
|
|
341
393
|
|
|
342
394
|
if (!sidebar) {
|
|
343
395
|
return
|
|
@@ -358,9 +410,11 @@ onDOMContentLoaded(() => {
|
|
|
358
410
|
enablePersistenceAttr === 'true'
|
|
359
411
|
}
|
|
360
412
|
|
|
361
|
-
// Initialize the PushMenu plugin (a unique instance
|
|
413
|
+
// Initialize the PushMenu plugin (a unique instance per sidebar element;
|
|
414
|
+
// Turbo navigations swap in a fresh element, so a fresh instance is
|
|
415
|
+
// created and the old one is garbage-collected with the old <body>).
|
|
362
416
|
|
|
363
|
-
const pushMenu =
|
|
417
|
+
const pushMenu = PushMenu.getOrCreateInstance(sidebar, config)
|
|
364
418
|
pushMenu.init()
|
|
365
419
|
|
|
366
420
|
// Update the sidebar state only when the viewport crosses the sidebar
|
|
@@ -416,27 +470,6 @@ onDOMContentLoaded(() => {
|
|
|
416
470
|
event.preventDefault()
|
|
417
471
|
pushMenu.collapse()
|
|
418
472
|
})
|
|
419
|
-
|
|
420
|
-
// Handle click events on sidebar toggle buttons.
|
|
421
|
-
|
|
422
|
-
const fullBtn = document.querySelectorAll(SELECTOR_SIDEBAR_TOGGLE)
|
|
423
|
-
|
|
424
|
-
fullBtn.forEach(btn => {
|
|
425
|
-
btn.addEventListener('click', event => {
|
|
426
|
-
event.preventDefault()
|
|
427
|
-
|
|
428
|
-
let button = event.currentTarget as HTMLElement | undefined
|
|
429
|
-
|
|
430
|
-
if (button?.dataset.lteToggle !== 'sidebar') {
|
|
431
|
-
button = button?.closest(SELECTOR_SIDEBAR_TOGGLE) as HTMLElement | undefined
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
if (button) {
|
|
435
|
-
event?.preventDefault()
|
|
436
|
-
pushMenu.toggle()
|
|
437
|
-
}
|
|
438
|
-
})
|
|
439
|
-
})
|
|
440
473
|
})
|
|
441
474
|
|
|
442
475
|
export default PushMenu
|
package/src/ts/treeview.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* --------------------------------------------
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { BaseComponent, dispatchCustomEvent } from './base-component'
|
|
9
10
|
import {
|
|
10
11
|
onDOMContentLoaded,
|
|
11
12
|
slideDown,
|
|
@@ -18,10 +19,14 @@ import {
|
|
|
18
19
|
* ------------------------------------------------------------------------
|
|
19
20
|
*/
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
const EVENT_KEY = `.${DATA_KEY}`
|
|
22
|
+
const NAME = 'treeview'
|
|
23
|
+
const EVENT_KEY = `.lte.${NAME}`
|
|
24
24
|
|
|
25
|
+
// Cancelable "before" events (dispatched on the nav-item as an action starts)
|
|
26
|
+
const EVENT_EXPAND = `expand${EVENT_KEY}`
|
|
27
|
+
const EVENT_COLLAPSE = `collapse${EVENT_KEY}`
|
|
28
|
+
|
|
29
|
+
// "After" events (dispatched on the nav-item when the animation finished)
|
|
25
30
|
const EVENT_EXPANDED = `expanded${EVENT_KEY}`
|
|
26
31
|
const EVENT_COLLAPSED = `collapsed${EVENT_KEY}`
|
|
27
32
|
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}`
|
|
@@ -56,17 +61,30 @@ const setAriaExpanded = (navItem: Element, expanded: boolean): void => {
|
|
|
56
61
|
* ====================================================
|
|
57
62
|
*/
|
|
58
63
|
|
|
59
|
-
class Treeview {
|
|
60
|
-
|
|
64
|
+
class Treeview extends BaseComponent {
|
|
65
|
+
static get NAME(): string {
|
|
66
|
+
return NAME
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static getInstance(element: Element | null | undefined): Treeview | null {
|
|
70
|
+
return this._getInstance(element) as Treeview | null
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static getOrCreateInstance(element: HTMLElement, config: Partial<Config> = {}): Treeview {
|
|
74
|
+
return this.getInstance(element) ?? new this(element, config)
|
|
75
|
+
}
|
|
76
|
+
|
|
61
77
|
_config: Config
|
|
62
78
|
|
|
63
|
-
constructor(element: HTMLElement, config: Config) {
|
|
64
|
-
|
|
79
|
+
constructor(element: HTMLElement, config: Partial<Config> = {}) {
|
|
80
|
+
super(element)
|
|
65
81
|
this._config = { ...Default, ...config }
|
|
66
82
|
}
|
|
67
83
|
|
|
68
84
|
open(): void {
|
|
69
|
-
|
|
85
|
+
if (dispatchCustomEvent(this._element, EVENT_EXPAND, { cancelable: true }).defaultPrevented) {
|
|
86
|
+
return
|
|
87
|
+
}
|
|
70
88
|
|
|
71
89
|
if (this._config.accordion) {
|
|
72
90
|
const openMenuList = this._element.parentElement?.querySelectorAll(`${SELECTOR_NAV_ITEM}.${CLASS_NAME_MENU_OPEN}`)
|
|
@@ -90,26 +108,36 @@ class Treeview {
|
|
|
90
108
|
this._element.classList.add(CLASS_NAME_MENU_OPEN)
|
|
91
109
|
setAriaExpanded(this._element, true)
|
|
92
110
|
|
|
93
|
-
const childElement = this._element
|
|
111
|
+
const childElement = this._element.querySelector(SELECTOR_TREEVIEW_MENU) as HTMLElement | undefined
|
|
94
112
|
if (childElement) {
|
|
95
113
|
slideDown(childElement, this._config.animationSpeed)
|
|
96
114
|
}
|
|
97
115
|
|
|
98
|
-
|
|
116
|
+
setTimeout(() => {
|
|
117
|
+
if (this._element.classList.contains(CLASS_NAME_MENU_OPEN)) {
|
|
118
|
+
dispatchCustomEvent(this._element, EVENT_EXPANDED)
|
|
119
|
+
}
|
|
120
|
+
}, this._config.animationSpeed)
|
|
99
121
|
}
|
|
100
122
|
|
|
101
123
|
close(): void {
|
|
102
|
-
|
|
124
|
+
if (dispatchCustomEvent(this._element, EVENT_COLLAPSE, { cancelable: true }).defaultPrevented) {
|
|
125
|
+
return
|
|
126
|
+
}
|
|
103
127
|
|
|
104
128
|
this._element.classList.remove(CLASS_NAME_MENU_OPEN)
|
|
105
129
|
setAriaExpanded(this._element, false)
|
|
106
130
|
|
|
107
|
-
const childElement = this._element
|
|
131
|
+
const childElement = this._element.querySelector(SELECTOR_TREEVIEW_MENU) as HTMLElement | undefined
|
|
108
132
|
if (childElement) {
|
|
109
133
|
slideUp(childElement, this._config.animationSpeed)
|
|
110
134
|
}
|
|
111
135
|
|
|
112
|
-
|
|
136
|
+
setTimeout(() => {
|
|
137
|
+
if (!this._element.classList.contains(CLASS_NAME_MENU_OPEN)) {
|
|
138
|
+
dispatchCustomEvent(this._element, EVENT_COLLAPSED)
|
|
139
|
+
}
|
|
140
|
+
}, this._config.animationSpeed)
|
|
113
141
|
}
|
|
114
142
|
|
|
115
143
|
toggle(): void {
|
|
@@ -125,8 +153,50 @@ class Treeview {
|
|
|
125
153
|
* ------------------------------------------------------------------------
|
|
126
154
|
* Data Api implementation
|
|
127
155
|
* ------------------------------------------------------------------------
|
|
156
|
+
* Clicks are handled by one delegated listener on `document`, so nav items
|
|
157
|
+
* added after load (dynamic menus, Turbo Frames) work without
|
|
158
|
+
* re-initialisation. Initial state (pre-opened menus, ARIA stamping) is
|
|
159
|
+
* applied per page load below.
|
|
128
160
|
*/
|
|
129
161
|
|
|
162
|
+
document.addEventListener('click', event => {
|
|
163
|
+
const target = event.target
|
|
164
|
+
|
|
165
|
+
if (!(target instanceof Element)) {
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const toggleRoot = target.closest(SELECTOR_DATA_TOGGLE) as HTMLElement | null
|
|
170
|
+
|
|
171
|
+
if (!toggleRoot) {
|
|
172
|
+
return
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const targetItem = target.closest(SELECTOR_NAV_ITEM) as HTMLElement | null
|
|
176
|
+
const targetLink = target.closest(SELECTOR_NAV_LINK)
|
|
177
|
+
|
|
178
|
+
// Avoid creating Treeview instances on non menu elements
|
|
179
|
+
if (!targetItem?.querySelector(SELECTOR_TREEVIEW_MENU)) {
|
|
180
|
+
return
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (target.getAttribute('href') === '#' || targetLink?.getAttribute('href') === '#') {
|
|
184
|
+
event.preventDefault()
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Read config from data attributes on the treeview root, falling back to
|
|
188
|
+
// Default. The config of the first interaction sticks to the instance.
|
|
189
|
+
const accordionAttr = toggleRoot.dataset.accordion
|
|
190
|
+
const animationSpeedAttr = toggleRoot.dataset.animationSpeed
|
|
191
|
+
|
|
192
|
+
const config: Config = {
|
|
193
|
+
accordion: accordionAttr === undefined ? Default.accordion : accordionAttr === 'true',
|
|
194
|
+
animationSpeed: animationSpeedAttr === undefined ? Default.animationSpeed : Number(animationSpeedAttr)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
Treeview.getOrCreateInstance(targetItem, config).toggle()
|
|
198
|
+
})
|
|
199
|
+
|
|
130
200
|
onDOMContentLoaded(() => {
|
|
131
201
|
const openMenuItems = document.querySelectorAll(`${SELECTOR_NAV_ITEM}.${CLASS_NAME_MENU_OPEN}`)
|
|
132
202
|
|
|
@@ -149,42 +219,6 @@ onDOMContentLoaded(() => {
|
|
|
149
219
|
}
|
|
150
220
|
})
|
|
151
221
|
})
|
|
152
|
-
|
|
153
|
-
const button = document.querySelectorAll(SELECTOR_DATA_TOGGLE)
|
|
154
|
-
|
|
155
|
-
button.forEach(btn => {
|
|
156
|
-
btn.addEventListener('click', event => {
|
|
157
|
-
const target = event.target as HTMLElement
|
|
158
|
-
const targetItem = target.closest(SELECTOR_NAV_ITEM) as HTMLElement | undefined
|
|
159
|
-
const targetLink = target.closest(SELECTOR_NAV_LINK) as HTMLAnchorElement | undefined
|
|
160
|
-
const targetTreeviewMenu = targetItem?.querySelector(SELECTOR_TREEVIEW_MENU) as HTMLElement | undefined
|
|
161
|
-
const lteToggleElement = event.currentTarget as HTMLElement
|
|
162
|
-
|
|
163
|
-
// Avoid creating Treeview instances on non menu elements
|
|
164
|
-
if (!targetTreeviewMenu) {
|
|
165
|
-
return
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (target?.getAttribute('href') === '#' || targetLink?.getAttribute('href') === '#') {
|
|
169
|
-
event.preventDefault()
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (targetItem) {
|
|
173
|
-
// Read data attributes
|
|
174
|
-
const accordionAttr = lteToggleElement.dataset.accordion
|
|
175
|
-
const animationSpeedAttr = lteToggleElement.dataset.animationSpeed
|
|
176
|
-
|
|
177
|
-
// Build config from data attributes, fallback to Default
|
|
178
|
-
const config: Config = {
|
|
179
|
-
accordion: accordionAttr === undefined ? Default.accordion : accordionAttr === 'true',
|
|
180
|
-
animationSpeed: animationSpeedAttr === undefined ? Default.animationSpeed : Number(animationSpeedAttr)
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const data = new Treeview(targetItem, config)
|
|
184
|
-
data.toggle()
|
|
185
|
-
}
|
|
186
|
-
})
|
|
187
|
-
})
|
|
188
222
|
})
|
|
189
223
|
|
|
190
|
-
export default Treeview
|
|
224
|
+
export default Treeview
|
package/src/ts/util/index.ts
CHANGED
|
@@ -109,7 +109,7 @@ const safePropertyAccess = (obj: Record<string, unknown>, property: string): unk
|
|
|
109
109
|
* the previous animation's steps: without this, rapidly toggling a treeview or
|
|
110
110
|
* card leaves a stale cleanup timer that strips height/transition mid-animation
|
|
111
111
|
* and desyncs the element's display state from its component's classes. */
|
|
112
|
-
const slideTimers = new WeakMap<HTMLElement,
|
|
112
|
+
const slideTimers = new WeakMap<HTMLElement, Array<ReturnType<typeof globalThis.setTimeout>>>()
|
|
113
113
|
|
|
114
114
|
const cancelSlide = (target: HTMLElement): void => {
|
|
115
115
|
const timers = slideTimers.get(target) ?? []
|