@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
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* spacing helpers, and theme value accessors.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type {
|
|
8
|
+
import type { SpacingFunction, SpacingOptions } from '../types';
|
|
9
9
|
|
|
10
10
|
// ============================================================================
|
|
11
11
|
// Color Manipulation Utilities
|
|
@@ -184,172 +184,3 @@ export function createSpacing(spacingInput: SpacingOptions = 4): SpacingFunction
|
|
|
184
184
|
};
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
/**
|
|
188
|
-
* Get spacing value from theme
|
|
189
|
-
*
|
|
190
|
-
* @param theme - Theme object
|
|
191
|
-
* @param values - Spacing multipliers
|
|
192
|
-
* @returns Spacing string
|
|
193
|
-
*/
|
|
194
|
-
export function spacing(theme: Theme, ...values: number[]): string {
|
|
195
|
-
return theme.spacing(...values);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// ============================================================================
|
|
199
|
-
// Theme Value Accessors
|
|
200
|
-
// ============================================================================
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Safely get a nested value from theme using dot notation
|
|
204
|
-
*
|
|
205
|
-
* @param theme - Theme object
|
|
206
|
-
* @param path - Dot-notation path (e.g., 'palette.primary.main')
|
|
207
|
-
* @param fallback - Fallback value if path not found
|
|
208
|
-
* @returns Theme value or fallback
|
|
209
|
-
*/
|
|
210
|
-
export function getThemeValue<T = any>(theme: Theme, path: string, fallback?: T): T {
|
|
211
|
-
const keys = path.split('.');
|
|
212
|
-
let value: any = theme;
|
|
213
|
-
|
|
214
|
-
for (const key of keys) {
|
|
215
|
-
if (value && typeof value === 'object' && key in value) {
|
|
216
|
-
value = value[key];
|
|
217
|
-
} else {
|
|
218
|
-
return fallback as T;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return value as T;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Check if a theme is a JS theme (created with createTheme)
|
|
227
|
-
*/
|
|
228
|
-
export function isJSTheme(theme: any): theme is Theme {
|
|
229
|
-
return theme && typeof theme === 'object' && theme.__isJSTheme === true;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// ============================================================================
|
|
233
|
-
// Responsive Utilities
|
|
234
|
-
// ============================================================================
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Get media query for breakpoint up
|
|
238
|
-
*/
|
|
239
|
-
export function breakpointUp(theme: Theme, key: keyof Theme['breakpoints']['values'] | number): string {
|
|
240
|
-
return theme.breakpoints.up(key);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Get media query for breakpoint down
|
|
245
|
-
*/
|
|
246
|
-
export function breakpointDown(theme: Theme, key: keyof Theme['breakpoints']['values'] | number): string {
|
|
247
|
-
return theme.breakpoints.down(key);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Get media query for breakpoint between
|
|
252
|
-
*/
|
|
253
|
-
export function breakpointBetween(
|
|
254
|
-
theme: Theme,
|
|
255
|
-
start: keyof Theme['breakpoints']['values'] | number,
|
|
256
|
-
end: keyof Theme['breakpoints']['values'] | number
|
|
257
|
-
): string {
|
|
258
|
-
return theme.breakpoints.between(start, end);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// ============================================================================
|
|
262
|
-
// Typography Utilities
|
|
263
|
-
// ============================================================================
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Get typography variant styles
|
|
267
|
-
*/
|
|
268
|
-
export function getTypography(theme: Theme, variant: keyof Theme['typography']): any {
|
|
269
|
-
return theme.typography[variant] ?? {};
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Convert rem to px based on theme font size
|
|
274
|
-
*/
|
|
275
|
-
export function remToPx(theme: Theme, rem: number): number {
|
|
276
|
-
return rem * theme.typography.fontSize;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Convert px to rem based on theme font size
|
|
281
|
-
*/
|
|
282
|
-
export function pxToRem(theme: Theme, px: number): string {
|
|
283
|
-
return `${px / theme.typography.fontSize}rem`;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// ============================================================================
|
|
287
|
-
// Shadow Utilities
|
|
288
|
-
// ============================================================================
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Get shadow value from theme
|
|
292
|
-
*/
|
|
293
|
-
export function getShadow(theme: Theme, level: keyof Theme['shadows']): string {
|
|
294
|
-
return theme.shadows[level] || 'none';
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// ============================================================================
|
|
298
|
-
// Transition Utilities
|
|
299
|
-
// ============================================================================
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Create a transition string
|
|
303
|
-
*/
|
|
304
|
-
export function createTransition(
|
|
305
|
-
theme: Theme,
|
|
306
|
-
props: string | string[],
|
|
307
|
-
options?: {
|
|
308
|
-
duration?: keyof Theme['transitions']['duration'] | number;
|
|
309
|
-
easing?: keyof Theme['transitions']['easing'] | string;
|
|
310
|
-
delay?: number;
|
|
311
|
-
}
|
|
312
|
-
): string {
|
|
313
|
-
const properties = Array.isArray(props) ? props : [props];
|
|
314
|
-
const duration =
|
|
315
|
-
typeof options?.duration === 'number'
|
|
316
|
-
? options.duration
|
|
317
|
-
: theme.transitions.duration[options?.duration || 'standard'];
|
|
318
|
-
const easing =
|
|
319
|
-
typeof options?.easing === 'string' && !options.easing.includes('(')
|
|
320
|
-
? theme.transitions.easing[options.easing as keyof Theme['transitions']['easing']]
|
|
321
|
-
: options?.easing || theme.transitions.easing.easeInOut;
|
|
322
|
-
const delay = options?.delay || 0;
|
|
323
|
-
|
|
324
|
-
return properties
|
|
325
|
-
.map((prop) => `${prop} ${duration}ms ${easing}${delay ? ` ${delay}ms` : ''}`)
|
|
326
|
-
.join(', ');
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
* Get transition duration
|
|
331
|
-
*/
|
|
332
|
-
export function getTransitionDuration(
|
|
333
|
-
theme: Theme,
|
|
334
|
-
key: keyof Theme['transitions']['duration']
|
|
335
|
-
): number {
|
|
336
|
-
return theme.transitions.duration[key] ?? 300;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* Get transition easing
|
|
341
|
-
*/
|
|
342
|
-
export function getTransitionEasing(theme: Theme, key: keyof Theme['transitions']['easing']): string {
|
|
343
|
-
return theme.transitions.easing[key] ?? 'cubic-bezier(0.4, 0, 0.2, 1)';
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// ============================================================================
|
|
347
|
-
// Z-Index Utilities
|
|
348
|
-
// ============================================================================
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Get z-index value from theme
|
|
352
|
-
*/
|
|
353
|
-
export function getZIndex(theme: Theme, key: keyof Theme['zIndex']): number {
|
|
354
|
-
return theme.zIndex[key] ?? 0;
|
|
355
|
-
}
|
|
@@ -1644,6 +1644,46 @@ export interface DataTableColumn {
|
|
|
1644
1644
|
* Width of the column (CSS value)
|
|
1645
1645
|
*/
|
|
1646
1646
|
width?: string;
|
|
1647
|
+
|
|
1648
|
+
/**
|
|
1649
|
+
* Minimum width for resizable columns (CSS value)
|
|
1650
|
+
*/
|
|
1651
|
+
minWidth?: string;
|
|
1652
|
+
|
|
1653
|
+
/**
|
|
1654
|
+
* Maximum width for resizable columns (CSS value)
|
|
1655
|
+
*/
|
|
1656
|
+
maxWidth?: string;
|
|
1657
|
+
|
|
1658
|
+
/**
|
|
1659
|
+
* Whether the column is resizable
|
|
1660
|
+
*/
|
|
1661
|
+
resizable?: boolean;
|
|
1662
|
+
|
|
1663
|
+
/**
|
|
1664
|
+
* Whether the column is visible by default
|
|
1665
|
+
*/
|
|
1666
|
+
visible?: boolean;
|
|
1667
|
+
|
|
1668
|
+
/**
|
|
1669
|
+
* Whether the column can be reordered
|
|
1670
|
+
*/
|
|
1671
|
+
reorderable?: boolean;
|
|
1672
|
+
|
|
1673
|
+
/**
|
|
1674
|
+
* Custom filter function for column-specific filtering
|
|
1675
|
+
*/
|
|
1676
|
+
filterFunction?: (value: any, filterValue: string) => boolean;
|
|
1677
|
+
|
|
1678
|
+
/**
|
|
1679
|
+
* Filter type for column-specific filtering
|
|
1680
|
+
*/
|
|
1681
|
+
filterType?: 'text' | 'select' | 'date' | 'number' | 'custom';
|
|
1682
|
+
|
|
1683
|
+
/**
|
|
1684
|
+
* Options for select-type filters
|
|
1685
|
+
*/
|
|
1686
|
+
filterOptions?: Array<{ label: string; value: any }>;
|
|
1647
1687
|
}
|
|
1648
1688
|
|
|
1649
1689
|
/**
|
|
@@ -1661,6 +1701,16 @@ export interface SortConfig {
|
|
|
1661
1701
|
direction: 'asc' | 'desc';
|
|
1662
1702
|
}
|
|
1663
1703
|
|
|
1704
|
+
/**
|
|
1705
|
+
* Row selection mode
|
|
1706
|
+
*/
|
|
1707
|
+
export type SelectionMode = 'single' | 'multiple' | 'none';
|
|
1708
|
+
|
|
1709
|
+
/**
|
|
1710
|
+
* Export format
|
|
1711
|
+
*/
|
|
1712
|
+
export type ExportFormat = 'csv' | 'excel' | 'json';
|
|
1713
|
+
|
|
1664
1714
|
/**
|
|
1665
1715
|
* DataTable component properties
|
|
1666
1716
|
*/
|
|
@@ -1735,6 +1785,101 @@ export interface DataTableProps extends BaseComponentProps {
|
|
|
1735
1785
|
* Can be a boolean to enable with default settings, or an object with AtomixGlassProps to customize the effect
|
|
1736
1786
|
*/
|
|
1737
1787
|
glass?: AtomixGlassProps | boolean;
|
|
1788
|
+
|
|
1789
|
+
/**
|
|
1790
|
+
* Row selection mode ('single', 'multiple', or 'none')
|
|
1791
|
+
*/
|
|
1792
|
+
selectionMode?: SelectionMode;
|
|
1793
|
+
|
|
1794
|
+
/**
|
|
1795
|
+
* Selected row IDs (for controlled selection)
|
|
1796
|
+
*/
|
|
1797
|
+
selectedRowIds?: (string | number)[];
|
|
1798
|
+
|
|
1799
|
+
/**
|
|
1800
|
+
* Callback when selection changes
|
|
1801
|
+
*/
|
|
1802
|
+
onSelectionChange?: (selectedRows: any[], selectedIds: (string | number)[]) => void;
|
|
1803
|
+
|
|
1804
|
+
/**
|
|
1805
|
+
* Key to use as unique identifier for rows (defaults to 'id')
|
|
1806
|
+
*/
|
|
1807
|
+
rowKey?: string | ((row: any) => string | number);
|
|
1808
|
+
|
|
1809
|
+
/**
|
|
1810
|
+
* Whether columns are resizable
|
|
1811
|
+
*/
|
|
1812
|
+
resizable?: boolean;
|
|
1813
|
+
|
|
1814
|
+
/**
|
|
1815
|
+
* Whether columns can be reordered
|
|
1816
|
+
*/
|
|
1817
|
+
reorderable?: boolean;
|
|
1818
|
+
|
|
1819
|
+
/**
|
|
1820
|
+
* Callback when column order changes
|
|
1821
|
+
*/
|
|
1822
|
+
onColumnReorder?: (columnKeys: string[]) => void;
|
|
1823
|
+
|
|
1824
|
+
/**
|
|
1825
|
+
* Whether to show column visibility toggle
|
|
1826
|
+
*/
|
|
1827
|
+
showColumnVisibility?: boolean;
|
|
1828
|
+
|
|
1829
|
+
/**
|
|
1830
|
+
* Callback when column visibility changes
|
|
1831
|
+
*/
|
|
1832
|
+
onColumnVisibilityChange?: (visibleColumns: string[]) => void;
|
|
1833
|
+
|
|
1834
|
+
/**
|
|
1835
|
+
* Whether to enable sticky headers
|
|
1836
|
+
*/
|
|
1837
|
+
stickyHeader?: boolean;
|
|
1838
|
+
|
|
1839
|
+
/**
|
|
1840
|
+
* Offset from top for sticky headers (CSS value)
|
|
1841
|
+
*/
|
|
1842
|
+
stickyHeaderOffset?: string;
|
|
1843
|
+
|
|
1844
|
+
/**
|
|
1845
|
+
* Whether to enable virtual scrolling for large datasets
|
|
1846
|
+
*/
|
|
1847
|
+
virtualScrolling?: boolean;
|
|
1848
|
+
|
|
1849
|
+
/**
|
|
1850
|
+
* Estimated row height for virtual scrolling (in pixels)
|
|
1851
|
+
*/
|
|
1852
|
+
estimatedRowHeight?: number;
|
|
1853
|
+
|
|
1854
|
+
/**
|
|
1855
|
+
* Number of rows to render outside visible area (overscan)
|
|
1856
|
+
*/
|
|
1857
|
+
overscan?: number;
|
|
1858
|
+
|
|
1859
|
+
/**
|
|
1860
|
+
* Whether to enable export functionality
|
|
1861
|
+
*/
|
|
1862
|
+
exportable?: boolean;
|
|
1863
|
+
|
|
1864
|
+
/**
|
|
1865
|
+
* Export formats available
|
|
1866
|
+
*/
|
|
1867
|
+
exportFormats?: ExportFormat[];
|
|
1868
|
+
|
|
1869
|
+
/**
|
|
1870
|
+
* Custom export filename
|
|
1871
|
+
*/
|
|
1872
|
+
exportFilename?: string;
|
|
1873
|
+
|
|
1874
|
+
/**
|
|
1875
|
+
* Callback for custom export logic
|
|
1876
|
+
*/
|
|
1877
|
+
onExport?: (format: ExportFormat, data: any[]) => void;
|
|
1878
|
+
|
|
1879
|
+
/**
|
|
1880
|
+
* Whether to show column-specific filters
|
|
1881
|
+
*/
|
|
1882
|
+
columnFilters?: boolean;
|
|
1738
1883
|
}
|
|
1739
1884
|
|
|
1740
1885
|
/**
|
|
@@ -114,7 +114,7 @@ export function hasCustomization(props: {
|
|
|
114
114
|
* Create data attributes for debugging
|
|
115
115
|
*/
|
|
116
116
|
export function createDebugAttrs(componentName: string, variant?: string): Record<string, string> {
|
|
117
|
-
if (process.env
|
|
117
|
+
if (typeof process === 'undefined' || process.env?.NODE_ENV !== 'development') return {};
|
|
118
118
|
|
|
119
119
|
return {
|
|
120
120
|
'data-component': componentName,
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { DataTableColumn, ExportFormat } from '../types/components';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sanitize cell content to prevent CSV injection
|
|
5
|
+
*/
|
|
6
|
+
function sanitizeCSVCell(cell: any): string {
|
|
7
|
+
const sanitized = String(cell ?? '').replace(/[\r\n\t]/g, ' ').replace(/"/g, '""');
|
|
8
|
+
// Prevent formula injection by prefixing dangerous characters
|
|
9
|
+
const dangerous = /^[=+\-@]/;
|
|
10
|
+
return dangerous.test(sanitized) ? `'${sanitized}` : sanitized;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Export data as CSV
|
|
15
|
+
*/
|
|
16
|
+
export function exportToCSV(
|
|
17
|
+
data: any[],
|
|
18
|
+
columns: DataTableColumn[],
|
|
19
|
+
filename: string = 'data-table.csv'
|
|
20
|
+
): void {
|
|
21
|
+
if (!data.length || !columns.length) return;
|
|
22
|
+
|
|
23
|
+
// Create headers
|
|
24
|
+
const headers = columns.map(col => col.title || col.key);
|
|
25
|
+
|
|
26
|
+
// Create rows
|
|
27
|
+
const rows = data.map(row => {
|
|
28
|
+
return columns.map(col => {
|
|
29
|
+
const value = row[col.key];
|
|
30
|
+
if (col.render) {
|
|
31
|
+
// For rendered cells, try to extract text content
|
|
32
|
+
// This is a simplified approach - in production you might want to handle React elements differently
|
|
33
|
+
return value ?? '';
|
|
34
|
+
}
|
|
35
|
+
return value ?? '';
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Convert to CSV string
|
|
40
|
+
const csvContent = [
|
|
41
|
+
headers.map(h => `"${sanitizeCSVCell(h)}"`).join(','),
|
|
42
|
+
...rows.map(row => row.map(cell => `"${sanitizeCSVCell(cell)}"`).join(',')),
|
|
43
|
+
].join('\n');
|
|
44
|
+
|
|
45
|
+
// Download
|
|
46
|
+
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
|
47
|
+
const url = URL.createObjectURL(blob);
|
|
48
|
+
const link = document.createElement('a');
|
|
49
|
+
link.download = filename.endsWith('.csv') ? filename : `${filename}.csv`;
|
|
50
|
+
link.href = url;
|
|
51
|
+
link.click();
|
|
52
|
+
URL.revokeObjectURL(url);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Export data as JSON
|
|
57
|
+
*/
|
|
58
|
+
export function exportToJSON(
|
|
59
|
+
data: any[],
|
|
60
|
+
filename: string = 'data-table.json'
|
|
61
|
+
): void {
|
|
62
|
+
if (!data.length) return;
|
|
63
|
+
|
|
64
|
+
const jsonContent = JSON.stringify(data, null, 2);
|
|
65
|
+
const blob = new Blob([jsonContent], { type: 'application/json;charset=utf-8;' });
|
|
66
|
+
const url = URL.createObjectURL(blob);
|
|
67
|
+
const link = document.createElement('a');
|
|
68
|
+
link.download = filename.endsWith('.json') ? filename : `${filename}.json`;
|
|
69
|
+
link.href = url;
|
|
70
|
+
link.click();
|
|
71
|
+
URL.revokeObjectURL(url);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Export data as Excel (XLSX) - simplified version using CSV with .xlsx extension
|
|
76
|
+
* Note: For true Excel format, you would need a library like xlsx or exceljs
|
|
77
|
+
*/
|
|
78
|
+
export function exportToExcel(
|
|
79
|
+
data: any[],
|
|
80
|
+
columns: DataTableColumn[],
|
|
81
|
+
filename: string = 'data-table.xlsx'
|
|
82
|
+
): void {
|
|
83
|
+
// For now, we'll export as CSV but with .xlsx extension
|
|
84
|
+
// In a production environment, you'd want to use a library like 'xlsx' or 'exceljs'
|
|
85
|
+
// to create a proper Excel file
|
|
86
|
+
if (!data.length || !columns.length) return;
|
|
87
|
+
|
|
88
|
+
// Create headers
|
|
89
|
+
const headers = columns.map(col => col.title || col.key);
|
|
90
|
+
|
|
91
|
+
// Create rows
|
|
92
|
+
const rows = data.map(row => {
|
|
93
|
+
return columns.map(col => {
|
|
94
|
+
const value = row[col.key];
|
|
95
|
+
return value ?? '';
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Convert to CSV format (Excel can open CSV files)
|
|
100
|
+
const csvContent = [
|
|
101
|
+
headers.map(h => `"${sanitizeCSVCell(h)}"`).join(','),
|
|
102
|
+
...rows.map(row => row.map(cell => `"${sanitizeCSVCell(cell)}"`).join(',')),
|
|
103
|
+
].join('\n');
|
|
104
|
+
|
|
105
|
+
// Download with .xlsx extension (though it's actually CSV)
|
|
106
|
+
// In production, use a proper Excel library
|
|
107
|
+
const blob = new Blob([csvContent], {
|
|
108
|
+
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
109
|
+
});
|
|
110
|
+
const url = URL.createObjectURL(blob);
|
|
111
|
+
const link = document.createElement('a');
|
|
112
|
+
link.download = filename.endsWith('.xlsx') ? filename : `${filename}.xlsx`;
|
|
113
|
+
link.href = url;
|
|
114
|
+
link.click();
|
|
115
|
+
URL.revokeObjectURL(url);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Export data in the specified format
|
|
120
|
+
*/
|
|
121
|
+
export function exportData(
|
|
122
|
+
format: ExportFormat,
|
|
123
|
+
data: any[],
|
|
124
|
+
columns: DataTableColumn[],
|
|
125
|
+
filename?: string
|
|
126
|
+
): void {
|
|
127
|
+
const defaultFilename = filename || 'data-table';
|
|
128
|
+
|
|
129
|
+
switch (format) {
|
|
130
|
+
case 'csv':
|
|
131
|
+
exportToCSV(data, columns, defaultFilename);
|
|
132
|
+
break;
|
|
133
|
+
case 'excel':
|
|
134
|
+
exportToExcel(data, columns, defaultFilename);
|
|
135
|
+
break;
|
|
136
|
+
case 'json':
|
|
137
|
+
exportToJSON(data, defaultFilename);
|
|
138
|
+
break;
|
|
139
|
+
default:
|
|
140
|
+
console.warn(`Unsupported export format: ${format}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
@@ -34,7 +34,7 @@ export function isMemoryMonitoringAvailable(): boolean {
|
|
|
34
34
|
return (
|
|
35
35
|
typeof performance !== 'undefined' &&
|
|
36
36
|
'memory' in performance &&
|
|
37
|
-
process.env
|
|
37
|
+
(typeof process === 'undefined' || process.env?.NODE_ENV === 'development')
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -133,7 +133,7 @@ export function monitorMemoryUsage(
|
|
|
133
133
|
if (snapshot) {
|
|
134
134
|
if (callback) {
|
|
135
135
|
callback(snapshot);
|
|
136
|
-
} else if (process.env
|
|
136
|
+
} else if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'development') {
|
|
137
137
|
console.log('[Memory Monitor]', {
|
|
138
138
|
used: formatBytes(snapshot.usedJSHeapSize),
|
|
139
139
|
total: formatBytes(snapshot.totalJSHeapSize),
|
|
@@ -175,7 +175,7 @@ export function trackComponentMemory(componentName: string) {
|
|
|
175
175
|
const after = getMemorySnapshot();
|
|
176
176
|
if (before && after) {
|
|
177
177
|
const leakInfo = detectMemoryLeak(before, after);
|
|
178
|
-
if (leakInfo.hasLeak && process.env
|
|
178
|
+
if (leakInfo.hasLeak && (typeof process === 'undefined' || process.env?.NODE_ENV === 'development')) {
|
|
179
179
|
console.warn(
|
|
180
180
|
`[Memory Monitor] Potential memory leak detected in ${componentName}:`,
|
|
181
181
|
leakInfo
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme Naming Utility
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent naming conventions for CSS classes, CSS variables,
|
|
5
|
+
* and JavaScript properties throughout the theme system.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export class ThemeNaming {
|
|
9
|
+
private static prefix = 'atomix';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Set the global prefix for all theme tokens
|
|
13
|
+
* @param newPrefix - New prefix to use
|
|
14
|
+
*/
|
|
15
|
+
static setPrefix(newPrefix: string): void {
|
|
16
|
+
this.prefix = newPrefix;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get the current prefix
|
|
21
|
+
*/
|
|
22
|
+
static getPrefix(): string {
|
|
23
|
+
return this.prefix;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Convert camelCase to kebab-case for CSS variables
|
|
28
|
+
* @param str - String to convert
|
|
29
|
+
*/
|
|
30
|
+
static camelToKebab(str: string): string {
|
|
31
|
+
return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Convert kebab-case to camelCase for JavaScript properties
|
|
36
|
+
* @param str - String to convert
|
|
37
|
+
*/
|
|
38
|
+
static kebabToCamel(str: string): string {
|
|
39
|
+
return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Create a CSS variable name
|
|
44
|
+
* @param token - Token name in camelCase
|
|
45
|
+
*/
|
|
46
|
+
static cssVar(token: string): string {
|
|
47
|
+
return `--${this.prefix}-${this.camelToKebab(token)}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Create a BEM CSS class name
|
|
52
|
+
* @param block - Block name
|
|
53
|
+
* @param element - Element name (optional)
|
|
54
|
+
* @param modifier - Modifier name (optional)
|
|
55
|
+
*/
|
|
56
|
+
static bemClass(block: string, element?: string, modifier?: string): string {
|
|
57
|
+
let className = `c-${block}`;
|
|
58
|
+
|
|
59
|
+
if (element) {
|
|
60
|
+
className += `__${element}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (modifier) {
|
|
64
|
+
className += `--${modifier}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return className;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Create a variant class name
|
|
72
|
+
* @param component - Component name
|
|
73
|
+
* @param variant - Variant name
|
|
74
|
+
*/
|
|
75
|
+
static variantClass(component: string, variant: string): string {
|
|
76
|
+
return `c-${component}--${variant}`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Create a size class name
|
|
81
|
+
* @param component - Component name
|
|
82
|
+
* @param size - Size name
|
|
83
|
+
*/
|
|
84
|
+
static sizeClass(component: string, size: string): string {
|
|
85
|
+
return `c-${component}--${size}`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Create a state class name
|
|
90
|
+
* @param component - Component name
|
|
91
|
+
* @param state - State name
|
|
92
|
+
*/
|
|
93
|
+
static stateClass(component: string, state: string): string {
|
|
94
|
+
return `c-${component}--${state}`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Create a utility class name
|
|
99
|
+
* @param utility - Utility name
|
|
100
|
+
*/
|
|
101
|
+
static utilityClass(utility: string): string {
|
|
102
|
+
return `u-${utility}`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Create a layout class name
|
|
107
|
+
* @param layout - Layout name
|
|
108
|
+
*/
|
|
109
|
+
static layoutClass(layout: string): string {
|
|
110
|
+
return `l-${layout}`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Create an object class name
|
|
115
|
+
* @param object - Object name
|
|
116
|
+
*/
|
|
117
|
+
static objectClass(object: string): string {
|
|
118
|
+
return `o-${object}`;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Export constants for common naming patterns
|
|
123
|
+
export const THEME_NAMING = {
|
|
124
|
+
PREFIX: 'atomix',
|
|
125
|
+
CSS_VAR: ThemeNaming.cssVar,
|
|
126
|
+
BEM_CLASS: ThemeNaming.bemClass,
|
|
127
|
+
VARIANT_CLASS: ThemeNaming.variantClass,
|
|
128
|
+
SIZE_CLASS: ThemeNaming.sizeClass,
|
|
129
|
+
STATE_CLASS: ThemeNaming.stateClass,
|
|
130
|
+
UTILITY_CLASS: ThemeNaming.utilityClass,
|
|
131
|
+
LAYOUT_CLASS: ThemeNaming.layoutClass,
|
|
132
|
+
OBJECT_CLASS: ThemeNaming.objectClass,
|
|
133
|
+
CAMEL_TO_KEBAB: ThemeNaming.camelToKebab,
|
|
134
|
+
KEBAB_TO_CAMEL: ThemeNaming.kebabToCamel,
|
|
135
|
+
};
|