@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,13 +1,13 @@
1
- import React from 'react';
1
+ import React, { forwardRef, ComponentRef } from 'react';
2
2
  import { View, Pressable } from 'react-native';
3
3
  import { CardProps } from './types';
4
4
  import { cardStyles } from './Card.styles';
5
5
 
6
- const Card: React.FC<CardProps> = ({
6
+ const Card = forwardRef<ComponentRef<typeof View> | ComponentRef<typeof Pressable>, CardProps>(({
7
7
  children,
8
- variant = 'default',
9
- padding = 'medium',
10
- radius = 'medium',
8
+ type = 'default',
9
+ padding = 'md',
10
+ radius = 'md',
11
11
  intent = 'neutral',
12
12
  clickable = false,
13
13
  onPress,
@@ -15,21 +15,22 @@ const Card: React.FC<CardProps> = ({
15
15
  style,
16
16
  testID,
17
17
  accessibilityLabel,
18
- }) => {
18
+ }, ref) => {
19
19
  // Apply variants
20
20
  cardStyles.useVariants({
21
- variant: variant as any,
22
- padding,
21
+ clickable,
23
22
  radius,
23
+ type,
24
+ padding,
24
25
  intent,
25
- clickable,
26
26
  disabled,
27
27
  });
28
-
28
+
29
29
  // Use appropriate component based on clickable state
30
30
  const Component = clickable ? Pressable : View;
31
31
 
32
32
  const componentProps = {
33
+ ref,
33
34
  style: [cardStyles.card, style],
34
35
  testID,
35
36
  accessibilityLabel,
@@ -47,6 +48,8 @@ const Card: React.FC<CardProps> = ({
47
48
  {children}
48
49
  </Component>
49
50
  );
50
- };
51
+ });
52
+
53
+ Card.displayName = 'Card';
51
54
 
52
55
  export default Card;
@@ -1,240 +1,166 @@
1
1
  import { StyleSheet } from 'react-native-unistyles';
2
+ import { Theme, Intent, CompoundVariants } from '@idealyst/theme';
2
3
 
3
- export const cardStyles = StyleSheet.create((theme) => ({
4
- card: {
5
- backgroundColor: theme.colors?.surface?.primary || '#ffffff',
6
- position: 'relative',
7
- overflow: 'hidden',
8
-
9
- variants: {
10
- variant: {
4
+ type CardType = 'default' | 'outlined' | 'elevated' | 'filled';
5
+ type CardPadding = 'none' | 'sm' | 'md' | 'lg';
6
+ type CardRadius = 'none' | 'sm' | 'md' | 'lg';
7
+ type CardIntent = Intent | 'info' | 'neutral';
8
+
9
+ export type CardVariants = {
10
+ type: CardType;
11
+ padding: CardPadding;
12
+ radius: CardRadius;
13
+ intent: CardIntent;
14
+ clickable: boolean;
15
+ disabled: boolean;
16
+ }
17
+
18
+ /**
19
+ * Create type variants (structure only, colors handled by compound variants)
20
+ */
21
+ function createTypeVariants(theme: Theme) {
22
+ return {
11
23
  default: {
12
- backgroundColor: theme.colors?.surface?.primary || '#ffffff',
13
- // React Native border properties
14
- borderWidth: 1,
15
- borderColor: theme.colors?.border?.primary || theme.palettes?.gray?.[200] || '#e5e7eb',
16
- // Web-specific border override
17
- _web: {
18
- border: `1px solid ${theme.colors?.border?.primary || theme.palettes?.gray?.[200] || '#e5e7eb'}`,
19
- },
24
+ backgroundColor: theme.colors.surface.primary,
25
+ borderWidth: 1,
26
+ borderStyle: 'solid' as const,
20
27
  },
21
28
  outlined: {
22
- backgroundColor: 'transparent',
23
- // React Native border properties
24
- borderWidth: 1,
25
- borderColor: theme.colors?.border?.primary || theme.palettes?.gray?.[300] || '#d1d5db',
26
- // Web-specific border override
27
- _web: {
28
- border: `1px solid ${theme.colors?.border?.primary || theme.palettes?.gray?.[300] || '#d1d5db'}`,
29
- },
29
+ backgroundColor: 'transparent',
30
+ borderWidth: 1,
31
+ borderStyle: 'solid' as const,
30
32
  },
31
33
  elevated: {
32
- backgroundColor: theme.colors?.surface?.primary || '#ffffff',
33
- borderWidth: 0,
34
- _web: {
35
- border: 'none',
36
- },
34
+ backgroundColor: theme.colors.surface.primary,
35
+ borderWidth: 0,
36
+ ...theme.shadows.md,
37
37
  },
38
38
  filled: {
39
- backgroundColor: theme.colors?.surface?.secondary || theme.palettes?.gray?.[50] || '#f9fafb',
40
- borderWidth: 0,
41
- _web: {
42
- border: 'none',
43
- },
44
- },
45
- },
46
- padding: {
47
- none: {
48
- padding: 0,
49
- },
50
- small: {
51
- padding: theme.spacing?.sm || 8,
52
- },
53
- medium: {
54
- padding: theme.spacing?.md || 12,
55
- },
56
- large: {
57
- padding: theme.spacing?.lg || 16,
58
- },
59
- },
60
- radius: {
61
- none: {
62
- borderRadius: 0,
63
- },
64
- small: {
65
- borderRadius: theme.borderRadius?.sm || 4,
66
- },
67
- medium: {
68
- borderRadius: theme.borderRadius?.md || 8,
69
- },
70
- large: {
71
- borderRadius: theme.borderRadius?.lg || 12,
72
- },
73
- },
74
- intent: {
75
- neutral: {
76
- // Default colors handled by variant
77
- },
78
- primary: {
79
- // Intent colors applied via compound variants
80
- },
81
- success: {
82
- // Intent colors applied via compound variants
83
- },
84
- error: {
85
- // Intent colors applied via compound variants
86
- },
87
- warning: {
88
- // Intent colors applied via compound variants
89
- },
90
- info: {
91
- // Intent colors applied via compound variants
92
- },
93
- },
94
- clickable: {
95
- true: {
96
- cursor: 'pointer',
97
- transition: 'all 0.2s ease',
98
- },
99
- false: {
100
- cursor: 'default',
101
- },
102
- },
103
- disabled: {
104
- true: {
105
- opacity: 0.6,
106
- cursor: 'not-allowed',
107
- },
108
- false: {
109
- opacity: 1,
110
- },
111
- },
112
- },
113
-
114
- compoundVariants: [
115
- // Elevated variant with shadows
116
- {
117
- variant: 'elevated',
118
- styles: {
119
- shadowColor: theme.shadows?.md?.shadowColor || '#000',
120
- shadowOffset: theme.shadows?.md?.shadowOffset || { width: 0, height: 4 },
121
- shadowOpacity: theme.shadows?.md?.shadowOpacity || 0.1,
122
- shadowRadius: theme.shadows?.md?.shadowRadius || 8,
123
- elevation: theme.shadows?.md?.elevation || 4,
124
- // More subtle shadow for web
125
- _web: {
126
- boxShadow: '0 2px 8px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04)',
127
- },
128
- },
129
- },
130
- // Intent color combinations for outlined variant
131
- {
132
- variant: 'outlined',
133
- intent: 'primary',
134
- styles: {
135
- borderColor: theme.intents?.primary?.main || '#3b82f6',
136
- _web: {
137
- border: `1px solid ${theme.intents?.primary?.main || '#3b82f6'}`,
138
- },
39
+ backgroundColor: theme.colors.surface.secondary,
40
+ borderWidth: 0,
139
41
  },
140
- },
141
- {
142
- variant: 'outlined',
143
- intent: 'success',
144
- styles: {
145
- borderColor: theme.intents?.success?.main || '#22c55e',
146
- _web: {
147
- border: `1px solid ${theme.intents?.success?.main || '#22c55e'}`,
148
- },
149
- },
150
- },
151
- {
152
- variant: 'outlined',
153
- intent: 'error',
154
- styles: {
155
- borderColor: theme.intents?.error?.main || '#ef4444',
156
- _web: {
157
- border: `1px solid ${theme.intents?.error?.main || '#ef4444'}`,
158
- },
159
- },
160
- },
161
- {
162
- variant: 'outlined',
163
- intent: 'warning',
164
- styles: {
165
- borderColor: theme.intents?.warning?.main || '#f59e0b',
166
- _web: {
167
- border: `1px solid ${theme.intents?.warning?.main || '#f59e0b'}`,
168
- },
169
- },
170
- },
171
- {
172
- variant: 'outlined',
42
+ } as const;
43
+ }
44
+
45
+ /**
46
+ * Create compound variants for type + intent combinations
47
+ */
48
+ function createCardCompoundVariants(theme: Theme) {
49
+ const compoundVariants: CompoundVariants<keyof CardVariants> = [];
50
+
51
+ // Add intent-based border colors for default and outlined types
52
+ for (const intent in theme.intents) {
53
+ const intentValue = theme.intents[intent as Intent];
54
+
55
+ // Default + intent
56
+ compoundVariants.push({
57
+ intent,
58
+ type: 'default',
59
+ styles: {
60
+ borderColor: intentValue.primary,
61
+ },
62
+ });
63
+
64
+ // Outlined + intent
65
+ compoundVariants.push({
66
+ intent,
67
+ type: 'outlined',
68
+ styles: {
69
+ borderColor: intentValue.primary,
70
+ },
71
+ });
72
+ }
73
+
74
+ // Add special intents (info, neutral)
75
+ compoundVariants.push({
173
76
  intent: 'info',
77
+ type: 'default',
174
78
  styles: {
175
- borderColor: theme.intents?.info?.main || '#06b6d4',
176
- _web: {
177
- border: `1px solid ${theme.intents?.info?.main || '#06b6d4'}`,
178
- },
179
- },
180
- },
181
- // Intent color combinations for filled variant
182
- {
183
- variant: 'filled',
184
- intent: 'primary',
185
- styles: {
186
- backgroundColor: theme.intents?.primary?.container || theme.palettes?.blue?.[50] || '#eff6ff',
79
+ borderColor: theme.colors.border.secondary,
187
80
  },
188
- },
189
- {
190
- variant: 'filled',
191
- intent: 'success',
81
+ });
82
+ compoundVariants.push({
83
+ intent: 'info',
84
+ type: 'outlined',
192
85
  styles: {
193
- backgroundColor: theme.intents?.success?.container || theme.palettes?.green?.[50] || '#f0fdf4',
86
+ borderColor: theme.colors.border.secondary,
194
87
  },
195
- },
196
- {
197
- variant: 'filled',
198
- intent: 'error',
88
+ });
89
+ compoundVariants.push({
90
+ intent: 'neutral',
91
+ type: 'default',
199
92
  styles: {
200
- backgroundColor: theme.intents?.error?.container || theme.palettes?.red?.[50] || '#fef2f2',
93
+ borderColor: theme.colors.border.secondary,
201
94
  },
202
- },
203
- {
204
- variant: 'filled',
205
- intent: 'warning',
95
+ });
96
+ compoundVariants.push({
97
+ intent: 'neutral',
98
+ type: 'outlined',
206
99
  styles: {
207
- backgroundColor: theme.intents?.warning?.container || theme.palettes?.amber?.[50] || '#fffbeb',
100
+ borderColor: theme.colors.border.secondary,
208
101
  },
209
- },
210
- {
211
- variant: 'filled',
212
- intent: 'info',
213
- styles: {
214
- backgroundColor: theme.intents?.info?.container || theme.palettes?.cyan?.[50] || '#ecfeff',
215
- },
216
- },
217
- ],
218
-
219
- _web: {
220
- display: 'flex',
221
- flexDirection: 'column',
222
- boxSizing: 'border-box',
223
- _hover: {
224
- // Hover effects for clickable cards
225
- },
226
- },
227
- },
228
- }));
102
+ });
103
+
104
+ return compoundVariants;
105
+ }
229
106
 
230
- // Add hover effects for clickable cards
231
- export const cardHoverStyles = StyleSheet.create((theme) => ({
232
- clickableHover: {
233
- _web: {
234
- _hover: {
235
- transform: 'translateY(-2px)',
236
- boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.06)',
237
- },
238
- },
239
- },
240
- }));
107
+ // Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel
108
+ // transform on native cannot resolve function calls to extract variant structures.
109
+ export const cardStyles = StyleSheet.create((theme: Theme) => {
110
+ return {
111
+ card: {
112
+ backgroundColor: theme.colors.surface.primary,
113
+ position: 'relative',
114
+ overflow: 'hidden',
115
+ variants: {
116
+ type: createTypeVariants(theme),
117
+ padding: {
118
+ none: { padding: 0 },
119
+ sm: { padding: 8 },
120
+ md: { padding: 16 },
121
+ lg: { padding: 24 },
122
+ },
123
+ radius: {
124
+ none: { borderRadius: 0 },
125
+ sm: { borderRadius: 4 },
126
+ md: { borderRadius: 8 },
127
+ lg: { borderRadius: 12 },
128
+ },
129
+ clickable: {
130
+ true: {
131
+ _web: {
132
+ cursor: 'pointer',
133
+ transition: 'all 0.2s ease',
134
+ _hover: {
135
+ transform: 'translateY(-2px)',
136
+ boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08), 0 2px 4px rgba(0, 0, 0, 0.06)',
137
+ },
138
+ },
139
+ },
140
+ false: {
141
+ _web: {
142
+ cursor: 'default',
143
+ },
144
+ },
145
+ },
146
+ disabled: {
147
+ true: {
148
+ opacity: 0.6,
149
+ _web: {
150
+ cursor: 'not-allowed',
151
+ },
152
+ },
153
+ false: {
154
+ opacity: 1,
155
+ },
156
+ },
157
+ },
158
+ compoundVariants: createCardCompoundVariants(theme),
159
+ _web: {
160
+ display: 'flex',
161
+ flexDirection: 'column',
162
+ boxSizing: 'border-box',
163
+ },
164
+ } as const,
165
+ };
166
+ });
@@ -1,21 +1,22 @@
1
- import React from 'react';
1
+ import React, { forwardRef } from 'react';
2
2
  import { getWebProps } from 'react-native-unistyles/web';
3
3
  import { CardProps } from './types';
4
- import { cardStyles, cardHoverStyles } from './Card.styles';
4
+ import { cardStyles } from './Card.styles';
5
+ import useMergeRefs from '../hooks/useMergeRefs';
5
6
 
6
- const Card: React.FC<CardProps> = ({
7
+ const Card = forwardRef<HTMLDivElement | HTMLButtonElement, CardProps>(({
7
8
  children,
8
- variant = 'default',
9
- padding = 'medium',
10
- radius = 'medium',
11
- intent = 'neutral',
9
+ type = 'default',
10
+ padding = 'md',
11
+ radius = 'md',
12
+ intent,
12
13
  clickable = false,
13
14
  onPress,
14
15
  disabled = false,
15
16
  style,
16
17
  testID,
17
18
  accessibilityLabel,
18
- }) => {
19
+ }, ref) => {
19
20
  const handleClick = () => {
20
21
  if (!disabled && clickable && onPress) {
21
22
  onPress();
@@ -24,30 +25,26 @@ const Card: React.FC<CardProps> = ({
24
25
 
25
26
  // Apply variants
26
27
  cardStyles.useVariants({
27
- variant: variant as any,
28
- padding,
28
+ clickable,
29
29
  radius,
30
+ type,
31
+ padding,
30
32
  intent,
31
- clickable,
32
33
  disabled,
33
34
  });
34
35
 
35
- // Create style arrays
36
- const cardStyleArray = [
37
- cardStyles.card,
38
- clickable && !disabled && cardHoverStyles.clickableHover,
39
- style,
40
- ].filter(Boolean);
41
-
42
36
  // Generate web props
43
- const webProps = getWebProps(cardStyleArray);
37
+ const webProps = getWebProps([cardStyles.card, style as any]);
38
+
39
+ const mergedRef = useMergeRefs(ref, webProps.ref);
44
40
 
45
41
  // Use appropriate HTML element based on clickable state
46
- const Component = clickable ? 'button' : 'div';
42
+ const Component: any = clickable ? 'button' : 'div';
47
43
 
48
44
  return (
49
45
  <Component
50
46
  {...webProps}
47
+ ref={mergedRef as any}
51
48
  onClick={clickable ? handleClick : undefined}
52
49
  disabled={clickable && disabled}
53
50
  data-testid={testID}
@@ -57,6 +54,8 @@ const Card: React.FC<CardProps> = ({
57
54
  {children}
58
55
  </Component>
59
56
  );
60
- };
57
+ });
58
+
59
+ Card.displayName = 'Card';
61
60
 
62
61
  export default Card;
package/src/Card/index.ts CHANGED
@@ -1,5 +1,5 @@
1
- // Platform-agnostic Card 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 './Card.web';
5
- export * from './types';
1
+ import CardComponent from './Card.web';
2
+
3
+ export default CardComponent;
4
+ export { CardComponent as Card };
5
+ export * from './types';
@@ -1,3 +1,5 @@
1
- // Web-specific Card export
2
- export { default } from './Card.web';
3
- export * from './types';
1
+ import CardComponent from './Card.web';
2
+
3
+ export default CardComponent;
4
+ export { CardComponent as Card };
5
+ export * from './types';
package/src/Card/types.ts CHANGED
@@ -1,57 +1,64 @@
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 CardIntentVariant = Intent;
7
+ export type CardType = 'default' | 'outlined' | 'elevated' | 'filled';
8
+ export type CardPaddingVariant = 'none' | Size;
9
+ export type CardRadiusVariant = 'none' | Size;
3
10
 
4
11
  export interface CardProps {
5
12
  /**
6
13
  * The content to display inside the card
7
14
  */
8
15
  children?: ReactNode;
9
-
16
+
10
17
  /**
11
18
  * The visual style variant of the card
12
19
  */
13
- variant?: 'default' | 'outlined' | 'elevated' | 'filled';
14
-
20
+ type?: CardType;
21
+
15
22
  /**
16
23
  * The padding size inside the card
17
24
  */
18
- padding?: 'none' | 'small' | 'medium' | 'large';
19
-
25
+ padding?: CardPaddingVariant;
26
+
20
27
  /**
21
28
  * The border radius of the card
22
29
  */
23
- radius?: 'none' | 'small' | 'medium' | 'large';
24
-
30
+ radius?: CardRadiusVariant;
31
+
25
32
  /**
26
33
  * The intent/color scheme of the card
27
34
  */
28
- intent?: IntentVariant;
29
-
35
+ intent?: CardIntentVariant;
36
+
30
37
  /**
31
38
  * Whether the card is clickable
32
39
  */
33
40
  clickable?: boolean;
34
-
41
+
35
42
  /**
36
43
  * Called when the card is pressed (if clickable)
37
44
  */
38
45
  onPress?: () => void;
39
-
46
+
40
47
  /**
41
48
  * Whether the card is disabled
42
49
  */
43
50
  disabled?: boolean;
44
-
51
+
45
52
  /**
46
53
  * Additional styles (platform-specific)
47
54
  */
48
- style?: any;
49
-
55
+ style?: StyleProp<ViewStyle>;
56
+
50
57
  /**
51
58
  * Test ID for testing
52
59
  */
53
60
  testID?: string;
54
-
61
+
55
62
  /**
56
63
  * Accessibility label
57
64
  */