@tabler/core 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/css/tabler-flags.css +1 -1
- package/dist/css/tabler-flags.css.map +1 -1
- package/dist/css/tabler-flags.min.css +1 -1
- package/dist/css/tabler-flags.min.css.map +1 -1
- package/dist/css/tabler-flags.rtl.css +1 -1
- package/dist/css/tabler-flags.rtl.css.map +1 -1
- package/dist/css/tabler-flags.rtl.min.css +1 -1
- package/dist/css/tabler-flags.rtl.min.css.map +1 -1
- package/dist/css/tabler-marketing.css +1 -1
- package/dist/css/tabler-marketing.css.map +1 -1
- package/dist/css/tabler-marketing.min.css +1 -1
- package/dist/css/tabler-marketing.min.css.map +1 -1
- package/dist/css/tabler-marketing.rtl.css +1 -1
- package/dist/css/tabler-marketing.rtl.css.map +1 -1
- package/dist/css/tabler-marketing.rtl.min.css +1 -1
- package/dist/css/tabler-marketing.rtl.min.css.map +1 -1
- package/dist/css/tabler-payments.css +1 -1
- package/dist/css/tabler-payments.css.map +1 -1
- package/dist/css/tabler-payments.min.css +1 -1
- package/dist/css/tabler-payments.min.css.map +1 -1
- package/dist/css/tabler-payments.rtl.css +1 -1
- package/dist/css/tabler-payments.rtl.css.map +1 -1
- package/dist/css/tabler-payments.rtl.min.css +1 -1
- package/dist/css/tabler-payments.rtl.min.css.map +1 -1
- package/dist/css/tabler-props.css +1 -1
- package/dist/css/tabler-props.css.map +1 -1
- package/dist/css/tabler-props.min.css +1 -1
- package/dist/css/tabler-props.min.css.map +1 -1
- package/dist/css/tabler-props.rtl.css +1 -1
- package/dist/css/tabler-props.rtl.css.map +1 -1
- package/dist/css/tabler-props.rtl.min.css +1 -1
- package/dist/css/tabler-props.rtl.min.css.map +1 -1
- package/dist/css/tabler-socials.css +1 -1
- package/dist/css/tabler-socials.css.map +1 -1
- package/dist/css/tabler-socials.min.css +1 -1
- package/dist/css/tabler-socials.min.css.map +1 -1
- package/dist/css/tabler-socials.rtl.css +1 -1
- package/dist/css/tabler-socials.rtl.css.map +1 -1
- package/dist/css/tabler-socials.rtl.min.css +1 -1
- package/dist/css/tabler-socials.rtl.min.css.map +1 -1
- package/dist/css/tabler-themes.css +1 -1
- package/dist/css/tabler-themes.css.map +1 -1
- package/dist/css/tabler-themes.min.css +1 -1
- package/dist/css/tabler-themes.min.css.map +1 -1
- package/dist/css/tabler-themes.rtl.css +1 -1
- package/dist/css/tabler-themes.rtl.css.map +1 -1
- package/dist/css/tabler-themes.rtl.min.css +1 -1
- package/dist/css/tabler-themes.rtl.min.css.map +1 -1
- package/dist/css/tabler-vendors.css +1 -1
- package/dist/css/tabler-vendors.css.map +1 -1
- package/dist/css/tabler-vendors.min.css +1 -1
- package/dist/css/tabler-vendors.min.css.map +1 -1
- package/dist/css/tabler-vendors.rtl.css +1 -1
- package/dist/css/tabler-vendors.rtl.css.map +1 -1
- package/dist/css/tabler-vendors.rtl.min.css +1 -1
- package/dist/css/tabler-vendors.rtl.min.css.map +1 -1
- package/dist/css/tabler.css +12 -2
- package/dist/css/tabler.css.map +1 -1
- package/dist/css/tabler.min.css +2 -2
- package/dist/css/tabler.min.css.map +1 -1
- package/dist/css/tabler.rtl.css +12 -2
- package/dist/css/tabler.rtl.css.map +1 -1
- package/dist/css/tabler.rtl.min.css +2 -2
- package/dist/css/tabler.rtl.min.css.map +1 -1
- package/dist/js/tabler-theme.esm.js +21 -6
- package/dist/js/tabler-theme.esm.js.map +1 -1
- package/dist/js/tabler-theme.esm.min.js +2 -2
- package/dist/js/tabler-theme.esm.min.js.map +1 -1
- package/dist/js/tabler-theme.js +21 -6
- package/dist/js/tabler-theme.js.map +1 -1
- package/dist/js/tabler-theme.min.js +2 -2
- package/dist/js/tabler-theme.min.js.map +1 -1
- package/dist/js/tabler.esm.js +332 -131
- package/dist/js/tabler.esm.js.map +1 -1
- package/dist/js/tabler.esm.min.js +2 -2
- package/dist/js/tabler.esm.min.js.map +1 -1
- package/dist/js/tabler.js +332 -131
- package/dist/js/tabler.js.map +1 -1
- package/dist/js/tabler.min.js +2 -2
- package/dist/js/tabler.min.js.map +1 -1
- package/dist/libs/vanilla-calendar-pro/index.js +2 -2
- package/dist/types/src/clipboard.d.ts +3 -0
- package/dist/types/src/confetti.d.ts +2 -0
- package/dist/types/src/countup.d.ts +2 -0
- package/dist/types/src/datepicker.d.ts +24 -6
- package/dist/types/src/input-mask.d.ts +2 -1
- package/dist/types/src/otp-input.d.ts +6 -2
- package/dist/types/src/strength.d.ts +1 -0
- package/dist/types/src/switch-icon.d.ts +1 -0
- package/js/src/autosize.ts +8 -3
- package/js/src/bootstrap/base-component.ts +12 -2
- package/js/src/bootstrap/dom/manipulator.ts +1 -1
- package/js/src/bootstrap/dropdown.ts +3 -1
- package/js/src/bootstrap/util/index.ts +14 -1
- package/js/src/clipboard.ts +26 -2
- package/js/src/confetti.ts +42 -7
- package/js/src/countup.ts +30 -12
- package/js/src/datepicker.ts +147 -27
- package/js/src/dropdown.ts +12 -5
- package/js/src/global.d.ts +4 -2
- package/js/src/input-mask.ts +7 -7
- package/js/src/otp-input.ts +99 -12
- package/js/src/popover.ts +13 -7
- package/js/src/sidebar.ts +14 -6
- package/js/src/sortable.ts +5 -1
- package/js/src/sparkline.ts +15 -6
- package/js/src/strength.ts +17 -4
- package/js/src/switch-icon.ts +15 -0
- package/js/src/tab.ts +17 -7
- package/js/src/toast.ts +19 -11
- package/js/src/tooltip.ts +16 -7
- package/js/tabler-theme.ts +28 -4
- package/package.json +2 -2
- package/scss/layout/_navbar.scss +1 -2
- package/scss/ui/_cards.scss +14 -2
package/js/src/popover.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { Popover } from './bootstrap'
|
|
2
|
+
import Manipulator from './bootstrap/dom/manipulator'
|
|
3
|
+
import { onDOMContentLoaded } from './bootstrap/util/index'
|
|
2
4
|
|
|
3
5
|
// js-docs-start popover-init
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
onDOMContentLoaded(() => {
|
|
7
|
+
for (const popoverTriggerEl of document.querySelectorAll<HTMLElement>('[data-bs-toggle="popover"], [data-tblr-toggle="popover"]')) {
|
|
8
|
+
try {
|
|
9
|
+
const options = {
|
|
10
|
+
delay: Manipulator.getDataAttribute(popoverTriggerEl, 'delay') ?? { show: 50, hide: 50 },
|
|
11
|
+
placement: Manipulator.getDataAttribute(popoverTriggerEl, 'placement') ?? 'auto',
|
|
12
|
+
}
|
|
13
|
+
Popover.getOrCreateInstance(popoverTriggerEl, options)
|
|
14
|
+
} catch (error) {
|
|
15
|
+
console.error(error)
|
|
16
|
+
}
|
|
10
17
|
}
|
|
11
|
-
return new Popover(popoverTriggerEl, options)
|
|
12
18
|
})
|
|
13
19
|
// js-docs-end popover-init
|
package/js/src/sidebar.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Dropdown } from './bootstrap'
|
|
2
|
+
import { onDOMContentLoaded } from './bootstrap/util/index'
|
|
2
3
|
|
|
3
4
|
/*
|
|
4
5
|
Folded sidebar toggle
|
|
5
6
|
*/
|
|
6
7
|
// js-docs-start sidebar-folded-toggle
|
|
7
8
|
const syncSidebarToggles = (folded: boolean): void => {
|
|
8
|
-
for (const toggle of document.querySelectorAll('[data-bs-toggle="sidebar-folded"]')) {
|
|
9
|
+
for (const toggle of document.querySelectorAll('[data-bs-toggle="sidebar-folded"], [data-tblr-toggle="sidebar-folded"]')) {
|
|
9
10
|
toggle.setAttribute('aria-pressed', String(folded))
|
|
10
11
|
}
|
|
11
12
|
}
|
|
@@ -28,8 +29,9 @@ document.addEventListener('click', (event: MouseEvent) => {
|
|
|
28
29
|
return
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
// A synthetic click dispatched on the document has no Element target.
|
|
33
|
+
const target = event.target
|
|
34
|
+
if (!(target instanceof Element) || target.closest('.navbar-vertical .dropdown-menu')) {
|
|
33
35
|
return
|
|
34
36
|
}
|
|
35
37
|
|
|
@@ -60,7 +62,8 @@ document.addEventListener(
|
|
|
60
62
|
// The folded state may come pre-render from localStorage (tabler-theme.js), so
|
|
61
63
|
// align the toggle buttons with it once the DOM is available. Server-rendered
|
|
62
64
|
// open submenus are also closed, so they don't hang as open flyouts.
|
|
63
|
-
|
|
65
|
+
// onDOMContentLoaded runs at once when the script loads after the event.
|
|
66
|
+
onDOMContentLoaded(() => {
|
|
64
67
|
const folded = (document.documentElement.getAttribute('data-bs-sidebar') ?? '').startsWith('folded')
|
|
65
68
|
syncSidebarToggles(folded)
|
|
66
69
|
|
|
@@ -73,7 +76,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
73
76
|
})
|
|
74
77
|
|
|
75
78
|
document.addEventListener('click', (event: MouseEvent) => {
|
|
76
|
-
const trigger =
|
|
79
|
+
const trigger = event.target instanceof Element ? event.target.closest('[data-bs-toggle="sidebar-folded"], [data-tblr-toggle="sidebar-folded"]') : null
|
|
77
80
|
if (!trigger) {
|
|
78
81
|
return
|
|
79
82
|
}
|
|
@@ -89,7 +92,12 @@ document.addEventListener('click', (event: MouseEvent) => {
|
|
|
89
92
|
html.removeAttribute('data-bs-sidebar')
|
|
90
93
|
}
|
|
91
94
|
|
|
92
|
-
|
|
95
|
+
// Storage may be blocked by the browser; the fold still applies to this page.
|
|
96
|
+
try {
|
|
97
|
+
localStorage.setItem('tabler-sidebar', willFold ? 'folded-hover' : 'default')
|
|
98
|
+
} catch {
|
|
99
|
+
// ignore
|
|
100
|
+
}
|
|
93
101
|
syncSidebarToggles(willFold)
|
|
94
102
|
|
|
95
103
|
// Close open sidebar dropdowns so an inline submenu doesn't turn into a
|
package/js/src/sortable.ts
CHANGED
|
@@ -101,7 +101,11 @@ class Sortable extends BaseComponent {
|
|
|
101
101
|
|
|
102
102
|
if (raw) {
|
|
103
103
|
try {
|
|
104
|
-
|
|
104
|
+
const parsed: unknown = JSON.parse(raw)
|
|
105
|
+
// Only an object carries options; `null`, a number or an array is ignored.
|
|
106
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
107
|
+
dataOptions = parsed as Record<string, unknown>
|
|
108
|
+
}
|
|
105
109
|
} catch {
|
|
106
110
|
// ignore invalid JSON
|
|
107
111
|
}
|
package/js/src/sparkline.ts
CHANGED
|
@@ -262,7 +262,9 @@ class Sparkline extends BaseComponent {
|
|
|
262
262
|
this._element.querySelector(`.${CLASS_NAME_LABEL}`)?.remove()
|
|
263
263
|
|
|
264
264
|
if (this._config.values.length === 0) {
|
|
265
|
-
this.
|
|
265
|
+
cancelAnimationFrame(this._frame)
|
|
266
|
+
previous?.remove()
|
|
267
|
+
EventHandler.trigger(this._element, EVENT_RENDERED)
|
|
266
268
|
return
|
|
267
269
|
}
|
|
268
270
|
|
|
@@ -308,7 +310,8 @@ class Sparkline extends BaseComponent {
|
|
|
308
310
|
|
|
309
311
|
dispose(): void {
|
|
310
312
|
cancelAnimationFrame(this._frame)
|
|
311
|
-
this._element.
|
|
313
|
+
this._element.querySelector('svg')?.remove()
|
|
314
|
+
this._element.querySelector(`.${CLASS_NAME_LABEL}`)?.remove()
|
|
312
315
|
super.dispose()
|
|
313
316
|
}
|
|
314
317
|
|
|
@@ -365,6 +368,12 @@ class Sparkline extends BaseComponent {
|
|
|
365
368
|
const pairs = Array.from(to.children).map((target, i) => {
|
|
366
369
|
const source = from.children[i]
|
|
367
370
|
const tweens: [string, string, string][] = []
|
|
371
|
+
for (const { name } of Array.from(source.attributes)) {
|
|
372
|
+
if (!target.hasAttribute(name)) {
|
|
373
|
+
source.removeAttribute(name)
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
368
377
|
for (const { name, value } of Array.from(target.attributes)) {
|
|
369
378
|
const start = source.getAttribute(name)
|
|
370
379
|
if (start === null || start === value) {
|
|
@@ -431,8 +440,8 @@ class Sparkline extends BaseComponent {
|
|
|
431
440
|
|
|
432
441
|
const { min, span } = rangeOf(cfg.values, cfg.min, cfg.max, ...(cfg.threshold === null ? [] : [cfg.threshold]))
|
|
433
442
|
const yOf = (value: number): number => cfg.pad + (1 - (value - min) / span) * (cfg.height - cfg.pad * 2)
|
|
434
|
-
const ys = cfg.values.map(yOf)
|
|
435
|
-
const step =
|
|
443
|
+
const ys = cfg.values.length === 1 ? [yOf(cfg.values[0]), yOf(cfg.values[0])] : cfg.values.map(yOf)
|
|
444
|
+
const step = cfg.width / (ys.length - 1)
|
|
436
445
|
|
|
437
446
|
if (cfg.threshold !== null) {
|
|
438
447
|
this._hairline(svg, yOf(cfg.threshold), 'threshold', true)
|
|
@@ -463,7 +472,7 @@ class Sparkline extends BaseComponent {
|
|
|
463
472
|
if (spotIndex >= 0) {
|
|
464
473
|
const spot = svgEl('circle')
|
|
465
474
|
setAttr(spot, {
|
|
466
|
-
cx: spotIndex * step,
|
|
475
|
+
cx: cfg.values.length === 1 ? cfg.width / 2 : spotIndex * step,
|
|
467
476
|
cy: ys[spotIndex],
|
|
468
477
|
r: getCssNumber(this._element, 'spot-size', 2),
|
|
469
478
|
fill: cssVar('spot'),
|
|
@@ -560,7 +569,7 @@ class Sparkline extends BaseComponent {
|
|
|
560
569
|
const cfg = this._config
|
|
561
570
|
const svg = this._createSvg()
|
|
562
571
|
|
|
563
|
-
const strokeWidth = getCssNumber(this._element, 'stroke-width',
|
|
572
|
+
const strokeWidth = getCssNumber(this._element, 'stroke-width', 2)
|
|
564
573
|
const radius = Math.max(0, Math.min(cfg.width, cfg.height) / 2 - strokeWidth / 2)
|
|
565
574
|
const cx = cfg.width / 2
|
|
566
575
|
const cy = cfg.height / 2
|
package/js/src/strength.ts
CHANGED
|
@@ -9,6 +9,7 @@ import BaseComponent from './bootstrap/base-component'
|
|
|
9
9
|
import EventHandler from './bootstrap/dom/event-handler'
|
|
10
10
|
import SelectorEngine from './bootstrap/dom/selector-engine'
|
|
11
11
|
import { initAll } from './bootstrap/util/component-functions'
|
|
12
|
+
import { getElement } from './bootstrap/util/index'
|
|
12
13
|
import type { ElementSelector } from './bootstrap/types'
|
|
13
14
|
|
|
14
15
|
type StrengthLevel = 'weak' | 'fair' | 'good' | 'strong'
|
|
@@ -164,17 +165,29 @@ class Strength extends BaseComponent {
|
|
|
164
165
|
}
|
|
165
166
|
|
|
166
167
|
// Private
|
|
168
|
+
_configAfterMerge(config: ComponentConfig): ComponentConfig {
|
|
169
|
+
// A partial `messages` or `weights` overrides only the keys it names.
|
|
170
|
+
return {
|
|
171
|
+
...config,
|
|
172
|
+
messages: { ...Default.messages, ...config.messages },
|
|
173
|
+
weights: { ...Default.weights, ...config.weights },
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
167
177
|
_getInput(): HTMLInputElement | null {
|
|
168
178
|
const { input } = this._config
|
|
169
179
|
if (input) {
|
|
170
|
-
return
|
|
180
|
+
return getElement(input) as HTMLInputElement | null
|
|
171
181
|
}
|
|
172
182
|
|
|
173
|
-
// Without an explicit selector only the meter's own parent is searched
|
|
174
|
-
//
|
|
183
|
+
// Without an explicit selector only the meter's own parent is searched.
|
|
184
|
+
// The nearest field before the meter wins, so a confirm-password field
|
|
185
|
+
// placed after it is never mistaken for the one being rated; a meter
|
|
186
|
+
// placed above its field falls back to the first field after it.
|
|
175
187
|
const parent = this._element.parentElement
|
|
176
188
|
const fields = parent ? (SelectorEngine.find(SELECTOR_PASSWORD, parent) as HTMLInputElement[]) : []
|
|
177
|
-
|
|
189
|
+
const precedingFields = fields.filter((field) => Boolean(field.compareDocumentPosition(this._element) & Node.DOCUMENT_POSITION_FOLLOWING))
|
|
190
|
+
return precedingFields[precedingFields.length - 1] ?? fields[0] ?? null
|
|
178
191
|
}
|
|
179
192
|
|
|
180
193
|
_getText(): HTMLElement | null {
|
package/js/src/switch-icon.ts
CHANGED
|
@@ -138,8 +138,19 @@ class SwitchIcon extends BaseComponent {
|
|
|
138
138
|
.finally(() => this.#setLoading(false))
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
dispose(): void {
|
|
142
|
+
// A wait() still pending must not leave the spinner on the button.
|
|
143
|
+
this.#setLoading(false)
|
|
144
|
+
super.dispose()
|
|
145
|
+
}
|
|
146
|
+
|
|
141
147
|
// Private
|
|
142
148
|
#setActive(active: boolean): void {
|
|
149
|
+
// A pending wait() may settle after dispose().
|
|
150
|
+
if (!this._element) {
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
|
|
143
154
|
this.#iconElement.classList.toggle(CLASS_NAME_ACTIVE, active)
|
|
144
155
|
this._element.setAttribute('aria-pressed', String(active))
|
|
145
156
|
|
|
@@ -147,6 +158,10 @@ class SwitchIcon extends BaseComponent {
|
|
|
147
158
|
}
|
|
148
159
|
|
|
149
160
|
#setLoading(loading: boolean): void {
|
|
161
|
+
if (!this._element) {
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
|
|
150
165
|
this.#iconElement.classList.toggle(CLASS_NAME_LOADING, loading)
|
|
151
166
|
if (loading) {
|
|
152
167
|
this._element.setAttribute('aria-busy', 'true')
|
package/js/src/tab.ts
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
import { Tab } from './bootstrap'
|
|
2
|
+
import { onDOMContentLoaded } from './bootstrap/util/index'
|
|
2
3
|
|
|
3
4
|
// js-docs-start tab-init
|
|
4
5
|
export const EnableActivationTabsFromLocationHash = (): void => {
|
|
5
6
|
const locationHash: string = window.location.hash
|
|
6
7
|
|
|
7
|
-
if (locationHash) {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
if (!locationHash) {
|
|
9
|
+
return
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
for (const tab of document.querySelectorAll<HTMLAnchorElement>('[data-bs-toggle="tab"], [data-tblr-toggle="tab"]')) {
|
|
13
|
+
if (tab.hash !== locationHash) {
|
|
14
|
+
continue
|
|
15
|
+
}
|
|
10
16
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
// A tab link outside a .nav/.list-group has no parent to switch in;
|
|
18
|
+
// show() would throw and stop the rest of the bundle.
|
|
19
|
+
try {
|
|
20
|
+
;(Tab.getOrCreateInstance(tab) as InstanceType<typeof Tab>).show()
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error(error)
|
|
23
|
+
}
|
|
14
24
|
}
|
|
15
25
|
}
|
|
16
26
|
|
|
17
|
-
EnableActivationTabsFromLocationHash
|
|
27
|
+
onDOMContentLoaded(EnableActivationTabsFromLocationHash)
|
|
18
28
|
// js-docs-end tab-init
|
package/js/src/toast.ts
CHANGED
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
import { Toast } from './bootstrap'
|
|
2
|
+
import SelectorEngine from './bootstrap/dom/selector-engine'
|
|
3
|
+
import { onDOMContentLoaded } from './bootstrap/util/index'
|
|
2
4
|
|
|
3
5
|
// js-docs-start toast-init
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
onDOMContentLoaded(() => {
|
|
7
|
+
for (const toastTriggerEl of document.querySelectorAll<HTMLElement>('[data-bs-toggle="toast"], [data-tblr-toggle="toast"]')) {
|
|
8
|
+
try {
|
|
9
|
+
// A trigger whose target is missing is left alone instead of getting a
|
|
10
|
+
// click handler that throws.
|
|
11
|
+
const toastEl = SelectorEngine.getElementFromSelector(toastTriggerEl)
|
|
12
|
+
if (!toastEl) {
|
|
13
|
+
continue
|
|
14
|
+
}
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
const toast = Toast.getOrCreateInstance(toastEl) as InstanceType<typeof Toast>
|
|
17
|
+
toastTriggerEl.addEventListener('click', () => {
|
|
18
|
+
toast.show()
|
|
19
|
+
})
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error(error)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
16
24
|
})
|
|
17
25
|
// js-docs-end toast-init
|
package/js/src/tooltip.ts
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import { Tooltip } from './bootstrap'
|
|
2
|
+
import Manipulator from './bootstrap/dom/manipulator'
|
|
3
|
+
import { onDOMContentLoaded } from './bootstrap/util/index'
|
|
2
4
|
|
|
3
5
|
// js-docs-start tooltip-init
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
// One element with a broken config must not stop the rest of the bundle, so
|
|
7
|
+
// every instance is created on its own. `data-bs-delay` on the element wins
|
|
8
|
+
// over the shorter default delay.
|
|
9
|
+
onDOMContentLoaded(() => {
|
|
10
|
+
for (const tooltipTriggerEl of document.querySelectorAll<HTMLElement>('[data-bs-toggle="tooltip"], [data-tblr-toggle="tooltip"]')) {
|
|
11
|
+
try {
|
|
12
|
+
const options = {
|
|
13
|
+
delay: Manipulator.getDataAttribute(tooltipTriggerEl, 'delay') ?? { show: 50, hide: 50 },
|
|
14
|
+
placement: Manipulator.getDataAttribute(tooltipTriggerEl, 'placement') ?? 'auto',
|
|
15
|
+
}
|
|
16
|
+
Tooltip.getOrCreateInstance(tooltipTriggerEl, options)
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.error(error)
|
|
19
|
+
}
|
|
10
20
|
}
|
|
11
|
-
return new Tooltip(tooltipTriggerEl, options)
|
|
12
21
|
})
|
|
13
22
|
// js-docs-end tooltip-init
|
package/js/tabler-theme.ts
CHANGED
|
@@ -9,16 +9,40 @@ const params = new URLSearchParams(window.location.search)
|
|
|
9
9
|
|
|
10
10
|
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)')
|
|
11
11
|
|
|
12
|
+
// A setting value is a short token: it ends up as a `data-bs-*` attribute on
|
|
13
|
+
// <html> and in localStorage, so anything else from the URL is ignored.
|
|
14
|
+
const VALUE_PATTERN = /^[a-z0-9-]{1,32}$/
|
|
15
|
+
|
|
16
|
+
// Accessing localStorage throws when site data is blocked (Chrome "block all
|
|
17
|
+
// cookies", Safari with storage disabled, partitioned third-party frames), so
|
|
18
|
+
// every access is guarded and the switcher falls back to the page defaults.
|
|
19
|
+
const storage = {
|
|
20
|
+
get(key: string): string | null {
|
|
21
|
+
try {
|
|
22
|
+
return localStorage.getItem(key)
|
|
23
|
+
} catch {
|
|
24
|
+
return null
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
set(key: string, value: string): void {
|
|
28
|
+
try {
|
|
29
|
+
localStorage.setItem(key, value)
|
|
30
|
+
} catch {
|
|
31
|
+
// ignore: the choice applies to this page only
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
|
|
12
36
|
for (const key in themeDefaults) {
|
|
13
37
|
const param = params.get(key)
|
|
14
38
|
let selectedValue: string
|
|
15
39
|
|
|
16
|
-
if (
|
|
17
|
-
|
|
40
|
+
if (param && VALUE_PATTERN.test(param)) {
|
|
41
|
+
storage.set('tabler-' + key, param)
|
|
18
42
|
selectedValue = param
|
|
19
43
|
} else {
|
|
20
44
|
// A stored choice wins; otherwise a server-rendered attribute is the starting value.
|
|
21
|
-
const storedTheme =
|
|
45
|
+
const storedTheme = storage.get('tabler-' + key)
|
|
22
46
|
const serverValue = document.documentElement.getAttribute('data-bs-' + key)
|
|
23
47
|
selectedValue = storedTheme ?? serverValue ?? themeDefaults[key as ThemeKey]
|
|
24
48
|
}
|
|
@@ -36,7 +60,7 @@ for (const key in themeDefaults) {
|
|
|
36
60
|
|
|
37
61
|
prefersDark.addEventListener('change', (event) => {
|
|
38
62
|
// No stored choice means the default, which is auto.
|
|
39
|
-
if ((
|
|
63
|
+
if ((storage.get('tabler-theme') ?? 'auto') === 'auto') {
|
|
40
64
|
if (event.matches) {
|
|
41
65
|
document.documentElement.setAttribute('data-bs-theme', 'dark')
|
|
42
66
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tabler/core",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"description": "Premium and Open Source dashboard template with responsive and high quality UI.",
|
|
5
5
|
"homepage": "https://tabler.io",
|
|
6
6
|
"repository": {
|
|
@@ -250,7 +250,7 @@
|
|
|
250
250
|
"tom-select": "^2.6.2",
|
|
251
251
|
"typed.js": "^3.0.0",
|
|
252
252
|
"typescript": "^7.0.2",
|
|
253
|
-
"vanilla-calendar-pro": "^3.
|
|
253
|
+
"vanilla-calendar-pro": "^3.4.0",
|
|
254
254
|
"vitest": "4.1.11"
|
|
255
255
|
},
|
|
256
256
|
"scripts": {
|
package/scss/layout/_navbar.scss
CHANGED
|
@@ -660,8 +660,7 @@ Navbar vertical
|
|
|
660
660
|
// The sidebar is rendered for the expanded state, so the active submenu can
|
|
661
661
|
// arrive open (.show). Folded, it would paint as a flyout until sidebar.ts
|
|
662
662
|
// closes it on DOMContentLoaded — a flicker on every reload. Menus opened by
|
|
663
|
-
// the Dropdown plugin carry a
|
|
664
|
-
// tabler.js, data-bs-popper from Bootstrap's own js), so only the
|
|
663
|
+
// the Dropdown plugin carry a data-bs-popper attribute, so only the
|
|
665
664
|
// server-rendered ones hide.
|
|
666
665
|
.navbar-vertical .dropdown-menu.show:not([data-bs-popper]):not([data-tblr-popper]) {
|
|
667
666
|
display: none;
|
package/scss/ui/_cards.scss
CHANGED
|
@@ -302,9 +302,21 @@ Stacked card
|
|
|
302
302
|
}
|
|
303
303
|
|
|
304
304
|
// Card progress
|
|
305
|
-
|
|
306
|
-
.card > .card-progress {
|
|
305
|
+
.card-progress {
|
|
307
306
|
--card-progress-height: #{$card-progress-height};
|
|
307
|
+
height: var(--card-progress-height);
|
|
308
|
+
|
|
309
|
+
&:last-child {
|
|
310
|
+
@include border-radius(0 0 2px 2px);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
&:first-child {
|
|
314
|
+
@include border-radius(2px 2px 0 0);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// `.card >` outranks the fallback above and ui/_progress.scss's later `.progress { position: relative; }`.
|
|
319
|
+
.card > .card-progress {
|
|
308
320
|
--card-progress-offset: calc(-1 * var(--card-border-width));
|
|
309
321
|
position: absolute;
|
|
310
322
|
inset: var(--card-progress-offset);
|