@idealyst/components 1.0.83 → 1.0.84

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 (316) hide show
  1. package/CLAUDE.md +199 -232
  2. package/README.md +5 -5
  3. package/package.json +20 -2
  4. package/plugin/README.md +272 -0
  5. package/plugin/test-cases.jsx +112 -0
  6. package/plugin/web-legacy.js +320 -0
  7. package/plugin/web.js +422 -124
  8. package/src/Accordion/Accordion.native.tsx +182 -0
  9. package/src/Accordion/Accordion.styles.tsx +260 -0
  10. package/src/Accordion/Accordion.web.tsx +147 -0
  11. package/src/Accordion/index.native.tsx +3 -0
  12. package/src/Accordion/index.ts +3 -0
  13. package/src/Accordion/index.web.tsx +3 -0
  14. package/src/Accordion/types.ts +23 -0
  15. package/src/ActivityIndicator/ActivityIndicator.native.tsx +17 -12
  16. package/src/ActivityIndicator/ActivityIndicator.styles.tsx +83 -109
  17. package/src/ActivityIndicator/ActivityIndicator.web.tsx +23 -17
  18. package/src/ActivityIndicator/index.ts +5 -2
  19. package/src/ActivityIndicator/index.web.ts +5 -2
  20. package/src/ActivityIndicator/types.ts +15 -10
  21. package/src/Alert/Alert.native.tsx +113 -0
  22. package/src/Alert/Alert.styles.tsx +304 -0
  23. package/src/Alert/Alert.web.tsx +123 -0
  24. package/src/Alert/index.native.ts +5 -0
  25. package/src/Alert/index.ts +5 -0
  26. package/src/Alert/index.web.ts +5 -0
  27. package/src/Alert/types.ts +21 -0
  28. package/src/Avatar/Avatar.native.tsx +8 -6
  29. package/src/Avatar/Avatar.styles.tsx +64 -58
  30. package/src/Avatar/Avatar.web.tsx +13 -8
  31. package/src/Avatar/index.ts +5 -2
  32. package/src/Avatar/index.web.ts +5 -2
  33. package/src/Avatar/types.ts +19 -13
  34. package/src/Badge/Badge.native.tsx +59 -14
  35. package/src/Badge/Badge.styles.tsx +125 -139
  36. package/src/Badge/Badge.web.tsx +72 -16
  37. package/src/Badge/index.ts +5 -2
  38. package/src/Badge/index.web.ts +5 -2
  39. package/src/Badge/types.ts +23 -11
  40. package/src/Breadcrumb/Breadcrumb.native.tsx +225 -0
  41. package/src/Breadcrumb/Breadcrumb.styles.tsx +234 -0
  42. package/src/Breadcrumb/Breadcrumb.web.tsx +268 -0
  43. package/src/Breadcrumb/index.native.ts +5 -0
  44. package/src/Breadcrumb/index.ts +5 -0
  45. package/src/Breadcrumb/index.web.ts +5 -0
  46. package/src/Breadcrumb/types.ts +56 -0
  47. package/src/Button/Button.native.tsx +75 -24
  48. package/src/Button/Button.styles.tsx +248 -205
  49. package/src/Button/Button.web.tsx +82 -25
  50. package/src/Button/index.ts +5 -5
  51. package/src/Button/index.web.ts +5 -3
  52. package/src/Button/types.ts +32 -15
  53. package/src/Card/Card.native.tsx +14 -11
  54. package/src/Card/Card.styles.tsx +146 -220
  55. package/src/Card/Card.web.tsx +20 -21
  56. package/src/Card/index.ts +5 -5
  57. package/src/Card/index.web.ts +5 -3
  58. package/src/Card/types.ts +24 -17
  59. package/src/Checkbox/Checkbox.native.tsx +24 -34
  60. package/src/Checkbox/Checkbox.styles.tsx +223 -275
  61. package/src/Checkbox/Checkbox.web.tsx +30 -37
  62. package/src/Checkbox/index.ts +5 -5
  63. package/src/Checkbox/index.web.ts +5 -3
  64. package/src/Checkbox/types.ts +26 -20
  65. package/src/Chip/Chip.native.tsx +126 -0
  66. package/src/Chip/Chip.styles.tsx +138 -0
  67. package/src/Chip/Chip.web.tsx +154 -0
  68. package/src/Chip/index.native.ts +5 -0
  69. package/src/Chip/index.ts +5 -0
  70. package/src/Chip/index.web.ts +5 -0
  71. package/src/Chip/types.ts +51 -0
  72. package/src/Dialog/Dialog.native.tsx +65 -12
  73. package/src/Dialog/Dialog.styles.tsx +154 -136
  74. package/src/Dialog/Dialog.web.tsx +16 -11
  75. package/src/Dialog/index.ts +5 -2
  76. package/src/Dialog/index.web.ts +5 -2
  77. package/src/Dialog/types.ts +22 -16
  78. package/src/Divider/Divider.native.tsx +19 -14
  79. package/src/Divider/Divider.styles.tsx +273 -595
  80. package/src/Divider/Divider.web.tsx +19 -12
  81. package/src/Divider/index.ts +5 -5
  82. package/src/Divider/index.web.ts +5 -3
  83. package/src/Divider/types.ts +28 -19
  84. package/src/Icon/Icon.native.tsx +17 -24
  85. package/src/Icon/Icon.styles.tsx +64 -48
  86. package/src/Icon/Icon.web.tsx +14 -11
  87. package/src/Icon/IconSvg/IconSvg.native.tsx +42 -0
  88. package/src/Icon/IconSvg/IconSvg.web.tsx +40 -0
  89. package/src/Icon/IconSvg/index.native.ts +1 -0
  90. package/src/Icon/IconSvg/index.ts +1 -0
  91. package/src/Icon/icon-resolver.native.ts +27 -0
  92. package/src/Icon/icon-resolver.ts +70 -0
  93. package/src/Icon/index.ts +5 -5
  94. package/src/Icon/index.web.ts +5 -3
  95. package/src/Icon/types.ts +17 -11
  96. package/src/Image/Image.native.tsx +86 -0
  97. package/src/Image/Image.styles.tsx +57 -0
  98. package/src/Image/Image.web.tsx +92 -0
  99. package/src/Image/index.native.ts +5 -0
  100. package/src/Image/index.ts +5 -0
  101. package/src/Image/types.ts +21 -0
  102. package/src/Input/Input.native.tsx +103 -26
  103. package/src/Input/Input.styles.tsx +240 -177
  104. package/src/Input/Input.web.tsx +141 -38
  105. package/src/Input/index.ts +5 -5
  106. package/src/Input/index.web.ts +5 -3
  107. package/src/Input/types.ts +43 -20
  108. package/src/List/List.native.tsx +56 -0
  109. package/src/List/List.styles.tsx +257 -0
  110. package/src/List/List.web.tsx +43 -0
  111. package/src/List/ListContext.tsx +16 -0
  112. package/src/List/ListItem.native.tsx +111 -0
  113. package/src/List/ListItem.web.tsx +110 -0
  114. package/src/List/ListSection.native.tsx +31 -0
  115. package/src/List/ListSection.web.tsx +33 -0
  116. package/src/List/index.native.tsx +5 -0
  117. package/src/List/index.ts +5 -0
  118. package/src/List/index.web.tsx +5 -0
  119. package/src/List/types.ts +42 -0
  120. package/src/Menu/Menu.native.tsx +150 -0
  121. package/src/Menu/Menu.styles.tsx +185 -0
  122. package/src/Menu/Menu.web.tsx +99 -0
  123. package/src/Menu/MenuItem.native.tsx +66 -0
  124. package/src/Menu/MenuItem.styles.tsx +119 -0
  125. package/src/Menu/MenuItem.web.tsx +67 -0
  126. package/src/Menu/index.native.ts +3 -0
  127. package/src/Menu/index.ts +3 -0
  128. package/src/Menu/index.web.ts +3 -0
  129. package/src/Menu/types.ts +30 -0
  130. package/src/Popover/Popover.native.tsx +102 -32
  131. package/src/Popover/Popover.styles.tsx +100 -67
  132. package/src/Popover/Popover.web.tsx +36 -260
  133. package/src/Popover/index.ts +5 -2
  134. package/src/Popover/index.web.ts +5 -2
  135. package/src/Popover/types.ts +14 -13
  136. package/src/Pressable/Pressable.native.tsx +7 -6
  137. package/src/Pressable/Pressable.web.tsx +8 -6
  138. package/src/Pressable/index.ts +5 -2
  139. package/src/Pressable/index.web.ts +5 -2
  140. package/src/Pressable/types.ts +11 -10
  141. package/src/Progress/Progress.native.tsx +179 -0
  142. package/src/Progress/Progress.styles.tsx +164 -0
  143. package/src/Progress/Progress.web.tsx +144 -0
  144. package/src/Progress/index.native.ts +1 -0
  145. package/src/Progress/index.ts +5 -0
  146. package/src/Progress/index.web.ts +5 -0
  147. package/src/Progress/types.ts +21 -0
  148. package/src/RadioButton/RadioButton.native.tsx +88 -0
  149. package/src/RadioButton/RadioButton.styles.tsx +163 -0
  150. package/src/RadioButton/RadioButton.web.tsx +85 -0
  151. package/src/RadioButton/RadioGroup.native.tsx +43 -0
  152. package/src/RadioButton/RadioGroup.web.tsx +49 -0
  153. package/src/RadioButton/index.native.ts +2 -0
  154. package/src/RadioButton/index.ts +2 -0
  155. package/src/RadioButton/index.web.ts +2 -0
  156. package/src/RadioButton/types.ts +29 -0
  157. package/src/SVGImage/SVGImage.native.tsx +9 -7
  158. package/src/SVGImage/SVGImage.styles.tsx +63 -55
  159. package/src/SVGImage/SVGImage.web.tsx +16 -13
  160. package/src/SVGImage/index.ts +5 -5
  161. package/src/SVGImage/index.web.ts +5 -2
  162. package/src/SVGImage/types.ts +7 -3
  163. package/src/Screen/Screen.native.tsx +43 -17
  164. package/src/Screen/Screen.styles.tsx +58 -54
  165. package/src/Screen/Screen.web.tsx +11 -5
  166. package/src/Screen/index.ts +5 -2
  167. package/src/Screen/index.web.ts +5 -2
  168. package/src/Screen/types.ts +23 -9
  169. package/src/Select/Select.native.tsx +140 -63
  170. package/src/Select/Select.styles.tsx +312 -302
  171. package/src/Select/Select.web.tsx +156 -316
  172. package/src/Select/index.ts +5 -2
  173. package/src/Select/index.web.ts +5 -2
  174. package/src/Select/types.ts +13 -7
  175. package/src/Skeleton/Skeleton.native.tsx +139 -0
  176. package/src/Skeleton/Skeleton.styles.tsx +59 -0
  177. package/src/Skeleton/Skeleton.web.tsx +112 -0
  178. package/src/Skeleton/index.native.ts +4 -0
  179. package/src/Skeleton/index.ts +5 -0
  180. package/src/Skeleton/index.web.ts +5 -0
  181. package/src/Skeleton/types.ts +75 -0
  182. package/src/Slider/Slider.native.tsx +248 -0
  183. package/src/Slider/Slider.styles.tsx +241 -0
  184. package/src/Slider/Slider.web.tsx +226 -0
  185. package/src/Slider/index.native.ts +3 -0
  186. package/src/Slider/index.ts +5 -0
  187. package/src/Slider/index.web.ts +5 -0
  188. package/src/Slider/types.ts +31 -0
  189. package/src/Switch/Switch.native.tsx +131 -0
  190. package/src/Switch/Switch.styles.tsx +169 -0
  191. package/src/Switch/Switch.web.tsx +121 -0
  192. package/src/Switch/index.native.ts +3 -0
  193. package/src/Switch/index.ts +5 -0
  194. package/src/Switch/index.web.ts +5 -0
  195. package/src/Switch/types.ts +21 -0
  196. package/src/TabBar/TabBar.native.tsx +142 -0
  197. package/src/TabBar/TabBar.styles.tsx +399 -0
  198. package/src/TabBar/TabBar.web.tsx +205 -0
  199. package/src/TabBar/index.native.tsx +3 -0
  200. package/src/TabBar/index.ts +3 -0
  201. package/src/TabBar/index.web.tsx +3 -0
  202. package/src/TabBar/types.ts +26 -0
  203. package/src/Table/Table.native.tsx +122 -0
  204. package/src/Table/Table.styles.tsx +283 -0
  205. package/src/Table/Table.web.tsx +112 -0
  206. package/src/Table/index.native.tsx +3 -0
  207. package/src/Table/index.ts +3 -0
  208. package/src/Table/index.web.tsx +3 -0
  209. package/src/Table/types.ts +28 -0
  210. package/src/Text/Text.native.tsx +12 -11
  211. package/src/Text/Text.styles.tsx +76 -64
  212. package/src/Text/Text.web.tsx +14 -9
  213. package/src/Text/index.ts +5 -5
  214. package/src/Text/index.web.ts +5 -3
  215. package/src/Text/types.ts +20 -13
  216. package/src/TextArea/TextArea.native.tsx +134 -0
  217. package/src/TextArea/TextArea.styles.tsx +175 -0
  218. package/src/TextArea/TextArea.web.tsx +156 -0
  219. package/src/TextArea/index.native.ts +3 -0
  220. package/src/TextArea/index.ts +3 -0
  221. package/src/TextArea/index.web.ts +3 -0
  222. package/src/TextArea/types.ts +30 -0
  223. package/src/Tooltip/Tooltip.native.tsx +165 -0
  224. package/src/Tooltip/Tooltip.styles.tsx +73 -0
  225. package/src/Tooltip/Tooltip.web.tsx +87 -0
  226. package/src/Tooltip/index.native.ts +3 -0
  227. package/src/Tooltip/index.ts +3 -0
  228. package/src/Tooltip/types.ts +18 -0
  229. package/src/Video/Video.native.tsx +105 -0
  230. package/src/Video/Video.styles.tsx +39 -0
  231. package/src/Video/Video.web.tsx +115 -0
  232. package/src/Video/index.native.ts +5 -0
  233. package/src/Video/index.ts +5 -0
  234. package/src/Video/types.ts +29 -0
  235. package/src/View/View.native.tsx +9 -14
  236. package/src/View/View.styles.tsx +101 -93
  237. package/src/View/View.web.tsx +16 -17
  238. package/src/View/index.ts +5 -5
  239. package/src/View/index.web.ts +5 -3
  240. package/src/View/types.ts +29 -21
  241. package/src/examples/AccordionExamples.tsx +126 -0
  242. package/src/examples/AlertExamples.tsx +280 -0
  243. package/src/examples/AvatarExamples.tsx +23 -23
  244. package/src/examples/BadgeExamples.tsx +109 -41
  245. package/src/examples/BreadcrumbExamples.tsx +312 -0
  246. package/src/examples/ButtonExamples.tsx +160 -33
  247. package/src/examples/CardExamples.tsx +40 -40
  248. package/src/examples/CheckboxExamples.tsx +12 -12
  249. package/src/examples/ChipExamples.tsx +197 -0
  250. package/src/examples/DialogExamples.tsx +22 -22
  251. package/src/examples/DividerExamples.tsx +49 -49
  252. package/src/examples/IconExamples.tsx +270 -54
  253. package/src/examples/ImageExamples.tsx +174 -0
  254. package/src/examples/InputExamples.tsx +75 -17
  255. package/src/examples/ListExamples.tsx +288 -0
  256. package/src/examples/MenuExamples.tsx +144 -0
  257. package/src/examples/PopoverExamples.tsx +69 -73
  258. package/src/examples/ProgressExamples.tsx +137 -0
  259. package/src/examples/RadioButtonExamples.tsx +161 -0
  260. package/src/examples/SVGImageExamples.tsx +19 -17
  261. package/src/examples/ScreenExamples.tsx +31 -31
  262. package/src/examples/SelectExamples.tsx +67 -67
  263. package/src/examples/SkeletonExamples.tsx +206 -0
  264. package/src/examples/SliderExamples.tsx +200 -0
  265. package/src/examples/SwitchExamples.tsx +182 -0
  266. package/src/examples/TabBarExamples.tsx +143 -0
  267. package/src/examples/TableExamples.tsx +280 -0
  268. package/src/examples/TextAreaExamples.tsx +173 -0
  269. package/src/examples/TextExamples.tsx +28 -32
  270. package/src/examples/ThemeExtensionExamples.tsx +10 -10
  271. package/src/examples/TooltipExamples.tsx +126 -0
  272. package/src/examples/VideoExamples.tsx +144 -0
  273. package/src/examples/ViewExamples.tsx +64 -56
  274. package/src/examples/index.ts +17 -3
  275. package/src/hooks/useMergeRefs.ts +16 -0
  276. package/src/hooks/useSmartPosition.native.ts +169 -0
  277. package/src/index.native.ts +80 -9
  278. package/src/index.ts +71 -1
  279. package/src/internal/BoundedModalContent.native.tsx +58 -0
  280. package/src/internal/PositionedPortal.tsx +254 -0
  281. package/src/internal/SafeAreaDebugOverlay.native.tsx +173 -0
  282. package/src/unistyles.d.ts +6 -0
  283. package/src/utils/buildSizeVariants.ts +16 -0
  284. package/src/utils/deepMerge.ts +43 -0
  285. package/src/utils/positionUtils.native.ts +280 -0
  286. package/src/utils/styleHelpers.ts +48 -0
  287. package/LLM-ACCESS-GUIDE.md +0 -143
  288. package/src/ActivityIndicator/README.md +0 -132
  289. package/src/Avatar/README.md +0 -139
  290. package/src/Badge/README.md +0 -170
  291. package/src/Button/Button.types.ts +0 -12
  292. package/src/Button/README.md +0 -262
  293. package/src/Card/README.md +0 -258
  294. package/src/Checkbox/README.md +0 -102
  295. package/src/Dialog/README.md +0 -210
  296. package/src/Divider/README.md +0 -108
  297. package/src/Icon/README.md +0 -81
  298. package/src/Input/README.md +0 -100
  299. package/src/SVGImage/README.md +0 -209
  300. package/src/Screen/README.md +0 -86
  301. package/src/Select/README.md +0 -166
  302. package/src/Text/README.md +0 -94
  303. package/src/View/README.md +0 -107
  304. package/src/examples/AllExamples.tsx +0 -88
  305. package/src/examples/README.md +0 -136
  306. package/src/examples/ValidationExamples.tsx +0 -95
  307. package/src/examples/extendedTheme.ts +0 -329
  308. package/src/theme/breakpoints.ts +0 -8
  309. package/src/theme/colorResolver.ts +0 -218
  310. package/src/theme/colors.ts +0 -315
  311. package/src/theme/defaultThemes.ts +0 -326
  312. package/src/theme/index.ts +0 -188
  313. package/src/theme/themeBuilder.ts +0 -602
  314. package/src/theme/unistyles.d.ts +0 -6
  315. package/src/theme/variantHelpers.ts +0 -584
  316. package/src/theme/variants.ts +0 -56
@@ -1,14 +1,17 @@
1
- import React, { useState, useEffect } from 'react';
1
+ import React, { useState, useEffect, forwardRef } from 'react';
2
2
  import { getWebProps } from 'react-native-unistyles/web';
3
3
  import { CheckboxProps } from './types';
4
- import { checkboxStyles, checkboxLabelStyles, checkboxCheckmarkStyles, checkboxHelperStyles } from './Checkbox.styles';
4
+ import { checkboxStyles } from './Checkbox.styles';
5
+ import { IconSvg } from '../Icon/IconSvg/IconSvg.web';
6
+ import { resolveIconPath } from '../Icon/icon-resolver';
7
+ import useMergeRefs from '../hooks/useMergeRefs';
5
8
 
6
- const Checkbox: React.FC<CheckboxProps> = ({
9
+ const Checkbox = forwardRef<HTMLDivElement, CheckboxProps>(({
7
10
  checked = false,
8
11
  indeterminate = false,
9
12
  disabled = false,
10
13
  onCheckedChange,
11
- size = 'medium',
14
+ size = 'md',
12
15
  intent = 'primary',
13
16
  variant = 'default',
14
17
  label,
@@ -19,54 +22,38 @@ const Checkbox: React.FC<CheckboxProps> = ({
19
22
  required = false,
20
23
  error,
21
24
  helperText,
22
- }) => {
25
+ }, ref) => {
23
26
  const [internalChecked, setInternalChecked] = useState(checked);
24
-
27
+
25
28
  useEffect(() => {
26
29
  setInternalChecked(checked);
27
30
  }, [checked]);
28
31
 
29
32
  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
30
33
  if (disabled) return;
31
-
34
+
32
35
  const newChecked = event.target.checked;
33
36
  setInternalChecked(newChecked);
34
37
  onCheckedChange?.(newChecked);
35
38
  };
36
39
 
37
- // Apply variants for main checkbox
40
+ // Apply variants
38
41
  checkboxStyles.useVariants({
39
42
  size,
40
- intent,
41
- variant: variant as any,
43
+ type: variant as any,
42
44
  checked: internalChecked,
43
45
  disabled,
44
- });
45
-
46
- // Apply variants for label
47
- checkboxLabelStyles.useVariants({
48
- size,
49
- disabled,
50
- });
51
-
52
- // Apply variants for checkmark
53
- checkboxCheckmarkStyles.useVariants({
54
- size,
55
- visible: internalChecked,
56
- });
57
-
58
- // Apply variants for helper text
59
- checkboxHelperStyles.useVariants({
60
- error: !!error,
46
+ visible: internalChecked || indeterminate,
47
+ error: Boolean(error),
61
48
  });
62
49
 
63
50
  // Create style arrays
64
- const wrapperStyleArray = [checkboxStyles.wrapper, style];
51
+ const wrapperStyleArray = [checkboxStyles.wrapper, style as any];
65
52
  const containerStyleArray = [checkboxStyles.container];
66
- const checkboxStyleArray = [checkboxStyles.checkbox];
67
- const labelStyleArray = [checkboxLabelStyles.label];
68
- const helperTextStyleArray = [checkboxHelperStyles.helperText];
69
- const checkmarkStyleArray = [checkboxCheckmarkStyles.checkmark];
53
+ const checkboxStyleArray = [checkboxStyles.checkbox({ intent })];
54
+ const labelStyleArray = [checkboxStyles.label];
55
+ const helperTextStyleArray = [checkboxStyles.helperText];
56
+ const checkmarkStyleArray = [checkboxStyles.checkmark];
70
57
 
71
58
  // Generate web props
72
59
  const wrapperProps = getWebProps(wrapperStyleArray);
@@ -79,8 +66,10 @@ const Checkbox: React.FC<CheckboxProps> = ({
79
66
  const labelContent = children || label;
80
67
  const displayHelperText = error || helperText;
81
68
 
69
+ const mergedRef = useMergeRefs(ref, wrapperProps.ref);
70
+
82
71
  return (
83
- <div {...wrapperProps}>
72
+ <div {...wrapperProps} ref={mergedRef}>
84
73
  <label {...containerProps}>
85
74
  <div style={{ position: 'relative' }}>
86
75
  <input
@@ -107,9 +96,11 @@ const Checkbox: React.FC<CheckboxProps> = ({
107
96
  />
108
97
  <div {...checkboxProps}>
109
98
  {(internalChecked || indeterminate) && (
110
- <div {...checkmarkProps}>
111
- {indeterminate ? '' : ''}
112
- </div>
99
+ <IconSvg
100
+ path={resolveIconPath(indeterminate ? 'minus' : 'check')}
101
+ {...checkmarkProps}
102
+ aria-label={indeterminate ? 'minus' : 'check'}
103
+ />
113
104
  )}
114
105
  </div>
115
106
  </div>
@@ -126,6 +117,8 @@ const Checkbox: React.FC<CheckboxProps> = ({
126
117
  )}
127
118
  </div>
128
119
  );
129
- };
120
+ });
121
+
122
+ Checkbox.displayName = 'Checkbox';
130
123
 
131
124
  export default Checkbox;
@@ -1,5 +1,5 @@
1
- // Platform-agnostic Checkbox export
2
- // Metro will resolve to index.native.ts for React Native
3
- // This file serves as fallback for web environments
4
- export { default } from './Checkbox.web';
5
- export * from './types';
1
+ import CheckboxComponent from './Checkbox.web';
2
+
3
+ export default CheckboxComponent;
4
+ export { CheckboxComponent as Checkbox };
5
+ export * from './types';
@@ -1,3 +1,5 @@
1
- // Web-specific Checkbox export
2
- export { default } from './Checkbox.web';
3
- export * from './types';
1
+ import CheckboxComponent from './Checkbox.web';
2
+
3
+ export default CheckboxComponent;
4
+ export { CheckboxComponent as Checkbox };
5
+ export * from './types';
@@ -1,77 +1,83 @@
1
- import { ReactNode } from 'react';
2
- import type { IntentVariant } from '../theme/variants';
1
+ import { Intent, Size } from '@idealyst/theme';
2
+ import type { ReactNode } from 'react';
3
+ import type { StyleProp, ViewStyle } from 'react-native';
4
+
5
+ // Component-specific type aliases for future extensibility
6
+ export type CheckboxIntentVariant = Intent;
7
+ export type CheckboxSizeVariant = Size;
8
+ export type CheckboxVariant = 'default' | 'outlined';
3
9
 
4
10
  export interface CheckboxProps {
5
11
  /**
6
12
  * Whether the checkbox is checked
7
13
  */
8
14
  checked?: boolean;
9
-
15
+
10
16
  /**
11
17
  * Whether the checkbox is in an indeterminate state
12
18
  */
13
19
  indeterminate?: boolean;
14
-
20
+
15
21
  /**
16
22
  * Whether the checkbox is disabled
17
23
  */
18
24
  disabled?: boolean;
19
-
25
+
20
26
  /**
21
27
  * Called when the checkbox state changes
22
28
  */
23
29
  onCheckedChange?: (checked: boolean) => void;
24
-
30
+
25
31
  /**
26
32
  * The size of the checkbox
27
33
  */
28
- size?: 'small' | 'medium' | 'large';
29
-
34
+ size?: CheckboxSizeVariant;
35
+
30
36
  /**
31
37
  * The intent/color scheme of the checkbox
32
38
  */
33
- intent?: IntentVariant;
34
-
39
+ intent?: CheckboxIntentVariant;
40
+
35
41
  /**
36
42
  * The visual style variant of the checkbox
37
43
  */
38
- variant?: 'default' | 'outlined';
39
-
44
+ variant?: CheckboxVariant;
45
+
40
46
  /**
41
47
  * Label text to display next to the checkbox
42
48
  */
43
49
  label?: string;
44
-
50
+
45
51
  /**
46
52
  * Custom label content (ReactNode)
47
53
  */
48
54
  children?: ReactNode;
49
-
55
+
50
56
  /**
51
57
  * Additional styles (platform-specific)
52
58
  */
53
- style?: any;
54
-
59
+ style?: StyleProp<ViewStyle>;
60
+
55
61
  /**
56
62
  * Test ID for testing
57
63
  */
58
64
  testID?: string;
59
-
65
+
60
66
  /**
61
67
  * Accessibility label
62
68
  */
63
69
  accessibilityLabel?: string;
64
-
70
+
65
71
  /**
66
72
  * Whether the checkbox is required
67
73
  */
68
74
  required?: boolean;
69
-
75
+
70
76
  /**
71
77
  * Error message to display
72
78
  */
73
79
  error?: string;
74
-
80
+
75
81
  /**
76
82
  * Helper text to display
77
83
  */
@@ -0,0 +1,126 @@
1
+ import React, { isValidElement, forwardRef, ComponentRef } from 'react';
2
+ import { Pressable, Text, View } from 'react-native';
3
+ import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
4
+ import { chipStyles } from './Chip.styles';
5
+ import { isIconName } from '../Icon/icon-resolver';
6
+ import type { ChipProps } from './types';
7
+
8
+ const Chip = forwardRef<ComponentRef<typeof Pressable>, ChipProps>(({
9
+ label,
10
+ type = 'filled',
11
+ intent = 'primary',
12
+ size = 'md',
13
+ icon,
14
+ deletable = false,
15
+ onDelete,
16
+ selectable = false,
17
+ selected = false,
18
+ onPress,
19
+ disabled = false,
20
+ style,
21
+ testID,
22
+ }, ref) => {
23
+ const handlePress = () => {
24
+ if (disabled) return;
25
+ if (onPress) {
26
+ onPress();
27
+ }
28
+ };
29
+
30
+ const handleDelete = () => {
31
+ if (disabled) return;
32
+ if (onDelete) {
33
+ onDelete();
34
+ }
35
+ };
36
+
37
+ // Compute actual selected state
38
+ const isSelected = selectable ? selected : false;
39
+
40
+ // Compute dynamic styles
41
+ const containerStyle = chipStyles.container(size, intent, type, isSelected, disabled);
42
+ const labelStyle = chipStyles.label(size, intent, type, isSelected);
43
+ const iconStyle = chipStyles.icon(size, intent, type, isSelected);
44
+ const deleteButtonStyle = chipStyles.deleteButton(size);
45
+ const deleteIconStyle = chipStyles.deleteIcon(size, intent, type, isSelected);
46
+
47
+ // Map chip size to icon size
48
+ const iconSize = size === 'sm' ? 12 : size === 'md' ? 14 : 16;
49
+ const deleteIconSize = size === 'sm' ? 10 : size === 'md' ? 11 : 12;
50
+
51
+ // Helper to render icon
52
+ const renderIcon = () => {
53
+ if (!icon) return null;
54
+
55
+ if (typeof icon === 'string' && isIconName(icon)) {
56
+ return (
57
+ <View style={iconStyle}>
58
+ <MaterialCommunityIcons
59
+ name={icon}
60
+ size={iconSize}
61
+ style={iconStyle}
62
+ />
63
+ </View>
64
+ );
65
+ } else if (isValidElement(icon)) {
66
+ return icon;
67
+ }
68
+ return null;
69
+ };
70
+
71
+ const isClickable = (onPress && !disabled) || (selectable && !disabled);
72
+
73
+ const innerContent = (
74
+ <>
75
+ {icon && renderIcon()}
76
+
77
+ <Text style={labelStyle}>{label}</Text>
78
+
79
+ {deletable && onDelete && (
80
+ <Pressable
81
+ style={deleteButtonStyle}
82
+ onPress={handleDelete}
83
+ disabled={disabled}
84
+ hitSlop={8}
85
+ accessibilityLabel="Delete"
86
+ accessibilityRole="button"
87
+ >
88
+ <MaterialCommunityIcons
89
+ name="close"
90
+ size={deleteIconSize}
91
+ style={deleteIconStyle}
92
+ />
93
+ </Pressable>
94
+ )}
95
+ </>
96
+ );
97
+
98
+ if (isClickable) {
99
+ return (
100
+ <Pressable
101
+ ref={ref}
102
+ onPress={handlePress}
103
+ disabled={disabled}
104
+ accessibilityRole="button"
105
+ accessibilityState={{
106
+ disabled,
107
+ selected: selectable ? selected : undefined,
108
+ }}
109
+ >
110
+ <View style={[containerStyle, style]} testID={testID}>
111
+ {innerContent}
112
+ </View>
113
+ </Pressable>
114
+ );
115
+ }
116
+
117
+ return (
118
+ <View ref={ref} style={[containerStyle, style]} testID={testID}>
119
+ {innerContent}
120
+ </View>
121
+ );
122
+ });
123
+
124
+ Chip.displayName = 'Chip';
125
+
126
+ export default Chip;
@@ -0,0 +1,138 @@
1
+ import { StyleSheet } from 'react-native-unistyles';
2
+ import { Theme, Intent} from '@idealyst/theme';
3
+
4
+ type ChipSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
5
+ type ChipType = 'filled' | 'outlined' | 'soft';
6
+ type ChipIntent = Intent;
7
+
8
+ // Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel
9
+ // transform on native cannot resolve function calls to extract variant structures.
10
+ export const chipStyles = StyleSheet.create((theme: Theme) => {
11
+ return {
12
+ container: (size: ChipSize, intent: ChipIntent, type: ChipType, selected: boolean, disabled: boolean) => {
13
+ const intentValue = theme.intents[intent];
14
+ const sizeValue = theme.sizes.chip[size];
15
+
16
+ // Compute colors based on type and selected state
17
+ let backgroundColor: string;
18
+ let borderColor: string;
19
+ let borderWidth: number;
20
+
21
+ if (type === 'filled') {
22
+ borderWidth = 1;
23
+ backgroundColor = selected ? intentValue.contrast : intentValue.primary;
24
+ borderColor = selected ? intentValue.primary : 'transparent';
25
+ } else if (type === 'outlined') {
26
+ borderWidth = 1;
27
+ backgroundColor = selected ? intentValue.primary : 'transparent';
28
+ borderColor = intentValue.primary;
29
+ } else { // soft
30
+ borderWidth = 0;
31
+ backgroundColor = selected ? intentValue.primary : intentValue.light;
32
+ borderColor = 'transparent';
33
+ }
34
+
35
+ return {
36
+ display: 'flex' as const,
37
+ flexDirection: 'row' as const,
38
+ alignItems: 'center' as const,
39
+ justifyContent: 'center' as const,
40
+ gap: 4,
41
+ paddingHorizontal: sizeValue.paddingHorizontal as number,
42
+ paddingVertical: sizeValue.paddingVertical as number,
43
+ minHeight: sizeValue.minHeight as number,
44
+ borderRadius: sizeValue.borderRadius as number,
45
+ backgroundColor,
46
+ borderColor,
47
+ borderWidth,
48
+ borderStyle: borderWidth > 0 ? ('solid' as const) : undefined,
49
+ opacity: disabled ? 0.5 : 1,
50
+ } as const;
51
+ },
52
+
53
+ label: (size: ChipSize, intent: ChipIntent, type: ChipType, selected: boolean) => {
54
+ const intentValue = theme.intents[intent];
55
+ const sizeValue = theme.sizes.chip[size];
56
+
57
+ // Compute color based on type and selected state
58
+ let color: string;
59
+
60
+ if (type === 'filled') {
61
+ color = selected ? intentValue.primary : intentValue.contrast;
62
+ } else if (type === 'outlined') {
63
+ color = selected ? theme.colors.text.inverse : intentValue.primary;
64
+ } else { // soft
65
+ color = selected ? theme.colors.text.inverse : intentValue.dark;
66
+ }
67
+
68
+ return {
69
+ fontFamily: 'inherit',
70
+ fontWeight: '500' as const,
71
+ fontSize: sizeValue.fontSize as number,
72
+ lineHeight: sizeValue.lineHeight as number,
73
+ color,
74
+ } as const;
75
+ },
76
+
77
+ icon: (size: ChipSize, intent: ChipIntent, type: ChipType, selected: boolean) => {
78
+ const intentValue = theme.intents[intent];
79
+ const sizeValue = theme.sizes.chip[size];
80
+
81
+ // Compute color based on type and selected state (same logic as label)
82
+ let color: string;
83
+
84
+ if (type === 'filled') {
85
+ color = selected ? intentValue.primary : intentValue.contrast;
86
+ } else if (type === 'outlined') {
87
+ color = selected ? theme.colors.text.inverse : intentValue.primary;
88
+ } else { // soft
89
+ color = selected ? theme.colors.text.inverse : intentValue.dark;
90
+ }
91
+
92
+ return {
93
+ display: 'flex' as const,
94
+ alignItems: 'center' as const,
95
+ justifyContent: 'center' as const,
96
+ width: sizeValue.iconSize as number,
97
+ height: sizeValue.iconSize as number,
98
+ color,
99
+ } as const;
100
+ },
101
+
102
+ deleteButton: (size: ChipSize) => {
103
+ const sizeValue = theme.sizes.chip[size];
104
+
105
+ return {
106
+ display: 'flex' as const,
107
+ alignItems: 'center' as const,
108
+ justifyContent: 'center' as const,
109
+ padding: 0,
110
+ marginLeft: 4,
111
+ borderRadius: 12,
112
+ width: sizeValue.iconSize as number,
113
+ height: sizeValue.iconSize as number,
114
+ } as const;
115
+ },
116
+
117
+ deleteIcon: (size: ChipSize, intent: ChipIntent, type: ChipType, selected: boolean) => {
118
+ const intentValue = theme.intents[intent];
119
+ const sizeValue = theme.sizes.chip[size];
120
+
121
+ // Compute color based on type and selected state (same logic as label/icon)
122
+ let color: string;
123
+
124
+ if (type === 'filled') {
125
+ color = selected ? intentValue.primary : intentValue.contrast;
126
+ } else if (type === 'outlined') {
127
+ color = selected ? theme.colors.text.inverse : intentValue.primary;
128
+ } else { // soft
129
+ color = selected ? theme.colors.text.inverse : intentValue.dark;
130
+ }
131
+
132
+ return {
133
+ fontSize: sizeValue.iconSize as number,
134
+ color,
135
+ } as const;
136
+ },
137
+ } as const;
138
+ });
@@ -0,0 +1,154 @@
1
+ import React, { isValidElement, forwardRef } from 'react';
2
+ import { getWebProps } from 'react-native-unistyles/web';
3
+ import { chipStyles } from './Chip.styles';
4
+ import type { ChipProps } from './types';
5
+ import { IconSvg } from '../Icon/IconSvg/IconSvg.web';
6
+ import { resolveIconPath, isIconName } from '../Icon/icon-resolver';
7
+ import useMergeRefs from '../hooks/useMergeRefs';
8
+
9
+ const Chip = forwardRef<HTMLDivElement, ChipProps>(({
10
+ label,
11
+ type = 'filled',
12
+ intent = 'primary',
13
+ size = 'md',
14
+ icon,
15
+ deletable = false,
16
+ onDelete,
17
+ deleteIcon = 'close',
18
+ selectable = false,
19
+ selected = false,
20
+ onPress,
21
+ disabled = false,
22
+ style,
23
+ testID,
24
+ }, ref) => {
25
+ // Compute actual selected state
26
+ const isSelected = selectable ? selected : false;
27
+
28
+ // Compute dynamic styles
29
+ const containerProps = getWebProps([chipStyles.container(size, intent, type, isSelected, disabled), style as any]);
30
+ const labelProps = getWebProps([chipStyles.label(size, intent, type, isSelected)]);
31
+ const iconProps = getWebProps([chipStyles.icon(size, intent, type, isSelected)]);
32
+ const deleteButtonProps = getWebProps([chipStyles.deleteButton(size)]);
33
+ const deleteIconProps = getWebProps([chipStyles.deleteIcon(size, intent, type, isSelected)]);
34
+
35
+ const handleClick = () => {
36
+ if (disabled) return;
37
+ if (onPress) {
38
+ onPress();
39
+ }
40
+ };
41
+
42
+ const handleDelete = (e: React.MouseEvent) => {
43
+ e.stopPropagation();
44
+ if (disabled) return;
45
+ if (onDelete) {
46
+ onDelete();
47
+ }
48
+ };
49
+
50
+ // Helper to render icon
51
+ const renderIcon = () => {
52
+ if (!icon) return null;
53
+
54
+ if (isIconName(icon)) {
55
+ const iconPath = resolveIconPath(icon);
56
+ return (
57
+ <IconSvg
58
+ path={iconPath}
59
+ {...iconProps}
60
+ aria-label={icon}
61
+ />
62
+ );
63
+ } else if (isValidElement(icon)) {
64
+ return icon;
65
+ }
66
+
67
+ return null;
68
+ };
69
+
70
+ // Helper to render delete icon
71
+ const renderDeleteIcon = () => {
72
+ if (isIconName(deleteIcon)) {
73
+ const iconPath = resolveIconPath(deleteIcon);
74
+ return (
75
+ <IconSvg
76
+ path={iconPath}
77
+ {...deleteIconProps}
78
+ aria-label={deleteIcon}
79
+ />
80
+ );
81
+ } else if (isValidElement(deleteIcon)) {
82
+ return deleteIcon;
83
+ }
84
+
85
+ return null;
86
+ };
87
+
88
+ const isClickable = (onPress && !disabled) || (selectable && !disabled);
89
+
90
+ const mergedRef = useMergeRefs(ref, containerProps.ref);
91
+
92
+ return (
93
+ <div
94
+ {...containerProps}
95
+ ref={mergedRef}
96
+ style={{
97
+ cursor: isClickable ? 'pointer' : 'default',
98
+ userSelect: 'none',
99
+ }}
100
+ onClick={handleClick}
101
+ data-testid={testID}
102
+ role={isClickable ? 'button' : undefined}
103
+ aria-disabled={disabled}
104
+ aria-pressed={selectable ? selected : undefined}
105
+ >
106
+ {icon && (
107
+ <span
108
+ {...iconProps}
109
+ style={{
110
+ display: 'inline-flex',
111
+ alignItems: 'center',
112
+ justifyContent: 'center',
113
+ }}
114
+ >
115
+ {renderIcon()}
116
+ </span>
117
+ )}
118
+
119
+ <span
120
+ {...labelProps}
121
+ style={{
122
+ display: 'inline-flex',
123
+ alignItems: 'center',
124
+ }}
125
+ >
126
+ {label}
127
+ </span>
128
+
129
+ {deletable && onDelete && (
130
+ <button
131
+ {...deleteButtonProps}
132
+ style={{
133
+ background: 'transparent',
134
+ border: 'none',
135
+ cursor: disabled ? 'default' : 'pointer',
136
+ display: 'flex',
137
+ alignItems: 'center',
138
+ justifyContent: 'center',
139
+ }}
140
+ onClick={handleDelete}
141
+ disabled={disabled}
142
+ aria-label="Delete"
143
+ type="button"
144
+ >
145
+ {renderDeleteIcon()}
146
+ </button>
147
+ )}
148
+ </div>
149
+ );
150
+ });
151
+
152
+ Chip.displayName = 'Chip';
153
+
154
+ export default Chip;
@@ -0,0 +1,5 @@
1
+ import ChipComponent from './Chip.native';
2
+
3
+ export default ChipComponent;
4
+ export { ChipComponent as Chip };
5
+ export type { ChipProps, ChipSize, ChipType, ChipIntent } from './types';
@@ -0,0 +1,5 @@
1
+ import ChipComponent from './Chip.web';
2
+
3
+ export default ChipComponent;
4
+ export { ChipComponent as Chip };
5
+ export type { ChipProps, ChipSize, ChipType, ChipIntent } from './types';
@@ -0,0 +1,5 @@
1
+ import ChipComponent from './Chip.web';
2
+
3
+ export default ChipComponent;
4
+ export { ChipComponent as Chip };
5
+ export type { ChipProps, ChipSize, ChipType, ChipIntent } from './types';