@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
@@ -0,0 +1,51 @@
1
+ import type { StyleProp, ViewStyle } from 'react-native';
2
+ import type { IconName } from '../Icon/icon-types';
3
+ import { Intent, Size } from '@idealyst/theme';
4
+
5
+ export type ChipSize = Size;
6
+ export type ChipType = 'filled' | 'outlined' | 'soft';
7
+ export type ChipIntent = Intent;
8
+
9
+ export interface ChipProps {
10
+ /** The text content of the chip */
11
+ label: string;
12
+
13
+ /** Visual style variant */
14
+ type?: ChipType;
15
+
16
+ /** Color intent/semantic meaning */
17
+ intent?: ChipIntent;
18
+
19
+ /** Size of the chip */
20
+ size?: ChipSize;
21
+
22
+ /** Icon to display before the label. Can be an icon name (string) or a custom React element */
23
+ icon?: IconName | React.ReactNode;
24
+
25
+ /** Whether the chip can be deleted */
26
+ deletable?: boolean;
27
+
28
+ /** Callback when delete button is pressed */
29
+ onDelete?: () => void;
30
+
31
+ /** Icon to display in the delete button. Defaults to 'close' */
32
+ deleteIcon?: IconName | React.ReactNode;
33
+
34
+ /** Whether the chip is selectable */
35
+ selectable?: boolean;
36
+
37
+ /** Whether the chip is selected (when selectable) */
38
+ selected?: boolean;
39
+
40
+ /** Callback when chip is pressed */
41
+ onPress?: () => void;
42
+
43
+ /** Whether the chip is disabled */
44
+ disabled?: boolean;
45
+
46
+ /** Custom style */
47
+ style?: StyleProp<ViewStyle>;
48
+
49
+ /** Test ID for testing */
50
+ testID?: string;
51
+ }
@@ -1,21 +1,57 @@
1
- import React, { useEffect } from 'react';
1
+ import React, { useEffect, forwardRef } from 'react';
2
2
  import { Modal, View, Text, TouchableOpacity, TouchableWithoutFeedback, BackHandler } from 'react-native';
3
+ import Animated, { useSharedValue, useAnimatedStyle, withTiming, Easing } from 'react-native-reanimated';
3
4
  import { DialogProps } from './types';
4
5
  import { dialogStyles } from './Dialog.styles';
5
6
 
6
- const Dialog: React.FC<DialogProps> = ({
7
+ const Dialog = forwardRef<View, DialogProps>(({
7
8
  open,
8
9
  onOpenChange,
9
10
  title,
10
11
  children,
11
- size = 'medium',
12
- variant = 'default',
12
+ size = 'md',
13
+ type = 'standard',
13
14
  showCloseButton = true,
14
15
  closeOnBackdropClick = true,
15
16
  animationType = 'fade',
16
17
  style,
17
18
  testID,
18
- }) => {
19
+ }, ref) => {
20
+ const backdropOpacity = useSharedValue(0);
21
+ const containerScale = useSharedValue(0.9);
22
+ const containerOpacity = useSharedValue(0);
23
+
24
+ // Animate in/out when open changes
25
+ useEffect(() => {
26
+ if (open) {
27
+ backdropOpacity.value = withTiming(1, {
28
+ duration: 200,
29
+ easing: Easing.out(Easing.ease),
30
+ });
31
+ containerScale.value = withTiming(1, {
32
+ duration: 250,
33
+ easing: Easing.out(Easing.cubic),
34
+ });
35
+ containerOpacity.value = withTiming(1, {
36
+ duration: 200,
37
+ easing: Easing.out(Easing.ease),
38
+ });
39
+ } else {
40
+ backdropOpacity.value = withTiming(0, {
41
+ duration: 150,
42
+ easing: Easing.in(Easing.ease),
43
+ });
44
+ containerScale.value = withTiming(0.9, {
45
+ duration: 150,
46
+ easing: Easing.in(Easing.cubic),
47
+ });
48
+ containerOpacity.value = withTiming(0, {
49
+ duration: 150,
50
+ easing: Easing.in(Easing.ease),
51
+ });
52
+ }
53
+ }, [open]);
54
+
19
55
  // Handle Android back button
20
56
  useEffect(() => {
21
57
  if (!open) return;
@@ -42,22 +78,37 @@ const Dialog: React.FC<DialogProps> = ({
42
78
  // Apply variants
43
79
  dialogStyles.useVariants({
44
80
  size,
45
- variant,
81
+ type,
82
+ });
83
+
84
+ const backdropAnimatedStyle = useAnimatedStyle(() => {
85
+ return {
86
+ opacity: backdropOpacity.value,
87
+ };
88
+ });
89
+
90
+ const containerAnimatedStyle = useAnimatedStyle(() => {
91
+ return {
92
+ opacity: containerOpacity.value,
93
+ transform: [
94
+ { scale: containerScale.value },
95
+ ],
96
+ };
46
97
  });
47
98
 
48
99
  return (
49
100
  <Modal
50
101
  visible={open}
51
102
  transparent
52
- animationType={animationType}
103
+ animationType="none"
53
104
  onRequestClose={() => onOpenChange(false)}
54
105
  statusBarTranslucent
55
106
  testID={testID}
56
107
  >
57
108
  <TouchableWithoutFeedback onPress={handleBackdropPress}>
58
- <View style={dialogStyles.backdrop}>
109
+ <Animated.View style={[dialogStyles.backdrop, backdropAnimatedStyle]}>
59
110
  <TouchableWithoutFeedback onPress={(e) => e.stopPropagation()}>
60
- <View style={[dialogStyles.container, style]}>
111
+ <Animated.View ref={ref as any} style={[dialogStyles.container, style, containerAnimatedStyle]}>
61
112
  {(title || showCloseButton) && (
62
113
  <View style={dialogStyles.header}>
63
114
  {title && (
@@ -80,12 +131,14 @@ const Dialog: React.FC<DialogProps> = ({
80
131
  <View style={dialogStyles.content}>
81
132
  {children}
82
133
  </View>
83
- </View>
134
+ </Animated.View>
84
135
  </TouchableWithoutFeedback>
85
- </View>
136
+ </Animated.View>
86
137
  </TouchableWithoutFeedback>
87
138
  </Modal>
88
139
  );
89
- };
140
+ });
141
+
142
+ Dialog.displayName = 'Dialog';
90
143
 
91
144
  export default Dialog;
@@ -1,148 +1,166 @@
1
1
  import { StyleSheet } from 'react-native-unistyles';
2
+ import { Theme, StylesheetStyles} from '@idealyst/theme';
3
+ type DialogSize = 'sm' | 'md' | 'lg' | 'fullscreen';
4
+ type DialogType = 'default' | 'alert' | 'confirmation';
2
5
 
3
- export const dialogStyles = StyleSheet.create((theme) => ({
4
- backdrop: {
5
- position: 'absolute',
6
- top: 0,
7
- left: 0,
8
- right: 0,
9
- bottom: 0,
10
- backgroundColor: 'rgba(0, 0, 0, 0.5)',
11
- display: 'flex',
12
- alignItems: 'center',
13
- justifyContent: 'center',
14
- zIndex: 1000,
15
-
16
- // Web-specific styles
17
- _web: {
18
- position: 'fixed',
19
- transition: 'opacity 150ms ease-out',
20
- },
21
- },
22
-
23
- container: {
24
- backgroundColor: theme.colors?.background?.primary || '#ffffff',
25
- borderRadius: theme.borderRadius?.lg || 12,
26
- shadowColor: '#000',
27
- shadowOffset: {
28
- width: 0,
29
- height: 10,
30
- },
31
- shadowOpacity: 0.25,
32
- shadowRadius: 20,
33
- elevation: 10,
34
- maxHeight: '90%',
35
-
36
- variants: {
37
- size: {
38
- small: {
39
- width: '90%',
40
- maxWidth: 400,
6
+ type DialogVariants = {
7
+ size: DialogSize;
8
+ type: DialogType;
9
+ }
10
+
11
+ export type ExpandedDialogStyles = StylesheetStyles<keyof DialogVariants>;
12
+
13
+ export type DialogStylesheet = {
14
+ backdrop: ExpandedDialogStyles;
15
+ container: ExpandedDialogStyles;
16
+ header: ExpandedDialogStyles;
17
+ title: ExpandedDialogStyles;
18
+ closeButton: ExpandedDialogStyles;
19
+ closeButtonText: ExpandedDialogStyles;
20
+ content: ExpandedDialogStyles;
21
+ modal: ExpandedDialogStyles;
22
+ }
23
+
24
+ /**
25
+ * Create size variants for container
26
+ */
27
+ function createContainerSizeVariants() {
28
+ return {
29
+ sm: {
30
+ width: '90%',
31
+ maxWidth: 400,
41
32
  },
42
- medium: {
43
- width: '90%',
44
- maxWidth: 600,
33
+ md: {
34
+ width: '90%',
35
+ maxWidth: 600,
45
36
  },
46
- large: {
47
- width: '90%',
48
- maxWidth: 800,
37
+ lg: {
38
+ width: '90%',
39
+ maxWidth: 800,
49
40
  },
50
41
  fullscreen: {
51
- width: '100%',
52
- height: '100%',
53
- borderRadius: 0,
54
- maxHeight: '100%',
42
+ width: '100%',
43
+ height: '100%',
44
+ borderRadius: 0,
45
+ maxHeight: '100%',
55
46
  },
56
- },
57
- variant: {
58
- default: {},
47
+ } as const;
48
+ }
49
+
50
+ /**
51
+ * Create type variants for container
52
+ */
53
+ function createContainerTypeVariants(theme: Theme) {
54
+ return {
55
+ standard: {},
59
56
  alert: {
60
- borderTopWidth: 4,
61
- borderTopColor: theme.colors?.border?.primary || '#e5e7eb',
57
+ borderTopWidth: 4,
58
+ borderTopColor: theme.colors.border.primary,
62
59
  },
63
60
  confirmation: {
64
- borderTopWidth: 4,
65
- borderTopColor: theme.colors?.border?.primary || '#e5e7eb',
61
+ borderTopWidth: 4,
62
+ borderTopColor: theme.colors.border.primary,
66
63
  },
67
- },
68
- },
69
-
70
- // Web-specific styles
71
- _web: {
72
- position: 'relative',
73
- display: 'flex',
74
- flexDirection: 'column',
75
- overflow: 'auto',
76
- boxShadow: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
77
- transition: 'opacity 150ms ease-out, transform 150ms ease-out',
78
- transformOrigin: 'center center',
79
- },
80
- },
81
-
82
- header: {
83
- borderBottomWidth: 1,
84
- borderBottomColor: theme.colors?.border?.primary || '#e5e7eb',
85
- display: 'flex',
86
- flexDirection: 'row',
87
- alignItems: 'center',
88
- justifyContent: 'space-between',
89
-
90
- _web: {
91
- borderBottomStyle: 'solid',
92
- },
93
- },
94
-
95
- title: {
96
- marginLeft: theme.spacing?.lg || 12,
97
- fontSize: 18,
98
- paddingVertical: theme.spacing.md,
99
- fontWeight: '600',
100
- color: theme.colors?.text?.primary || '#111827',
101
- flex: 1,
64
+ } as const;
65
+ }
102
66
 
103
- _web: {
104
- paddingVertical: theme.spacing.xs,
105
- }
106
- },
107
-
108
- closeButton: {
109
- width: 32,
110
- height: 32,
111
- marginRight: theme.spacing?.md || 12,
112
- borderRadius: 16,
113
- backgroundColor: 'transparent',
114
- border: 'none',
115
- display: 'flex',
116
- alignItems: 'center',
117
- justifyContent: 'center',
118
- cursor: 'pointer',
119
-
120
- _web: {
121
- _hover: {
122
- backgroundColor: theme.colors?.background?.secondary || '#f3f4f6',
123
- },
124
- },
125
- },
126
-
127
- closeButtonText: {
128
- fontSize: 18,
129
- color: theme.colors?.text?.secondary || '#6b7280',
130
- fontWeight: '500',
131
- },
132
-
133
- content: {
134
- padding: theme.spacing?.lg || 16,
135
-
136
- _web: {
137
- overflow: 'visible',
138
- maxHeight: 'none',
139
- },
140
- },
141
-
142
- // Native-specific modal styles
143
- modal: {
144
- margin: 0,
145
- justifyContent: 'center',
146
- alignItems: 'center',
147
- },
148
- }));
67
+ // Styles are inlined here instead of in @idealyst/theme because Unistyles' Babel transform on native cannot resolve function calls to extract variant structures.
68
+ export const dialogStyles = StyleSheet.create((theme: Theme) => {
69
+ return {
70
+ backdrop: {
71
+ position: 'absolute',
72
+ top: 0,
73
+ left: 0,
74
+ right: 0,
75
+ bottom: 0,
76
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
77
+ display: 'flex',
78
+ alignItems: 'center',
79
+ justifyContent: 'center',
80
+ zIndex: 1000,
81
+ _web: {
82
+ position: 'fixed',
83
+ transition: 'opacity 150ms ease-out',
84
+ },
85
+ },
86
+ container: {
87
+ backgroundColor: theme.colors.surface.primary,
88
+ borderRadius: 12,
89
+ shadowColor: '#000',
90
+ shadowOffset: { width: 0, height: 10 },
91
+ shadowOpacity: 0.25,
92
+ shadowRadius: 20,
93
+ elevation: 10,
94
+ maxHeight: '90%',
95
+ variants: {
96
+ size: createContainerSizeVariants(),
97
+ type: createContainerTypeVariants(theme),
98
+ },
99
+ _web: {
100
+ position: 'relative',
101
+ display: 'flex',
102
+ flexDirection: 'column',
103
+ overflow: 'auto',
104
+ boxShadow: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
105
+ transition: 'opacity 150ms ease-out, transform 150ms ease-out',
106
+ transformOrigin: 'center center',
107
+ },
108
+ },
109
+ header: {
110
+ borderBottomWidth: 1,
111
+ borderBottomColor: theme.colors.border.primary,
112
+ display: 'flex',
113
+ flexDirection: 'row',
114
+ alignItems: 'center',
115
+ justifyContent: 'space-between',
116
+ _web: {
117
+ borderBottomStyle: 'solid',
118
+ },
119
+ },
120
+ title: {
121
+ marginLeft: 24,
122
+ fontSize: 18,
123
+ paddingVertical: 16,
124
+ fontWeight: '600',
125
+ color: theme.colors.text.primary,
126
+ flex: 1,
127
+ _web: {
128
+ paddingVertical: 4,
129
+ },
130
+ },
131
+ closeButton: {
132
+ width: 32,
133
+ height: 32,
134
+ marginRight: 16,
135
+ borderRadius: 16,
136
+ backgroundColor: 'transparent',
137
+ display: 'flex',
138
+ alignItems: 'center',
139
+ justifyContent: 'center',
140
+ _web: {
141
+ border: 'none',
142
+ cursor: 'pointer',
143
+ _hover: {
144
+ backgroundColor: theme.colors.surface.secondary,
145
+ },
146
+ },
147
+ },
148
+ closeButtonText: {
149
+ fontSize: 18,
150
+ color: theme.colors.text.secondary,
151
+ fontWeight: '500',
152
+ },
153
+ content: {
154
+ padding: 24,
155
+ _web: {
156
+ overflow: 'visible',
157
+ maxHeight: 'none',
158
+ },
159
+ },
160
+ modal: {
161
+ margin: 0,
162
+ justifyContent: 'center',
163
+ alignItems: 'center',
164
+ },
165
+ };
166
+ });
@@ -1,24 +1,24 @@
1
- import React, { useEffect, useRef, useState } from 'react';
1
+ import React, { useEffect, useRef, useState, forwardRef } from 'react';
2
2
  import { createPortal } from 'react-dom';
3
3
  import { getWebProps } from 'react-native-unistyles/web';
4
4
  import { DialogProps } from './types';
5
5
  import { dialogStyles } from './Dialog.styles';
6
6
  import Icon from '../Icon';
7
+ import useMergeRefs from '../hooks/useMergeRefs';
7
8
 
8
-
9
- const Dialog: React.FC<DialogProps> = ({
9
+ const Dialog = forwardRef<HTMLDivElement, DialogProps>(({
10
10
  open,
11
11
  onOpenChange,
12
12
  title,
13
13
  children,
14
- size = 'medium',
15
- variant = 'default',
14
+ size = 'md',
15
+ type = 'standard',
16
16
  showCloseButton = true,
17
17
  closeOnBackdropClick = true,
18
18
  closeOnEscapeKey = true,
19
19
  style,
20
20
  testID,
21
- }) => {
21
+ }, ref) => {
22
22
  const dialogRef = useRef<HTMLDivElement>(null);
23
23
  const previousActiveElementRef = useRef<HTMLElement | null>(null);
24
24
  const [isVisible, setIsVisible] = useState(false);
@@ -104,7 +104,7 @@ const Dialog: React.FC<DialogProps> = ({
104
104
  // Apply variants
105
105
  dialogStyles.useVariants({
106
106
  size,
107
- variant,
107
+ type,
108
108
  });
109
109
 
110
110
  const backdropProps = getWebProps([
@@ -112,9 +112,9 @@ const Dialog: React.FC<DialogProps> = ({
112
112
  { opacity: isVisible ? 1 : 0 }
113
113
  ]);
114
114
  const containerProps = getWebProps([
115
- dialogStyles.container,
116
- style,
117
- isVisible
115
+ dialogStyles.container,
116
+ style as any,
117
+ isVisible
118
118
  ? { opacity: 1, transform: 'scale(1) translateY(0px)' }
119
119
  : { opacity: 0, transform: 'scale(0.96) translateY(-4px)' }
120
120
  ]);
@@ -123,9 +123,12 @@ const Dialog: React.FC<DialogProps> = ({
123
123
  const closeButtonProps = getWebProps([dialogStyles.closeButton]);
124
124
  const contentProps = getWebProps([dialogStyles.content]);
125
125
 
126
+ const mergedBackdropRef = useMergeRefs(ref, backdropProps.ref);
127
+
126
128
  const dialogContent = (
127
129
  <div
128
130
  {...backdropProps}
131
+ ref={mergedBackdropRef}
129
132
  onClick={handleBackdropClick}
130
133
  data-testid={testID}
131
134
  >
@@ -165,6 +168,8 @@ const Dialog: React.FC<DialogProps> = ({
165
168
  );
166
169
 
167
170
  return createPortal(dialogContent, document.body);
168
- };
171
+ });
172
+
173
+ Dialog.displayName = 'Dialog';
169
174
 
170
175
  export default Dialog;
@@ -1,2 +1,5 @@
1
- export { default } from './Dialog.web';
2
- export * from './types';
1
+ import DialogComponent from './Dialog.web';
2
+
3
+ export default DialogComponent;
4
+ export { DialogComponent as Dialog };
5
+ export * from './types';
@@ -1,2 +1,5 @@
1
- export { default } from './Dialog.web';
2
- export * from './types';
1
+ import DialogComponent from './Dialog.web';
2
+
3
+ export default DialogComponent;
4
+ export { DialogComponent as Dialog };
5
+ export * from './types';
@@ -1,61 +1,67 @@
1
- import { ReactNode } from 'react';
1
+ import type { ReactNode } from 'react';
2
+ import type { StyleProp, ViewStyle } from 'react-native';
3
+
4
+ // Component-specific type aliases for future extensibility
5
+ export type DialogSizeVariant = 'sm' | 'md' | 'lg' | 'fullscreen';
6
+ export type DialogType = 'standard' | 'alert' | 'confirmation';
7
+ export type DialogAnimationType = 'slide' | 'fade' | 'none';
2
8
 
3
9
  export interface DialogProps {
4
10
  /**
5
11
  * Whether the dialog is open/visible
6
12
  */
7
13
  open: boolean;
8
-
14
+
9
15
  /**
10
16
  * Called when the dialog should be opened or closed
11
17
  */
12
18
  onOpenChange: (open: boolean) => void;
13
-
19
+
14
20
  /**
15
21
  * Optional title for the dialog
16
22
  */
17
23
  title?: string;
18
-
24
+
19
25
  /**
20
26
  * The content to display inside the dialog
21
27
  */
22
28
  children: ReactNode;
23
-
29
+
24
30
  /**
25
31
  * The size of the dialog
26
32
  */
27
- size?: 'small' | 'medium' | 'large' | 'fullscreen';
28
-
33
+ size?: DialogSizeVariant;
34
+
29
35
  /**
30
36
  * The visual style variant of the dialog
31
37
  */
32
- variant?: 'default' | 'alert' | 'confirmation';
33
-
38
+ type?: DialogType,
39
+
34
40
  /**
35
41
  * Whether to show the close button in the header
36
42
  */
37
43
  showCloseButton?: boolean;
38
-
44
+
39
45
  /**
40
46
  * Whether clicking the backdrop should close the dialog
41
47
  */
42
48
  closeOnBackdropClick?: boolean;
43
-
49
+
44
50
  /**
45
51
  * Whether pressing escape key should close the dialog (web only)
46
52
  */
47
53
  closeOnEscapeKey?: boolean;
48
-
54
+
49
55
  /**
50
56
  * Animation type for the dialog (native only)
51
57
  */
52
- animationType?: 'slide' | 'fade' | 'none';
53
-
58
+ animationType?: DialogAnimationType;
59
+
54
60
  /**
55
61
  * Additional styles (platform-specific)
56
62
  */
57
- style?: any;
58
-
63
+ style?: StyleProp<ViewStyle>;
64
+
59
65
  /**
60
66
  * Test ID for testing
61
67
  */