@shohojdhara/atomix 0.3.7 → 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.
Files changed (53) hide show
  1. package/dist/atomix.css +77 -0
  2. package/dist/atomix.css.map +1 -1
  3. package/dist/atomix.min.css +77 -0
  4. package/dist/atomix.min.css.map +1 -1
  5. package/dist/charts.js.map +1 -1
  6. package/dist/core.d.ts +2 -2
  7. package/dist/core.js.map +1 -1
  8. package/dist/forms.js.map +1 -1
  9. package/dist/heavy.js.map +1 -1
  10. package/dist/index.d.ts +578 -515
  11. package/dist/index.esm.js +3157 -2626
  12. package/dist/index.esm.js.map +1 -1
  13. package/dist/index.js +10496 -9973
  14. package/dist/index.js.map +1 -1
  15. package/dist/index.min.js +1 -1
  16. package/dist/index.min.js.map +1 -1
  17. package/dist/theme.d.ts +237 -420
  18. package/dist/theme.js +1629 -1701
  19. package/dist/theme.js.map +1 -1
  20. package/package.json +1 -1
  21. package/src/components/DataTable/DataTable.stories.tsx +238 -0
  22. package/src/components/DataTable/DataTable.test.tsx +450 -0
  23. package/src/components/DataTable/DataTable.tsx +384 -61
  24. package/src/components/DatePicker/DatePicker.tsx +29 -38
  25. package/src/components/Upload/Upload.tsx +539 -40
  26. package/src/lib/composables/useDataTable.ts +355 -15
  27. package/src/lib/composables/useDatePicker.ts +19 -0
  28. package/src/lib/constants/components.ts +10 -0
  29. package/src/lib/theme/adapters/cssVariableMapper.ts +29 -14
  30. package/src/lib/theme/adapters/index.ts +1 -4
  31. package/src/lib/theme/config/configLoader.ts +53 -35
  32. package/src/lib/theme/core/composeTheme.ts +22 -30
  33. package/src/lib/theme/core/createTheme.ts +49 -26
  34. package/src/lib/theme/core/index.ts +0 -1
  35. package/src/lib/theme/generators/generateCSSNested.ts +4 -3
  36. package/src/lib/theme/generators/generateCSSVariables.ts +24 -16
  37. package/src/lib/theme/index.ts +10 -17
  38. package/src/lib/theme/runtime/ThemeApplicator.ts +6 -109
  39. package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +3 -3
  40. package/src/lib/theme/runtime/ThemeProvider.tsx +186 -44
  41. package/src/lib/theme/runtime/useTheme.ts +1 -1
  42. package/src/lib/theme/runtime/useThemeTokens.ts +7 -16
  43. package/src/lib/theme/test/testTheme.ts +2 -1
  44. package/src/lib/theme/types.ts +14 -14
  45. package/src/lib/theme/utils/componentTheming.ts +35 -27
  46. package/src/lib/theme/utils/domUtils.ts +57 -15
  47. package/src/lib/theme/utils/injectCSS.ts +0 -1
  48. package/src/lib/theme/utils/themeHelpers.ts +1 -39
  49. package/src/lib/theme/utils/themeUtils.ts +1 -170
  50. package/src/lib/types/components.ts +145 -0
  51. package/src/lib/utils/dataTableExport.ts +143 -0
  52. package/src/styles/06-components/_components.data-table.scss +95 -0
  53. package/src/lib/hooks/useThemeTokens.ts +0 -105
@@ -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 || page > Math.ceil(data.length / pageSize)) return;
304
+ if (page < 1) return;
124
305
  setCurrentPage(page);
125
306
  },
126
- [data.length, pageSize]
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
- // Filter data based on search query
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
- if (!searchQuery) return data;
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
- const lowercaseQuery = searchQuery.toLowerCase();
353
+ const column = columns.find(col => col.key === columnKey);
354
+ if (!column || !column.filterable) return true;
140
355
 
141
- return data.filter(row => {
142
- return columns.some(column => {
143
- const value = row[column.key];
144
- if (value == null) return false;
145
- return String(value).toLowerCase().includes(lowercaseQuery);
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
- }, [data, columns, searchQuery]);
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,
@@ -633,21 +633,31 @@ export const DATA_TABLE_CLASSES = {
633
633
  header: 'c-data-table__header',
634
634
  headerCell: 'c-data-table__header-cell',
635
635
  headerContent: 'c-data-table__header-content',
636
+ headerActions: 'c-data-table__header-actions',
636
637
  sortable: 'c-data-table__header-cell--sortable',
637
638
  sortIcon: 'c-data-table__sort-icon',
638
639
  row: 'c-data-table__row',
640
+ rowSelected: 'c-data-table__row--selected',
639
641
  cell: 'c-data-table__cell',
642
+ selectionCell: 'c-data-table__cell--selection',
640
643
  loadingCell: 'c-data-table__loading-cell',
641
644
  loadingIndicator: 'c-data-table__loading-indicator',
642
645
  emptyCell: 'c-data-table__empty-cell',
643
646
  toolbar: 'c-data-table-toolbar',
647
+ toolbarLeft: 'c-data-table-toolbar__left',
648
+ toolbarRight: 'c-data-table-toolbar__right',
644
649
  search: 'c-data-table-search',
645
650
  searchInput: 'c-data-table-search__input',
651
+ columnFilter: 'c-data-table__column-filter',
646
652
  pagination: 'c-data-table__pagination-container',
647
653
  striped: 'c-data-table--striped',
648
654
  bordered: 'c-data-table--bordered',
649
655
  dense: 'c-data-table--dense',
650
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',
651
661
  open: 'is-open',
652
662
  };
653
663
 
@@ -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
- vars: Record<string, string | number>,
172
- element: HTMLElement = document.documentElement
171
+ vars: Record<string, string | number>,
172
+ element?: HTMLElement
173
173
  ): void {
174
- Object.entries(vars).forEach(([key, value]) => {
175
- element.style.setProperty(key, String(value));
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
- varNames: string[],
187
- element: HTMLElement = document.documentElement
191
+ varNames: string[],
192
+ element?: HTMLElement
188
193
  ): void {
189
- varNames.forEach((varName) => {
190
- element.style.removeProperty(varName);
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
- varName: string,
203
- element: HTMLElement = document.documentElement
212
+ varName: string,
213
+ element?: HTMLElement
204
214
  ): string | null {
205
- return getComputedStyle(element).getPropertyValue(varName).trim() || null;
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 converting between Theme objects and DesignTokens
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 {