@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,121 +1,11 @@
1
- import React, { useEffect, useLayoutEffect, useRef, useState, useCallback } from 'react';
2
- import { createPortal } from 'react-dom';
1
+ import React, { useRef, forwardRef } from 'react';
3
2
  import { getWebProps } from 'react-native-unistyles/web';
4
- import { PopoverProps, PopoverPlacement } from './types';
3
+ import { PopoverProps } from './types';
5
4
  import { popoverStyles } from './Popover.styles';
5
+ import useMergeRefs from '../hooks/useMergeRefs';
6
+ import { PositionedPortal } from '../internal/PositionedPortal';
6
7
 
7
- interface PopoverPosition {
8
- top: number;
9
- left: number;
10
- placement: PopoverPlacement;
11
- }
12
-
13
- const calculatePosition = (
14
- anchorRect: DOMRect,
15
- popoverSize: { width: number; height: number },
16
- placement: PopoverPlacement,
17
- offset: number,
18
- showArrow: boolean = false
19
- ): PopoverPosition => {
20
- const viewport = {
21
- width: window.innerWidth,
22
- height: window.innerHeight,
23
- scrollX: window.scrollX,
24
- scrollY: window.scrollY,
25
- };
26
-
27
- let position = { top: 0, left: 0 };
28
- let finalPlacement = placement;
29
-
30
- // Add extra offset for arrow
31
- const arrowSize = 6;
32
- const finalOffset = showArrow ? offset + arrowSize : offset;
33
-
34
- // Calculate initial position based on placement
35
- switch (placement) {
36
- case 'top':
37
- position = {
38
- top: anchorRect.top + viewport.scrollY - popoverSize.height - finalOffset,
39
- left: anchorRect.left + viewport.scrollX + anchorRect.width / 2 - popoverSize.width / 2,
40
- };
41
- break;
42
- case 'top-start':
43
- position = {
44
- top: anchorRect.top + viewport.scrollY - popoverSize.height - finalOffset,
45
- left: anchorRect.left + viewport.scrollX,
46
- };
47
- break;
48
- case 'top-end':
49
- position = {
50
- top: anchorRect.top + viewport.scrollY - popoverSize.height - finalOffset,
51
- left: anchorRect.right + viewport.scrollX - popoverSize.width,
52
- };
53
- break;
54
- case 'bottom':
55
- position = {
56
- top: anchorRect.bottom + viewport.scrollY + finalOffset,
57
- left: anchorRect.left + viewport.scrollX + anchorRect.width / 2 - popoverSize.width / 2,
58
- };
59
- break;
60
- case 'bottom-start':
61
- position = {
62
- top: anchorRect.bottom + viewport.scrollY + finalOffset,
63
- left: anchorRect.left + viewport.scrollX,
64
- };
65
- break;
66
- case 'bottom-end':
67
- position = {
68
- top: anchorRect.bottom + viewport.scrollY + finalOffset,
69
- left: anchorRect.right + viewport.scrollX - popoverSize.width,
70
- };
71
- break;
72
- case 'left':
73
- position = {
74
- top: anchorRect.top + viewport.scrollY + anchorRect.height / 2 - popoverSize.height / 2,
75
- left: anchorRect.left + viewport.scrollX - popoverSize.width - finalOffset,
76
- };
77
- break;
78
- case 'left-start':
79
- position = {
80
- top: anchorRect.top + viewport.scrollY,
81
- left: anchorRect.left + viewport.scrollX - popoverSize.width - finalOffset,
82
- };
83
- break;
84
- case 'left-end':
85
- position = {
86
- top: anchorRect.bottom + viewport.scrollY - popoverSize.height,
87
- left: anchorRect.left + viewport.scrollX - popoverSize.width - finalOffset,
88
- };
89
- break;
90
- case 'right':
91
- position = {
92
- top: anchorRect.top + viewport.scrollY + anchorRect.height / 2 - popoverSize.height / 2,
93
- left: anchorRect.right + viewport.scrollX + finalOffset,
94
- };
95
- break;
96
- case 'right-start':
97
- position = {
98
- top: anchorRect.top + viewport.scrollY,
99
- left: anchorRect.right + viewport.scrollX + finalOffset,
100
- };
101
- break;
102
- case 'right-end':
103
- position = {
104
- top: anchorRect.bottom + viewport.scrollY - popoverSize.height,
105
- left: anchorRect.right + viewport.scrollX + finalOffset,
106
- };
107
- break;
108
- }
109
-
110
- // Constrain to viewport
111
- const padding = 8;
112
- position.left = Math.max(padding, Math.min(position.left, viewport.width - popoverSize.width - padding));
113
- position.top = Math.max(padding, Math.min(position.top, viewport.height + viewport.scrollY - popoverSize.height - padding));
114
-
115
- return { ...position, placement: finalPlacement };
116
- };
117
-
118
- const Popover: React.FC<PopoverProps> = ({
8
+ const Popover = forwardRef<HTMLDivElement, PopoverProps>(({
119
9
  open,
120
10
  onOpenChange,
121
11
  anchor,
@@ -126,162 +16,48 @@ const Popover: React.FC<PopoverProps> = ({
126
16
  closeOnEscapeKey = true,
127
17
  showArrow = false,
128
18
  testID,
129
- }) => {
19
+ }, ref) => {
130
20
  const popoverRef = useRef<HTMLDivElement>(null);
131
- const [isVisible, setIsVisible] = useState(false);
132
- const [shouldRender, setShouldRender] = useState(false);
133
- const [position, setPosition] = useState<PopoverPosition>({ top: 0, left: 0, placement });
134
-
135
- // Calculate position
136
- const updatePosition = useCallback(() => {
137
- if (!popoverRef.current) {
138
- return;
139
- }
140
-
141
- let anchorElement: Element | null = null;
142
-
143
- if (anchor && typeof anchor === 'object' && 'current' in anchor && anchor.current) {
144
- anchorElement = anchor.current;
145
- } else if (React.isValidElement(anchor)) {
146
- console.warn('Popover: React element anchors need to be refs for positioning');
147
- return;
148
- }
149
-
150
- if (!anchorElement) {
151
- return;
152
- }
153
-
154
- const anchorRect = anchorElement.getBoundingClientRect();
155
- const popoverRect = popoverRef.current.getBoundingClientRect();
156
-
157
- const newPosition = calculatePosition(
158
- anchorRect,
159
- { width: popoverRect.width || 200, height: popoverRect.height || 100 },
160
- placement,
161
- offset,
162
- showArrow
163
- );
164
-
165
- setPosition(newPosition);
166
- }, [anchor, placement, offset, showArrow]);
167
21
 
168
- // Handle mounting/unmounting with animation
169
- useEffect(() => {
170
- if (open && !shouldRender) {
171
- setShouldRender(true);
172
- // Set visible immediately to render the DOM element
173
- setIsVisible(true);
174
- } else if (!open && shouldRender) {
175
- setIsVisible(false);
176
- const timer = setTimeout(() => {
177
- setShouldRender(false);
178
- }, 150);
179
- return () => clearTimeout(timer);
180
- }
181
- }, [open, shouldRender]);
182
-
183
- // Position calculation after DOM is ready
184
- useLayoutEffect(() => {
185
- if (shouldRender && isVisible) {
186
- // Use a microtask to ensure the ref is attached
187
- Promise.resolve().then(() => {
188
- if (popoverRef.current) {
189
- updatePosition();
190
- }
191
- });
192
- }
193
- }, [shouldRender, isVisible, anchor, placement, offset, showArrow]);
194
-
195
- // Update position on scroll/resize
196
- useEffect(() => {
197
- if (shouldRender && isVisible) {
198
- const handleResize = () => updatePosition();
199
- const handleScroll = () => updatePosition();
200
-
201
- window.addEventListener('resize', handleResize);
202
- window.addEventListener('scroll', handleScroll, true);
203
-
204
- return () => {
205
- window.removeEventListener('resize', handleResize);
206
- window.removeEventListener('scroll', handleScroll, true);
207
- };
208
- }
209
- }, [updatePosition, shouldRender, isVisible]);
210
-
211
- // Handle escape key
212
- useEffect(() => {
213
- if (!open || !closeOnEscapeKey) return;
214
-
215
- const handleEscape = (event: KeyboardEvent) => {
216
- if (event.key === 'Escape') {
217
- onOpenChange(false);
218
- }
219
- };
220
-
221
- document.addEventListener('keydown', handleEscape);
222
- return () => document.removeEventListener('keydown', handleEscape);
223
- }, [open, closeOnEscapeKey, onOpenChange]);
224
-
225
- // Handle click outside
226
- useEffect(() => {
227
- if (!open || !closeOnClickOutside) return;
22
+ popoverStyles.useVariants({});
228
23
 
229
- const handleClickOutside = (event: MouseEvent) => {
230
- if (popoverRef.current && !popoverRef.current.contains(event.target as Node)) {
231
- // Check if click was on anchor element
232
- let anchorElement: Element | null = null;
233
- if (anchor && typeof anchor === 'object' && 'current' in anchor && anchor.current) {
234
- anchorElement = anchor.current;
235
- }
236
-
237
- if (anchorElement && anchorElement.contains(event.target as Node)) {
238
- return; // Don't close if clicked on anchor
239
- }
240
-
241
- onOpenChange(false);
242
- }
243
- };
24
+ const containerProps = getWebProps([popoverStyles.container]);
25
+ const contentProps = getWebProps([popoverStyles.content]);
244
26
 
245
- document.addEventListener('mousedown', handleClickOutside);
246
- return () => document.removeEventListener('mousedown', handleClickOutside);
247
- }, [open, closeOnClickOutside, onOpenChange, anchor]);
27
+ const mergedPopoverRef = useMergeRefs(ref, popoverRef);
248
28
 
249
- if (!shouldRender) return null;
29
+ // Extract anchor ref if it's a ref object
30
+ let anchorRef: React.RefObject<HTMLElement> | undefined;
31
+ if (anchor && typeof anchor === 'object' && 'current' in anchor) {
32
+ anchorRef = anchor as React.RefObject<HTMLElement>;
33
+ }
250
34
 
251
- // Use Unistyles with wrapper approach
252
- popoverStyles.useVariants({});
253
-
254
- const containerProps = getWebProps([
255
- popoverStyles.container,
256
- {
257
- opacity: isVisible ? 1 : 0,
258
- transform: isVisible ? 'scale(1)' : 'scale(0.95)',
259
- }
260
- ]);
261
- const contentProps = getWebProps([popoverStyles.content]);
35
+ if (!anchorRef) {
36
+ console.warn('Popover: anchor must be a ref object');
37
+ return null;
38
+ }
262
39
 
263
- console.log(position)
264
-
265
- const popoverContent = (
266
- <div
267
- ref={popoverRef}
268
- style={{
269
- position: 'fixed',
270
- zIndex: 9999,
271
- top: position.top,
272
- left: position.left,
273
- }}
274
- data-testid={testID}
40
+ return (
41
+ <PositionedPortal
42
+ open={open}
43
+ anchor={anchorRef}
44
+ placement={placement}
45
+ offset={offset}
46
+ onClickOutside={closeOnClickOutside ? () => onOpenChange(false) : undefined}
47
+ onEscapeKey={closeOnEscapeKey ? () => onOpenChange(false) : undefined}
48
+ zIndex={9999}
275
49
  >
276
- <div {...containerProps}>
277
- <div {...contentProps}>
278
- {children}
50
+ <div ref={mergedPopoverRef} data-testid={testID}>
51
+ <div {...containerProps}>
52
+ <div {...contentProps}>
53
+ {children}
54
+ </div>
279
55
  </div>
280
56
  </div>
281
- </div>
57
+ </PositionedPortal>
282
58
  );
59
+ });
283
60
 
284
- return createPortal(popoverContent, document.body);
285
- };
61
+ Popover.displayName = 'Popover';
286
62
 
287
63
  export default Popover;
@@ -1,2 +1,5 @@
1
- export { default } from './Popover.web';
2
- export * from './types';
1
+ import PopoverComponent from './Popover.web';
2
+
3
+ export default PopoverComponent;
4
+ export { PopoverComponent as Popover };
5
+ export * from './types';
@@ -1,2 +1,5 @@
1
- export { default } from './Popover.web';
2
- export * from './types';
1
+ import PopoverComponent from './Popover.web';
2
+
3
+ export default PopoverComponent;
4
+ export { PopoverComponent as Popover };
5
+ export * from './types';
@@ -1,6 +1,7 @@
1
- import { ReactNode } from 'react';
1
+ import type { ReactNode } from 'react';
2
+ import type { StyleProp, ViewStyle } from 'react-native';
2
3
 
3
- export type PopoverPlacement =
4
+ export type PopoverPlacement =
4
5
  | 'top' | 'top-start' | 'top-end'
5
6
  | 'bottom' | 'bottom-start' | 'bottom-end'
6
7
  | 'left' | 'left-start' | 'left-end'
@@ -11,53 +12,53 @@ export interface PopoverProps {
11
12
  * Whether the popover is open/visible
12
13
  */
13
14
  open: boolean;
14
-
15
+
15
16
  /**
16
17
  * Called when the popover should be opened or closed
17
18
  */
18
19
  onOpenChange: (open: boolean) => void;
19
-
20
+
20
21
  /**
21
22
  * The anchor element to position the popover relative to
22
23
  * Can be a React element or a ref to a DOM element
23
24
  */
24
25
  anchor: ReactNode | React.RefObject<Element>;
25
-
26
+
26
27
  /**
27
28
  * The content to display inside the popover
28
29
  */
29
30
  children: ReactNode;
30
-
31
+
31
32
  /**
32
33
  * Preferred placement of the popover relative to anchor
33
34
  */
34
35
  placement?: PopoverPlacement;
35
-
36
+
36
37
  /**
37
38
  * Distance from the anchor element in pixels
38
39
  */
39
40
  offset?: number;
40
-
41
+
41
42
  /**
42
43
  * Whether clicking outside should close the popover
43
44
  */
44
45
  closeOnClickOutside?: boolean;
45
-
46
+
46
47
  /**
47
48
  * Whether pressing escape key should close the popover (web only)
48
49
  */
49
50
  closeOnEscapeKey?: boolean;
50
-
51
+
51
52
  /**
52
53
  * Whether to show an arrow pointing to the anchor
53
54
  */
54
55
  showArrow?: boolean;
55
-
56
+
56
57
  /**
57
58
  * Additional styles (platform-specific)
58
59
  */
59
- style?: any;
60
-
60
+ style?: StyleProp<ViewStyle>;
61
+
61
62
  /**
62
63
  * Test ID for testing
63
64
  */
@@ -1,8 +1,8 @@
1
- import React from 'react';
1
+ import React, { forwardRef } from 'react';
2
2
  import { TouchableWithoutFeedback, View } from 'react-native';
3
3
  import { PressableProps } from './types';
4
4
 
5
- const Pressable: React.FC<PressableProps> = ({
5
+ const Pressable = forwardRef<View, PressableProps>(({
6
6
  children,
7
7
  onPress,
8
8
  onPressIn,
@@ -12,7 +12,7 @@ const Pressable: React.FC<PressableProps> = ({
12
12
  testID,
13
13
  accessibilityLabel,
14
14
  accessibilityRole,
15
- }) => {
15
+ }, ref) => {
16
16
  return (
17
17
  <TouchableWithoutFeedback
18
18
  onPress={disabled ? undefined : onPress}
@@ -21,13 +21,14 @@ const Pressable: React.FC<PressableProps> = ({
21
21
  disabled={disabled}
22
22
  testID={testID}
23
23
  accessibilityLabel={accessibilityLabel}
24
- accessibilityRole={accessibilityRole}
25
24
  >
26
- <View style={style}>
25
+ <View ref={ref} style={style}>
27
26
  {children}
28
27
  </View>
29
28
  </TouchableWithoutFeedback>
30
29
  );
31
- };
30
+ });
31
+
32
+ Pressable.displayName = 'Pressable';
32
33
 
33
34
  export default Pressable;
@@ -1,7 +1,7 @@
1
- import React, { useCallback, useState } from 'react';
1
+ import React, { useCallback, useState, forwardRef } from 'react';
2
2
  import { PressableProps } from './types';
3
3
 
4
- const Pressable: React.FC<PressableProps> = ({
4
+ const Pressable = forwardRef<HTMLDivElement, PressableProps>(({
5
5
  children,
6
6
  onPress,
7
7
  onPressIn,
@@ -11,7 +11,7 @@ const Pressable: React.FC<PressableProps> = ({
11
11
  testID,
12
12
  accessibilityLabel,
13
13
  accessibilityRole = 'button',
14
- }) => {
14
+ }, ref) => {
15
15
  const [isPressed, setIsPressed] = useState(false);
16
16
 
17
17
  const handleMouseDown = useCallback(() => {
@@ -40,7 +40,6 @@ const Pressable: React.FC<PressableProps> = ({
40
40
  }, [disabled, onPress]);
41
41
 
42
42
  const webStyle = {
43
- ...style,
44
43
  cursor: disabled ? 'default' : 'pointer',
45
44
  outline: 'none',
46
45
  userSelect: 'none' as const,
@@ -51,9 +50,10 @@ const Pressable: React.FC<PressableProps> = ({
51
50
 
52
51
  return (
53
52
  <div
53
+ ref={ref}
54
54
  role={accessibilityRole}
55
55
  tabIndex={disabled ? -1 : 0}
56
- style={webStyle}
56
+ style={[webStyle, style] as any}
57
57
  onMouseDown={handleMouseDown}
58
58
  onMouseUp={handleMouseUp}
59
59
  onMouseLeave={handleMouseUp} // Handle mouse leave as press out
@@ -66,6 +66,8 @@ const Pressable: React.FC<PressableProps> = ({
66
66
  {children}
67
67
  </div>
68
68
  );
69
- };
69
+ });
70
+
71
+ Pressable.displayName = 'Pressable';
70
72
 
71
73
  export default Pressable;
@@ -1,2 +1,5 @@
1
- export { default } from './Pressable.web';
2
- export * from './types';
1
+ import PressableComponent from './Pressable.web';
2
+
3
+ export default PressableComponent;
4
+ export { PressableComponent as Pressable };
5
+ export * from './types';
@@ -1,2 +1,5 @@
1
- export { default } from './Pressable.web';
2
- export * from './types';
1
+ import PressableComponent from './Pressable.web';
2
+
3
+ export default PressableComponent;
4
+ export { PressableComponent as Pressable };
5
+ export * from './types';
@@ -1,46 +1,47 @@
1
- import { ReactNode } from 'react';
1
+ import type { ReactNode } from 'react';
2
+ import type { StyleProp, ViewStyle } from 'react-native';
2
3
 
3
4
  export interface PressableProps {
4
5
  /**
5
6
  * Content to render inside the pressable area
6
7
  */
7
8
  children?: ReactNode;
8
-
9
+
9
10
  /**
10
11
  * Called when the press gesture is activated
11
12
  */
12
13
  onPress?: () => void;
13
-
14
+
14
15
  /**
15
16
  * Called when the press gesture starts
16
17
  */
17
18
  onPressIn?: () => void;
18
-
19
+
19
20
  /**
20
21
  * Called when the press gesture ends
21
22
  */
22
23
  onPressOut?: () => void;
23
-
24
+
24
25
  /**
25
26
  * Whether the pressable is disabled
26
27
  */
27
28
  disabled?: boolean;
28
-
29
+
29
30
  /**
30
31
  * Additional styles to apply
31
32
  */
32
- style?: any;
33
-
33
+ style?: StyleProp<ViewStyle>;
34
+
34
35
  /**
35
36
  * Test ID for testing
36
37
  */
37
38
  testID?: string;
38
-
39
+
39
40
  /**
40
41
  * Accessibility label for screen readers
41
42
  */
42
43
  accessibilityLabel?: string;
43
-
44
+
44
45
  /**
45
46
  * Accessibility role (web)
46
47
  */