@shohojdhara/atomix 0.3.6 → 0.3.8
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 +3 -3
- package/dist/atomix.css +77 -0
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +77 -0
- package/dist/atomix.min.css.map +1 -1
- package/dist/charts.js +50 -142
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +2 -2
- package/dist/core.js +179 -274
- package/dist/core.js.map +1 -1
- package/dist/forms.js +50 -142
- package/dist/forms.js.map +1 -1
- package/dist/heavy.js +179 -274
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +1255 -1226
- package/dist/index.esm.js +2806 -2958
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +3113 -3269
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/theme.d.ts +313 -667
- package/dist/theme.js +1818 -2589
- package/dist/theme.js.map +1 -1
- package/package.json +1 -1
- package/src/components/AtomixGlass/AtomixGlass.tsx +128 -356
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +1 -1
- package/src/components/Button/Button.tsx +85 -167
- package/src/components/DataTable/DataTable.stories.tsx +238 -0
- package/src/components/DataTable/DataTable.test.tsx +450 -0
- package/src/components/DataTable/DataTable.tsx +384 -61
- package/src/components/DatePicker/DatePicker.tsx +29 -38
- package/src/components/Upload/Upload.tsx +539 -40
- package/src/lib/composables/useAtomixGlass.ts +7 -7
- package/src/lib/composables/useDataTable.ts +355 -15
- package/src/lib/composables/useDatePicker.ts +19 -0
- package/src/lib/config/loader.ts +2 -3
- package/src/lib/constants/components.ts +17 -0
- package/src/lib/hooks/usePerformanceMonitor.ts +1 -1
- package/src/lib/theme/adapters/cssVariableMapper.ts +29 -14
- package/src/lib/theme/adapters/index.ts +1 -4
- package/src/lib/theme/config/configLoader.ts +82 -223
- package/src/lib/theme/config/loader.ts +15 -21
- package/src/lib/theme/constants/constants.ts +1 -1
- package/src/lib/theme/core/ThemeRegistry.ts +75 -279
- package/src/lib/theme/core/composeTheme.ts +30 -88
- package/src/lib/theme/core/createTheme.ts +88 -51
- package/src/lib/theme/core/createThemeObject.ts +2 -2
- package/src/lib/theme/core/index.ts +15 -2
- package/src/lib/theme/errors/errors.ts +1 -1
- package/src/lib/theme/generators/generateCSSNested.ts +131 -0
- package/src/lib/theme/generators/generateCSSVariables.ts +24 -16
- package/src/lib/theme/generators/index.ts +6 -0
- package/src/lib/theme/index.ts +45 -27
- package/src/lib/theme/runtime/ThemeApplicator.ts +6 -109
- package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +1 -1
- package/src/lib/theme/runtime/ThemeProvider.tsx +393 -544
- package/src/lib/theme/runtime/index.ts +1 -0
- package/src/lib/theme/runtime/useTheme.ts +1 -1
- package/src/lib/theme/runtime/useThemeTokens.ts +122 -0
- package/src/lib/theme/test/testTheme.ts +2 -1
- package/src/lib/theme/types.ts +14 -14
- package/src/lib/theme/utils/componentTheming.ts +140 -0
- package/src/lib/theme/utils/domUtils.ts +57 -15
- package/src/lib/theme/utils/injectCSS.ts +0 -1
- package/src/lib/theme/utils/naming.ts +100 -0
- package/src/lib/theme/utils/themeHelpers.ts +1 -39
- package/src/lib/theme/utils/themeUtils.ts +1 -170
- package/src/lib/types/components.ts +145 -0
- package/src/lib/utils/componentUtils.ts +1 -1
- package/src/lib/utils/dataTableExport.ts +143 -0
- package/src/lib/utils/memoryMonitor.ts +3 -3
- package/src/lib/utils/themeNaming.ts +135 -0
- package/src/styles/06-components/_components.data-table.scss +95 -0
|
@@ -309,14 +309,14 @@ export function useAtomixGlass({
|
|
|
309
309
|
// timestamp: new Date().toISOString(),
|
|
310
310
|
// });
|
|
311
311
|
// }
|
|
312
|
-
} else if (process.env
|
|
312
|
+
} else if ((typeof process === 'undefined' || process.env?.NODE_ENV !== 'production') && debugCornerRadius) {
|
|
313
313
|
// console.log(
|
|
314
314
|
// '[AtomixGlass] No corner radius found, using default:',
|
|
315
315
|
// CONSTANTS.DEFAULT_CORNER_RADIUS
|
|
316
316
|
// );
|
|
317
317
|
}
|
|
318
318
|
} catch (error) {
|
|
319
|
-
if (process.env
|
|
319
|
+
if ((typeof process === 'undefined' || process.env?.NODE_ENV !== 'production') && debugCornerRadius) {
|
|
320
320
|
console.error('[AtomixGlass] Error extracting corner radius:', error);
|
|
321
321
|
}
|
|
322
322
|
}
|
|
@@ -412,7 +412,7 @@ export function useAtomixGlass({
|
|
|
412
412
|
}
|
|
413
413
|
} catch (styleError) {
|
|
414
414
|
// Silently continue if getting computed style fails for this element
|
|
415
|
-
if (process.env
|
|
415
|
+
if (typeof process === 'undefined' || process.env?.NODE_ENV === 'development') {
|
|
416
416
|
console.debug('AtomixGlass: Error getting computed style for element:', styleError);
|
|
417
417
|
}
|
|
418
418
|
}
|
|
@@ -484,7 +484,7 @@ export function useAtomixGlass({
|
|
|
484
484
|
}
|
|
485
485
|
} catch (error) {
|
|
486
486
|
// Enhanced error logging with context
|
|
487
|
-
if (process.env
|
|
487
|
+
if (typeof process === 'undefined' || process.env?.NODE_ENV === 'development') {
|
|
488
488
|
console.warn('AtomixGlass: Error detecting background brightness:', error);
|
|
489
489
|
}
|
|
490
490
|
const result = false;
|
|
@@ -607,7 +607,7 @@ export function useAtomixGlass({
|
|
|
607
607
|
setInternalMouseOffset(newOffset);
|
|
608
608
|
setInternalGlobalMousePosition(globalPos);
|
|
609
609
|
|
|
610
|
-
if (process.env
|
|
610
|
+
if ((typeof process === 'undefined' || process.env?.NODE_ENV !== 'production') && enablePerformanceMonitoring) {
|
|
611
611
|
const endTime = performance.now();
|
|
612
612
|
const duration = endTime - startTime;
|
|
613
613
|
// if (duration > 5) {
|
|
@@ -964,7 +964,7 @@ export function useAtomixGlass({
|
|
|
964
964
|
};
|
|
965
965
|
|
|
966
966
|
// Debug logging
|
|
967
|
-
if (process.env
|
|
967
|
+
if ((typeof process === 'undefined' || process.env?.NODE_ENV !== 'production') && debugOverLight) {
|
|
968
968
|
console.log('[AtomixGlass] OverLight Config:', {
|
|
969
969
|
isOverLight,
|
|
970
970
|
config: {
|
|
@@ -996,7 +996,7 @@ export function useAtomixGlass({
|
|
|
996
996
|
}
|
|
997
997
|
|
|
998
998
|
// Debug logging for non-object configs
|
|
999
|
-
if (process.env
|
|
999
|
+
if ((typeof process === 'undefined' || process.env?.NODE_ENV !== 'production') && debugOverLight) {
|
|
1000
1000
|
console.log('[AtomixGlass] OverLight Config:', {
|
|
1001
1001
|
isOverLight,
|
|
1002
1002
|
configType: typeof overLight === 'boolean' ? (overLight ? 'true' : 'false') : overLight,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useState, useEffect, useCallback, useMemo } from 'react';
|
|
2
|
-
import { DataTableColumn, SortConfig } from '../types/components';
|
|
1
|
+
import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
|
|
2
|
+
import { DataTableColumn, SortConfig, SelectionMode } from '../types/components';
|
|
3
3
|
|
|
4
4
|
export interface UseDataTableProps {
|
|
5
5
|
/**
|
|
@@ -36,6 +36,46 @@ export interface UseDataTableProps {
|
|
|
36
36
|
* Initial sort configuration
|
|
37
37
|
*/
|
|
38
38
|
initialSortConfig?: SortConfig;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Row selection mode
|
|
42
|
+
*/
|
|
43
|
+
selectionMode?: SelectionMode;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Selected row IDs (controlled)
|
|
47
|
+
*/
|
|
48
|
+
selectedRowIds?: (string | number)[];
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Callback when selection changes
|
|
52
|
+
*/
|
|
53
|
+
onSelectionChange?: (selectedRows: any[], selectedIds: (string | number)[]) => void;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Key to use as unique identifier for rows
|
|
57
|
+
*/
|
|
58
|
+
rowKey?: string | ((row: any) => string | number);
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Column-specific filters
|
|
62
|
+
*/
|
|
63
|
+
columnFilters?: boolean;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Whether columns can be reordered
|
|
67
|
+
*/
|
|
68
|
+
reorderable?: boolean;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Callback when column order changes
|
|
72
|
+
*/
|
|
73
|
+
onColumnReorder?: (columnKeys: string[]) => void;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Callback when column visibility changes
|
|
77
|
+
*/
|
|
78
|
+
onColumnVisibilityChange?: (visibleColumns: string[]) => void;
|
|
39
79
|
}
|
|
40
80
|
|
|
41
81
|
export interface UseDataTableReturn {
|
|
@@ -73,6 +113,84 @@ export interface UseDataTableReturn {
|
|
|
73
113
|
* Handle search input
|
|
74
114
|
*/
|
|
75
115
|
handleSearch: (query: string) => void;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Selected row IDs
|
|
119
|
+
*/
|
|
120
|
+
selectedRowIds: (string | number)[];
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Selected rows data
|
|
124
|
+
*/
|
|
125
|
+
selectedRows: any[];
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Handle row selection
|
|
129
|
+
*/
|
|
130
|
+
handleRowSelect: (rowId: string | number, selected: boolean) => void;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Handle select all
|
|
134
|
+
*/
|
|
135
|
+
handleSelectAll: (selected: boolean) => void;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Whether all rows are selected
|
|
139
|
+
*/
|
|
140
|
+
isAllSelected: boolean;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Whether some rows are selected
|
|
144
|
+
*/
|
|
145
|
+
isIndeterminate: boolean;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Column order
|
|
149
|
+
*/
|
|
150
|
+
columnOrder: string[];
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Visible columns
|
|
154
|
+
*/
|
|
155
|
+
visibleColumns: DataTableColumn[];
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Column visibility map
|
|
159
|
+
*/
|
|
160
|
+
columnVisibility: Record<string, boolean>;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Handle column visibility toggle
|
|
164
|
+
*/
|
|
165
|
+
handleColumnVisibilityToggle: (columnKey: string) => void;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Column-specific filter values
|
|
169
|
+
*/
|
|
170
|
+
columnFilterValues: Record<string, string>;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Handle column filter change
|
|
174
|
+
*/
|
|
175
|
+
handleColumnFilterChange: (columnKey: string, value: string) => void;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Clear all column filters
|
|
179
|
+
*/
|
|
180
|
+
clearColumnFilters: () => void;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Get unique row ID
|
|
185
|
+
*/
|
|
186
|
+
function getRowId(row: any, rowKey?: string | ((row: any) => string | number)): string | number {
|
|
187
|
+
if (typeof rowKey === 'function') {
|
|
188
|
+
return rowKey(row);
|
|
189
|
+
}
|
|
190
|
+
if (typeof rowKey === 'string') {
|
|
191
|
+
return row[rowKey];
|
|
192
|
+
}
|
|
193
|
+
return row.id ?? row.key ?? JSON.stringify(row);
|
|
76
194
|
}
|
|
77
195
|
|
|
78
196
|
/**
|
|
@@ -86,6 +204,14 @@ export function useDataTable({
|
|
|
86
204
|
pageSize = 10,
|
|
87
205
|
onSort,
|
|
88
206
|
initialSortConfig,
|
|
207
|
+
selectionMode = 'none',
|
|
208
|
+
selectedRowIds: controlledSelectedRowIds,
|
|
209
|
+
onSelectionChange,
|
|
210
|
+
rowKey,
|
|
211
|
+
columnFilters = false,
|
|
212
|
+
reorderable = false,
|
|
213
|
+
onColumnReorder,
|
|
214
|
+
onColumnVisibilityChange,
|
|
89
215
|
}: UseDataTableProps): UseDataTableReturn {
|
|
90
216
|
// Sort state
|
|
91
217
|
const [sortConfig, setSortConfig] = useState<SortConfig | null>(initialSortConfig || null);
|
|
@@ -96,6 +222,61 @@ export function useDataTable({
|
|
|
96
222
|
// Search state
|
|
97
223
|
const [searchQuery, setSearchQuery] = useState<string>('');
|
|
98
224
|
|
|
225
|
+
// Selection state
|
|
226
|
+
const [internalSelectedRowIds, setInternalSelectedRowIds] = useState<(string | number)[]>([]);
|
|
227
|
+
const selectedRowIds = controlledSelectedRowIds ?? internalSelectedRowIds;
|
|
228
|
+
|
|
229
|
+
// Column order state
|
|
230
|
+
const [columnOrder, setColumnOrder] = useState<string[]>(() => columns.map(col => col.key));
|
|
231
|
+
|
|
232
|
+
// Column visibility state
|
|
233
|
+
const [columnVisibility, setColumnVisibility] = useState<Record<string, boolean>>(() => {
|
|
234
|
+
const visibility: Record<string, boolean> = {};
|
|
235
|
+
columns.forEach(col => {
|
|
236
|
+
visibility[col.key] = col.visible !== false;
|
|
237
|
+
});
|
|
238
|
+
return visibility;
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Column-specific filter values
|
|
242
|
+
const [columnFilterValues, setColumnFilterValues] = useState<Record<string, string>>({});
|
|
243
|
+
|
|
244
|
+
// Update column order when columns prop changes
|
|
245
|
+
useEffect(() => {
|
|
246
|
+
const newOrder = columns.map(col => col.key);
|
|
247
|
+
const currentOrderSet = new Set(columnOrder);
|
|
248
|
+
const newOrderSet = new Set(newOrder);
|
|
249
|
+
|
|
250
|
+
// Only update if there are actual differences
|
|
251
|
+
if (
|
|
252
|
+
newOrder.length !== columnOrder.length ||
|
|
253
|
+
!newOrder.every(key => currentOrderSet.has(key)) ||
|
|
254
|
+
!columnOrder.every(key => newOrderSet.has(key))
|
|
255
|
+
) {
|
|
256
|
+
setColumnOrder(newOrder);
|
|
257
|
+
}
|
|
258
|
+
}, [columns]);
|
|
259
|
+
|
|
260
|
+
// Update column visibility when columns prop changes
|
|
261
|
+
useEffect(() => {
|
|
262
|
+
setColumnVisibility(prev => {
|
|
263
|
+
const updated: Record<string, boolean> = { ...prev };
|
|
264
|
+
columns.forEach(col => {
|
|
265
|
+
if (!(col.key in updated)) {
|
|
266
|
+
updated[col.key] = col.visible !== false;
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
return updated;
|
|
270
|
+
});
|
|
271
|
+
}, [columns]);
|
|
272
|
+
|
|
273
|
+
// Visible columns based on order and visibility
|
|
274
|
+
const visibleColumns = useMemo(() => {
|
|
275
|
+
return columnOrder
|
|
276
|
+
.map(key => columns.find(col => col.key === key))
|
|
277
|
+
.filter((col): col is DataTableColumn => col !== undefined && columnVisibility[col.key] !== false);
|
|
278
|
+
}, [columns, columnOrder, columnVisibility]);
|
|
279
|
+
|
|
99
280
|
// Handle sorting
|
|
100
281
|
const handleSort = useCallback(
|
|
101
282
|
(key: string) => {
|
|
@@ -120,10 +301,10 @@ export function useDataTable({
|
|
|
120
301
|
// Handle page change
|
|
121
302
|
const handlePageChange = useCallback(
|
|
122
303
|
(page: number) => {
|
|
123
|
-
if (page < 1
|
|
304
|
+
if (page < 1) return;
|
|
124
305
|
setCurrentPage(page);
|
|
125
306
|
},
|
|
126
|
-
[
|
|
307
|
+
[]
|
|
127
308
|
);
|
|
128
309
|
|
|
129
310
|
// Handle search
|
|
@@ -132,20 +313,62 @@ export function useDataTable({
|
|
|
132
313
|
setCurrentPage(1); // Reset to first page when searching
|
|
133
314
|
}, []);
|
|
134
315
|
|
|
135
|
-
//
|
|
316
|
+
// Handle column filter change
|
|
317
|
+
const handleColumnFilterChange = useCallback((columnKey: string, value: string) => {
|
|
318
|
+
setColumnFilterValues(prev => ({
|
|
319
|
+
...prev,
|
|
320
|
+
[columnKey]: value,
|
|
321
|
+
}));
|
|
322
|
+
setCurrentPage(1); // Reset to first page when filtering
|
|
323
|
+
}, []);
|
|
324
|
+
|
|
325
|
+
// Clear all column filters
|
|
326
|
+
const clearColumnFilters = useCallback(() => {
|
|
327
|
+
setColumnFilterValues({});
|
|
328
|
+
setCurrentPage(1);
|
|
329
|
+
}, []);
|
|
330
|
+
|
|
331
|
+
// Filter data based on search query and column filters
|
|
136
332
|
const filteredData = useMemo(() => {
|
|
137
|
-
|
|
333
|
+
let result = data;
|
|
334
|
+
|
|
335
|
+
// Apply global search
|
|
336
|
+
if (searchQuery) {
|
|
337
|
+
const lowercaseQuery = searchQuery.toLowerCase();
|
|
338
|
+
result = result.filter(row => {
|
|
339
|
+
return visibleColumns.some(column => {
|
|
340
|
+
const value = row[column.key];
|
|
341
|
+
if (value == null) return false;
|
|
342
|
+
return String(value).toLowerCase().includes(lowercaseQuery);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Apply column-specific filters
|
|
348
|
+
if (columnFilters) {
|
|
349
|
+
result = result.filter(row => {
|
|
350
|
+
return Object.entries(columnFilterValues).every(([columnKey, filterValue]) => {
|
|
351
|
+
if (!filterValue) return true;
|
|
138
352
|
|
|
139
|
-
|
|
353
|
+
const column = columns.find(col => col.key === columnKey);
|
|
354
|
+
if (!column || !column.filterable) return true;
|
|
140
355
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
356
|
+
const cellValue = row[columnKey];
|
|
357
|
+
if (cellValue == null) return false;
|
|
358
|
+
|
|
359
|
+
// Use custom filter function if provided
|
|
360
|
+
if (column.filterFunction) {
|
|
361
|
+
return column.filterFunction(cellValue, filterValue);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Default text filter
|
|
365
|
+
return String(cellValue).toLowerCase().includes(filterValue.toLowerCase());
|
|
366
|
+
});
|
|
146
367
|
});
|
|
147
|
-
}
|
|
148
|
-
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return result;
|
|
371
|
+
}, [data, visibleColumns, searchQuery, columnFilterValues, columnFilters, columns]);
|
|
149
372
|
|
|
150
373
|
// Sort data
|
|
151
374
|
const sortedData = useMemo(() => {
|
|
@@ -182,6 +405,110 @@ export function useDataTable({
|
|
|
182
405
|
return Math.max(1, Math.ceil(sortedData.length / pageSize));
|
|
183
406
|
}, [sortedData.length, paginated, pageSize]);
|
|
184
407
|
|
|
408
|
+
// Selected rows data
|
|
409
|
+
const selectedRows = useMemo(() => {
|
|
410
|
+
if (selectionMode === 'none' || selectedRowIds.length === 0) return [];
|
|
411
|
+
return sortedData.filter(row => selectedRowIds.includes(getRowId(row, rowKey)));
|
|
412
|
+
}, [sortedData, selectedRowIds, selectionMode, rowKey]);
|
|
413
|
+
|
|
414
|
+
// Handle row selection
|
|
415
|
+
const handleRowSelect = useCallback(
|
|
416
|
+
(rowId: string | number, selected: boolean) => {
|
|
417
|
+
if (selectionMode === 'none') return;
|
|
418
|
+
|
|
419
|
+
let newSelectedIds: (string | number)[];
|
|
420
|
+
|
|
421
|
+
if (selectionMode === 'single') {
|
|
422
|
+
newSelectedIds = selected ? [rowId] : [];
|
|
423
|
+
} else {
|
|
424
|
+
// multiple
|
|
425
|
+
if (selected) {
|
|
426
|
+
newSelectedIds = [...selectedRowIds, rowId];
|
|
427
|
+
} else {
|
|
428
|
+
newSelectedIds = selectedRowIds.filter(id => id !== rowId);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (!controlledSelectedRowIds) {
|
|
433
|
+
setInternalSelectedRowIds(newSelectedIds);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if (onSelectionChange) {
|
|
437
|
+
const selectedRowsData = sortedData.filter(row => newSelectedIds.includes(getRowId(row, rowKey)));
|
|
438
|
+
onSelectionChange(selectedRowsData, newSelectedIds);
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
[selectionMode, selectedRowIds, controlledSelectedRowIds, onSelectionChange, sortedData, rowKey]
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
// Handle select all
|
|
445
|
+
const handleSelectAll = useCallback(
|
|
446
|
+
(selected: boolean) => {
|
|
447
|
+
if (selectionMode !== 'multiple') return;
|
|
448
|
+
|
|
449
|
+
const newSelectedIds = selected
|
|
450
|
+
? paginatedData.map(row => getRowId(row, rowKey))
|
|
451
|
+
: [];
|
|
452
|
+
|
|
453
|
+
if (!controlledSelectedRowIds) {
|
|
454
|
+
setInternalSelectedRowIds(newSelectedIds);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (onSelectionChange) {
|
|
458
|
+
const selectedRowsData = sortedData.filter(row => newSelectedIds.includes(getRowId(row, rowKey)));
|
|
459
|
+
onSelectionChange(selectedRowsData, newSelectedIds);
|
|
460
|
+
}
|
|
461
|
+
},
|
|
462
|
+
[selectionMode, paginatedData, sortedData, controlledSelectedRowIds, onSelectionChange, rowKey]
|
|
463
|
+
);
|
|
464
|
+
|
|
465
|
+
// Check if all rows are selected
|
|
466
|
+
const isAllSelected = useMemo(() => {
|
|
467
|
+
if (selectionMode !== 'multiple' || paginatedData.length === 0) return false;
|
|
468
|
+
return paginatedData.every(row => selectedRowIds.includes(getRowId(row, rowKey)));
|
|
469
|
+
}, [selectionMode, paginatedData, selectedRowIds, rowKey]);
|
|
470
|
+
|
|
471
|
+
// Check if some rows are selected (indeterminate)
|
|
472
|
+
const isIndeterminate = useMemo(() => {
|
|
473
|
+
if (selectionMode !== 'multiple' || paginatedData.length === 0) return false;
|
|
474
|
+
const selectedCount = paginatedData.filter(row => selectedRowIds.includes(getRowId(row, rowKey))).length;
|
|
475
|
+
return selectedCount > 0 && selectedCount < paginatedData.length;
|
|
476
|
+
}, [selectionMode, paginatedData, selectedRowIds, rowKey]);
|
|
477
|
+
|
|
478
|
+
// Handle column visibility toggle
|
|
479
|
+
const handleColumnVisibilityToggle = useCallback(
|
|
480
|
+
(columnKey: string) => {
|
|
481
|
+
setColumnVisibility(prev => {
|
|
482
|
+
const updated = { ...prev, [columnKey]: !prev[columnKey] };
|
|
483
|
+
if (onColumnVisibilityChange) {
|
|
484
|
+
const visibleKeys = Object.entries(updated)
|
|
485
|
+
.filter(([, visible]) => visible)
|
|
486
|
+
.map(([key]) => key);
|
|
487
|
+
onColumnVisibilityChange(visibleKeys);
|
|
488
|
+
}
|
|
489
|
+
return updated;
|
|
490
|
+
});
|
|
491
|
+
},
|
|
492
|
+
[onColumnVisibilityChange]
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
// Handle column reorder
|
|
496
|
+
const handleColumnReorder = useCallback(
|
|
497
|
+
(fromIndex: number, toIndex: number) => {
|
|
498
|
+
const newOrder = [...columnOrder];
|
|
499
|
+
const [removed] = newOrder.splice(fromIndex, 1);
|
|
500
|
+
if (removed) {
|
|
501
|
+
newOrder.splice(toIndex, 0, removed);
|
|
502
|
+
setColumnOrder(newOrder);
|
|
503
|
+
|
|
504
|
+
if (onColumnReorder) {
|
|
505
|
+
onColumnReorder(newOrder);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
[columnOrder, onColumnReorder]
|
|
510
|
+
);
|
|
511
|
+
|
|
185
512
|
// Reset to first page when data changes
|
|
186
513
|
useEffect(() => {
|
|
187
514
|
setCurrentPage(1);
|
|
@@ -189,7 +516,7 @@ export function useDataTable({
|
|
|
189
516
|
|
|
190
517
|
// Reset current page if it's out of bounds
|
|
191
518
|
useEffect(() => {
|
|
192
|
-
if (currentPage > totalPages) {
|
|
519
|
+
if (currentPage > totalPages && totalPages > 0) {
|
|
193
520
|
setCurrentPage(Math.max(1, totalPages));
|
|
194
521
|
}
|
|
195
522
|
}, [currentPage, totalPages]);
|
|
@@ -202,6 +529,19 @@ export function useDataTable({
|
|
|
202
529
|
handleSort,
|
|
203
530
|
handlePageChange,
|
|
204
531
|
handleSearch,
|
|
532
|
+
selectedRowIds,
|
|
533
|
+
selectedRows,
|
|
534
|
+
handleRowSelect,
|
|
535
|
+
handleSelectAll,
|
|
536
|
+
isAllSelected,
|
|
537
|
+
isIndeterminate,
|
|
538
|
+
columnOrder,
|
|
539
|
+
visibleColumns,
|
|
540
|
+
columnVisibility,
|
|
541
|
+
handleColumnVisibilityToggle,
|
|
542
|
+
columnFilterValues,
|
|
543
|
+
handleColumnFilterChange,
|
|
544
|
+
clearColumnFilters,
|
|
205
545
|
};
|
|
206
546
|
}
|
|
207
547
|
|
|
@@ -248,6 +248,22 @@ export function useDatePicker({
|
|
|
248
248
|
[currentMonth]
|
|
249
249
|
);
|
|
250
250
|
|
|
251
|
+
// Decade navigation handlers
|
|
252
|
+
const handlePrevDecade = useCallback(() => {
|
|
253
|
+
// Move back 12 years (since generateYears shows 12 years)
|
|
254
|
+
setViewDate(new Date(currentYear - 12, currentMonth, 1));
|
|
255
|
+
}, [currentYear, currentMonth]);
|
|
256
|
+
|
|
257
|
+
const handleNextDecade = useCallback(() => {
|
|
258
|
+
// Move forward 12 years (since generateYears shows 12 years)
|
|
259
|
+
setViewDate(new Date(currentYear + 12, currentMonth, 1));
|
|
260
|
+
}, [currentYear, currentMonth]);
|
|
261
|
+
|
|
262
|
+
// Switch from year view back to day view
|
|
263
|
+
const switchToDayView = useCallback(() => {
|
|
264
|
+
setViewMode('days');
|
|
265
|
+
}, []);
|
|
266
|
+
|
|
251
267
|
// Handle today button click
|
|
252
268
|
const handleTodayClick = useCallback(() => {
|
|
253
269
|
const todayDate = new Date();
|
|
@@ -546,8 +562,11 @@ export function useDatePicker({
|
|
|
546
562
|
// View mode handlers
|
|
547
563
|
switchToMonthView,
|
|
548
564
|
switchToYearView,
|
|
565
|
+
switchToDayView,
|
|
549
566
|
selectMonth,
|
|
550
567
|
selectYear,
|
|
568
|
+
handlePrevDecade,
|
|
569
|
+
handleNextDecade,
|
|
551
570
|
|
|
552
571
|
// Data generators
|
|
553
572
|
generateDays,
|
package/src/lib/config/loader.ts
CHANGED
|
@@ -46,7 +46,7 @@ export function loadAtomixConfig(
|
|
|
46
46
|
// In browser environments, config loading is not supported
|
|
47
47
|
if (typeof window !== 'undefined') {
|
|
48
48
|
if (required) {
|
|
49
|
-
throw new Error('
|
|
49
|
+
throw new Error('loadAtomixConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.');
|
|
50
50
|
}
|
|
51
51
|
return defaultConfig;
|
|
52
52
|
}
|
|
@@ -144,5 +144,4 @@ export function resolveConfigPath(): string | null {
|
|
|
144
144
|
return null;
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
export default loadAtomixConfig;
|
|
148
|
-
|
|
147
|
+
export default loadAtomixConfig;
|
|
@@ -32,6 +32,13 @@ export const CLASS_PREFIX = {
|
|
|
32
32
|
/**
|
|
33
33
|
* Button-specific constants
|
|
34
34
|
*/
|
|
35
|
+
export const THEME_NAMING = {
|
|
36
|
+
BUTTON_PREFIX: 'btn',
|
|
37
|
+
ICON_ELEMENT: 'icon',
|
|
38
|
+
LABEL_ELEMENT: 'label',
|
|
39
|
+
SPINNER_ELEMENT: 'spinner',
|
|
40
|
+
};
|
|
41
|
+
|
|
35
42
|
export const BUTTON = {
|
|
36
43
|
BASE_CLASS: 'c-btn',
|
|
37
44
|
ICON_CLASS: 'c-btn__icon',
|
|
@@ -626,21 +633,31 @@ export const DATA_TABLE_CLASSES = {
|
|
|
626
633
|
header: 'c-data-table__header',
|
|
627
634
|
headerCell: 'c-data-table__header-cell',
|
|
628
635
|
headerContent: 'c-data-table__header-content',
|
|
636
|
+
headerActions: 'c-data-table__header-actions',
|
|
629
637
|
sortable: 'c-data-table__header-cell--sortable',
|
|
630
638
|
sortIcon: 'c-data-table__sort-icon',
|
|
631
639
|
row: 'c-data-table__row',
|
|
640
|
+
rowSelected: 'c-data-table__row--selected',
|
|
632
641
|
cell: 'c-data-table__cell',
|
|
642
|
+
selectionCell: 'c-data-table__cell--selection',
|
|
633
643
|
loadingCell: 'c-data-table__loading-cell',
|
|
634
644
|
loadingIndicator: 'c-data-table__loading-indicator',
|
|
635
645
|
emptyCell: 'c-data-table__empty-cell',
|
|
636
646
|
toolbar: 'c-data-table-toolbar',
|
|
647
|
+
toolbarLeft: 'c-data-table-toolbar__left',
|
|
648
|
+
toolbarRight: 'c-data-table-toolbar__right',
|
|
637
649
|
search: 'c-data-table-search',
|
|
638
650
|
searchInput: 'c-data-table-search__input',
|
|
651
|
+
columnFilter: 'c-data-table__column-filter',
|
|
639
652
|
pagination: 'c-data-table__pagination-container',
|
|
640
653
|
striped: 'c-data-table--striped',
|
|
641
654
|
bordered: 'c-data-table--bordered',
|
|
642
655
|
dense: 'c-data-table--dense',
|
|
643
656
|
loading: 'c-data-table--loading',
|
|
657
|
+
stickyHeader: 'c-data-table--sticky-header',
|
|
658
|
+
dragging: 'c-data-table__header-cell--dragging',
|
|
659
|
+
dragOver: 'c-data-table__header-cell--drag-over',
|
|
660
|
+
resizeHandle: 'c-data-table__resize-handle',
|
|
644
661
|
open: 'is-open',
|
|
645
662
|
};
|
|
646
663
|
|
|
@@ -77,7 +77,7 @@ export interface UsePerformanceMonitorOptions {
|
|
|
77
77
|
export function usePerformanceMonitor(options: UsePerformanceMonitorOptions) {
|
|
78
78
|
const {
|
|
79
79
|
componentName,
|
|
80
|
-
logToConsole = process.env
|
|
80
|
+
logToConsole = (typeof process === 'undefined' || process.env?.NODE_ENV === 'development'),
|
|
81
81
|
warnThreshold = 16,
|
|
82
82
|
onMetrics,
|
|
83
83
|
} = options;
|
|
@@ -164,16 +164,21 @@ export function mapSCSSTokensToCSSVars(
|
|
|
164
164
|
/**
|
|
165
165
|
* Apply CSS variables to an element
|
|
166
166
|
*
|
|
167
|
-
* @param element - Target element (defaults to document.documentElement)
|
|
168
167
|
* @param vars - CSS variables to apply
|
|
168
|
+
* @param element - Target element (defaults to document.documentElement)
|
|
169
169
|
*/
|
|
170
170
|
export function applyCSSVariables(
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
vars: Record<string, string | number>,
|
|
172
|
+
element?: HTMLElement
|
|
173
173
|
): void {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
174
|
+
if (typeof window === 'undefined') {
|
|
175
|
+
return; // SSR safety
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const target = element || document.documentElement;
|
|
179
|
+
Object.entries(vars).forEach(([key, value]) => {
|
|
180
|
+
target.style.setProperty(key, String(value));
|
|
181
|
+
});
|
|
177
182
|
}
|
|
178
183
|
|
|
179
184
|
/**
|
|
@@ -183,12 +188,17 @@ export function applyCSSVariables(
|
|
|
183
188
|
* @param element - Target element (defaults to document.documentElement)
|
|
184
189
|
*/
|
|
185
190
|
export function removeCSSVariables(
|
|
186
|
-
|
|
187
|
-
|
|
191
|
+
varNames: string[],
|
|
192
|
+
element?: HTMLElement
|
|
188
193
|
): void {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
194
|
+
if (typeof window === 'undefined') {
|
|
195
|
+
return; // SSR safety
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const target = element || document.documentElement;
|
|
199
|
+
varNames.forEach((varName) => {
|
|
200
|
+
target.style.removeProperty(varName);
|
|
201
|
+
});
|
|
192
202
|
}
|
|
193
203
|
|
|
194
204
|
/**
|
|
@@ -199,10 +209,15 @@ export function removeCSSVariables(
|
|
|
199
209
|
* @returns Variable value or null if not found
|
|
200
210
|
*/
|
|
201
211
|
export function getCSSVariable(
|
|
202
|
-
|
|
203
|
-
|
|
212
|
+
varName: string,
|
|
213
|
+
element?: HTMLElement
|
|
204
214
|
): string | null {
|
|
205
|
-
|
|
215
|
+
if (typeof window === 'undefined') {
|
|
216
|
+
return null; // SSR safety
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const target = element || document.documentElement;
|
|
220
|
+
return getComputedStyle(target).getPropertyValue(varName).trim() || null;
|
|
206
221
|
}
|
|
207
222
|
|
|
208
223
|
/**
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Theme Adapters
|
|
3
3
|
*
|
|
4
|
-
* Adapters for
|
|
4
|
+
* Adapters for working with DesignTokens and CSS variables
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
export {
|
|
8
|
-
themeToDesignTokens,
|
|
9
8
|
designTokensToCSSVars,
|
|
10
|
-
createDesignTokensFromTheme,
|
|
11
|
-
designTokensToTheme,
|
|
12
9
|
} from './themeAdapter';
|
|
13
10
|
|
|
14
11
|
export {
|