@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
@@ -6,78 +6,80 @@ import { AtomixGlass } from '../AtomixGlass/AtomixGlass';
6
6
  /**
7
7
  * Radio - A component for radio button inputs
8
8
  */
9
- export const Radio: React.FC<RadioProps> = memo(({
10
- label,
11
- checked = false,
12
- onChange,
13
- className = '',
14
- style,
15
- disabled = false,
16
- required = false,
17
- id,
18
- name,
19
- value,
20
- invalid = false,
21
- valid = false,
22
- 'aria-label': ariaLabel,
23
- 'aria-describedby': ariaDescribedBy,
24
- glass,
25
- }) => {
26
- const { generateRadioClass } = useRadio({
27
- disabled,
28
- invalid,
29
- valid,
30
- });
9
+ export const Radio: React.FC<RadioProps> = memo(
10
+ ({
11
+ label,
12
+ checked = false,
13
+ onChange,
14
+ className = '',
15
+ style,
16
+ disabled = false,
17
+ required = false,
18
+ id,
19
+ name,
20
+ value,
21
+ invalid = false,
22
+ valid = false,
23
+ 'aria-label': ariaLabel,
24
+ 'aria-describedby': ariaDescribedBy,
25
+ glass,
26
+ }) => {
27
+ const { generateRadioClass } = useRadio({
28
+ disabled,
29
+ invalid,
30
+ valid,
31
+ });
31
32
 
32
- const radioClass = generateRadioClass({
33
- className: `${className} ${glass ? 'c-radio--glass' : ''}`.trim(),
34
- disabled,
35
- invalid,
36
- valid,
37
- });
33
+ const radioClass = generateRadioClass({
34
+ className: `${className} ${glass ? 'c-radio--glass' : ''}`.trim(),
35
+ disabled,
36
+ invalid,
37
+ valid,
38
+ });
38
39
 
39
- const radioContent = (
40
- <div className={radioClass} style={style}>
41
- <input
42
- type="radio"
43
- className="c-radio__input"
44
- checked={checked}
45
- onChange={onChange}
46
- disabled={disabled}
47
- required={required}
48
- id={id}
49
- name={name}
50
- value={value}
51
- aria-label={!label ? ariaLabel : undefined}
52
- aria-describedby={ariaDescribedBy}
53
- aria-invalid={invalid}
54
- />
55
- {label && (
56
- <label className="c-radio__label" htmlFor={id}>
57
- {label}
58
- </label>
59
- )}
60
- </div>
61
- );
40
+ const radioContent = (
41
+ <div className={radioClass} style={style}>
42
+ <input
43
+ type="radio"
44
+ className="c-radio__input"
45
+ checked={checked}
46
+ onChange={onChange}
47
+ disabled={disabled}
48
+ required={required}
49
+ id={id}
50
+ name={name}
51
+ value={value}
52
+ aria-label={!label ? ariaLabel : undefined}
53
+ aria-describedby={ariaDescribedBy}
54
+ aria-invalid={invalid}
55
+ />
56
+ {label && (
57
+ <label className="c-radio__label" htmlFor={id}>
58
+ {label}
59
+ </label>
60
+ )}
61
+ </div>
62
+ );
62
63
 
63
- if (glass) {
64
- // Default glass settings for radio buttons
65
- const defaultGlassProps = {
66
- displacementScale: 40,
67
- blurAmount: 1,
68
- saturation: 160,
69
- aberrationIntensity: 0.3,
70
- cornerRadius: 6,
71
- mode: 'shader' as const,
72
- };
64
+ if (glass) {
65
+ // Default glass settings for radio buttons
66
+ const defaultGlassProps = {
67
+ displacementScale: 40,
68
+ blurAmount: 1,
69
+ saturation: 160,
70
+ aberrationIntensity: 0.3,
71
+ cornerRadius: 6,
72
+ mode: 'shader' as const,
73
+ };
73
74
 
74
- const glassProps = glass === true ? defaultGlassProps : { ...defaultGlassProps, ...glass };
75
+ const glassProps = glass === true ? defaultGlassProps : { ...defaultGlassProps, ...glass };
75
76
 
76
- return <AtomixGlass {...glassProps}>{radioContent}</AtomixGlass>;
77
- }
77
+ return <AtomixGlass {...glassProps}>{radioContent}</AtomixGlass>;
78
+ }
78
79
 
79
- return radioContent;
80
- });
80
+ return radioContent;
81
+ }
82
+ );
81
83
 
82
84
  export type { RadioProps };
83
85
 
@@ -7,204 +7,206 @@ import { AtomixGlass } from '../AtomixGlass/AtomixGlass';
7
7
  /**
8
8
  * Select - A component for dropdown selection
9
9
  */
10
- export const Select: React.FC<SelectProps> = memo(({
11
- options = [],
12
- value,
13
- onChange,
14
- onBlur,
15
- onFocus,
16
- placeholder = 'Select an option',
17
- className = '',
18
- style,
19
- disabled = false,
20
- required = false,
21
- id,
22
- name,
23
- size = 'md',
24
- invalid = false,
25
- valid = false,
26
- multiple = false,
27
- 'aria-label': ariaLabel,
28
- 'aria-describedby': ariaDescribedBy,
29
- glass,
30
- }) => {
31
- const { generateSelectClass } = useSelect({
32
- size,
33
- disabled,
34
- invalid,
35
- valid,
36
- });
37
-
38
- const selectClass = generateSelectClass({
39
- className: `${className} ${glass ? 'c-select--glass' : ''}`.trim(),
40
- size,
41
- disabled,
42
- invalid,
43
- valid,
44
- });
45
-
46
- const [isOpen, setIsOpen] = useState(false);
47
- const [selectedLabel, setSelectedLabel] = useState(placeholder);
48
- const dropdownRef = useRef<HTMLDivElement>(null);
49
- const panelRef = useRef<HTMLDivElement>(null);
50
- const bodyRef = useRef<HTMLDivElement>(null);
51
- const nativeSelectRef = useRef<HTMLSelectElement>(null);
52
-
53
- // Update selected label when value changes
54
- useEffect(() => {
55
- if (value) {
56
- const selectedOption = options.find(opt => opt.value === value);
57
- if (selectedOption) {
58
- setSelectedLabel(selectedOption.label);
10
+ export const Select: React.FC<SelectProps> = memo(
11
+ ({
12
+ options = [],
13
+ value,
14
+ onChange,
15
+ onBlur,
16
+ onFocus,
17
+ placeholder = 'Select an option',
18
+ className = '',
19
+ style,
20
+ disabled = false,
21
+ required = false,
22
+ id,
23
+ name,
24
+ size = 'md',
25
+ invalid = false,
26
+ valid = false,
27
+ multiple = false,
28
+ 'aria-label': ariaLabel,
29
+ 'aria-describedby': ariaDescribedBy,
30
+ glass,
31
+ }) => {
32
+ const { generateSelectClass } = useSelect({
33
+ size,
34
+ disabled,
35
+ invalid,
36
+ valid,
37
+ });
38
+
39
+ const selectClass = generateSelectClass({
40
+ className: `${className} ${glass ? 'c-select--glass' : ''}`.trim(),
41
+ size,
42
+ disabled,
43
+ invalid,
44
+ valid,
45
+ });
46
+
47
+ const [isOpen, setIsOpen] = useState(false);
48
+ const [selectedLabel, setSelectedLabel] = useState(placeholder);
49
+ const dropdownRef = useRef<HTMLDivElement>(null);
50
+ const panelRef = useRef<HTMLDivElement>(null);
51
+ const bodyRef = useRef<HTMLDivElement>(null);
52
+ const nativeSelectRef = useRef<HTMLSelectElement>(null);
53
+
54
+ // Update selected label when value changes
55
+ useEffect(() => {
56
+ if (value) {
57
+ const selectedOption = options.find(opt => opt.value === value);
58
+ if (selectedOption) {
59
+ setSelectedLabel(selectedOption.label);
60
+ }
61
+ } else {
62
+ setSelectedLabel(placeholder);
59
63
  }
60
- } else {
61
- setSelectedLabel(placeholder);
62
- }
63
- }, [value, options, placeholder]);
64
-
65
- // Handle click outside to close dropdown
66
- useEffect(() => {
67
- const handleClickOutside = (event: MouseEvent) => {
68
- if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
69
- setIsOpen(false);
70
- if (bodyRef.current) {
64
+ }, [value, options, placeholder]);
65
+
66
+ // Handle click outside to close dropdown
67
+ useEffect(() => {
68
+ const handleClickOutside = (event: MouseEvent) => {
69
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
70
+ setIsOpen(false);
71
+ if (bodyRef.current) {
72
+ bodyRef.current.style.height = '0px';
73
+ }
74
+ }
75
+ };
76
+
77
+ document.addEventListener('mousedown', handleClickOutside);
78
+ return () => {
79
+ document.removeEventListener('mousedown', handleClickOutside);
80
+ };
81
+ }, []);
82
+
83
+ // Toggle dropdown
84
+ const handleToggle = () => {
85
+ if (!disabled) {
86
+ if (!isOpen && bodyRef.current && panelRef.current) {
87
+ bodyRef.current.style.height = `${panelRef.current.clientHeight}px`;
88
+ } else if (bodyRef.current) {
71
89
  bodyRef.current.style.height = '0px';
72
90
  }
91
+ setIsOpen(!isOpen);
73
92
  }
74
93
  };
75
94
 
76
- document.addEventListener('mousedown', handleClickOutside);
77
- return () => {
78
- document.removeEventListener('mousedown', handleClickOutside);
79
- };
80
- }, []);
81
-
82
- // Toggle dropdown
83
- const handleToggle = () => {
84
- if (!disabled) {
85
- if (!isOpen && bodyRef.current && panelRef.current) {
86
- bodyRef.current.style.height = `${panelRef.current.clientHeight}px`;
87
- } else if (bodyRef.current) {
95
+ // Handle item selection
96
+ const handleItemClick = (option: { value: string; label: string }) => {
97
+ setSelectedLabel(option.label);
98
+ setIsOpen(false);
99
+ if (bodyRef.current) {
88
100
  bodyRef.current.style.height = '0px';
89
101
  }
90
- setIsOpen(!isOpen);
91
- }
92
- };
93
-
94
- // Handle item selection
95
- const handleItemClick = (option: { value: string; label: string }) => {
96
- setSelectedLabel(option.label);
97
- setIsOpen(false);
98
- if (bodyRef.current) {
99
- bodyRef.current.style.height = '0px';
100
- }
101
102
 
102
- if (nativeSelectRef.current) {
103
- nativeSelectRef.current.value = option.value;
104
- }
103
+ if (nativeSelectRef.current) {
104
+ nativeSelectRef.current.value = option.value;
105
+ }
105
106
 
106
- if (onChange) {
107
- // Create a synthetic event
108
- const event = {
109
- target: {
110
- name,
111
- value: option.value,
112
- },
113
- } as React.ChangeEvent<HTMLSelectElement>;
114
- onChange(event);
115
- }
116
- };
117
-
118
- const selectContent = (
119
- <div
120
- className={`${selectClass} ${isOpen ? SELECT.CLASSES.IS_OPEN : ''}`}
121
- ref={dropdownRef}
122
- style={style}
123
- aria-expanded={isOpen}
124
- >
125
- {/* Native select for accessibility and form submission */}
126
- <select
127
- ref={nativeSelectRef}
128
- value={value}
129
- onChange={onChange}
130
- onBlur={onBlur}
131
- onFocus={onFocus}
132
- disabled={disabled}
133
- required={required}
134
- id={id}
135
- name={name}
136
- multiple={multiple}
137
- aria-label={ariaLabel}
138
- aria-describedby={ariaDescribedBy}
139
- aria-invalid={invalid}
140
- style={{ display: 'none' }}
107
+ if (onChange) {
108
+ // Create a synthetic event
109
+ const event = {
110
+ target: {
111
+ name,
112
+ value: option.value,
113
+ },
114
+ } as React.ChangeEvent<HTMLSelectElement>;
115
+ onChange(event);
116
+ }
117
+ };
118
+
119
+ const selectContent = (
120
+ <div
121
+ className={`${selectClass} ${isOpen ? SELECT.CLASSES.IS_OPEN : ''}`}
122
+ ref={dropdownRef}
123
+ style={style}
124
+ aria-expanded={isOpen}
141
125
  >
142
- {placeholder && (
143
- <option value="" disabled>
144
- {placeholder}
145
- </option>
146
- )}
147
- {options.map(option => (
148
- <option key={option.value} value={option.value} disabled={option.disabled}>
149
- {option.label}
150
- </option>
151
- ))}
152
- </select>
153
-
154
- {/* Custom Select UI */}
155
- <div className={SELECT.CLASSES.SELECTED} onClick={handleToggle} aria-disabled={disabled}>
156
- {selectedLabel}
157
- </div>
126
+ {/* Native select for accessibility and form submission */}
127
+ <select
128
+ ref={nativeSelectRef}
129
+ value={value}
130
+ onChange={onChange}
131
+ onBlur={onBlur}
132
+ onFocus={onFocus}
133
+ disabled={disabled}
134
+ required={required}
135
+ id={id}
136
+ name={name}
137
+ multiple={multiple}
138
+ aria-label={ariaLabel}
139
+ aria-describedby={ariaDescribedBy}
140
+ aria-invalid={invalid}
141
+ style={{ display: 'none' }}
142
+ >
143
+ {placeholder && (
144
+ <option value="" disabled>
145
+ {placeholder}
146
+ </option>
147
+ )}
148
+ {options.map(option => (
149
+ <option key={option.value} value={option.value} disabled={option.disabled}>
150
+ {option.label}
151
+ </option>
152
+ ))}
153
+ </select>
154
+
155
+ {/* Custom Select UI */}
156
+ <div className={SELECT.CLASSES.SELECTED} onClick={handleToggle} aria-disabled={disabled}>
157
+ {selectedLabel}
158
+ </div>
158
159
 
159
- <i className={`${SELECT.CLASSES.ICON_CARET} ${SELECT.CLASSES.TOGGLE_ICON}`} />
160
-
161
- <div className={SELECT.CLASSES.SELECT_BODY} ref={bodyRef} style={{ height: 0 }}>
162
- <div className={SELECT.CLASSES.SELECT_PANEL} ref={panelRef}>
163
- <ul className={SELECT.CLASSES.SELECT_ITEMS}>
164
- {options.map((option, index) => (
165
- <li
166
- key={option.value}
167
- className={SELECT.CLASSES.SELECT_ITEM}
168
- data-value={option.value}
169
- onClick={() => !option.disabled && handleItemClick(option)}
170
- >
171
- <label htmlFor={`SelectItem${index}`} className="c-checkbox">
172
- <input
173
- type="checkbox"
174
- id={`SelectItem${index}`}
175
- className="c-checkbox__input c-select__item-input"
176
- checked={value === option.value}
177
- readOnly
178
- disabled={option.disabled}
179
- />
180
- <div className="c-select__item-label">{option.label}</div>
181
- </label>
182
- </li>
183
- ))}
184
- </ul>
160
+ <i className={`${SELECT.CLASSES.ICON_CARET} ${SELECT.CLASSES.TOGGLE_ICON}`} />
161
+
162
+ <div className={SELECT.CLASSES.SELECT_BODY} ref={bodyRef} style={{ height: 0 }}>
163
+ <div className={SELECT.CLASSES.SELECT_PANEL} ref={panelRef}>
164
+ <ul className={SELECT.CLASSES.SELECT_ITEMS}>
165
+ {options.map((option, index) => (
166
+ <li
167
+ key={option.value}
168
+ className={SELECT.CLASSES.SELECT_ITEM}
169
+ data-value={option.value}
170
+ onClick={() => !option.disabled && handleItemClick(option)}
171
+ >
172
+ <label htmlFor={`SelectItem${index}`} className="c-checkbox">
173
+ <input
174
+ type="checkbox"
175
+ id={`SelectItem${index}`}
176
+ className="c-checkbox__input c-select__item-input"
177
+ checked={value === option.value}
178
+ readOnly
179
+ disabled={option.disabled}
180
+ />
181
+ <div className="c-select__item-label">{option.label}</div>
182
+ </label>
183
+ </li>
184
+ ))}
185
+ </ul>
186
+ </div>
185
187
  </div>
186
188
  </div>
187
- </div>
188
- );
189
-
190
- if (glass) {
191
- // Default glass settings for select components
192
- const defaultGlassProps = {
193
- displacementScale: 60,
194
- blurAmount: 1,
195
- saturation: 180,
196
- aberrationIntensity: 0.2,
197
- cornerRadius: 12,
198
- mode: 'shader' as const,
199
- };
200
-
201
- const glassProps = glass === true ? defaultGlassProps : { ...defaultGlassProps, ...glass };
189
+ );
190
+
191
+ if (glass) {
192
+ // Default glass settings for select components
193
+ const defaultGlassProps = {
194
+ displacementScale: 60,
195
+ blurAmount: 1,
196
+ saturation: 180,
197
+ aberrationIntensity: 0.2,
198
+ cornerRadius: 12,
199
+ mode: 'shader' as const,
200
+ };
201
+
202
+ const glassProps = glass === true ? defaultGlassProps : { ...defaultGlassProps, ...glass };
203
+
204
+ return <AtomixGlass {...glassProps}>{selectContent}</AtomixGlass>;
205
+ }
202
206
 
203
- return <AtomixGlass {...glassProps}>{selectContent}</AtomixGlass>;
207
+ return selectContent;
204
208
  }
205
-
206
- return selectContent;
207
- });
209
+ );
208
210
 
209
211
  export type { SelectProps };
210
212
 
@@ -4,42 +4,37 @@ import { Textarea } from './Textarea';
4
4
 
5
5
  // Mock AtomixGlass component
6
6
  vi.mock('../AtomixGlass/AtomixGlass', () => ({
7
- AtomixGlass: ({ children, ...props }: any) => (
8
- <div data-testid="atomix-glass" data-glass-props={JSON.stringify(props)}>
9
- {children}
10
- </div>
11
- ),
7
+ AtomixGlass: ({ children, ...props }: any) => (
8
+ <div data-testid="atomix-glass" data-glass-props={JSON.stringify(props)}>
9
+ {children}
10
+ </div>
11
+ ),
12
12
  }));
13
13
 
14
14
  describe('Textarea Component', () => {
15
- it('renders correctly', () => {
16
- render(<Textarea placeholder="Test Textarea" />);
17
- expect(screen.getByPlaceholderText('Test Textarea')).toBeInTheDocument();
18
- });
15
+ it('renders correctly', () => {
16
+ render(<Textarea placeholder="Test Textarea" />);
17
+ expect(screen.getByPlaceholderText('Test Textarea')).toBeInTheDocument();
18
+ });
19
19
 
20
- it('handles uncontrolled defaultValue', () => {
21
- render(<Textarea defaultValue="Default Textarea Value" />);
22
- const textarea = screen.getByDisplayValue('Default Textarea Value');
23
- expect(textarea).toBeInTheDocument();
24
- expect(textarea).toHaveValue('Default Textarea Value');
25
- });
20
+ it('handles uncontrolled defaultValue', () => {
21
+ render(<Textarea defaultValue="Default Textarea Value" />);
22
+ const textarea = screen.getByDisplayValue('Default Textarea Value');
23
+ expect(textarea).toBeInTheDocument();
24
+ expect(textarea).toHaveValue('Default Textarea Value');
25
+ });
26
26
 
27
- it('calls onChange when typing', () => {
28
- const handleChange = vi.fn();
29
- render(<Textarea onChange={handleChange} />);
30
- const textarea = screen.getByRole('textbox');
31
- fireEvent.change(textarea, { target: { value: 'New Textarea Value' } });
32
- expect(handleChange).toHaveBeenCalledTimes(1);
33
- });
27
+ it('calls onChange when typing', () => {
28
+ const handleChange = vi.fn();
29
+ render(<Textarea onChange={handleChange} />);
30
+ const textarea = screen.getByRole('textbox');
31
+ fireEvent.change(textarea, { target: { value: 'New Textarea Value' } });
32
+ expect(handleChange).toHaveBeenCalledTimes(1);
33
+ });
34
34
 
35
- it('applies accessibility attributes', () => {
36
- render(
37
- <Textarea
38
- aria-label="Accessible Textarea"
39
- invalid
40
- />
41
- );
42
- const textarea = screen.getByLabelText('Accessible Textarea');
43
- expect(textarea).toHaveAttribute('aria-invalid', 'true');
44
- });
35
+ it('applies accessibility attributes', () => {
36
+ render(<Textarea aria-label="Accessible Textarea" invalid />);
37
+ const textarea = screen.getByLabelText('Accessible Textarea');
38
+ expect(textarea).toHaveAttribute('aria-invalid', 'true');
39
+ });
45
40
  });