@dodlhuat/basix 1.2.0 → 1.2.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/README.md +56 -1
- package/css/accordion.scss +86 -87
- package/css/alert.scss +137 -137
- package/css/button.scss +48 -0
- package/css/calendar.scss +957 -0
- package/css/card.scss +65 -65
- package/css/chart.scss +270 -157
- package/css/chat-bubbles.scss +134 -68
- package/css/chips.scss +109 -19
- package/css/colors.scss +32 -32
- package/css/datepicker.scss +336 -336
- package/css/defaults.scss +90 -90
- package/css/docs.scss +529 -0
- package/css/editor.scss +36 -0
- package/css/file-uploader.scss +1 -1
- package/css/flyout-menu.scss +361 -361
- package/css/form.scss +0 -15
- package/css/gallery.scss +65 -6
- package/css/grid.scss +41 -40
- package/css/group-picker.scss +345 -0
- package/css/guitar-chords.css +250 -250
- package/css/icons.scss +330 -330
- package/css/parameters.scss +3 -3
- package/css/placeholder.scss +33 -33
- package/css/popover.scss +206 -0
- package/css/progress.scss +76 -32
- package/css/properties.scss +51 -36
- package/css/push-menu.scss +302 -174
- package/css/reset.scss +39 -39
- package/css/scrollbar.scss +62 -5
- package/css/sidebar-nav.scss +92 -0
- package/css/spinner.scss +65 -65
- package/css/stepper.scss +48 -12
- package/css/style.css +3159 -254
- package/css/style.css.map +1 -1
- package/css/style.min.css +1 -1
- package/css/style.scss +51 -45
- package/css/table.scss +199 -199
- package/css/tabs.scss +154 -123
- package/css/timeline.scss +83 -38
- package/css/timepicker.scss +100 -5
- package/css/toast.scss +81 -81
- package/css/virtual-dropdown.scss +35 -29
- package/js/calendar.js +532 -0
- package/js/calendar.ts +706 -0
- package/js/chart.js +573 -257
- package/js/chart.ts +692 -0
- package/js/code-viewer.js +10 -10
- package/js/code-viewer.ts +188 -188
- package/js/datepicker.ts +627 -627
- package/js/docs-nav.js +204 -0
- package/js/dropdown.ts +179 -179
- package/js/editor.js +50 -6
- package/js/editor.ts +483 -444
- package/js/file-uploader.js +1 -0
- package/js/file-uploader.ts +1 -0
- package/js/flyout-menu.js +14 -14
- package/js/flyout-menu.ts +249 -249
- package/js/form-builder.js +106 -106
- package/js/gallery.js +14 -8
- package/js/gallery.ts +245 -236
- package/js/group-picker.js +342 -0
- package/js/group-picker.ts +447 -0
- package/js/guitar-chords.js +268 -268
- package/js/lazy-loader.js +121 -121
- package/js/modal.ts +166 -166
- package/js/popover.js +163 -0
- package/js/popover.ts +219 -0
- package/js/position.js +108 -0
- package/js/position.ts +111 -0
- package/js/push-menu.js +113 -0
- package/js/push-menu.ts +284 -145
- package/js/request.js +50 -50
- package/js/scroll.ts +47 -47
- package/js/scrollbar.js +13 -0
- package/js/scrollbar.ts +324 -307
- package/js/select.ts +216 -216
- package/js/sidebar-nav.js +41 -0
- package/js/sidebar-nav.ts +66 -0
- package/js/table.ts +452 -452
- package/js/tabs.ts +279 -279
- package/js/theme.js +17 -6
- package/js/theme.ts +234 -224
- package/js/toast.ts +137 -137
- package/js/tooltip.js +6 -60
- package/js/tooltip.ts +184 -251
- package/js/tsconfig.json +18 -18
- package/js/utils.ts +83 -83
- package/js/virtual-dropdown.js +25 -25
- package/js/virtual-dropdown.ts +365 -365
- package/package.json +39 -39
- package/js/index.js +0 -816
- package/js/index.ts +0 -987
package/js/theme.ts
CHANGED
|
@@ -1,225 +1,235 @@
|
|
|
1
|
-
type ThemeMode = 'light' | 'dark';
|
|
2
|
-
|
|
3
|
-
interface ThemeElements {
|
|
4
|
-
toggleBtn: HTMLElement;
|
|
5
|
-
icon: HTMLElement;
|
|
6
|
-
status: HTMLElement | null;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
class Theme {
|
|
10
|
-
private static readonly STORAGE_KEY = 'theme';
|
|
11
|
-
private static root: HTMLElement;
|
|
12
|
-
private static elements: ThemeElements | null = null;
|
|
13
|
-
private static mediaQuery: MediaQueryList | null = null;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Initializes the theme system with toggle functionality and system preference detection
|
|
17
|
-
*/
|
|
18
|
-
public static init(): void {
|
|
19
|
-
this.root = document.documentElement;
|
|
20
|
-
|
|
21
|
-
// Get DOM elements
|
|
22
|
-
const toggleBtn = document.getElementById('theme-toggle');
|
|
23
|
-
const icon = document.getElementById('theme-icon');
|
|
24
|
-
const status = document.getElementById('status');
|
|
25
|
-
|
|
26
|
-
// Validate required elements
|
|
27
|
-
if (!toggleBtn || !icon) {
|
|
28
|
-
console.error('Theme toggle: missing DOM elements', { toggleBtn, icon });
|
|
29
|
-
if (status) {
|
|
30
|
-
status.textContent = 'Error: missing toggle elements (check IDs).';
|
|
31
|
-
}
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
this.elements = { toggleBtn, icon, status };
|
|
36
|
-
|
|
37
|
-
// Initialize media query
|
|
38
|
-
if (window.matchMedia) {
|
|
39
|
-
this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Apply initial theme
|
|
43
|
-
const savedTheme = this.getSavedTheme();
|
|
44
|
-
const systemTheme = this.getSystemTheme();
|
|
45
|
-
const initialTheme = savedTheme || systemTheme;
|
|
46
|
-
this.applyTheme(initialTheme);
|
|
47
|
-
|
|
48
|
-
// Bind event listeners
|
|
49
|
-
this.bindToggleClick();
|
|
50
|
-
this.bindKeyboardShortcut();
|
|
51
|
-
this.bindSystemThemeChange();
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Safely retrieves the saved theme from localStorage
|
|
56
|
-
*/
|
|
57
|
-
private static getSavedTheme(): ThemeMode | null {
|
|
58
|
-
try {
|
|
59
|
-
const saved = localStorage.getItem(this.STORAGE_KEY);
|
|
60
|
-
return saved === 'dark' || saved === 'light' ? saved : null;
|
|
61
|
-
} catch (e) {
|
|
62
|
-
console.warn('localStorage.getItem failed', e);
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Safely saves the theme to localStorage
|
|
69
|
-
*/
|
|
70
|
-
private static saveTheme(theme: ThemeMode): void {
|
|
71
|
-
try {
|
|
72
|
-
localStorage.setItem(this.STORAGE_KEY, theme);
|
|
73
|
-
} catch (e) {
|
|
74
|
-
console.warn('localStorage.setItem failed', e);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Gets the system-preferred theme
|
|
80
|
-
*/
|
|
81
|
-
private static getSystemTheme(): ThemeMode {
|
|
82
|
-
return this.mediaQuery?.matches ? 'dark' : 'light';
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Gets the current active theme
|
|
87
|
-
*/
|
|
88
|
-
private static getCurrentTheme(): ThemeMode {
|
|
89
|
-
const current = this.root.getAttribute('data-theme');
|
|
90
|
-
return current === 'dark' ? 'dark' : 'light';
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Applies a theme to the document
|
|
95
|
-
*/
|
|
96
|
-
private static applyTheme(theme: ThemeMode): void {
|
|
97
|
-
if (!this.elements) return;
|
|
98
|
-
|
|
99
|
-
this.root.setAttribute('data-theme', theme);
|
|
100
|
-
|
|
101
|
-
const isDark = theme === 'dark';
|
|
102
|
-
const { toggleBtn, icon } = this.elements;
|
|
103
|
-
|
|
104
|
-
// Update button state
|
|
105
|
-
toggleBtn.setAttribute('aria-pressed', String(isDark));
|
|
106
|
-
toggleBtn.setAttribute('aria-label', `Switch to ${isDark ? 'light' : 'dark'} mode`);
|
|
107
|
-
|
|
108
|
-
// Update icon
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
icon.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
1
|
+
type ThemeMode = 'light' | 'dark';
|
|
2
|
+
|
|
3
|
+
interface ThemeElements {
|
|
4
|
+
toggleBtn: HTMLElement;
|
|
5
|
+
icon: HTMLElement;
|
|
6
|
+
status: HTMLElement | null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
class Theme {
|
|
10
|
+
private static readonly STORAGE_KEY = 'theme';
|
|
11
|
+
private static root: HTMLElement;
|
|
12
|
+
private static elements: ThemeElements | null = null;
|
|
13
|
+
private static mediaQuery: MediaQueryList | null = null;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Initializes the theme system with toggle functionality and system preference detection
|
|
17
|
+
*/
|
|
18
|
+
public static init(): void {
|
|
19
|
+
this.root = document.documentElement;
|
|
20
|
+
|
|
21
|
+
// Get DOM elements
|
|
22
|
+
const toggleBtn = document.getElementById('theme-toggle');
|
|
23
|
+
const icon = document.getElementById('theme-icon');
|
|
24
|
+
const status = document.getElementById('status');
|
|
25
|
+
|
|
26
|
+
// Validate required elements
|
|
27
|
+
if (!toggleBtn || !icon) {
|
|
28
|
+
console.error('Theme toggle: missing DOM elements', { toggleBtn, icon });
|
|
29
|
+
if (status) {
|
|
30
|
+
status.textContent = 'Error: missing toggle elements (check IDs).';
|
|
31
|
+
}
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this.elements = { toggleBtn, icon, status };
|
|
36
|
+
|
|
37
|
+
// Initialize media query
|
|
38
|
+
if (window.matchMedia) {
|
|
39
|
+
this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Apply initial theme
|
|
43
|
+
const savedTheme = this.getSavedTheme();
|
|
44
|
+
const systemTheme = this.getSystemTheme();
|
|
45
|
+
const initialTheme = savedTheme || systemTheme;
|
|
46
|
+
this.applyTheme(initialTheme);
|
|
47
|
+
|
|
48
|
+
// Bind event listeners
|
|
49
|
+
this.bindToggleClick();
|
|
50
|
+
this.bindKeyboardShortcut();
|
|
51
|
+
this.bindSystemThemeChange();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Safely retrieves the saved theme from localStorage
|
|
56
|
+
*/
|
|
57
|
+
private static getSavedTheme(): ThemeMode | null {
|
|
58
|
+
try {
|
|
59
|
+
const saved = localStorage.getItem(this.STORAGE_KEY);
|
|
60
|
+
return saved === 'dark' || saved === 'light' ? saved : null;
|
|
61
|
+
} catch (e) {
|
|
62
|
+
console.warn('localStorage.getItem failed', e);
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Safely saves the theme to localStorage
|
|
69
|
+
*/
|
|
70
|
+
private static saveTheme(theme: ThemeMode): void {
|
|
71
|
+
try {
|
|
72
|
+
localStorage.setItem(this.STORAGE_KEY, theme);
|
|
73
|
+
} catch (e) {
|
|
74
|
+
console.warn('localStorage.setItem failed', e);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Gets the system-preferred theme
|
|
80
|
+
*/
|
|
81
|
+
private static getSystemTheme(): ThemeMode {
|
|
82
|
+
return this.mediaQuery?.matches ? 'dark' : 'light';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Gets the current active theme
|
|
87
|
+
*/
|
|
88
|
+
private static getCurrentTheme(): ThemeMode {
|
|
89
|
+
const current = this.root.getAttribute('data-theme');
|
|
90
|
+
return current === 'dark' ? 'dark' : 'light';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Applies a theme to the document
|
|
95
|
+
*/
|
|
96
|
+
private static applyTheme(theme: ThemeMode): void {
|
|
97
|
+
if (!this.elements) return;
|
|
98
|
+
|
|
99
|
+
this.root.setAttribute('data-theme', theme);
|
|
100
|
+
|
|
101
|
+
const isDark = theme === 'dark';
|
|
102
|
+
const { toggleBtn, icon } = this.elements;
|
|
103
|
+
|
|
104
|
+
// Update button state
|
|
105
|
+
toggleBtn.setAttribute('aria-pressed', String(isDark));
|
|
106
|
+
toggleBtn.setAttribute('aria-label', `Switch to ${isDark ? 'light' : 'dark'} mode`);
|
|
107
|
+
|
|
108
|
+
// Update icon — SVG sprite via <use> or font icon via class
|
|
109
|
+
const useEl = icon.querySelector('use');
|
|
110
|
+
if (useEl) {
|
|
111
|
+
const iconName = isDark ? icon.dataset.iconDark : icon.dataset.iconLight;
|
|
112
|
+
if (iconName) {
|
|
113
|
+
const existingHref = useEl.getAttribute('href') ?? '';
|
|
114
|
+
const basePath = existingHref.includes('#') ? existingHref.split('#')[0] : '';
|
|
115
|
+
useEl.setAttribute('href', `${basePath}#${iconName}`);
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
if (isDark) {
|
|
119
|
+
icon.classList.remove('icon-light');
|
|
120
|
+
icon.classList.add('icon-dark');
|
|
121
|
+
} else {
|
|
122
|
+
icon.classList.remove('icon-dark');
|
|
123
|
+
icon.classList.add('icon-light');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Toggles between light and dark theme
|
|
130
|
+
*/
|
|
131
|
+
private static toggleTheme(): void {
|
|
132
|
+
if (!this.elements) return;
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
const current = this.getCurrentTheme();
|
|
136
|
+
const next: ThemeMode = current === 'dark' ? 'light' : 'dark';
|
|
137
|
+
|
|
138
|
+
this.saveTheme(next);
|
|
139
|
+
this.applyTheme(next);
|
|
140
|
+
} catch (err) {
|
|
141
|
+
console.error('Error toggling theme', err);
|
|
142
|
+
if (this.elements.status) {
|
|
143
|
+
this.elements.status.textContent = 'Error toggling theme (see console).';
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Binds click event to toggle button
|
|
150
|
+
*/
|
|
151
|
+
private static bindToggleClick(): void {
|
|
152
|
+
if (!this.elements) return;
|
|
153
|
+
|
|
154
|
+
this.elements.toggleBtn.addEventListener('click', () => {
|
|
155
|
+
this.toggleTheme();
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Binds keyboard shortcut (Ctrl/Cmd+J) for theme toggle
|
|
161
|
+
*/
|
|
162
|
+
private static bindKeyboardShortcut(): void {
|
|
163
|
+
window.addEventListener('keydown', (ev: KeyboardEvent) => {
|
|
164
|
+
const isMac = /Mac|iPhone|iPod|iPad/i.test(navigator.platform);
|
|
165
|
+
const modifierPressed = isMac ? ev.metaKey : ev.ctrlKey;
|
|
166
|
+
|
|
167
|
+
if (modifierPressed && ev.key.toLowerCase() === 'j') {
|
|
168
|
+
ev.preventDefault();
|
|
169
|
+
this.toggleTheme();
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Binds listener for system theme changes
|
|
176
|
+
* Only applies if user hasn't explicitly saved a preference
|
|
177
|
+
*/
|
|
178
|
+
private static bindSystemThemeChange(): void {
|
|
179
|
+
if (!this.mediaQuery) return;
|
|
180
|
+
|
|
181
|
+
const handler = (e: MediaQueryListEvent | MediaQueryList): void => {
|
|
182
|
+
// Only apply system theme if user hasn't saved a preference
|
|
183
|
+
if (!this.getSavedTheme()) {
|
|
184
|
+
const matches = 'matches' in e ? e.matches : (e as MediaQueryList).matches;
|
|
185
|
+
this.applyTheme(matches ? 'dark' : 'light');
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// Modern API
|
|
190
|
+
if ('addEventListener' in this.mediaQuery) {
|
|
191
|
+
this.mediaQuery.addEventListener('change', handler as (e: MediaQueryListEvent) => void);
|
|
192
|
+
}
|
|
193
|
+
// Legacy API (deprecated but still supported in older browsers)
|
|
194
|
+
else if ('addListener' in this.mediaQuery) {
|
|
195
|
+
(this.mediaQuery as any).addListener(handler);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Public API: Get the current theme
|
|
201
|
+
*/
|
|
202
|
+
public static getTheme(): ThemeMode {
|
|
203
|
+
return this.getCurrentTheme();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Public API: Set the theme programmatically
|
|
208
|
+
*/
|
|
209
|
+
public static setTheme(theme: ThemeMode): void {
|
|
210
|
+
this.saveTheme(theme);
|
|
211
|
+
this.applyTheme(theme);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Public API: Reset to system preference
|
|
216
|
+
*/
|
|
217
|
+
public static resetToSystem(): void {
|
|
218
|
+
try {
|
|
219
|
+
localStorage.removeItem(this.STORAGE_KEY);
|
|
220
|
+
const systemTheme = this.getSystemTheme();
|
|
221
|
+
this.applyTheme(systemTheme);
|
|
222
|
+
} catch (e) {
|
|
223
|
+
console.warn('Failed to reset theme', e);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Public API: Check if user has a saved preference
|
|
229
|
+
*/
|
|
230
|
+
public static hasSavedPreference(): boolean {
|
|
231
|
+
return this.getSavedTheme() !== null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
225
235
|
export { Theme };
|