@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,67 +1,79 @@
1
1
  import { StyleSheet } from "react-native-unistyles";
2
- import { generateColorVariants } from "../theme/variantHelpers";
2
+ import { Theme, StylesheetStyles, Styles, DynamicStyles } from '@idealyst/theme';
3
+ import { buildSizeVariants } from '../utils/buildSizeVariants';
4
+ import { TextAlignVariant, TextColorVariant, TextSizeVariant, TextWeightVariant } from "./types";
3
5
 
4
- const textStyles = StyleSheet.create((theme) => ({
5
- text: {
6
- variants: {
7
- size: {
8
- small: {
9
- fontSize: theme.typography.fontSize.xs,
10
- lineHeight: theme.typography.fontSize.xs * 1.33,
11
- },
12
- medium: {
13
- fontSize: theme.typography.fontSize.md,
14
- lineHeight: theme.typography.fontSize.md * 1.5,
15
- },
16
- large: {
17
- fontSize: theme.typography.fontSize.lg,
18
- lineHeight: theme.typography.fontSize.lg * 1.4,
19
- },
20
- xlarge: {
21
- fontSize: theme.typography.fontSize.xl,
22
- lineHeight: theme.typography.fontSize.xl * 1.33,
23
- },
24
- },
25
- weight: {
26
- light: {
27
- fontWeight: theme.typography.fontWeight.light,
28
- },
29
- normal: {
30
- fontWeight: theme.typography.fontWeight.regular,
31
- },
32
- medium: {
33
- fontWeight: theme.typography.fontWeight.medium,
34
- },
35
- semibold: {
36
- fontWeight: theme.typography.fontWeight.semibold,
37
- },
38
- bold: {
39
- fontWeight: theme.typography.fontWeight.bold,
40
- },
41
- },
42
- align: {
43
- left: {
44
- textAlign: 'left',
45
- },
46
- center: {
47
- textAlign: 'center',
48
- },
49
- right: {
50
- textAlign: 'right',
51
- },
52
- },
53
- // Dynamically generated color variants
54
- color: generateColorVariants(theme),
55
- },
56
- color: theme.colors.text.primary, // Default text color
57
- margin: 0,
58
- padding: 0,
59
- // Web-specific styles
60
- _web: {
61
- fontFamily: 'inherit',
62
- lineHeight: 'inherit',
63
- },
64
- },
65
- }));
6
+ type TextVariants = {
7
+ size: TextSizeVariant;
8
+ weight: TextWeightVariant;
9
+ align: TextAlignVariant;
10
+ color: TextColorVariant;
11
+ }
66
12
 
67
- export default textStyles;
13
+ export type TextStylesheet = {
14
+ text: DynamicStyles<keyof TextVariants>;
15
+ }
16
+
17
+ /**
18
+ * Create size variants for text
19
+ */
20
+ function createSizeVariants(theme: Theme): any {
21
+ return buildSizeVariants(theme, 'text', (size) => ({
22
+ fontSize: size.fontSize,
23
+ lineHeight: size.lineHeight,
24
+ }));
25
+ }
26
+
27
+ function createTextStyles(theme: Theme) {
28
+ return ({ color }: Partial<TextVariants>) => {
29
+ const colorValue = theme.colors.text[color] || theme.colors.text.primary;
30
+ return {
31
+ margin: 0,
32
+ padding: 0,
33
+ color: colorValue,
34
+ variants: {
35
+ size: createSizeVariants(theme) as any,
36
+ weight: {
37
+ light: {
38
+ fontWeight: '300',
39
+ },
40
+ normal: {
41
+ fontWeight: '400',
42
+ },
43
+ medium: {
44
+ fontWeight: '500',
45
+ },
46
+ semibold: {
47
+ fontWeight: '600',
48
+ },
49
+ bold: {
50
+ fontWeight: '700',
51
+ },
52
+ } as const,
53
+ align: {
54
+ left: {
55
+ textAlign: 'left',
56
+ },
57
+ center: {
58
+ textAlign: 'center',
59
+ },
60
+ right: {
61
+ textAlign: 'right',
62
+ },
63
+ } as const,
64
+ } as const,
65
+ _web: {
66
+ fontFamily: 'inherit',
67
+ lineHeight: 'inherit',
68
+ },
69
+ } as const;
70
+ }
71
+ }
72
+
73
+ // Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel
74
+ // transform on native cannot resolve function calls to extract variant structures.
75
+ export const textStyles = StyleSheet.create((theme: Theme) => {
76
+ return {
77
+ text: createTextStyles(theme),
78
+ } as TextStylesheet;
79
+ });
@@ -1,41 +1,46 @@
1
- import React from 'react';
1
+ import React, { forwardRef } from 'react';
2
2
  import { getWebProps } from 'react-native-unistyles/web';
3
3
  import { TextProps } from './types';
4
- import textStyles from './Text.styles';
4
+ import { textStyles } from './Text.styles';
5
+ import useMergeRefs from '../hooks/useMergeRefs';
5
6
 
6
- const Text: React.FC<TextProps> = ({
7
+ const Text = forwardRef<HTMLSpanElement, TextProps>(({
7
8
  children,
8
- size = 'medium',
9
+ size = 'md',
9
10
  weight = 'normal',
10
- color,
11
+ color = 'primary',
11
12
  align = 'left',
12
13
  style,
13
14
  testID,
14
- }) => {
15
+ }, ref) => {
15
16
  textStyles.useVariants({
16
17
  size,
17
18
  weight,
18
19
  align,
19
- color: color
20
20
  });
21
21
 
22
22
  // Create the style array following the official documentation pattern
23
23
  const textStyleArray = [
24
- textStyles.text,
24
+ textStyles.text({ color }),
25
25
  style,
26
26
  ];
27
27
 
28
28
  // Use getWebProps to generate className and ref for web
29
29
  const webProps = getWebProps(textStyleArray);
30
30
 
31
+ const mergedRef = useMergeRefs(ref, webProps.ref);
32
+
31
33
  return (
32
34
  <span
33
35
  {...webProps}
36
+ ref={mergedRef}
34
37
  data-testid={testID}
35
38
  >
36
39
  {children}
37
40
  </span>
38
41
  );
39
- };
42
+ });
43
+
44
+ Text.displayName = 'Text';
40
45
 
41
46
  export default Text;
package/src/Text/index.ts CHANGED
@@ -1,5 +1,5 @@
1
- // Platform-agnostic Text export
2
- // Bundlers will resolve to index.web.ts (web) or index.native.ts (React Native)
3
- // This file serves as fallback for web environments
4
- export { default } from './Text.web';
5
- export * from './types';
1
+ import TextComponent from './Text.web';
2
+
3
+ export default TextComponent;
4
+ export { TextComponent as Text };
5
+ export * from './types';
@@ -1,3 +1,5 @@
1
- // Web-specific Text export
2
- export { default } from './Text.web';
3
- export * from './types';
1
+ import TextComponent from './Text.web';
2
+
3
+ export default TextComponent;
4
+ export { TextComponent as Text };
5
+ export * from './types';
package/src/Text/types.ts CHANGED
@@ -1,37 +1,44 @@
1
- import { ReactNode } from 'react';
2
- import type { DisplayColorVariant } from '../theme/variants';
1
+ import { Text } from '@idealyst/theme';
2
+ import type { ReactNode } from 'react';
3
+ import type { StyleProp, TextStyle } from 'react-native';
4
+
5
+ // Component-specific type aliases for future extensibility
6
+ export type TextColorVariant = Text;
7
+ export type TextSizeVariant = 'sm' | 'md' | 'lg' | 'xl'; // Using sm/md/lg/xl for consistency
8
+ export type TextWeightVariant = 'light' | 'normal' | 'medium' | 'semibold' | 'bold';
9
+ export type TextAlignVariant = 'left' | 'center' | 'right';
3
10
 
4
11
  export interface TextProps {
5
12
  /**
6
13
  * The text content to display
7
14
  */
8
15
  children: ReactNode;
9
-
16
+
10
17
  /**
11
18
  * The size variant of the text
12
19
  */
13
- size?: 'small' | 'medium' | 'large' | 'xlarge';
14
-
20
+ size?: TextSizeVariant;
21
+
15
22
  /**
16
23
  * The weight of the text
17
24
  */
18
- weight?: 'light' | 'normal' | 'medium' | 'semibold' | 'bold';
19
-
25
+ weight?: TextWeightVariant;
26
+
20
27
  /**
21
28
  * The color of the text
22
29
  */
23
- color?: DisplayColorVariant;
24
-
30
+ color?: TextColorVariant;
31
+
25
32
  /**
26
33
  * Text alignment
27
34
  */
28
- align?: 'left' | 'center' | 'right';
29
-
35
+ align?: TextAlignVariant;
36
+
30
37
  /**
31
38
  * Additional styles (platform-specific)
32
39
  */
33
- style?: any;
34
-
40
+ style?: StyleProp<TextStyle>;
41
+
35
42
  /**
36
43
  * Test ID for testing
37
44
  */
@@ -0,0 +1,134 @@
1
+ import React, { useState, forwardRef } from 'react';
2
+ import { View, TextInput, NativeSyntheticEvent, TextInputContentSizeChangeEventData } from 'react-native';
3
+ import { textAreaStyles } from './TextArea.styles';
4
+ import Text from '../Text';
5
+ import type { TextAreaProps } from './types';
6
+
7
+ const TextArea = forwardRef<TextInput, TextAreaProps>(({
8
+ value: controlledValue,
9
+ defaultValue = '',
10
+ onChange,
11
+ placeholder,
12
+ disabled = false,
13
+ minHeight,
14
+ maxHeight,
15
+ autoGrow = false,
16
+ maxLength,
17
+ rows = 4,
18
+ label,
19
+ error,
20
+ helperText,
21
+ showCharacterCount = false,
22
+ intent = 'primary',
23
+ size = 'md',
24
+ style,
25
+ textareaStyle,
26
+ testID,
27
+ }, ref) => {
28
+ const [internalValue, setInternalValue] = useState(defaultValue);
29
+ const [contentHeight, setContentHeight] = useState<number | undefined>(undefined);
30
+
31
+ const value = controlledValue !== undefined ? controlledValue : internalValue;
32
+ const hasError = Boolean(error);
33
+
34
+ // Apply variants
35
+ textAreaStyles.useVariants({
36
+ size,
37
+ intent,
38
+ disabled,
39
+ hasError,
40
+ resize: 'none',
41
+ isNearLimit: maxLength ? value.length >= maxLength * 0.9 : false,
42
+ isAtLimit: maxLength ? value.length >= maxLength : false,
43
+ });
44
+
45
+ const handleChange = (newValue: string) => {
46
+ if (maxLength && newValue.length > maxLength) {
47
+ return;
48
+ }
49
+
50
+ if (controlledValue === undefined) {
51
+ setInternalValue(newValue);
52
+ }
53
+
54
+ onChange?.(newValue);
55
+ };
56
+
57
+ const handleContentSizeChange = (e: NativeSyntheticEvent<TextInputContentSizeChangeEventData>) => {
58
+ if (!autoGrow) return;
59
+
60
+ let newHeight = e.nativeEvent.contentSize.height;
61
+
62
+ // Apply min/max height constraints
63
+ if (minHeight && newHeight < minHeight) {
64
+ newHeight = minHeight;
65
+ }
66
+
67
+ if (maxHeight && newHeight > maxHeight) {
68
+ newHeight = maxHeight;
69
+ }
70
+
71
+ setContentHeight(newHeight);
72
+ };
73
+
74
+ const showFooter = (error || helperText) || (showCharacterCount && maxLength);
75
+
76
+ return (
77
+ <View style={[textAreaStyles.container, style]} testID={testID}>
78
+ {label && (
79
+ <Text style={textAreaStyles.label}>{label}</Text>
80
+ )}
81
+
82
+ <View style={textAreaStyles.textareaContainer}>
83
+ <TextInput
84
+ ref={ref}
85
+ style={[
86
+ textAreaStyles.textarea({ intent, disabled, hasError }),
87
+ {
88
+ textAlignVertical: 'top',
89
+ },
90
+ maxHeight && { maxHeight },
91
+ { height: autoGrow ? contentHeight : rows * 24 },
92
+ textareaStyle,
93
+ ]}
94
+ value={value}
95
+ onChangeText={handleChange}
96
+ onContentSizeChange={handleContentSizeChange}
97
+ placeholder={placeholder}
98
+ editable={!disabled}
99
+ multiline
100
+ numberOfLines={0}
101
+ maxLength={maxLength}
102
+ placeholderTextColor="#999"
103
+ />
104
+ </View>
105
+
106
+ {showFooter && (
107
+ <View style={textAreaStyles.footer}>
108
+ <View style={{ flex: 1 }}>
109
+ {error && (
110
+ <Text style={textAreaStyles.helperText}>
111
+ {error}
112
+ </Text>
113
+ )}
114
+ {!error && helperText && (
115
+ <Text style={textAreaStyles.helperText}>
116
+ {helperText}
117
+ </Text>
118
+ )}
119
+ </View>
120
+
121
+ {showCharacterCount && maxLength && (
122
+ <Text style={textAreaStyles.characterCount}>
123
+ {value.length}/{maxLength}
124
+ </Text>
125
+ )}
126
+ </View>
127
+ )}
128
+ </View>
129
+ );
130
+ });
131
+
132
+ TextArea.displayName = 'TextArea';
133
+
134
+ export default TextArea;
@@ -0,0 +1,175 @@
1
+ import { StyleSheet } from 'react-native-unistyles';
2
+ import { Theme, StylesheetStyles, Intent, Size} from '@idealyst/theme';
3
+ import { buildSizeVariants } from '../utils/buildSizeVariants';
4
+ import { TextAreaIntentVariant } from './types';
5
+
6
+
7
+ /**
8
+ * Create size variants for textarea
9
+ */
10
+ function createTextareaSizeVariants(theme: Theme) {
11
+ return buildSizeVariants(theme, 'textarea', (size) => ({
12
+ fontSize: size.fontSize,
13
+ padding: size.padding,
14
+ lineHeight: size.lineHeight,
15
+ minHeight: size.minHeight,
16
+ }));
17
+ }
18
+
19
+ /**
20
+ * Get textarea styles based on intent, disabled, and hasError state
21
+ */
22
+ function getTextareaIntentStyles(theme: Theme, intent: TextAreaIntentVariant, disabled: boolean, hasError: boolean) {
23
+ if (disabled || hasError) {
24
+ return {} as const;
25
+ }
26
+
27
+ const intentValue = theme.intents[intent];
28
+ const baseStyles: any = {};
29
+
30
+ // For success and warning, set border color
31
+ if (intent === 'success' || intent === 'warning') {
32
+ baseStyles.borderColor = intentValue.primary;
33
+ }
34
+
35
+ // Focus styles for all intents when not disabled and not in error
36
+ baseStyles._web = {
37
+ _focus: {
38
+ borderColor: intentValue.primary,
39
+ boxShadow: `0 0 0 2px ${intentValue.primary}33`,
40
+ },
41
+ };
42
+
43
+ return baseStyles;
44
+ }
45
+
46
+ const createTextareaStyles = (theme: Theme) => {
47
+ return ({ intent, disabled, hasError }: { intent: TextAreaIntentVariant, disabled: boolean, hasError: boolean }) => {
48
+ const intentStyles = getTextareaIntentStyles(theme, intent, disabled, hasError);
49
+
50
+ return {
51
+ width: '100%',
52
+ color: theme.colors.text.primary,
53
+ backgroundColor: theme.colors.surface.primary,
54
+ borderWidth: 1,
55
+ borderStyle: 'solid',
56
+ borderColor: theme.colors.border.primary,
57
+ borderRadius: 8,
58
+ lineHeight: 'normal',
59
+ ...intentStyles,
60
+ variants: {
61
+ size: createTextareaSizeVariants(theme),
62
+ disabled: {
63
+ true: {
64
+ opacity: 0.5,
65
+ backgroundColor: theme.colors.surface.secondary,
66
+ _web: {
67
+ cursor: 'not-allowed',
68
+ },
69
+ },
70
+ false: {},
71
+ },
72
+ hasError: {
73
+ true: {
74
+ borderColor: theme.intents.error.primary,
75
+ },
76
+ false: {},
77
+ },
78
+ resize: {
79
+ none: {
80
+ _web: {
81
+ resize: 'none',
82
+ },
83
+ },
84
+ vertical: {
85
+ _web: {
86
+ resize: 'vertical',
87
+ },
88
+ },
89
+ horizontal: {
90
+ _web: {
91
+ resize: 'horizontal',
92
+ },
93
+ },
94
+ both: {
95
+ _web: {
96
+ resize: 'both',
97
+ },
98
+ },
99
+ },
100
+ },
101
+ _web: {
102
+ fontFamily: 'inherit',
103
+ outline: 'none',
104
+ transition: 'border-color 0.2s ease, box-shadow 0.2s ease',
105
+ boxSizing: 'border-box',
106
+ overflowY: 'hidden',
107
+ },
108
+ } as const;
109
+ }
110
+ }
111
+
112
+ // Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel transform on native cannot resolve function calls to extract variant structures.
113
+ export const textAreaStyles = StyleSheet.create((theme: Theme) => {
114
+ return {
115
+ container: {
116
+ display: 'flex',
117
+ flexDirection: 'column',
118
+ gap: 4,
119
+ },
120
+ label: {
121
+ fontSize: 14,
122
+ fontWeight: '500',
123
+ color: theme.colors.text.primary,
124
+ variants: {
125
+ disabled: {
126
+ true: {
127
+ opacity: 0.5,
128
+ },
129
+ false: {},
130
+ },
131
+ },
132
+ },
133
+ textareaContainer: {
134
+ position: 'relative',
135
+ },
136
+ textarea: createTextareaStyles(theme),
137
+ helperText: {
138
+ fontSize: 12,
139
+ color: theme.colors.text.secondary,
140
+ variants: {
141
+ hasError: {
142
+ true: {
143
+ color: theme.intents.error.primary,
144
+ },
145
+ false: {},
146
+ },
147
+ },
148
+ },
149
+ footer: {
150
+ display: 'flex',
151
+ flexDirection: 'row',
152
+ justifyContent: 'space-between',
153
+ alignItems: 'center',
154
+ gap: 4,
155
+ },
156
+ characterCount: {
157
+ fontSize: 12,
158
+ color: theme.colors.text.secondary,
159
+ variants: {
160
+ isNearLimit: {
161
+ true: {
162
+ color: theme.intents.warning.primary,
163
+ },
164
+ false: {},
165
+ },
166
+ isAtLimit: {
167
+ true: {
168
+ color: theme.intents.error.primary,
169
+ },
170
+ false: {},
171
+ },
172
+ },
173
+ },
174
+ };
175
+ });