@shohojdhara/atomix 0.3.15 → 0.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.
Files changed (245) hide show
  1. package/build-tools/index.d.ts +31 -30
  2. package/build-tools/package.json +4 -21
  3. package/dist/atomix.css +20924 -2611
  4. package/dist/atomix.css.map +1 -1
  5. package/dist/atomix.min.css +76 -2
  6. package/dist/atomix.min.css.map +1 -1
  7. package/dist/build-tools/index.d.ts +31 -30
  8. package/dist/build-tools/package.json +4 -21
  9. package/dist/charts.js.map +1 -1
  10. package/dist/core.js.map +1 -1
  11. package/dist/forms.js.map +1 -1
  12. package/dist/heavy.js.map +1 -1
  13. package/dist/index.d.ts +144 -18
  14. package/dist/index.esm.js +110 -55
  15. package/dist/index.esm.js.map +1 -1
  16. package/dist/index.js +110 -55
  17. package/dist/index.js.map +1 -1
  18. package/dist/index.min.js +1 -1
  19. package/dist/index.min.js.map +1 -1
  20. package/dist/layout.js.map +1 -1
  21. package/dist/theme.d.ts +9 -9
  22. package/dist/theme.js.map +1 -1
  23. package/package.json +1 -1
  24. package/src/components/Accordion/Accordion.stories.tsx +32 -23
  25. package/src/components/Accordion/Accordion.test.tsx +70 -50
  26. package/src/components/Accordion/Accordion.tsx +99 -94
  27. package/src/components/AtomixGlass/AtomixGlass.test.tsx +1 -1
  28. package/src/components/AtomixGlass/GlassFilter.tsx +9 -16
  29. package/src/components/AtomixGlass/glass-utils.ts +4 -3
  30. package/src/components/AtomixGlass/shader-utils.ts +128 -52
  31. package/src/components/AtomixGlass/stories/Playground.stories.tsx +1 -1
  32. package/src/components/AtomixGlass/stories/Shaders.stories.tsx +1 -1
  33. package/src/components/Avatar/Avatar.stories.tsx +45 -62
  34. package/src/components/Avatar/Avatar.tsx +58 -56
  35. package/src/components/Badge/Badge.stories.tsx +20 -9
  36. package/src/components/Badge/Badge.test.tsx +41 -41
  37. package/src/components/Badge/Badge.tsx +64 -62
  38. package/src/components/Block/Block.stories.tsx +14 -4
  39. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +9 -8
  40. package/src/components/Breadcrumb/Breadcrumb.tsx +62 -60
  41. package/src/components/Button/Button.stories.tsx +13 -22
  42. package/src/components/Button/Button.test.tsx +97 -81
  43. package/src/components/Button/Button.tsx +46 -14
  44. package/src/components/Button/ButtonGroup.stories.tsx +37 -32
  45. package/src/components/Button/ButtonGroup.tsx +4 -15
  46. package/src/components/Callout/Callout.stories.tsx +109 -16
  47. package/src/components/Card/Card.stories.tsx +67 -36
  48. package/src/components/Card/Card.tsx +30 -14
  49. package/src/components/Chart/AreaChart.tsx +1 -1
  50. package/src/components/Chart/CandlestickChart.tsx +23 -16
  51. package/src/components/Chart/Chart.stories.tsx +4 -9
  52. package/src/components/Chart/Chart.tsx +40 -44
  53. package/src/components/Chart/ChartRenderer.tsx +39 -12
  54. package/src/components/Chart/ChartToolbar.tsx +21 -5
  55. package/src/components/Chart/DonutChart.tsx +1 -1
  56. package/src/components/Chart/FunnelChart.tsx +4 -1
  57. package/src/components/Chart/GaugeChart.tsx +3 -1
  58. package/src/components/Chart/HeatmapChart.tsx +50 -37
  59. package/src/components/Chart/LineChart.tsx +3 -2
  60. package/src/components/Chart/MultiAxisChart.tsx +24 -16
  61. package/src/components/Chart/RadarChart.tsx +19 -17
  62. package/src/components/Chart/ScatterChart.tsx +29 -21
  63. package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +6 -2
  64. package/src/components/ColorModeToggle/ColorModeToggle.tsx +15 -3
  65. package/src/components/Countdown/Countdown.stories.tsx +7 -7
  66. package/src/components/DataTable/DataTable.stories.tsx +43 -38
  67. package/src/components/DataTable/DataTable.test.tsx +26 -148
  68. package/src/components/DataTable/DataTable.tsx +485 -456
  69. package/src/components/DatePicker/DatePicker.stories.tsx +32 -47
  70. package/src/components/DatePicker/DatePicker.tsx +31 -26
  71. package/src/components/Dropdown/Dropdown.stories.tsx +2 -5
  72. package/src/components/Dropdown/Dropdown.tsx +313 -299
  73. package/src/components/EdgePanel/EdgePanel.stories.tsx +6 -19
  74. package/src/components/EdgePanel/EdgePanel.tsx +1 -3
  75. package/src/components/Footer/Footer.stories.tsx +21 -16
  76. package/src/components/Footer/Footer.tsx +130 -128
  77. package/src/components/Footer/FooterLink.tsx +2 -2
  78. package/src/components/Form/Checkbox.test.tsx +49 -49
  79. package/src/components/Form/Checkbox.tsx +108 -100
  80. package/src/components/Form/Form.stories.tsx +2 -10
  81. package/src/components/Form/Input.stories.tsx +22 -39
  82. package/src/components/Form/Input.test.tsx +38 -44
  83. package/src/components/Form/Radio.stories.tsx +6 -12
  84. package/src/components/Form/Radio.tsx +68 -66
  85. package/src/components/Form/Select.tsx +184 -182
  86. package/src/components/Form/Textarea.test.tsx +27 -32
  87. package/src/components/Hero/Hero.stories.tsx +56 -23
  88. package/src/components/Hero/Hero.tsx +201 -55
  89. package/src/components/Icon/index.ts +7 -1
  90. package/src/components/List/List.tsx +19 -23
  91. package/src/components/Modal/Modal.stories.tsx +2 -1
  92. package/src/components/Modal/Modal.tsx +130 -127
  93. package/src/components/Navigation/Menu/MegaMenu.tsx +70 -70
  94. package/src/components/Navigation/Nav/NavDropdown.tsx +1 -5
  95. package/src/components/Navigation/SideMenu/SideMenu.stories.tsx +128 -28
  96. package/src/components/Navigation/SideMenu/SideMenu.tsx +5 -7
  97. package/src/components/Navigation/SideMenu/SideMenuItem.tsx +4 -5
  98. package/src/components/Pagination/Pagination.stories.tsx +7 -4
  99. package/src/components/Pagination/Pagination.tsx +199 -202
  100. package/src/components/PhotoViewer/PhotoViewer.tsx +4 -1
  101. package/src/components/Popover/Popover.stories.tsx +99 -192
  102. package/src/components/Popover/Popover.tsx +41 -37
  103. package/src/components/Progress/Progress.stories.tsx +35 -44
  104. package/src/components/River/River.stories.tsx +2 -1
  105. package/src/components/SectionIntro/SectionIntro.stories.tsx +71 -71
  106. package/src/components/Slider/Slider.stories.tsx +12 -4
  107. package/src/components/Spinner/Spinner.stories.tsx +3 -1
  108. package/src/components/Spinner/Spinner.test.tsx +23 -23
  109. package/src/components/Spinner/Spinner.tsx +43 -46
  110. package/src/components/Steps/Steps.stories.tsx +8 -6
  111. package/src/components/Tabs/Tabs.stories.tsx +12 -9
  112. package/src/components/Tabs/Tabs.tsx +74 -72
  113. package/src/components/Toggle/Toggle.stories.tsx +27 -13
  114. package/src/components/Toggle/Toggle.test.tsx +65 -70
  115. package/src/components/Toggle/Toggle.tsx +4 -1
  116. package/src/components/Tooltip/Tooltip.stories.tsx +24 -20
  117. package/src/components/Tooltip/Tooltip.tsx +104 -106
  118. package/src/components/Upload/Upload.stories.tsx +129 -127
  119. package/src/components/Upload/Upload.tsx +287 -283
  120. package/src/components/VideoPlayer/VideoPlayer.tsx +6 -1
  121. package/src/components/index.ts +13 -2
  122. package/src/layouts/Grid/Grid.stories.tsx +9 -3
  123. package/src/layouts/MasonryGrid/MasonryGrid.tsx +5 -1
  124. package/src/lib/__tests__/theme-tools.test.ts +32 -6
  125. package/src/lib/composables/shared-mouse-tracker.ts +13 -14
  126. package/src/lib/composables/useAtomixGlass.ts +106 -49
  127. package/src/lib/composables/useChartExport.ts +1 -1
  128. package/src/lib/composables/useDataTable.ts +29 -17
  129. package/src/lib/composables/useHero.ts +58 -14
  130. package/src/lib/composables/useHeroBackgroundSlider.ts +2 -9
  131. package/src/lib/composables/useInput.ts +10 -8
  132. package/src/lib/composables/useSideMenu.ts +6 -5
  133. package/src/lib/composables/useTooltip.ts +1 -2
  134. package/src/lib/composables/useVideoPlayer.ts +44 -35
  135. package/src/lib/config/index.ts +154 -154
  136. package/src/lib/constants/cssVariables.ts +29 -29
  137. package/src/lib/hooks/__tests__/useComponentCustomization.test.ts +2 -6
  138. package/src/lib/hooks/index.ts +1 -1
  139. package/src/lib/hooks/useComponentCustomization.ts +11 -17
  140. package/src/lib/hooks/usePerformanceMonitor.ts +6 -7
  141. package/src/lib/patterns/__tests__/slots.test.ts +1 -1
  142. package/src/lib/patterns/index.ts +1 -1
  143. package/src/lib/patterns/slots.tsx +8 -13
  144. package/src/lib/storybook/InteractiveDemo.tsx +13 -18
  145. package/src/lib/storybook/PreviewContainer.tsx +1 -1
  146. package/src/lib/storybook/VariantsGrid.tsx +3 -7
  147. package/src/lib/storybook/index.ts +1 -1
  148. package/src/lib/theme/adapters/cssVariableMapper.ts +47 -74
  149. package/src/lib/theme/adapters/index.ts +3 -9
  150. package/src/lib/theme/adapters/themeAdapter.ts +41 -26
  151. package/src/lib/theme/config/index.ts +1 -1
  152. package/src/lib/theme/config/types.ts +2 -2
  153. package/src/lib/theme/config/validator.ts +10 -5
  154. package/src/lib/theme/constants/constants.ts +2 -2
  155. package/src/lib/theme/constants/index.ts +1 -2
  156. package/src/lib/theme/core/__tests__/createTheme.test.ts +20 -22
  157. package/src/lib/theme/core/composeTheme.ts +32 -26
  158. package/src/lib/theme/core/createTheme.ts +1 -1
  159. package/src/lib/theme/core/createThemeObject.ts +308 -301
  160. package/src/lib/theme/core/index.ts +3 -3
  161. package/src/lib/theme/devtools/CLI.ts +106 -104
  162. package/src/lib/theme/devtools/Comparator.tsx +50 -32
  163. package/src/lib/theme/devtools/DesignTokensCustomizer.stories.tsx +50 -48
  164. package/src/lib/theme/devtools/DesignTokensCustomizer.tsx +257 -63
  165. package/src/lib/theme/devtools/Inspector.tsx +75 -60
  166. package/src/lib/theme/devtools/LiveEditor.tsx +97 -76
  167. package/src/lib/theme/devtools/Preview.tsx +150 -106
  168. package/src/lib/theme/devtools/ThemeValidator.ts +29 -21
  169. package/src/lib/theme/devtools/index.ts +3 -9
  170. package/src/lib/theme/devtools/useHistory.ts +23 -21
  171. package/src/lib/theme/errors/errors.ts +12 -11
  172. package/src/lib/theme/errors/index.ts +2 -7
  173. package/src/lib/theme/generators/generateCSS.ts +9 -13
  174. package/src/lib/theme/generators/generateCSSNested.ts +1 -6
  175. package/src/lib/theme/generators/generateCSSVariables.ts +673 -630
  176. package/src/lib/theme/generators/index.ts +1 -4
  177. package/src/lib/theme/i18n/index.ts +1 -1
  178. package/src/lib/theme/i18n/rtl.ts +13 -13
  179. package/src/lib/theme/index.ts +7 -16
  180. package/src/lib/theme/runtime/ThemeApplicator.ts +4 -4
  181. package/src/lib/theme/runtime/ThemeContext.tsx +1 -1
  182. package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +19 -23
  183. package/src/lib/theme/runtime/ThemeProvider.tsx +230 -239
  184. package/src/lib/theme/runtime/__tests__/ThemeProvider.integration.test.tsx +1 -1
  185. package/src/lib/theme/runtime/__tests__/ThemeProvider.test.tsx +24 -29
  186. package/src/lib/theme/runtime/index.ts +2 -5
  187. package/src/lib/theme/runtime/useTheme.ts +18 -18
  188. package/src/lib/theme/runtime/useThemeTokens.ts +22 -22
  189. package/src/lib/theme/test/testTheme.ts +15 -16
  190. package/src/lib/theme/tokens/index.ts +2 -7
  191. package/src/lib/theme/tokens/tokens.ts +25 -24
  192. package/src/lib/theme/types.ts +428 -411
  193. package/src/lib/theme/utils/__tests__/themeValidation.test.ts +3 -3
  194. package/src/lib/theme/utils/componentTheming.ts +18 -18
  195. package/src/lib/theme/utils/domUtils.ts +277 -289
  196. package/src/lib/theme/utils/index.ts +1 -2
  197. package/src/lib/theme/utils/injectCSS.ts +10 -14
  198. package/src/lib/theme/utils/naming.ts +20 -16
  199. package/src/lib/theme/utils/themeHelpers.ts +10 -12
  200. package/src/lib/theme/utils/themeUtils.ts +85 -86
  201. package/src/lib/theme/utils/themeValidation.ts +82 -33
  202. package/src/lib/theme-tools.ts +8 -6
  203. package/src/lib/types/components.ts +172 -71
  204. package/src/lib/types/partProps.ts +1 -1
  205. package/src/lib/utils/__tests__/csv.test.ts +1 -1
  206. package/src/lib/utils/componentUtils.ts +8 -12
  207. package/src/lib/utils/csv.ts +3 -1
  208. package/src/lib/utils/dataTableExport.ts +1 -5
  209. package/src/lib/utils/fontPreloader.ts +10 -19
  210. package/src/lib/utils/icons.ts +4 -1
  211. package/src/lib/utils/index.ts +2 -6
  212. package/src/lib/utils/memoryMonitor.ts +10 -8
  213. package/src/lib/utils/themeNaming.ts +2 -2
  214. package/src/styles/01-settings/_index.scss +0 -1
  215. package/src/styles/01-settings/_settings.colors.scss +8 -8
  216. package/src/styles/01-settings/_settings.design-tokens.scss +61 -50
  217. package/src/styles/01-settings/_settings.navbar.scss +1 -1
  218. package/src/styles/01-settings/_settings.spacing.scss +3 -4
  219. package/src/styles/01-settings/_settings.tooltip.scss +1 -1
  220. package/src/styles/01-settings/_settings.typography.scss +1 -1
  221. package/src/styles/02-tools/_tools.button.scss +51 -21
  222. package/src/styles/02-tools/_tools.utility-api.scss +30 -18
  223. package/src/styles/03-generic/_generic.root.scss +4 -3
  224. package/src/styles/06-components/_components.atomix-glass.scss +13 -9
  225. package/src/styles/06-components/_components.button.scss +16 -4
  226. package/src/styles/06-components/_components.callout.scss +27 -21
  227. package/src/styles/06-components/_components.card.scss +5 -14
  228. package/src/styles/06-components/_components.chart.scss +22 -19
  229. package/src/styles/06-components/_components.checkbox.scss +3 -1
  230. package/src/styles/06-components/_components.color-mode-toggle.scss +3 -1
  231. package/src/styles/06-components/_components.edge-panel.scss +9 -2
  232. package/src/styles/06-components/_components.footer.scss +1 -1
  233. package/src/styles/06-components/_components.side-menu.scss +5 -5
  234. package/src/styles/06-components/_components.toggle.scss +18 -0
  235. package/src/styles/06-components/_index.scss +1 -1
  236. package/src/styles/06-components/old.chart.styles.scss +0 -2
  237. package/src/styles/99-utilities/_utilities.border.scss +69 -27
  238. package/src/styles/99-utilities/_utilities.display.scss +1 -1
  239. package/src/styles/99-utilities/_utilities.opacity.scss +10 -0
  240. package/src/styles/99-utilities/_utilities.position.scss +16 -9
  241. package/src/styles/99-utilities/_utilities.scss +1 -1
  242. package/src/styles/99-utilities/_utilities.sizes.scss +47 -18
  243. package/src/styles/99-utilities/_utilities.spacing.scss +118 -66
  244. package/src/styles/99-utilities/_utilities.text-gradient.scss +30 -30
  245. package/src/styles/99-utilities/_utilities.text.scss +67 -46
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Theme Utilities
3
- *
3
+ *
4
4
  * Utility functions for theme operations
5
5
  */
6
6
 
@@ -9,4 +9,3 @@ export * from './themeUtils';
9
9
  export * from './themeValidation';
10
10
  export * from './domUtils';
11
11
  export * from './injectCSS';
12
-
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * CSS Injection Utilities
3
- *
3
+ *
4
4
  * Inject CSS into HTML head via <style> element.
5
5
  */
6
6
 
@@ -13,26 +13,23 @@ function isBrowser(): boolean {
13
13
 
14
14
  /**
15
15
  * Inject CSS into HTML head via <style> element
16
- *
16
+ *
17
17
  * Creates or updates a style element in the document head.
18
18
  * If an element with the same ID exists, it will be updated.
19
- *
19
+ *
20
20
  * @param css - CSS string to inject
21
21
  * @param id - Style element ID (default: 'atomix-theme')
22
- *
22
+ *
23
23
  * @example
24
24
  * ```typescript
25
25
  * const css = ':root { --atomix-color-primary: #7AFFD7; }';
26
26
  * injectCSS(css);
27
- *
27
+ *
28
28
  * // With custom ID
29
29
  * injectCSS(css, 'my-custom-theme');
30
30
  * ```
31
31
  */
32
- export function injectCSS(
33
- css: string,
34
- id: string = 'atomix-theme'
35
- ): void {
32
+ export function injectCSS(css: string, id: string = 'atomix-theme'): void {
36
33
  if (!isBrowser()) {
37
34
  return;
38
35
  }
@@ -51,11 +48,11 @@ export function injectCSS(
51
48
 
52
49
  /**
53
50
  * Remove injected CSS from DOM
54
- *
51
+ *
55
52
  * Removes the style element with the given ID from the document head.
56
- *
53
+ *
57
54
  * @param id - Style element ID to remove (default: 'atomix-theme')
58
- *
55
+ *
59
56
  * @example
60
57
  * ```typescript
61
58
  * removeCSS(); // Removes default 'atomix-theme'
@@ -75,7 +72,7 @@ export function removeCSS(id: string = 'atomix-theme'): void {
75
72
 
76
73
  /**
77
74
  * Check if CSS is already injected
78
- *
75
+ *
79
76
  * @param id - Style element ID to check (default: 'atomix-theme')
80
77
  * @returns True if style element exists
81
78
  */
@@ -86,4 +83,3 @@ export function isCSSInjected(id: string = 'atomix-theme'): boolean {
86
83
 
87
84
  return document.getElementById(id) !== null;
88
85
  }
89
-
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Naming Utilities
3
- *
3
+ *
4
4
  * Provides consistent naming conventions across the theme system
5
5
  */
6
6
 
@@ -14,13 +14,17 @@ export interface NamingOptions {
14
14
  /**
15
15
  * Generate consistent CSS class names following BEM methodology
16
16
  */
17
- export function generateClassName(block: string, element?: string, modifiers?: Record<string, boolean | string>): string {
17
+ export function generateClassName(
18
+ block: string,
19
+ element?: string,
20
+ modifiers?: Record<string, boolean | string>
21
+ ): string {
18
22
  let className = block;
19
-
23
+
20
24
  if (element) {
21
25
  className += `__${element}`;
22
26
  }
23
-
27
+
24
28
  if (modifiers) {
25
29
  Object.entries(modifiers).forEach(([key, value]) => {
26
30
  if (value) {
@@ -31,7 +35,7 @@ export function generateClassName(block: string, element?: string, modifiers?: R
31
35
  }
32
36
  });
33
37
  }
34
-
38
+
35
39
  return className;
36
40
  }
37
41
 
@@ -40,23 +44,23 @@ export function generateClassName(block: string, element?: string, modifiers?: R
40
44
  */
41
45
  export function generateCSSVariableName(property: string, options: NamingOptions = {}): string {
42
46
  const { prefix = 'atomix', component, variant, state } = options;
43
-
47
+
44
48
  const parts = [prefix];
45
-
49
+
46
50
  if (component) {
47
51
  parts.push(component);
48
52
  }
49
-
53
+
50
54
  if (variant) {
51
55
  parts.push(variant);
52
56
  }
53
-
57
+
54
58
  if (state) {
55
59
  parts.push(state);
56
60
  }
57
-
61
+
58
62
  parts.push(property);
59
-
63
+
60
64
  return `--${parts.join('-')}`;
61
65
  }
62
66
 
@@ -65,7 +69,7 @@ export function generateCSSVariableName(property: string, options: NamingOptions
65
69
  */
66
70
  export function normalizeThemeTokens(tokens: Record<string, any>): Record<string, any> {
67
71
  const normalized: Record<string, any> = {};
68
-
72
+
69
73
  for (const [key, value] of Object.entries(tokens)) {
70
74
  if (typeof value === 'object' && value !== null) {
71
75
  // Recursively normalize nested objects
@@ -75,7 +79,7 @@ export function normalizeThemeTokens(tokens: Record<string, any>): Record<string
75
79
  normalized[key] = value;
76
80
  }
77
81
  }
78
-
82
+
79
83
  return normalized;
80
84
  }
81
85
 
@@ -83,7 +87,7 @@ export function normalizeThemeTokens(tokens: Record<string, any>): Record<string
83
87
  * Convert camelCase to kebab-case for CSS custom properties
84
88
  */
85
89
  export function camelToKebab(str: string): string {
86
- return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
90
+ return str.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`);
87
91
  }
88
92
 
89
93
  /**
@@ -95,6 +99,6 @@ export function themePropertyToCSSVar(propertyPath: string, prefix: string = 'at
95
99
  .split('.')
96
100
  .map(part => camelToKebab(part))
97
101
  .join('-');
98
-
102
+
99
103
  return `--${prefix}-${path}`;
100
- }
104
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Theme Helper Functions
3
- *
3
+ *
4
4
  * Utility functions for working with DesignTokens
5
5
  */
6
6
 
@@ -8,33 +8,31 @@ import type { DesignTokens } from '../tokens/tokens';
8
8
 
9
9
  /**
10
10
  * Check if a value is DesignTokens
11
- *
11
+ *
12
12
  * Type guard to check if an object is DesignTokens format.
13
- *
13
+ *
14
14
  * @param value - Value to check
15
15
  * @returns True if value is DesignTokens
16
16
  */
17
17
  export function isDesignTokens(value: unknown): value is DesignTokens {
18
18
  if (!value || typeof value !== 'object') return false;
19
-
19
+
20
20
  // DesignTokens is a flat object with string keys, no nested structures
21
21
  const obj = value as Record<string, unknown>;
22
-
22
+
23
23
  // Check for absence of Theme-specific properties
24
24
  if ('palette' in obj || 'typography' in obj || '__isJSTheme' in obj) {
25
25
  return false;
26
26
  }
27
-
27
+
28
28
  // Check if it has DesignTokens-like structure (flat string keys)
29
29
  const keys = Object.keys(obj);
30
30
  if (keys.length === 0) return false;
31
-
31
+
32
32
  // Check if keys look like DesignTokens (kebab-case, no nesting)
33
- const hasDesignTokenKeys = keys.some(key =>
34
- /^[a-z]+(-[a-z0-9]+)*$/.test(key) &&
35
- typeof obj[key] === 'string'
33
+ const hasDesignTokenKeys = keys.some(
34
+ key => /^[a-z]+(-[a-z0-9]+)*$/.test(key) && typeof obj[key] === 'string'
36
35
  );
37
-
36
+
38
37
  return hasDesignTokenKeys;
39
38
  }
40
-
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Theme Utilities
3
- *
3
+ *
4
4
  * Helper utilities for working with themes, including color manipulation,
5
5
  * spacing helpers, and theme value accessors.
6
6
  */
@@ -15,27 +15,27 @@ import type { SpacingFunction, SpacingOptions } from '../types';
15
15
  * Convert hex color to RGB object
16
16
  */
17
17
  export function hexToRgb(hex: string): { r: number; g: number; b: number } | null {
18
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
19
- return result
20
- ? {
21
- r: parseInt(result[1]!, 16),
22
- g: parseInt(result[2]!, 16),
23
- b: parseInt(result[3]!, 16),
24
- }
25
- : null;
18
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
19
+ return result
20
+ ? {
21
+ r: parseInt(result[1]!, 16),
22
+ g: parseInt(result[2]!, 16),
23
+ b: parseInt(result[3]!, 16),
24
+ }
25
+ : null;
26
26
  }
27
27
 
28
28
  /**
29
29
  * Convert RGB to hex color
30
30
  */
31
31
  export function rgbToHex(r: number, g: number, b: number): string {
32
- const toHex = (val: number) => {
33
- const hex = Math.round(Math.max(0, Math.min(255, val)))
34
- .toString(16)
35
- .padStart(2, '0');
36
- return hex;
37
- };
38
- return `#${toHex(r ?? 0)}${toHex(g ?? 0)}${toHex(b ?? 0)}`;
32
+ const toHex = (val: number) => {
33
+ const hex = Math.round(Math.max(0, Math.min(255, val)))
34
+ .toString(16)
35
+ .padStart(2, '0');
36
+ return hex;
37
+ };
38
+ return `#${toHex(r ?? 0)}${toHex(g ?? 0)}${toHex(b ?? 0)}`;
39
39
  }
40
40
 
41
41
  /**
@@ -43,106 +43,106 @@ export function rgbToHex(r: number, g: number, b: number): string {
43
43
  * Used for determining contrast ratios
44
44
  */
45
45
  export function getLuminance(color: string): number {
46
- const rgb = hexToRgb(color);
47
- if (!rgb) return 0;
46
+ const rgb = hexToRgb(color);
47
+ if (!rgb) return 0;
48
48
 
49
- const { r, g, b } = rgb;
50
- const [rs, gs, bs] = [r ?? 0, g ?? 0, b ?? 0].map((c) => {
51
- const val = c / 255;
52
- return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4);
53
- });
49
+ const { r, g, b } = rgb;
50
+ const [rs, gs, bs] = [r ?? 0, g ?? 0, b ?? 0].map(c => {
51
+ const val = c / 255;
52
+ return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4);
53
+ });
54
54
 
55
- return 0.2126 * (rs ?? 0) + 0.7152 * (gs ?? 0) + 0.0722 * (bs ?? 0);
55
+ return 0.2126 * (rs ?? 0) + 0.7152 * (gs ?? 0) + 0.0722 * (bs ?? 0);
56
56
  }
57
57
 
58
58
  /**
59
59
  * Calculate contrast ratio between two colors
60
60
  */
61
61
  export function getContrastRatio(foreground: string, background: string): number {
62
- const lumA = getLuminance(foreground);
63
- const lumB = getLuminance(background);
64
- return (Math.max(lumA, lumB) + 0.05) / (Math.min(lumA, lumB) + 0.05);
62
+ const lumA = getLuminance(foreground);
63
+ const lumB = getLuminance(background);
64
+ return (Math.max(lumA, lumB) + 0.05) / (Math.min(lumA, lumB) + 0.05);
65
65
  }
66
66
 
67
67
  /**
68
68
  * Get appropriate contrast text color (black or white) for a background color
69
69
  */
70
70
  export function getContrastText(background: string, threshold: number = 3): string {
71
- const contrastWithWhite = getContrastRatio('#FFFFFF', background);
72
- const contrastWithBlack = getContrastRatio('#000000', background);
73
-
74
- if (contrastWithWhite >= threshold) {
75
- return '#FFFFFF';
76
- }
77
- if (contrastWithBlack >= threshold) {
78
- return '#000000';
79
- }
80
-
81
- // Default to white if neither meets threshold
82
- return contrastWithWhite > contrastWithBlack ? '#FFFFFF' : '#000000';
71
+ const contrastWithWhite = getContrastRatio('#FFFFFF', background);
72
+ const contrastWithBlack = getContrastRatio('#000000', background);
73
+
74
+ if (contrastWithWhite >= threshold) {
75
+ return '#FFFFFF';
76
+ }
77
+ if (contrastWithBlack >= threshold) {
78
+ return '#000000';
79
+ }
80
+
81
+ // Default to white if neither meets threshold
82
+ return contrastWithWhite > contrastWithBlack ? '#FFFFFF' : '#000000';
83
83
  }
84
84
 
85
85
  /**
86
86
  * Lighten a color by a given amount
87
- *
87
+ *
88
88
  * @param color - Hex color string
89
89
  * @param amount - Amount to lighten (0-1), default 0.2
90
90
  * @returns Lightened hex color
91
91
  */
92
92
  export function lighten(color: string, amount: number = 0.2): string {
93
- const rgb = hexToRgb(color);
94
- if (!rgb) return color;
93
+ const rgb = hexToRgb(color);
94
+ if (!rgb) return color;
95
95
 
96
- const { r, g, b } = rgb;
97
- const lightenValue = (val: number) => Math.min(255, Math.round(val + (255 - val) * amount));
96
+ const { r, g, b } = rgb;
97
+ const lightenValue = (val: number) => Math.min(255, Math.round(val + (255 - val) * amount));
98
98
 
99
- return rgbToHex(lightenValue(r), lightenValue(g), lightenValue(b));
99
+ return rgbToHex(lightenValue(r), lightenValue(g), lightenValue(b));
100
100
  }
101
101
 
102
102
  /**
103
103
  * Darken a color by a given amount
104
- *
104
+ *
105
105
  * @param color - Hex color string
106
106
  * @param amount - Amount to darken (0-1), default 0.2
107
107
  * @returns Darkened hex color
108
108
  */
109
109
  export function darken(color: string, amount: number = 0.2): string {
110
- const rgb = hexToRgb(color);
111
- if (!rgb) return color;
110
+ const rgb = hexToRgb(color);
111
+ if (!rgb) return color;
112
112
 
113
- const { r, g, b } = rgb;
114
- const darkenValue = (val: number) => Math.max(0, Math.round(val * (1 - amount)));
113
+ const { r, g, b } = rgb;
114
+ const darkenValue = (val: number) => Math.max(0, Math.round(val * (1 - amount)));
115
115
 
116
- return rgbToHex(darkenValue(r), darkenValue(g), darkenValue(b));
116
+ return rgbToHex(darkenValue(r), darkenValue(g), darkenValue(b));
117
117
  }
118
118
 
119
119
  /**
120
120
  * Add alpha (opacity) to a color
121
- *
121
+ *
122
122
  * @param color - Hex color string
123
123
  * @param opacity - Opacity value (0-1)
124
124
  * @returns RGBA color string
125
125
  */
126
126
  export function alpha(color: string, opacity: number): string {
127
- const rgb = hexToRgb(color);
128
- if (!rgb) return color;
127
+ const rgb = hexToRgb(color);
128
+ if (!rgb) return color;
129
129
 
130
- const { r, g, b } = rgb;
131
- const clampedOpacity = Math.max(0, Math.min(1, opacity));
130
+ const { r, g, b } = rgb;
131
+ const clampedOpacity = Math.max(0, Math.min(1, opacity));
132
132
 
133
- return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
133
+ return `rgba(${r}, ${g}, ${b}, ${clampedOpacity})`;
134
134
  }
135
135
 
136
136
  /**
137
137
  * Emphasize a color (lighten if dark, darken if light)
138
- *
138
+ *
139
139
  * @param color - Hex color string
140
140
  * @param coefficient - Amount to emphasize (0-1), default 0.15
141
141
  * @returns Emphasized hex color
142
142
  */
143
143
  export function emphasize(color: string, coefficient: number = 0.15): string {
144
- const luminance = getLuminance(color);
145
- return luminance > 0.5 ? darken(color, coefficient) : lighten(color, coefficient);
144
+ const luminance = getLuminance(color);
145
+ return luminance > 0.5 ? darken(color, coefficient) : lighten(color, coefficient);
146
146
  }
147
147
 
148
148
  // ============================================================================
@@ -151,36 +151,35 @@ export function emphasize(color: string, coefficient: number = 0.15): string {
151
151
 
152
152
  /**
153
153
  * Create a spacing function from various input types
154
- *
154
+ *
155
155
  * @param spacingInput - Spacing configuration (number, array, or function), default 4
156
156
  * @returns Spacing function
157
157
  */
158
158
  export function createSpacing(spacingInput: SpacingOptions = 4): SpacingFunction {
159
- // If it's already a function, return it
160
- if (typeof spacingInput === 'function') {
161
- return spacingInput;
162
- }
163
-
164
- // If it's a number, create a function that multiplies by that number
165
- if (typeof spacingInput === 'number') {
166
- return (...values: number[]) => {
167
- if (values.length === 0) return '0px';
168
- return values.map((value) => `${value * spacingInput}px`).join(' ');
169
- };
170
- }
171
-
172
- // If it's an array, use it as a scale
173
- if (Array.isArray(spacingInput)) {
174
- return (...values: number[]) => {
175
- if (values.length === 0) return '0px';
176
- return values.map((value) => `${spacingInput[value] || value}px`).join(' ');
177
- };
178
- }
179
-
180
- // Default to 4px base
159
+ // If it's already a function, return it
160
+ if (typeof spacingInput === 'function') {
161
+ return spacingInput;
162
+ }
163
+
164
+ // If it's a number, create a function that multiplies by that number
165
+ if (typeof spacingInput === 'number') {
181
166
  return (...values: number[]) => {
182
- if (values.length === 0) return '0px';
183
- return values.map((value) => `${value * 4}px`).join(' ');
167
+ if (values.length === 0) return '0px';
168
+ return values.map(value => `${value * spacingInput}px`).join(' ');
184
169
  };
185
- }
170
+ }
186
171
 
172
+ // If it's an array, use it as a scale
173
+ if (Array.isArray(spacingInput)) {
174
+ return (...values: number[]) => {
175
+ if (values.length === 0) return '0px';
176
+ return values.map(value => `${spacingInput[value] || value}px`).join(' ');
177
+ };
178
+ }
179
+
180
+ // Default to 4px base
181
+ return (...values: number[]) => {
182
+ if (values.length === 0) return '0px';
183
+ return values.map(value => `${value * 4}px`).join(' ');
184
+ };
185
+ }
@@ -154,9 +154,9 @@ function hslToRgb(hsl: string): { r: number; g: number; b: number } | null {
154
154
  const hue2rgb = (p: number, q: number, t: number): number => {
155
155
  if (t < 0) t += 1;
156
156
  if (t > 1) t -= 1;
157
- if (t < 1/6) return p + (q - p) * 6 * t;
158
- if (t < 1/2) return q;
159
- if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
157
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
158
+ if (t < 1 / 2) return q;
159
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
160
160
  return p;
161
161
  };
162
162
 
@@ -167,15 +167,15 @@ function hslToRgb(hsl: string): { r: number; g: number; b: number } | null {
167
167
  } else {
168
168
  const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
169
169
  const p = 2 * l - q;
170
- r = hue2rgb(p, q, h + 1/3);
170
+ r = hue2rgb(p, q, h + 1 / 3);
171
171
  g = hue2rgb(p, q, h);
172
- b = hue2rgb(p, q, h - 1/3);
172
+ b = hue2rgb(p, q, h - 1 / 3);
173
173
  }
174
174
 
175
175
  return {
176
176
  r: Math.round(r * 255),
177
177
  g: Math.round(g * 255),
178
- b: Math.round(b * 255)
178
+ b: Math.round(b * 255),
179
179
  };
180
180
  }
181
181
 
@@ -298,42 +298,87 @@ export function validateColorFormats(tokens: Partial<DesignTokens>): {
298
298
  // Only validate tokens that are intended to be actual colors, not gradients, font weights, etc.
299
299
  const colorTokenKeys = new Set([
300
300
  // Base colors
301
- 'primary', 'secondary', 'success', 'info', 'warning', 'error', 'light', 'dark',
301
+ 'primary',
302
+ 'secondary',
303
+ 'success',
304
+ 'info',
305
+ 'warning',
306
+ 'error',
307
+ 'light',
308
+ 'dark',
302
309
  // Text emphasis
303
- 'primary-text-emphasis', 'secondary-text-emphasis', 'tertiary-text-emphasis',
304
- 'disabled-text-emphasis', 'invert-text-emphasis', 'brand-text-emphasis',
305
- 'error-text-emphasis', 'success-text-emphasis', 'warning-text-emphasis',
306
- 'info-text-emphasis', 'light-text-emphasis', 'dark-text-emphasis',
310
+ 'primary-text-emphasis',
311
+ 'secondary-text-emphasis',
312
+ 'tertiary-text-emphasis',
313
+ 'disabled-text-emphasis',
314
+ 'invert-text-emphasis',
315
+ 'brand-text-emphasis',
316
+ 'error-text-emphasis',
317
+ 'success-text-emphasis',
318
+ 'warning-text-emphasis',
319
+ 'info-text-emphasis',
320
+ 'light-text-emphasis',
321
+ 'dark-text-emphasis',
307
322
  // Background subtle
308
- 'primary-bg-subtle', 'secondary-bg-subtle', 'tertiary-bg-subtle', 'invert-bg-subtle',
309
- 'brand-bg-subtle', 'error-bg-subtle', 'success-bg-subtle', 'warning-bg-subtle',
310
- 'info-bg-subtle', 'light-bg-subtle', 'dark-bg-subtle',
323
+ 'primary-bg-subtle',
324
+ 'secondary-bg-subtle',
325
+ 'tertiary-bg-subtle',
326
+ 'invert-bg-subtle',
327
+ 'brand-bg-subtle',
328
+ 'error-bg-subtle',
329
+ 'success-bg-subtle',
330
+ 'warning-bg-subtle',
331
+ 'info-bg-subtle',
332
+ 'light-bg-subtle',
333
+ 'dark-bg-subtle',
311
334
  // Border subtle
312
- 'primary-border-subtle', 'secondary-border-subtle', 'success-border-subtle',
313
- 'error-border-subtle', 'warning-border-subtle', 'info-border-subtle',
314
- 'brand-border-subtle', 'light-border-subtle', 'dark-border-subtle',
335
+ 'primary-border-subtle',
336
+ 'secondary-border-subtle',
337
+ 'success-border-subtle',
338
+ 'error-border-subtle',
339
+ 'warning-border-subtle',
340
+ 'info-border-subtle',
341
+ 'brand-border-subtle',
342
+ 'light-border-subtle',
343
+ 'dark-border-subtle',
315
344
  // Hover states
316
- 'primary-hover', 'secondary-hover', 'light-hover', 'dark-hover',
317
- 'error-hover', 'success-hover', 'warning-hover', 'info-hover',
345
+ 'primary-hover',
346
+ 'secondary-hover',
347
+ 'light-hover',
348
+ 'dark-hover',
349
+ 'error-hover',
350
+ 'success-hover',
351
+ 'warning-hover',
352
+ 'info-hover',
318
353
  // Colors from scales (primary, red, green, blue, yellow)
319
354
  ...Array.from({ length: 10 }, (_, i) => [
320
- `primary-${i + 1}`, `red-${i + 1}`, `green-${i + 1}`, `blue-${i + 1}`, `yellow-${i + 1}`
355
+ `primary-${i + 1}`,
356
+ `red-${i + 1}`,
357
+ `green-${i + 1}`,
358
+ `blue-${i + 1}`,
359
+ `yellow-${i + 1}`,
321
360
  ]).flat(),
322
361
  // Gray scale
323
362
  ...Array.from({ length: 10 }, (_, i) => `gray-${i + 1}`),
324
363
  // Body colors
325
- 'body-color', 'heading-color',
364
+ 'body-color',
365
+ 'heading-color',
326
366
  // Link colors
327
- 'link-color', 'link-hover-color',
367
+ 'link-color',
368
+ 'link-hover-color',
328
369
  // Highlight & code
329
- 'highlight-bg', 'code-color',
370
+ 'highlight-bg',
371
+ 'code-color',
330
372
  // Border colors
331
- 'border-color', 'border-color-translucent',
373
+ 'border-color',
374
+ 'border-color-translucent',
332
375
  // Focus ring
333
376
  'focus-border-color',
334
377
  // Form validation
335
- 'form-valid-color', 'form-valid-border-color',
336
- 'form-invalid-color', 'form-invalid-border-color',
378
+ 'form-valid-color',
379
+ 'form-valid-border-color',
380
+ 'form-invalid-color',
381
+ 'form-invalid-border-color',
337
382
  ]);
338
383
 
339
384
  for (const key of colorTokenKeys) {
@@ -437,7 +482,10 @@ export interface ValidationOptions {
437
482
  /**
438
483
  * Comprehensive validation of DesignTokens
439
484
  */
440
- export function validateDesignTokens(tokens: Partial<DesignTokens>, options: ValidationOptions = {}): ThemeValidationResult {
485
+ export function validateDesignTokens(
486
+ tokens: Partial<DesignTokens>,
487
+ options: ValidationOptions = {}
488
+ ): ThemeValidationResult {
441
489
  const results = [];
442
490
 
443
491
  if (!options.skipRequiredTokens) {
@@ -461,7 +509,9 @@ export function validateDesignTokens(tokens: Partial<DesignTokens>, options: Val
461
509
  if (!valid) {
462
510
  logger.error(
463
511
  'DesignTokens validation failed',
464
- new Error(`Validation failed with ${allErrors.length} errors and ${allWarnings.length} warnings`),
512
+ new Error(
513
+ `Validation failed with ${allErrors.length} errors and ${allWarnings.length} warnings`
514
+ ),
465
515
  {
466
516
  errors: allErrors,
467
517
  warnings: allWarnings,
@@ -469,10 +519,9 @@ export function validateDesignTokens(tokens: Partial<DesignTokens>, options: Val
469
519
  }
470
520
  );
471
521
  } else if (allWarnings.length > 0) {
472
- logger.warn(
473
- `DesignTokens validation passed with ${allWarnings.length} warnings`,
474
- { warnings: allWarnings }
475
- );
522
+ logger.warn(`DesignTokens validation passed with ${allWarnings.length} warnings`, {
523
+ warnings: allWarnings,
524
+ });
476
525
  } else {
477
526
  logger.debug('DesignTokens validation passed');
478
527
  }
@@ -498,4 +547,4 @@ export function validateAndMergeTokens(partialTokens?: Partial<DesignTokens>): {
498
547
  tokens: merged,
499
548
  validation,
500
549
  };
501
- }
550
+ }