@dodlhuat/basix 1.3.4 → 1.4.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/README.md +160 -18
- package/css/checkbox.scss +15 -2
- package/css/color-picker.scss +278 -0
- package/css/datepicker.scss +5 -3
- package/css/push-menu.scss +7 -0
- package/css/stepper.scss +1 -1
- package/css/style.css +291 -6
- package/css/style.css.map +1 -1
- package/css/style.min.css +1 -1
- package/css/style.min.css.map +1 -1
- package/css/style.scss +1 -0
- package/css/table.scss +33 -0
- package/js/bottom-sheet.d.ts +0 -2
- package/js/bottom-sheet.js +0 -2
- package/js/calendar.d.ts +9 -17
- package/js/calendar.js +4 -7
- package/js/carousel.d.ts +0 -2
- package/js/carousel.js +1 -3
- package/js/chart.d.ts +6 -14
- package/js/chart.js +3 -5
- package/js/code-viewer.d.ts +2 -1
- package/js/code-viewer.js +8 -2
- package/js/color-picker.d.ts +50 -0
- package/js/color-picker.js +291 -0
- package/js/context-menu.d.ts +0 -3
- package/js/context-menu.js +0 -3
- package/js/datepicker.d.ts +0 -4
- package/js/datepicker.js +0 -1
- package/js/docs-nav.js +1 -0
- package/js/dropdown.d.ts +1 -4
- package/js/dropdown.js +0 -1
- package/js/editor.d.ts +4 -3
- package/js/editor.js +50 -35
- package/js/file-uploader.d.ts +0 -4
- package/js/file-uploader.js +0 -1
- package/js/flyout-menu.d.ts +0 -2
- package/js/flyout-menu.js +0 -1
- package/js/gallery.d.ts +1 -4
- package/js/gallery.js +18 -23
- package/js/group-picker.d.ts +0 -5
- package/js/group-picker.js +6 -8
- package/js/lightbox.d.ts +1 -4
- package/js/lightbox.js +6 -10
- package/js/modal.d.ts +0 -2
- package/js/modal.js +0 -1
- package/js/popover.d.ts +0 -3
- package/js/popover.js +0 -2
- package/js/position.d.ts +0 -13
- package/js/position.js +0 -12
- package/js/push-menu.d.ts +0 -3
- package/js/push-menu.js +6 -11
- package/js/range-slider.d.ts +0 -1
- package/js/range-slider.js +2 -3
- package/js/scroll.d.ts +0 -2
- package/js/scroll.js +5 -6
- package/js/scrollbar.d.ts +2 -10
- package/js/scrollbar.js +25 -42
- package/js/select.d.ts +2 -3
- package/js/select.js +6 -9
- package/js/sidebar-nav.d.ts +4 -15
- package/js/sidebar-nav.js +21 -35
- package/js/stepper.d.ts +5 -2
- package/js/stepper.js +42 -6
- package/js/table.d.ts +1 -56
- package/js/table.js +4 -56
- package/js/tabs.d.ts +1 -32
- package/js/tabs.js +7 -39
- package/js/theme.d.ts +0 -44
- package/js/theme.js +0 -44
- package/js/timepicker.d.ts +1 -4
- package/js/timepicker.js +1 -2
- package/js/toast.d.ts +0 -2
- package/js/toast.js +0 -1
- package/js/tooltip.d.ts +0 -4
- package/js/tooltip.js +0 -1
- package/js/tree.d.ts +0 -3
- package/js/tree.js +9 -11
- package/js/utils.d.ts +0 -10
- package/js/utils.js +2 -42
- package/js/virtual-dropdown.d.ts +3 -5
- package/js/virtual-dropdown.js +17 -66
- package/package.json +1 -1
package/js/table.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { Select } from
|
|
2
|
-
/** Dynamic data table with sorting, filtering, and pagination. */
|
|
1
|
+
import { Select } from './select.js';
|
|
3
2
|
class Table {
|
|
4
3
|
container;
|
|
5
4
|
data;
|
|
@@ -21,9 +20,9 @@ class Table {
|
|
|
21
20
|
throw new Error(`Table: Element not found for selector "${elementOrSelector}"`);
|
|
22
21
|
}
|
|
23
22
|
this.container = element;
|
|
24
|
-
this.data = options.data
|
|
25
|
-
this.columns = options.columns
|
|
26
|
-
this.pageSize = options.pageSize
|
|
23
|
+
this.data = options.data ?? [];
|
|
24
|
+
this.columns = options.columns ?? [];
|
|
25
|
+
this.pageSize = options.pageSize ?? 10;
|
|
27
26
|
this.currentPage = 1;
|
|
28
27
|
this.sortColumn = null;
|
|
29
28
|
this.sortDirection = 'asc';
|
|
@@ -33,9 +32,6 @@ class Table {
|
|
|
33
32
|
}
|
|
34
33
|
this.init();
|
|
35
34
|
}
|
|
36
|
-
/**
|
|
37
|
-
* Parses an existing HTML table in the DOM to extract data and columns
|
|
38
|
-
*/
|
|
39
35
|
parseTableFromDOM() {
|
|
40
36
|
const table = this.container.querySelector('table');
|
|
41
37
|
if (!table)
|
|
@@ -63,17 +59,11 @@ class Table {
|
|
|
63
59
|
});
|
|
64
60
|
this.container.innerHTML = '';
|
|
65
61
|
}
|
|
66
|
-
/**
|
|
67
|
-
* Initializes the table by rendering controls, structure, and content
|
|
68
|
-
*/
|
|
69
62
|
init() {
|
|
70
63
|
this.renderControls();
|
|
71
64
|
this.renderTableStructure();
|
|
72
65
|
this.render();
|
|
73
66
|
}
|
|
74
|
-
/**
|
|
75
|
-
* Renders the search and page size controls
|
|
76
|
-
*/
|
|
77
67
|
renderControls() {
|
|
78
68
|
const controlsDiv = document.createElement('div');
|
|
79
69
|
controlsDiv.className = 'table-controls';
|
|
@@ -108,9 +98,6 @@ class Table {
|
|
|
108
98
|
this.container.appendChild(controlsDiv);
|
|
109
99
|
new Select('#' + pageSizeSelect.id);
|
|
110
100
|
}
|
|
111
|
-
/**
|
|
112
|
-
* Creates the table structure (table, thead, tbody, pagination container)
|
|
113
|
-
*/
|
|
114
101
|
renderTableStructure() {
|
|
115
102
|
const wrapper = document.createElement('div');
|
|
116
103
|
wrapper.className = 'table-wrapper';
|
|
@@ -140,9 +127,6 @@ class Table {
|
|
|
140
127
|
this.tableHeader = thead;
|
|
141
128
|
this.paginationContainer = paginationDiv;
|
|
142
129
|
}
|
|
143
|
-
/**
|
|
144
|
-
* Returns filtered and sorted data based on current state
|
|
145
|
-
*/
|
|
146
130
|
getFilteredAndSortedData() {
|
|
147
131
|
let processedData = [...this.data];
|
|
148
132
|
if (this.filterText) {
|
|
@@ -173,9 +157,6 @@ class Table {
|
|
|
173
157
|
}
|
|
174
158
|
return processedData;
|
|
175
159
|
}
|
|
176
|
-
/**
|
|
177
|
-
* Renders the table body, pagination, and header sort indicators
|
|
178
|
-
*/
|
|
179
160
|
render() {
|
|
180
161
|
const processedData = this.getFilteredAndSortedData();
|
|
181
162
|
const totalItems = processedData.length;
|
|
@@ -193,9 +174,6 @@ class Table {
|
|
|
193
174
|
this.renderPagination(totalItems, totalPages, startIndex, endIndex);
|
|
194
175
|
this.updateHeaderSortIcons();
|
|
195
176
|
}
|
|
196
|
-
/**
|
|
197
|
-
* Renders the table body rows
|
|
198
|
-
*/
|
|
199
177
|
renderBody(data) {
|
|
200
178
|
this.tableBody.innerHTML = '';
|
|
201
179
|
if (data.length === 0) {
|
|
@@ -219,9 +197,6 @@ class Table {
|
|
|
219
197
|
this.tableBody.appendChild(tr);
|
|
220
198
|
});
|
|
221
199
|
}
|
|
222
|
-
/**
|
|
223
|
-
* Updates the sort direction indicators in table headers
|
|
224
|
-
*/
|
|
225
200
|
updateHeaderSortIcons() {
|
|
226
201
|
const ths = this.tableHeader.querySelectorAll('th');
|
|
227
202
|
ths.forEach(th => {
|
|
@@ -231,9 +206,6 @@ class Table {
|
|
|
231
206
|
}
|
|
232
207
|
});
|
|
233
208
|
}
|
|
234
|
-
/**
|
|
235
|
-
* Renders pagination controls and info
|
|
236
|
-
*/
|
|
237
209
|
renderPagination(totalItems, totalPages, startIndex, endIndex) {
|
|
238
210
|
this.paginationContainer.innerHTML = '';
|
|
239
211
|
if (totalItems === 0)
|
|
@@ -270,17 +242,11 @@ class Table {
|
|
|
270
242
|
buttonsDiv.appendChild(nextBtn);
|
|
271
243
|
this.paginationContainer.appendChild(buttonsDiv);
|
|
272
244
|
}
|
|
273
|
-
/**
|
|
274
|
-
* Handles search input changes
|
|
275
|
-
*/
|
|
276
245
|
handleSearch(text) {
|
|
277
246
|
this.filterText = text;
|
|
278
247
|
this.currentPage = 1;
|
|
279
248
|
this.render();
|
|
280
249
|
}
|
|
281
|
-
/**
|
|
282
|
-
* Handles column header clicks for sorting
|
|
283
|
-
*/
|
|
284
250
|
handleSort(key) {
|
|
285
251
|
if (this.sortColumn === key) {
|
|
286
252
|
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
|
|
@@ -291,24 +257,15 @@ class Table {
|
|
|
291
257
|
}
|
|
292
258
|
this.render();
|
|
293
259
|
}
|
|
294
|
-
/**
|
|
295
|
-
* Handles page size changes
|
|
296
|
-
*/
|
|
297
260
|
handlePageSizeChange(size) {
|
|
298
261
|
this.pageSize = size;
|
|
299
262
|
this.currentPage = 1;
|
|
300
263
|
this.render();
|
|
301
264
|
}
|
|
302
|
-
/**
|
|
303
|
-
* Sets the current page and re-renders
|
|
304
|
-
*/
|
|
305
265
|
setPage(page) {
|
|
306
266
|
this.currentPage = page;
|
|
307
267
|
this.render();
|
|
308
268
|
}
|
|
309
|
-
/**
|
|
310
|
-
* Assigns a unique ID to an element, incrementing if necessary
|
|
311
|
-
*/
|
|
312
269
|
assignUniqueId(element, baseId) {
|
|
313
270
|
if (!element || !baseId)
|
|
314
271
|
return null;
|
|
@@ -327,25 +284,16 @@ class Table {
|
|
|
327
284
|
element.id = uniqueId;
|
|
328
285
|
return uniqueId;
|
|
329
286
|
}
|
|
330
|
-
/**
|
|
331
|
-
* Public API: Updates the table data and re-renders
|
|
332
|
-
*/
|
|
333
287
|
setData(data) {
|
|
334
288
|
this.data = data;
|
|
335
289
|
this.currentPage = 1;
|
|
336
290
|
this.render();
|
|
337
291
|
}
|
|
338
|
-
/**
|
|
339
|
-
* Public API: Updates the columns and re-renders
|
|
340
|
-
*/
|
|
341
292
|
setColumns(columns) {
|
|
342
293
|
this.columns = columns;
|
|
343
294
|
this.container.innerHTML = '';
|
|
344
295
|
this.init();
|
|
345
296
|
}
|
|
346
|
-
/**
|
|
347
|
-
* Public API: Gets the current filtered and sorted data
|
|
348
|
-
*/
|
|
349
297
|
getData() {
|
|
350
298
|
return this.getFilteredAndSortedData();
|
|
351
299
|
}
|
package/js/tabs.d.ts
CHANGED
|
@@ -1,59 +1,28 @@
|
|
|
1
1
|
type TabLayout = 'horizontal' | 'vertical';
|
|
2
2
|
type MenuPosition = 'top' | 'bottom' | 'left' | 'right';
|
|
3
|
-
/** Configuration options for a Tabs instance. */
|
|
4
3
|
interface TabsOptions {
|
|
5
4
|
layout?: TabLayout;
|
|
6
5
|
defaultTab?: number;
|
|
7
6
|
menuPos?: MenuPosition;
|
|
8
7
|
onChange?: (index: number) => void;
|
|
9
8
|
}
|
|
10
|
-
/** Tabbed content component with horizontal/vertical layouts and keyboard navigation. */
|
|
11
9
|
declare class Tabs {
|
|
12
10
|
private container;
|
|
13
11
|
private options;
|
|
14
12
|
private tabItems;
|
|
15
13
|
private tabPanels;
|
|
16
14
|
private currentTab;
|
|
15
|
+
private abortController;
|
|
17
16
|
constructor(elementOrSelector: string | HTMLElement, options?: TabsOptions);
|
|
18
|
-
/**
|
|
19
|
-
* Initializes the tabs component
|
|
20
|
-
*/
|
|
21
17
|
private init;
|
|
22
|
-
/**
|
|
23
|
-
* Binds click events to tab items
|
|
24
|
-
*/
|
|
25
18
|
private bindEvents;
|
|
26
|
-
/**
|
|
27
|
-
* Handles keyboard navigation (Arrow keys, Home, End)
|
|
28
|
-
*/
|
|
29
19
|
private handleKeyboardNavigation;
|
|
30
|
-
/**
|
|
31
|
-
* Activates a tab by index
|
|
32
|
-
*/
|
|
33
20
|
private activateTab;
|
|
34
|
-
/**
|
|
35
|
-
* Public API: Programmatically activate a tab
|
|
36
|
-
*/
|
|
37
21
|
goToTab(index: number): void;
|
|
38
|
-
/**
|
|
39
|
-
* Public API: Get the currently active tab index
|
|
40
|
-
*/
|
|
41
22
|
getCurrentTab(): number;
|
|
42
|
-
/**
|
|
43
|
-
* Public API: Get the total number of tabs
|
|
44
|
-
*/
|
|
45
23
|
getTabCount(): number;
|
|
46
|
-
/**
|
|
47
|
-
* Public API: Enable a tab
|
|
48
|
-
*/
|
|
49
24
|
enableTab(index: number): void;
|
|
50
|
-
/**
|
|
51
|
-
* Public API: Disable a tab
|
|
52
|
-
*/
|
|
53
25
|
disableTab(index: number): void;
|
|
54
|
-
/**
|
|
55
|
-
* Public API: Destroy the tabs instance and clean up
|
|
56
|
-
*/
|
|
57
26
|
destroy(): void;
|
|
58
27
|
}
|
|
59
28
|
export { Tabs };
|
package/js/tabs.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/** Tabbed content component with horizontal/vertical layouts and keyboard navigation. */
|
|
2
1
|
class Tabs {
|
|
3
2
|
container;
|
|
4
3
|
options;
|
|
5
4
|
tabItems;
|
|
6
5
|
tabPanels;
|
|
7
6
|
currentTab;
|
|
7
|
+
abortController = new AbortController();
|
|
8
8
|
constructor(elementOrSelector, options = {}) {
|
|
9
9
|
const element = typeof elementOrSelector === 'string'
|
|
10
10
|
? document.querySelector(elementOrSelector)
|
|
@@ -13,11 +13,11 @@ class Tabs {
|
|
|
13
13
|
throw new Error(`Tabs: Element not found for selector "${elementOrSelector}"`);
|
|
14
14
|
}
|
|
15
15
|
this.container = element;
|
|
16
|
-
const layout = options.layout
|
|
16
|
+
const layout = options.layout ?? 'horizontal';
|
|
17
17
|
this.options = {
|
|
18
18
|
layout,
|
|
19
19
|
defaultTab: options.defaultTab ?? 0,
|
|
20
|
-
menuPos: options.menuPos
|
|
20
|
+
menuPos: options.menuPos ?? (layout === 'vertical' ? 'left' : 'top'),
|
|
21
21
|
onChange: options.onChange
|
|
22
22
|
};
|
|
23
23
|
this.currentTab = this.options.defaultTab;
|
|
@@ -25,9 +25,6 @@ class Tabs {
|
|
|
25
25
|
this.tabPanels = this.container.querySelectorAll('.tab-panel');
|
|
26
26
|
this.init();
|
|
27
27
|
}
|
|
28
|
-
/**
|
|
29
|
-
* Initializes the tabs component
|
|
30
|
-
*/
|
|
31
28
|
init() {
|
|
32
29
|
if (this.options.layout === 'vertical') {
|
|
33
30
|
this.container.classList.add('tabs-vertical');
|
|
@@ -48,19 +45,17 @@ class Tabs {
|
|
|
48
45
|
this.bindEvents();
|
|
49
46
|
this.activateTab(this.options.defaultTab);
|
|
50
47
|
}
|
|
51
|
-
/**
|
|
52
|
-
* Binds click events to tab items
|
|
53
|
-
*/
|
|
54
48
|
bindEvents() {
|
|
49
|
+
const sig = { signal: this.abortController.signal };
|
|
55
50
|
this.tabItems.forEach((item, index) => {
|
|
56
51
|
item.addEventListener('click', (e) => {
|
|
57
52
|
e.preventDefault();
|
|
58
53
|
this.activateTab(index);
|
|
59
|
-
});
|
|
54
|
+
}, sig);
|
|
60
55
|
item.addEventListener('keydown', (e) => {
|
|
61
56
|
const keyEvent = e;
|
|
62
57
|
this.handleKeyboardNavigation(keyEvent, index);
|
|
63
|
-
});
|
|
58
|
+
}, sig);
|
|
64
59
|
item.setAttribute('role', 'tab');
|
|
65
60
|
item.setAttribute('tabindex', index === this.options.defaultTab ? '0' : '-1');
|
|
66
61
|
item.setAttribute('aria-selected', index === this.options.defaultTab ? 'true' : 'false');
|
|
@@ -70,9 +65,6 @@ class Tabs {
|
|
|
70
65
|
panel.setAttribute('aria-hidden', index === this.options.defaultTab ? 'false' : 'true');
|
|
71
66
|
});
|
|
72
67
|
}
|
|
73
|
-
/**
|
|
74
|
-
* Handles keyboard navigation (Arrow keys, Home, End)
|
|
75
|
-
*/
|
|
76
68
|
handleKeyboardNavigation(e, currentIndex) {
|
|
77
69
|
let newIndex = currentIndex;
|
|
78
70
|
const isVertical = this.options.layout === 'vertical';
|
|
@@ -117,9 +109,6 @@ class Tabs {
|
|
|
117
109
|
this.tabItems[newIndex].focus();
|
|
118
110
|
}
|
|
119
111
|
}
|
|
120
|
-
/**
|
|
121
|
-
* Activates a tab by index
|
|
122
|
-
*/
|
|
123
112
|
activateTab(index) {
|
|
124
113
|
if (index < 0 || index >= this.tabItems.length) {
|
|
125
114
|
console.warn(`Invalid tab index: ${index}`);
|
|
@@ -145,30 +134,18 @@ class Tabs {
|
|
|
145
134
|
this.options.onChange(index);
|
|
146
135
|
}
|
|
147
136
|
}
|
|
148
|
-
/**
|
|
149
|
-
* Public API: Programmatically activate a tab
|
|
150
|
-
*/
|
|
151
137
|
goToTab(index) {
|
|
152
138
|
this.activateTab(index);
|
|
153
139
|
if (this.tabItems[index]) {
|
|
154
140
|
this.tabItems[index].focus();
|
|
155
141
|
}
|
|
156
142
|
}
|
|
157
|
-
/**
|
|
158
|
-
* Public API: Get the currently active tab index
|
|
159
|
-
*/
|
|
160
143
|
getCurrentTab() {
|
|
161
144
|
return this.currentTab;
|
|
162
145
|
}
|
|
163
|
-
/**
|
|
164
|
-
* Public API: Get the total number of tabs
|
|
165
|
-
*/
|
|
166
146
|
getTabCount() {
|
|
167
147
|
return this.tabItems.length;
|
|
168
148
|
}
|
|
169
|
-
/**
|
|
170
|
-
* Public API: Enable a tab
|
|
171
|
-
*/
|
|
172
149
|
enableTab(index) {
|
|
173
150
|
if (index < 0 || index >= this.tabItems.length)
|
|
174
151
|
return;
|
|
@@ -177,9 +154,6 @@ class Tabs {
|
|
|
177
154
|
tab.removeAttribute('aria-disabled');
|
|
178
155
|
tab.style.pointerEvents = '';
|
|
179
156
|
}
|
|
180
|
-
/**
|
|
181
|
-
* Public API: Disable a tab
|
|
182
|
-
*/
|
|
183
157
|
disableTab(index) {
|
|
184
158
|
if (index < 0 || index >= this.tabItems.length)
|
|
185
159
|
return;
|
|
@@ -194,14 +168,8 @@ class Tabs {
|
|
|
194
168
|
}
|
|
195
169
|
}
|
|
196
170
|
}
|
|
197
|
-
/**
|
|
198
|
-
* Public API: Destroy the tabs instance and clean up
|
|
199
|
-
*/
|
|
200
171
|
destroy() {
|
|
201
|
-
this.
|
|
202
|
-
const newItem = item.cloneNode(true);
|
|
203
|
-
item.parentNode?.replaceChild(newItem, item);
|
|
204
|
-
});
|
|
172
|
+
this.abortController.abort();
|
|
205
173
|
this.container.classList.remove('tabs-vertical');
|
|
206
174
|
this.tabItems.forEach((item) => {
|
|
207
175
|
item.removeAttribute('role');
|
package/js/theme.d.ts
CHANGED
|
@@ -1,66 +1,22 @@
|
|
|
1
1
|
type ThemeMode = 'light' | 'dark';
|
|
2
|
-
/** Static class for managing light/dark theme switching with system preference and localStorage persistence. */
|
|
3
2
|
declare class Theme {
|
|
4
3
|
private static readonly STORAGE_KEY;
|
|
5
4
|
private static root;
|
|
6
5
|
private static elements;
|
|
7
6
|
private static mediaQuery;
|
|
8
|
-
/**
|
|
9
|
-
* Initializes the theme system with toggle functionality and system preference detection
|
|
10
|
-
*/
|
|
11
7
|
static init(): void;
|
|
12
|
-
/**
|
|
13
|
-
* Safely retrieves the saved theme from localStorage
|
|
14
|
-
*/
|
|
15
8
|
private static getSavedTheme;
|
|
16
|
-
/**
|
|
17
|
-
* Safely saves the theme to localStorage
|
|
18
|
-
*/
|
|
19
9
|
private static saveTheme;
|
|
20
|
-
/**
|
|
21
|
-
* Gets the system-preferred theme
|
|
22
|
-
*/
|
|
23
10
|
private static getSystemTheme;
|
|
24
|
-
/**
|
|
25
|
-
* Gets the current active theme
|
|
26
|
-
*/
|
|
27
11
|
private static getCurrentTheme;
|
|
28
|
-
/**
|
|
29
|
-
* Applies a theme to the document
|
|
30
|
-
*/
|
|
31
12
|
private static applyTheme;
|
|
32
|
-
/**
|
|
33
|
-
* Toggles between light and dark theme
|
|
34
|
-
*/
|
|
35
13
|
private static toggleTheme;
|
|
36
|
-
/**
|
|
37
|
-
* Binds click event to toggle button
|
|
38
|
-
*/
|
|
39
14
|
private static bindToggleClick;
|
|
40
|
-
/**
|
|
41
|
-
* Binds keyboard shortcut (Ctrl/Cmd+J) for theme toggle
|
|
42
|
-
*/
|
|
43
15
|
private static bindKeyboardShortcut;
|
|
44
|
-
/**
|
|
45
|
-
* Binds listener for system theme changes
|
|
46
|
-
* Only applies if user hasn't explicitly saved a preference
|
|
47
|
-
*/
|
|
48
16
|
private static bindSystemThemeChange;
|
|
49
|
-
/**
|
|
50
|
-
* Public API: Get the current theme
|
|
51
|
-
*/
|
|
52
17
|
static getTheme(): ThemeMode;
|
|
53
|
-
/**
|
|
54
|
-
* Public API: Set the theme programmatically
|
|
55
|
-
*/
|
|
56
18
|
static setTheme(theme: ThemeMode): void;
|
|
57
|
-
/**
|
|
58
|
-
* Public API: Reset to system preference
|
|
59
|
-
*/
|
|
60
19
|
static resetToSystem(): void;
|
|
61
|
-
/**
|
|
62
|
-
* Public API: Check if user has a saved preference
|
|
63
|
-
*/
|
|
64
20
|
static hasSavedPreference(): boolean;
|
|
65
21
|
}
|
|
66
22
|
export { Theme };
|
package/js/theme.js
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
/** Static class for managing light/dark theme switching with system preference and localStorage persistence. */
|
|
2
1
|
class Theme {
|
|
3
2
|
static STORAGE_KEY = 'theme';
|
|
4
3
|
static root;
|
|
5
4
|
static elements = null;
|
|
6
5
|
static mediaQuery = null;
|
|
7
|
-
/**
|
|
8
|
-
* Initializes the theme system with toggle functionality and system preference detection
|
|
9
|
-
*/
|
|
10
6
|
static init() {
|
|
11
7
|
this.root = document.documentElement;
|
|
12
8
|
const toggleBtn = document.getElementById('theme-toggle');
|
|
@@ -31,9 +27,6 @@ class Theme {
|
|
|
31
27
|
this.bindKeyboardShortcut();
|
|
32
28
|
this.bindSystemThemeChange();
|
|
33
29
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Safely retrieves the saved theme from localStorage
|
|
36
|
-
*/
|
|
37
30
|
static getSavedTheme() {
|
|
38
31
|
try {
|
|
39
32
|
const saved = localStorage.getItem(this.STORAGE_KEY);
|
|
@@ -44,9 +37,6 @@ class Theme {
|
|
|
44
37
|
return null;
|
|
45
38
|
}
|
|
46
39
|
}
|
|
47
|
-
/**
|
|
48
|
-
* Safely saves the theme to localStorage
|
|
49
|
-
*/
|
|
50
40
|
static saveTheme(theme) {
|
|
51
41
|
try {
|
|
52
42
|
localStorage.setItem(this.STORAGE_KEY, theme);
|
|
@@ -55,22 +45,13 @@ class Theme {
|
|
|
55
45
|
console.warn('localStorage.setItem failed', e);
|
|
56
46
|
}
|
|
57
47
|
}
|
|
58
|
-
/**
|
|
59
|
-
* Gets the system-preferred theme
|
|
60
|
-
*/
|
|
61
48
|
static getSystemTheme() {
|
|
62
49
|
return this.mediaQuery?.matches ? 'dark' : 'light';
|
|
63
50
|
}
|
|
64
|
-
/**
|
|
65
|
-
* Gets the current active theme
|
|
66
|
-
*/
|
|
67
51
|
static getCurrentTheme() {
|
|
68
52
|
const current = this.root.getAttribute('data-theme');
|
|
69
53
|
return current === 'dark' ? 'dark' : 'light';
|
|
70
54
|
}
|
|
71
|
-
/**
|
|
72
|
-
* Applies a theme to the document
|
|
73
|
-
*/
|
|
74
55
|
static applyTheme(theme) {
|
|
75
56
|
if (!this.elements)
|
|
76
57
|
return;
|
|
@@ -99,9 +80,6 @@ class Theme {
|
|
|
99
80
|
}
|
|
100
81
|
}
|
|
101
82
|
}
|
|
102
|
-
/**
|
|
103
|
-
* Toggles between light and dark theme
|
|
104
|
-
*/
|
|
105
83
|
static toggleTheme() {
|
|
106
84
|
if (!this.elements)
|
|
107
85
|
return;
|
|
@@ -118,9 +96,6 @@ class Theme {
|
|
|
118
96
|
}
|
|
119
97
|
}
|
|
120
98
|
}
|
|
121
|
-
/**
|
|
122
|
-
* Binds click event to toggle button
|
|
123
|
-
*/
|
|
124
99
|
static bindToggleClick() {
|
|
125
100
|
if (!this.elements)
|
|
126
101
|
return;
|
|
@@ -128,9 +103,6 @@ class Theme {
|
|
|
128
103
|
this.toggleTheme();
|
|
129
104
|
});
|
|
130
105
|
}
|
|
131
|
-
/**
|
|
132
|
-
* Binds keyboard shortcut (Ctrl/Cmd+J) for theme toggle
|
|
133
|
-
*/
|
|
134
106
|
static bindKeyboardShortcut() {
|
|
135
107
|
window.addEventListener('keydown', (ev) => {
|
|
136
108
|
const isMac = /Mac|iPhone|iPod|iPad/i.test(navigator.platform);
|
|
@@ -141,10 +113,6 @@ class Theme {
|
|
|
141
113
|
}
|
|
142
114
|
});
|
|
143
115
|
}
|
|
144
|
-
/**
|
|
145
|
-
* Binds listener for system theme changes
|
|
146
|
-
* Only applies if user hasn't explicitly saved a preference
|
|
147
|
-
*/
|
|
148
116
|
static bindSystemThemeChange() {
|
|
149
117
|
if (!this.mediaQuery)
|
|
150
118
|
return;
|
|
@@ -161,22 +129,13 @@ class Theme {
|
|
|
161
129
|
this.mediaQuery.addListener(handler);
|
|
162
130
|
}
|
|
163
131
|
}
|
|
164
|
-
/**
|
|
165
|
-
* Public API: Get the current theme
|
|
166
|
-
*/
|
|
167
132
|
static getTheme() {
|
|
168
133
|
return this.getCurrentTheme();
|
|
169
134
|
}
|
|
170
|
-
/**
|
|
171
|
-
* Public API: Set the theme programmatically
|
|
172
|
-
*/
|
|
173
135
|
static setTheme(theme) {
|
|
174
136
|
this.saveTheme(theme);
|
|
175
137
|
this.applyTheme(theme);
|
|
176
138
|
}
|
|
177
|
-
/**
|
|
178
|
-
* Public API: Reset to system preference
|
|
179
|
-
*/
|
|
180
139
|
static resetToSystem() {
|
|
181
140
|
try {
|
|
182
141
|
localStorage.removeItem(this.STORAGE_KEY);
|
|
@@ -187,9 +146,6 @@ class Theme {
|
|
|
187
146
|
console.warn('Failed to reset theme', e);
|
|
188
147
|
}
|
|
189
148
|
}
|
|
190
|
-
/**
|
|
191
|
-
* Public API: Check if user has a saved preference
|
|
192
|
-
*/
|
|
193
149
|
static hasSavedPreference() {
|
|
194
150
|
return this.getSavedTheme() !== null;
|
|
195
151
|
}
|
package/js/timepicker.d.ts
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
/** A start/end time pair as HH:MM strings. */
|
|
2
1
|
interface TimeSpan {
|
|
3
2
|
start: string;
|
|
4
3
|
end: string;
|
|
5
4
|
}
|
|
6
|
-
/** Configuration options for a TimeSpanPicker instance. */
|
|
7
5
|
interface TimeSpanPickerOptions {
|
|
8
6
|
onChange?: (start: string, end: string) => void;
|
|
9
7
|
defaultStart?: string;
|
|
10
8
|
defaultEnd?: string;
|
|
11
9
|
fromString?: string;
|
|
12
|
-
|
|
10
|
+
toLabel?: string;
|
|
13
11
|
}
|
|
14
|
-
/** Interactive time-range picker with a draggable bar and dual time inputs. */
|
|
15
12
|
declare class TimeSpanPicker {
|
|
16
13
|
private container;
|
|
17
14
|
private startTimeInput;
|
package/js/timepicker.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** Interactive time-range picker with a draggable bar and dual time inputs. */
|
|
2
1
|
class TimeSpanPicker {
|
|
3
2
|
container;
|
|
4
3
|
startTimeInput;
|
|
@@ -27,7 +26,7 @@ class TimeSpanPicker {
|
|
|
27
26
|
this.onChange = options?.onChange;
|
|
28
27
|
this.uid = `tsp-${Math.random().toString(36).slice(2, 9)}`;
|
|
29
28
|
this.fromString = options?.fromString ?? 'From';
|
|
30
|
-
this.toLabel = options?.
|
|
29
|
+
this.toLabel = options?.toLabel ?? 'To';
|
|
31
30
|
this.render();
|
|
32
31
|
this.startTimeInput = this.queryEl('.timespan-start');
|
|
33
32
|
this.endTimeInput = this.queryEl('.timespan-end');
|
package/js/toast.d.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
type ToastType = 'success' | 'error' | 'warning' | 'info';
|
|
2
|
-
/** Options for creating a Toast notification. */
|
|
3
2
|
interface ToastOptions {
|
|
4
3
|
content: string;
|
|
5
4
|
header?: string;
|
|
6
5
|
type?: ToastType;
|
|
7
6
|
closeable?: boolean;
|
|
8
7
|
}
|
|
9
|
-
/** Dismissible notification banner with optional auto-hide timer and progress bar. */
|
|
10
8
|
declare class Toast {
|
|
11
9
|
private readonly content;
|
|
12
10
|
private readonly header;
|
package/js/toast.js
CHANGED
package/js/tooltip.d.ts
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
/** Configuration options for a Tooltip instance. */
|
|
2
1
|
interface TooltipOptions {
|
|
3
2
|
position?: 'top' | 'bottom' | 'left' | 'right' | 'auto';
|
|
4
3
|
offset?: number;
|
|
5
4
|
delay?: number;
|
|
6
5
|
className?: string;
|
|
7
|
-
/** Set to true when content is trusted HTML (e.g. from data-tooltip-id).
|
|
8
|
-
* Defaults to false — content is treated as plain text and escaped. */
|
|
9
6
|
isHtml?: boolean;
|
|
10
7
|
}
|
|
11
|
-
/** Lightweight tooltip that positions itself relative to a trigger element. */
|
|
12
8
|
declare class Tooltip {
|
|
13
9
|
private static activeTooltip;
|
|
14
10
|
private static idCounter;
|
package/js/tooltip.js
CHANGED
package/js/tree.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
type NodeType = 'file' | 'folder';
|
|
2
|
-
/** Configuration options for a TreeComponent instance. */
|
|
3
2
|
interface TreeOptions {
|
|
4
3
|
onSelect?: (node: TreeNode) => void;
|
|
5
4
|
}
|
|
6
|
-
/** Represents a single node in a tree structure, either a file or folder. */
|
|
7
5
|
declare class TreeNode {
|
|
8
6
|
label: string;
|
|
9
7
|
type: NodeType;
|
|
@@ -14,7 +12,6 @@ declare class TreeNode {
|
|
|
14
12
|
childrenContainer: HTMLUListElement | null;
|
|
15
13
|
constructor(label: string, type?: NodeType, children?: TreeNode[]);
|
|
16
14
|
}
|
|
17
|
-
/** Renders an interactive collapsible tree view from a list of TreeNode objects. */
|
|
18
15
|
declare class TreeComponent {
|
|
19
16
|
private container;
|
|
20
17
|
private data;
|
package/js/tree.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** Represents a single node in a tree structure, either a file or folder. */
|
|
2
1
|
class TreeNode {
|
|
3
2
|
label;
|
|
4
3
|
type;
|
|
@@ -17,7 +16,6 @@ class TreeNode {
|
|
|
17
16
|
this.childrenContainer = null;
|
|
18
17
|
}
|
|
19
18
|
}
|
|
20
|
-
/** Renders an interactive collapsible tree view from a list of TreeNode objects. */
|
|
21
19
|
class TreeComponent {
|
|
22
20
|
container;
|
|
23
21
|
data;
|
|
@@ -81,18 +79,18 @@ class TreeComponent {
|
|
|
81
79
|
iconDiv.className = 'tree-icon';
|
|
82
80
|
if (type === 'folder') {
|
|
83
81
|
iconDiv.innerHTML = `
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
83
|
+
<path d="M9 18l6-6-6-6" stroke-linecap="round" stroke-linejoin="round"/>
|
|
84
|
+
</svg>
|
|
85
|
+
`;
|
|
88
86
|
}
|
|
89
87
|
else {
|
|
90
88
|
iconDiv.innerHTML = `
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
89
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
90
|
+
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" stroke-linecap="round" stroke-linejoin="round"/>
|
|
91
|
+
<path d="M13 2v7h7" stroke-linecap="round" stroke-linejoin="round"/>
|
|
92
|
+
</svg>
|
|
93
|
+
`;
|
|
96
94
|
}
|
|
97
95
|
return iconDiv;
|
|
98
96
|
}
|