ferns-ui 0.47.9 → 1.0.0-beta.0

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 (402) hide show
  1. package/dist/Accordion.d.ts +3 -0
  2. package/dist/Accordion.js +31 -0
  3. package/dist/Accordion.js.map +1 -0
  4. package/dist/ActionSheet.d.ts +9 -10
  5. package/dist/ActionSheet.js +8 -6
  6. package/dist/ActionSheet.js.map +1 -1
  7. package/dist/AddressField.d.ts +3 -0
  8. package/dist/AddressField.js +33 -0
  9. package/dist/AddressField.js.map +1 -0
  10. package/dist/Avatar.d.ts +2 -2
  11. package/dist/Avatar.js +132 -96
  12. package/dist/Avatar.js.map +1 -1
  13. package/dist/Badge.d.ts +1 -1
  14. package/dist/Badge.js +90 -20
  15. package/dist/Badge.js.map +1 -1
  16. package/dist/Banner.d.ts +1 -1
  17. package/dist/Banner.js +89 -51
  18. package/dist/Banner.js.map +1 -1
  19. package/dist/Body.js +4 -4
  20. package/dist/Body.js.map +1 -1
  21. package/dist/BooleanField.d.ts +3 -0
  22. package/dist/BooleanField.js +90 -0
  23. package/dist/BooleanField.js.map +1 -0
  24. package/dist/Box.js +80 -80
  25. package/dist/Box.js.map +1 -1
  26. package/dist/Button.d.ts +2 -2
  27. package/dist/Button.js +87 -109
  28. package/dist/Button.js.map +1 -1
  29. package/dist/Card.js +2 -2
  30. package/dist/Card.js.map +1 -1
  31. package/dist/CheckBox.d.ts +2 -2
  32. package/dist/CheckBox.js +23 -35
  33. package/dist/CheckBox.js.map +1 -1
  34. package/dist/Common.d.ts +1071 -406
  35. package/dist/Common.js +39 -3
  36. package/dist/Common.js.map +1 -1
  37. package/dist/CommonIconTypes.d.ts +3 -0
  38. package/dist/CommonIconTypes.js +2 -0
  39. package/dist/CommonIconTypes.js.map +1 -0
  40. package/dist/CustomSelectField.d.ts +3 -0
  41. package/dist/CustomSelectField.js +64 -0
  42. package/dist/CustomSelectField.js.map +1 -0
  43. package/dist/DateTimeActionSheet.d.ts +1 -1
  44. package/dist/DateTimeActionSheet.js +177 -156
  45. package/dist/DateTimeActionSheet.js.map +1 -1
  46. package/dist/DateTimeField.d.ts +3 -3
  47. package/dist/DateTimeField.js +140 -30
  48. package/dist/DateTimeField.js.map +1 -1
  49. package/dist/DateUtilities.js.map +1 -1
  50. package/dist/DateUtilities.test.js +2 -1
  51. package/dist/DateUtilities.test.js.map +1 -1
  52. package/dist/DecimalRangeActionSheet.js +3 -15
  53. package/dist/DecimalRangeActionSheet.js.map +1 -1
  54. package/dist/DismissButton.d.ts +3 -0
  55. package/dist/DismissButton.js +14 -0
  56. package/dist/DismissButton.js.map +1 -0
  57. package/dist/EmailField.d.ts +3 -0
  58. package/dist/EmailField.js +52 -0
  59. package/dist/EmailField.js.map +1 -0
  60. package/dist/ErrorBoundary.d.ts +1 -1
  61. package/dist/ErrorPage.js +2 -2
  62. package/dist/ErrorPage.js.map +1 -1
  63. package/dist/FernsProvider.js +1 -1
  64. package/dist/FernsProvider.js.map +1 -1
  65. package/dist/Field.d.ts +2 -2
  66. package/dist/Field.js +67 -136
  67. package/dist/Field.js.map +1 -1
  68. package/dist/Heading.js +37 -16
  69. package/dist/Heading.js.map +1 -1
  70. package/dist/HeightActionSheet.js +3 -7
  71. package/dist/HeightActionSheet.js.map +1 -1
  72. package/dist/Hyperlink.js +7 -1
  73. package/dist/Hyperlink.js.map +1 -1
  74. package/dist/Icon.d.ts +1 -2
  75. package/dist/Icon.js +8 -10
  76. package/dist/Icon.js.map +1 -1
  77. package/dist/IconButton.d.ts +2 -2
  78. package/dist/IconButton.js +93 -92
  79. package/dist/IconButton.js.map +1 -1
  80. package/dist/InfoTooltipButton.d.ts +1 -1
  81. package/dist/InfoTooltipButton.js +2 -2
  82. package/dist/InfoTooltipButton.js.map +1 -1
  83. package/dist/Link.d.ts +1 -1
  84. package/dist/Link.js +7 -3
  85. package/dist/Link.js.map +1 -1
  86. package/dist/MobileAddressAutoComplete.js +8 -8
  87. package/dist/MobileAddressAutoComplete.js.map +1 -1
  88. package/dist/Modal.d.ts +2 -2
  89. package/dist/Modal.js +95 -80
  90. package/dist/Modal.js.map +1 -1
  91. package/dist/MultiselectField.d.ts +3 -0
  92. package/dist/MultiselectField.js +49 -0
  93. package/dist/MultiselectField.js.map +1 -0
  94. package/dist/NumberField.d.ts +3 -0
  95. package/dist/NumberField.js +49 -0
  96. package/dist/NumberField.js.map +1 -0
  97. package/dist/NumberPickerActionSheet.js +2 -2
  98. package/dist/NumberPickerActionSheet.js.map +1 -1
  99. package/dist/OpenAPIContext.js.map +1 -1
  100. package/dist/Page.js +6 -6
  101. package/dist/Page.js.map +1 -1
  102. package/dist/Pagination.d.ts +2 -8
  103. package/dist/Pagination.js +107 -13
  104. package/dist/Pagination.js.map +1 -1
  105. package/dist/PasswordField.d.ts +2 -0
  106. package/dist/PasswordField.js +6 -0
  107. package/dist/PasswordField.js.map +1 -0
  108. package/dist/PhoneNumberField.d.ts +3 -0
  109. package/dist/PhoneNumberField.js +79 -0
  110. package/dist/PhoneNumberField.js.map +1 -0
  111. package/dist/PickerSelect.d.ts +6 -67
  112. package/dist/PickerSelect.js +145 -115
  113. package/dist/PickerSelect.js.map +1 -1
  114. package/dist/Radio.d.ts +3 -0
  115. package/dist/Radio.js +21 -0
  116. package/dist/Radio.js.map +1 -0
  117. package/dist/RadioField.d.ts +3 -0
  118. package/dist/RadioField.js +22 -0
  119. package/dist/RadioField.js.map +1 -0
  120. package/dist/SegmentedControl.d.ts +1 -1
  121. package/dist/SegmentedControl.js +35 -67
  122. package/dist/SegmentedControl.js.map +1 -1
  123. package/dist/SelectField.d.ts +3 -0
  124. package/dist/SelectField.js +20 -0
  125. package/dist/SelectField.js.map +1 -0
  126. package/dist/SideDrawer.js +8 -2
  127. package/dist/SideDrawer.js.map +1 -1
  128. package/dist/Signature.d.ts +1 -0
  129. package/dist/Signature.js +8 -7
  130. package/dist/Signature.js.map +1 -1
  131. package/dist/Signature.native.js +8 -7
  132. package/dist/Signature.native.js.map +1 -1
  133. package/dist/SignatureField.d.ts +3 -0
  134. package/dist/SignatureField.js +54 -0
  135. package/dist/SignatureField.js.map +1 -0
  136. package/dist/Spinner.js +17 -2
  137. package/dist/Spinner.js.map +1 -1
  138. package/dist/SplitPage.d.ts +1 -1
  139. package/dist/SplitPage.js +10 -10
  140. package/dist/SplitPage.js.map +1 -1
  141. package/dist/SplitPage.native.js +7 -7
  142. package/dist/SplitPage.native.js.map +1 -1
  143. package/dist/TapToEdit.d.ts +3 -3
  144. package/dist/TapToEdit.js +40 -32
  145. package/dist/TapToEdit.js.map +1 -1
  146. package/dist/Text.d.ts +1 -1
  147. package/dist/Text.js +70 -64
  148. package/dist/Text.js.map +1 -1
  149. package/dist/TextArea.d.ts +1 -1
  150. package/dist/TextArea.js +2 -14
  151. package/dist/TextArea.js.map +1 -1
  152. package/dist/TextField.d.ts +2 -2
  153. package/dist/TextField.js +89 -206
  154. package/dist/TextField.js.map +1 -1
  155. package/dist/TextFieldNumberActionSheet.js +2 -2
  156. package/dist/TextFieldNumberActionSheet.js.map +1 -1
  157. package/dist/Theme.d.ts +87 -3
  158. package/dist/Theme.js +197 -98
  159. package/dist/Theme.js.map +1 -1
  160. package/dist/TimezonePicker.js +3 -5
  161. package/dist/TimezonePicker.js.map +1 -1
  162. package/dist/Toast.d.ts +18 -5
  163. package/dist/Toast.js +130 -31
  164. package/dist/Toast.js.map +1 -1
  165. package/dist/Tooltip.d.ts +2 -2
  166. package/dist/Tooltip.js +189 -89
  167. package/dist/Tooltip.js.map +1 -1
  168. package/dist/UnifiedAddressAutoComplete.js +2 -2
  169. package/dist/UnifiedAddressAutoComplete.js.map +1 -1
  170. package/dist/Unifier.js.map +1 -1
  171. package/dist/Utilities.js +5 -3
  172. package/dist/Utilities.js.map +1 -1
  173. package/dist/WebAddressAutocomplete.js +2 -2
  174. package/dist/WebAddressAutocomplete.js.map +1 -1
  175. package/dist/fieldElements/FieldError.d.ts +6 -0
  176. package/dist/fieldElements/FieldError.js +14 -0
  177. package/dist/fieldElements/FieldError.js.map +1 -0
  178. package/dist/fieldElements/FieldHelperText.d.ts +6 -0
  179. package/dist/fieldElements/FieldHelperText.js +11 -0
  180. package/dist/fieldElements/FieldHelperText.js.map +1 -0
  181. package/dist/fieldElements/FieldTitle.d.ts +6 -0
  182. package/dist/fieldElements/FieldTitle.js +19 -0
  183. package/dist/fieldElements/FieldTitle.js.map +1 -0
  184. package/dist/fieldElements/index.d.ts +3 -0
  185. package/dist/fieldElements/index.js +4 -0
  186. package/dist/fieldElements/index.js.map +1 -0
  187. package/dist/icons/MobileIcon.d.ts +3 -0
  188. package/dist/icons/MobileIcon.js +24 -0
  189. package/dist/icons/MobileIcon.js.map +1 -0
  190. package/dist/icons/OfflineIcon.d.ts +3 -0
  191. package/dist/icons/OfflineIcon.js +23 -0
  192. package/dist/icons/OfflineIcon.js.map +1 -0
  193. package/dist/icons/OnlineIcon.d.ts +3 -0
  194. package/dist/icons/OnlineIcon.js +24 -0
  195. package/dist/icons/OnlineIcon.js.map +1 -0
  196. package/dist/icons/OutOfficeIcon.d.ts +3 -0
  197. package/dist/icons/OutOfficeIcon.js +24 -0
  198. package/dist/icons/OutOfficeIcon.js.map +1 -0
  199. package/dist/icons/index.d.ts +4 -0
  200. package/dist/icons/index.js +5 -0
  201. package/dist/icons/index.js.map +1 -0
  202. package/dist/index.d.ts +28 -14
  203. package/dist/index.js +28 -14
  204. package/dist/index.js.map +1 -1
  205. package/dist/setupTests.d.ts +1 -0
  206. package/dist/setupTests.js +1 -1
  207. package/dist/setupTests.js.map +1 -1
  208. package/dist/{Table.d.ts → table/Table.d.ts} +2 -2
  209. package/dist/{Table.js → table/Table.js} +18 -10
  210. package/dist/table/Table.js.map +1 -0
  211. package/dist/table/TableBadge.d.ts +6 -0
  212. package/dist/table/TableBadge.js +22 -0
  213. package/dist/table/TableBadge.js.map +1 -0
  214. package/dist/table/TableBoolean.d.ts +6 -0
  215. package/dist/table/TableBoolean.js +39 -0
  216. package/dist/table/TableBoolean.js.map +1 -0
  217. package/dist/table/TableDate.d.ts +3 -0
  218. package/dist/table/TableDate.js +26 -0
  219. package/dist/table/TableDate.js.map +1 -0
  220. package/dist/{TableHeader.d.ts → table/TableHeader.d.ts} +1 -1
  221. package/dist/{TableHeader.js → table/TableHeader.js} +2 -2
  222. package/dist/table/TableHeader.js.map +1 -0
  223. package/dist/{TableHeaderCell.d.ts → table/TableHeaderCell.d.ts} +2 -2
  224. package/dist/table/TableHeaderCell.js +58 -0
  225. package/dist/table/TableHeaderCell.js.map +1 -0
  226. package/dist/table/TableIconButton.d.ts +3 -0
  227. package/dist/table/TableIconButton.js +42 -0
  228. package/dist/table/TableIconButton.js.map +1 -0
  229. package/dist/table/TableNumber.d.ts +3 -0
  230. package/dist/table/TableNumber.js +18 -0
  231. package/dist/table/TableNumber.js.map +1 -0
  232. package/dist/{TableRow.d.ts → table/TableRow.d.ts} +1 -1
  233. package/dist/table/TableRow.js +28 -0
  234. package/dist/table/TableRow.js.map +1 -0
  235. package/dist/table/TableText.d.ts +3 -0
  236. package/dist/table/TableText.js +18 -0
  237. package/dist/table/TableText.js.map +1 -0
  238. package/dist/table/TableTitle.d.ts +3 -0
  239. package/dist/table/TableTitle.js +22 -0
  240. package/dist/table/TableTitle.js.map +1 -0
  241. package/dist/{tableContext.d.ts → table/tableContext.d.ts} +1 -1
  242. package/dist/table/tableContext.js.map +1 -0
  243. package/package.json +10 -4
  244. package/src/Accordion.tsx +84 -0
  245. package/src/ActionSheet.tsx +8 -5
  246. package/src/AddressField.tsx +122 -0
  247. package/src/Avatar.tsx +193 -147
  248. package/src/Badge.tsx +107 -49
  249. package/src/Banner.tsx +158 -111
  250. package/src/Body.tsx +4 -4
  251. package/src/BooleanField.tsx +122 -0
  252. package/src/Box.tsx +92 -82
  253. package/src/Button.tsx +151 -167
  254. package/src/Card.tsx +2 -2
  255. package/src/CheckBox.tsx +30 -111
  256. package/src/Common.ts +1304 -2041
  257. package/src/CommonIconTypes.ts +2030 -0
  258. package/src/CustomSelectField.tsx +116 -0
  259. package/src/DateTimeActionSheet.tsx +347 -255
  260. package/src/DateTimeField.tsx +168 -61
  261. package/src/DateUtilities.test.ts +6 -2
  262. package/src/DateUtilities.tsx +1 -1
  263. package/src/DecimalRangeActionSheet.tsx +2 -17
  264. package/src/DismissButton.tsx +31 -0
  265. package/src/EmailField.tsx +70 -0
  266. package/src/ErrorPage.tsx +2 -2
  267. package/src/FernsProvider.tsx +1 -1
  268. package/src/Field.tsx +83 -345
  269. package/src/Heading.tsx +44 -16
  270. package/src/HeightActionSheet.tsx +2 -9
  271. package/src/Hyperlink.tsx +8 -1
  272. package/src/Icon.tsx +22 -14
  273. package/src/IconButton.tsx +188 -156
  274. package/src/InfoTooltipButton.tsx +4 -6
  275. package/src/Link.tsx +14 -5
  276. package/src/MobileAddressAutoComplete.tsx +17 -13
  277. package/src/Modal.tsx +214 -190
  278. package/src/MultiselectField.tsx +103 -0
  279. package/src/NumberField.tsx +55 -0
  280. package/src/NumberPickerActionSheet.tsx +1 -4
  281. package/src/OpenAPIContext.tsx +1 -1
  282. package/src/Page.tsx +9 -13
  283. package/src/Pagination.tsx +171 -36
  284. package/src/PasswordField.tsx +7 -0
  285. package/src/PhoneNumberField.tsx +103 -0
  286. package/src/PickerSelect.tsx +169 -151
  287. package/src/Radio.tsx +33 -0
  288. package/src/RadioField.tsx +43 -0
  289. package/src/SegmentedControl.tsx +44 -96
  290. package/src/SelectField.tsx +41 -0
  291. package/src/SideDrawer.tsx +8 -2
  292. package/src/Signature.native.tsx +16 -9
  293. package/src/Signature.tsx +19 -11
  294. package/src/SignatureField.tsx +92 -0
  295. package/src/Spinner.tsx +16 -2
  296. package/src/SplitPage.native.tsx +9 -7
  297. package/src/SplitPage.tsx +11 -12
  298. package/src/TapToEdit.tsx +67 -39
  299. package/src/Text.tsx +79 -69
  300. package/src/TextArea.tsx +2 -2
  301. package/src/TextField.tsx +133 -285
  302. package/src/TextFieldNumberActionSheet.tsx +1 -4
  303. package/src/Theme.tsx +223 -172
  304. package/src/TimezonePicker.tsx +3 -18
  305. package/src/Toast.tsx +193 -70
  306. package/src/Tooltip.tsx +258 -141
  307. package/src/UnifiedAddressAutoComplete.tsx +3 -3
  308. package/src/Unifier.ts +4 -4
  309. package/src/Utilities.tsx +11 -3
  310. package/src/WebAddressAutocomplete.tsx +2 -3
  311. package/src/fieldElements/FieldError.tsx +24 -0
  312. package/src/fieldElements/FieldHelperText.tsx +20 -0
  313. package/src/fieldElements/FieldTitle.tsx +31 -0
  314. package/src/fieldElements/index.tsx +3 -0
  315. package/src/icons/MobileIcon.tsx +41 -0
  316. package/src/icons/OfflineIcon.tsx +38 -0
  317. package/src/icons/OnlineIcon.tsx +40 -0
  318. package/src/icons/OutOfficeIcon.tsx +37 -0
  319. package/src/icons/index.ts +4 -0
  320. package/src/index.tsx +28 -14
  321. package/src/setupTests.ts +1 -0
  322. package/src/{Table.tsx → table/Table.tsx} +24 -14
  323. package/src/table/TableBadge.tsx +46 -0
  324. package/src/table/TableBoolean.tsx +70 -0
  325. package/src/table/TableDate.tsx +38 -0
  326. package/src/{TableHeader.tsx → table/TableHeader.tsx} +3 -3
  327. package/src/table/TableHeaderCell.tsx +93 -0
  328. package/src/table/TableIconButton.tsx +62 -0
  329. package/src/table/TableNumber.tsx +29 -0
  330. package/src/{TableRow.tsx → table/TableRow.tsx} +28 -25
  331. package/src/table/TableText.tsx +29 -0
  332. package/src/table/TableTitle.tsx +32 -0
  333. package/src/{tableContext.tsx → table/tableContext.tsx} +1 -1
  334. package/dist/BlurBox.d.ts +0 -5
  335. package/dist/BlurBox.js +0 -28
  336. package/dist/BlurBox.js.map +0 -1
  337. package/dist/BlurBox.native.d.ts +0 -6
  338. package/dist/BlurBox.native.js +0 -30
  339. package/dist/BlurBox.native.js.map +0 -1
  340. package/dist/CustomSelect.d.ts +0 -3
  341. package/dist/CustomSelect.js +0 -47
  342. package/dist/CustomSelect.js.map +0 -1
  343. package/dist/DateTimeField.android.d.ts +0 -3
  344. package/dist/DateTimeField.android.js +0 -67
  345. package/dist/DateTimeField.android.js.map +0 -1
  346. package/dist/DateTimeField.ios.d.ts +0 -3
  347. package/dist/DateTimeField.ios.js +0 -49
  348. package/dist/DateTimeField.ios.js.map +0 -1
  349. package/dist/FieldWithLabels.d.ts +0 -3
  350. package/dist/FieldWithLabels.js +0 -8
  351. package/dist/FieldWithLabels.js.map +0 -1
  352. package/dist/Form.d.ts +0 -16
  353. package/dist/Form.js +0 -89
  354. package/dist/Form.js.map +0 -1
  355. package/dist/HeaderButtons.d.ts +0 -31
  356. package/dist/HeaderButtons.js +0 -53
  357. package/dist/HeaderButtons.js.map +0 -1
  358. package/dist/Mask.d.ts +0 -2
  359. package/dist/Mask.js +0 -19
  360. package/dist/Mask.js.map +0 -1
  361. package/dist/Pill.d.ts +0 -3
  362. package/dist/Pill.js +0 -8
  363. package/dist/Pill.js.map +0 -1
  364. package/dist/Pog.d.ts +0 -3
  365. package/dist/Pog.js +0 -48
  366. package/dist/Pog.js.map +0 -1
  367. package/dist/ProgressBar.d.ts +0 -3
  368. package/dist/ProgressBar.js +0 -35
  369. package/dist/ProgressBar.js.map +0 -1
  370. package/dist/SelectList.d.ts +0 -27
  371. package/dist/SelectList.js +0 -56
  372. package/dist/SelectList.js.map +0 -1
  373. package/dist/Switch.d.ts +0 -3
  374. package/dist/Switch.js +0 -20
  375. package/dist/Switch.js.map +0 -1
  376. package/dist/Table.js.map +0 -1
  377. package/dist/TableHeader.js.map +0 -1
  378. package/dist/TableHeaderCell.js +0 -36
  379. package/dist/TableHeaderCell.js.map +0 -1
  380. package/dist/TableRow.js +0 -30
  381. package/dist/TableRow.js.map +0 -1
  382. package/dist/WithLabel.d.ts +0 -3
  383. package/dist/WithLabel.js +0 -15
  384. package/dist/WithLabel.js.map +0 -1
  385. package/dist/tableContext.js.map +0 -1
  386. package/src/BlurBox.native.tsx +0 -40
  387. package/src/BlurBox.tsx +0 -31
  388. package/src/CustomSelect.tsx +0 -80
  389. package/src/DateTimeField.android.tsx +0 -103
  390. package/src/DateTimeField.ios.tsx +0 -85
  391. package/src/FieldWithLabels.tsx +0 -36
  392. package/src/Form.tsx +0 -175
  393. package/src/HeaderButtons.tsx +0 -107
  394. package/src/Mask.tsx +0 -21
  395. package/src/Pill.tsx +0 -22
  396. package/src/Pog.tsx +0 -75
  397. package/src/ProgressBar.tsx +0 -47
  398. package/src/SelectList.tsx +0 -109
  399. package/src/Switch.tsx +0 -18
  400. package/src/TableHeaderCell.tsx +0 -72
  401. package/src/WithLabel.tsx +0 -45
  402. /package/dist/{tableContext.js → table/tableContext.js} +0 -0
package/src/Tooltip.tsx CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import {useContext} from "react";
2
+ import {FC, useCallback, useEffect, useRef, useState} from "react";
3
3
  import {
4
4
  Dimensions,
5
5
  LayoutChangeEvent,
@@ -7,14 +7,15 @@ import {
7
7
  Platform,
8
8
  Pressable,
9
9
  View,
10
+ ViewStyle,
10
11
  } from "react-native";
11
12
  import {Portal} from "react-native-portalize";
12
13
 
13
- import {TooltipDirection, TooltipProps} from "./Common";
14
+ import {TooltipPosition, TooltipProps} from "./Common";
14
15
  import {Text} from "./Text";
15
- import {ThemeContext} from "./Theme";
16
+ import { useTheme } from "./Theme";
16
17
 
17
- const TOOLTIP_OFFSET = 8;
18
+ const TOOLTIP_OFFSET = 6;
18
19
  // How many pixels to leave between the tooltip and the edge of the screen
19
20
  const TOOLTIP_OVERFLOW_PADDING = 20;
20
21
 
@@ -25,28 +26,20 @@ type ChildrenMeasurement = {
25
26
  pageY: number;
26
27
  };
27
28
 
29
+ // empty object is a fallback for when the tooltip is not measured yet
28
30
  type Measurement = {
29
- children: ChildrenMeasurement;
30
- tooltip: LayoutRectangle;
31
+ children: ChildrenMeasurement | {};
32
+ tooltip: LayoutRectangle | {};
31
33
  measured: boolean;
32
- idealDirection?: TooltipDirection;
33
- };
34
-
35
- const overflowLeft = (x: number): boolean => {
36
- return x < TOOLTIP_OVERFLOW_PADDING;
37
- };
38
-
39
- const overflowRight = (x: number): boolean => {
40
- const {width: layoutWidth} = Dimensions.get("window");
41
- return x + TOOLTIP_OVERFLOW_PADDING > layoutWidth;
34
+ idealPosition?: TooltipPosition;
42
35
  };
43
36
 
44
37
  const getTooltipPosition = ({
45
38
  children,
46
39
  tooltip,
47
40
  measured,
48
- idealDirection,
49
- }: Measurement): {} | {left: number; top: number} => {
41
+ idealPosition,
42
+ }: Measurement): {} | {left: number; top: number; finalPosition: TooltipPosition} => {
50
43
  if (!measured) {
51
44
  console.debug("No measurements for child yet, cannot show tooltip yet.");
52
45
  return {};
@@ -57,117 +50,212 @@ const getTooltipPosition = ({
57
50
  height: childrenHeight,
58
51
  pageX: childrenX,
59
52
  width: childrenWidth,
60
- }: ChildrenMeasurement = children;
61
- const {width: tooltipWidth, height: tooltipHeight} = tooltip;
53
+ }: ChildrenMeasurement = children as ChildrenMeasurement;
54
+ const {width: tooltipWidth, height: tooltipHeight} = tooltip as LayoutRectangle;
55
+
62
56
  const horizontalCenter = childrenX + childrenWidth / 2;
63
57
  const right = childrenX + childrenWidth + TOOLTIP_OFFSET;
64
58
  const left = childrenX - tooltipWidth - TOOLTIP_OFFSET;
65
-
66
59
  const top = childrenY - tooltipHeight - TOOLTIP_OFFSET;
67
60
  const bottom = childrenY + childrenHeight + TOOLTIP_OFFSET;
68
- const verticalCenter = top + childrenHeight + TOOLTIP_OFFSET;
61
+ const verticalCenter = childrenY + childrenHeight / 2 - tooltipHeight / 2;
69
62
 
70
- // Top is overflowed if it would go off either side or the top of the screen.
71
63
  const overflowTop = top < TOOLTIP_OVERFLOW_PADDING;
72
-
73
- // Bottom is overflowed if it would go off either side or the bottom of the screen.
74
64
  const overflowBottom =
75
65
  bottom + tooltipHeight + TOOLTIP_OVERFLOW_PADDING > Dimensions.get("window").height;
66
+ const overflowLeft = left < TOOLTIP_OVERFLOW_PADDING;
67
+ const overflowRight =
68
+ right + tooltipWidth > Dimensions.get("window").width - TOOLTIP_OVERFLOW_PADDING;
69
+ let finalPosition: TooltipPosition = idealPosition || "top";
70
+ // Try to place the tooltip in the ideal position if possible
71
+ switch (idealPosition) {
72
+ case "left":
73
+ if (!overflowLeft) {
74
+ return {left, top: verticalCenter, finalPosition};
75
+ }
76
+ break;
77
+ case "right":
78
+ if (!overflowRight) {
79
+ return {left: right, top: verticalCenter, finalPosition};
80
+ }
81
+ break;
82
+ case "top":
83
+ if (!overflowTop) {
84
+ return {left: horizontalCenter - tooltipWidth / 2, top, finalPosition};
85
+ }
86
+ break;
87
+ case "bottom":
88
+ if (!overflowBottom) {
89
+ return {left: horizontalCenter - tooltipWidth / 2, top: bottom, finalPosition};
90
+ }
91
+ break;
92
+ }
76
93
 
77
- // If it would overflow to the right, try to put it above, if not, put it on the left.
78
- // If it would overflow to the left, try to put it above, if not, put it to the right.
79
-
80
- // Happy path:
81
- if (idealDirection === "left" && !overflowLeft(left)) {
82
- return {left, top: verticalCenter};
83
- } else if (idealDirection === "right" && !overflowRight(right + tooltipWidth)) {
84
- return {left: right, top: verticalCenter};
85
- } else if (
86
- idealDirection === "bottom" &&
87
- !overflowBottom &&
88
- !overflowLeft(horizontalCenter - tooltipWidth) &&
89
- !overflowRight(horizontalCenter + tooltipWidth)
90
- ) {
91
- return {left: horizontalCenter - tooltipWidth / 2, top: bottom};
94
+ // Fallback to an alternate position if the ideal position overflows
95
+ if (!overflowBottom) {
96
+ finalPosition = "bottom";
97
+ return {left: horizontalCenter - tooltipWidth / 2, top: bottom, finalPosition};
98
+ } else if (!overflowTop) {
99
+ finalPosition = "top";
100
+ return {left: horizontalCenter - tooltipWidth / 2, top, finalPosition};
101
+ } else if (!overflowLeft) {
102
+ finalPosition = "left";
103
+ return {left, top: verticalCenter, finalPosition};
92
104
  } else {
93
- // At this point, we're either trying to place it above or below, and force it into the
94
- // viewport.
105
+ finalPosition = "right";
106
+ return {
107
+ left: Dimensions.get("window").width - TOOLTIP_OVERFLOW_PADDING - tooltipWidth,
108
+ top: verticalCenter,
109
+ finalPosition,
110
+ };
111
+ }
112
+ };
95
113
 
96
- let y = top;
97
- if ((idealDirection === "bottom" && !overflowBottom) || overflowTop) {
98
- y = bottom;
99
- }
114
+ const Arrow: FC<{position: TooltipPosition; color: string}> = ({position, color}) => {
115
+ const getArrowStyle = (): ViewStyle => {
116
+ const arrowStyles = {
117
+ top: {
118
+ borderLeftWidth: 6,
119
+ borderRightWidth: 6,
120
+ borderTopWidth: 6,
121
+ marginBottom: 8,
122
+ borderLeftColor: "transparent",
123
+ borderRightColor: "transparent",
124
+ borderBottomColor: color,
125
+ },
126
+ bottom: {
127
+ borderLeftWidth: 6,
128
+ borderRightWidth: 6,
129
+ borderBottomWidth: 6,
130
+ marginTop: 8,
131
+ borderLeftColor: "transparent",
132
+ borderRightColor: "transparent",
133
+ borderTopColor: color,
134
+ },
135
+ left: {
136
+ borderTopWidth: 6,
137
+ borderBottomWidth: 6,
138
+ borderLeftWidth: 6,
139
+ marginRight: 8,
140
+ borderTopColor: "transparent",
141
+ borderBottomColor: "transparent",
142
+ borderLeftColor: color,
143
+ },
144
+ right: {
145
+ borderTopWidth: 6,
146
+ borderBottomWidth: 6,
147
+ borderRightWidth: 6,
148
+ marginLeft: 8,
149
+ borderTopColor: "transparent",
150
+ borderBottomColor: "transparent",
151
+ borderRightColor: color,
152
+ },
153
+ };
154
+ return {
155
+ width: 0,
156
+ height: 0,
157
+ alignSelf: "center",
158
+ borderStyle: "solid",
159
+ ...arrowStyles[position],
160
+ } as ViewStyle;
161
+ };
100
162
 
101
- // If it fits in the viewport, center it above the child.
102
- if (
103
- !overflowLeft(horizontalCenter - tooltipWidth) &&
104
- !overflowRight(horizontalCenter + tooltipWidth)
105
- ) {
106
- return {left: horizontalCenter - tooltipWidth / 2, top: y};
107
- }
108
- // Failing that, if it fits on the left, put it there, otherwise to the right.
109
- // We know it's smaller than the viewport.
110
- else if (overflowLeft(horizontalCenter - tooltipWidth)) {
111
- return {left: TOOLTIP_OVERFLOW_PADDING, top: y};
112
- } else {
113
- return {
114
- left: Dimensions.get("window").width - TOOLTIP_OVERFLOW_PADDING - tooltipWidth,
115
- top: y,
116
- };
117
- }
118
- }
163
+ const arrowStyle = getArrowStyle();
164
+ return <View style={arrowStyle} />;
119
165
  };
120
166
 
121
- export const Tooltip = (props: TooltipProps) => {
122
- const {theme} = useContext(ThemeContext);
123
- const {text, children, bgColor, idealDirection} = props;
124
- const hoverDelay = 500;
167
+ export const Tooltip: FC<TooltipProps> = ({text, children, idealPosition, includeArrow}) => {
168
+ const {theme} = useTheme();
169
+ const hoverDelay = 800;
125
170
  const hoverEndDelay = 0;
126
- const [visible, setVisible] = React.useState(false);
171
+ const [visible, setVisible] = useState(false);
172
+ const [finalPosition, setFinalPosition] = useState<TooltipPosition>("top");
127
173
 
128
- const [measurement, setMeasurement] = React.useState({
174
+ const [measurement, setMeasurement] = useState<Measurement>({
129
175
  children: {},
130
176
  tooltip: {},
131
177
  measured: false,
132
178
  });
133
- const showTooltipTimer = React.useRef<NodeJS.Timeout>();
134
- const hideTooltipTimer = React.useRef<NodeJS.Timeout>();
135
- const childrenWrapperRef = React.useRef() as React.MutableRefObject<View>;
136
-
137
- const touched = React.useRef(false);
138
179
 
180
+ const showTooltipTimer = useRef<NodeJS.Timeout>();
181
+ const hideTooltipTimer = useRef<NodeJS.Timeout>();
182
+ const childrenWrapperRef = useRef<View>(null);
183
+ const touched = useRef(false);
139
184
  const isWeb = Platform.OS === "web";
140
185
 
141
186
  // If the tooltip is visible, and the user clicks outside of the tooltip, hide it.
142
- React.useEffect(() => {
187
+ useEffect(() => {
143
188
  return () => {
144
189
  if (showTooltipTimer.current) {
145
190
  clearTimeout(showTooltipTimer.current);
146
191
  }
147
-
148
192
  if (hideTooltipTimer.current) {
149
193
  clearTimeout(hideTooltipTimer.current);
150
194
  }
151
195
  };
152
196
  }, []);
153
197
 
154
- const handleOnLayout = ({nativeEvent: {layout}}: LayoutChangeEvent) => {
155
- if (childrenWrapperRef?.current && !childrenWrapperRef?.current?.measure) {
156
- console.error("Tooltip: childrenWrapperRef does not have a measure method.");
157
- return;
158
- } else if (!childrenWrapperRef?.current) {
159
- console.error("Tooltip: childrenWrapperRef is null.");
198
+ const getArrowContainerStyle = (): ViewStyle => {
199
+ if (!includeArrow) {
200
+ return {};
160
201
  }
161
- childrenWrapperRef?.current?.measure((_x, _y, width, height, pageX, pageY) => {
162
- setMeasurement({
163
- children: {pageX, pageY, height, width},
164
- tooltip: {...layout},
165
- measured: true,
166
- });
167
- });
202
+ const containerStyles = {
203
+ top: {
204
+ bottom: -12,
205
+ left: "50%",
206
+ transform: [{translateX: -6}],
207
+ },
208
+ bottom: {
209
+ top: -12,
210
+ left: "50%",
211
+ transform: [{translateX: -6}],
212
+ },
213
+ left: {
214
+ right: -12,
215
+ top: "50%",
216
+ transform: [{translateY: -6}],
217
+ },
218
+ right: {
219
+ left: -12,
220
+ top: "50%",
221
+ transform: [{translateY: -6}],
222
+ },
223
+ };
224
+ return {position: "absolute", ...containerStyles[finalPosition]} as ViewStyle;
168
225
  };
169
226
 
170
- const handleTouchStart = () => {
227
+ const arrowContainerStyles = getArrowContainerStyle();
228
+
229
+ const handleOnLayout = useCallback(
230
+ ({nativeEvent: {layout}}: LayoutChangeEvent) => {
231
+ if (childrenWrapperRef?.current && !childrenWrapperRef?.current?.measure) {
232
+ console.error("Tooltip: childrenWrapperRef does not have a measure method.");
233
+ return;
234
+ } else if (!childrenWrapperRef?.current) {
235
+ console.error("Tooltip: childrenWrapperRef is null.");
236
+ }
237
+
238
+ childrenWrapperRef?.current?.measure((_x, _y, width, height, pageX, pageY) => {
239
+ setMeasurement({
240
+ children: {pageX, pageY, height, width},
241
+ tooltip: {...layout},
242
+ measured: true,
243
+ });
244
+ const position = getTooltipPosition({
245
+ children: {pageX, pageY, height, width},
246
+ tooltip: {...layout},
247
+ measured: true,
248
+ idealPosition,
249
+ });
250
+ if ("finalPosition" in position) {
251
+ setFinalPosition(position.finalPosition);
252
+ }
253
+ });
254
+ },
255
+ [setMeasurement, idealPosition]
256
+ );
257
+
258
+ const handleTouchStart = useCallback(() => {
171
259
  if (hideTooltipTimer.current) {
172
260
  clearTimeout(hideTooltipTimer.current);
173
261
  }
@@ -176,9 +264,9 @@ export const Tooltip = (props: TooltipProps) => {
176
264
  touched.current = true;
177
265
  setVisible(true);
178
266
  }, 100);
179
- };
267
+ }, []);
180
268
 
181
- const handleHoverIn = () => {
269
+ const handleHoverIn = useCallback(() => {
182
270
  if (hideTooltipTimer.current) {
183
271
  clearTimeout(hideTooltipTimer.current);
184
272
  }
@@ -187,9 +275,9 @@ export const Tooltip = (props: TooltipProps) => {
187
275
  touched.current = true;
188
276
  setVisible(true);
189
277
  }, hoverDelay);
190
- };
278
+ }, [hoverDelay]);
191
279
 
192
- const handleHoverOut = () => {
280
+ const handleHoverOut = useCallback(() => {
193
281
  touched.current = false;
194
282
  if (showTooltipTimer.current) {
195
283
  clearTimeout(showTooltipTimer.current);
@@ -197,16 +285,18 @@ export const Tooltip = (props: TooltipProps) => {
197
285
 
198
286
  hideTooltipTimer.current = setTimeout(() => {
199
287
  setVisible(false);
200
- setMeasurement({children: {}, tooltip: {}, measured: false});
288
+ setMeasurement({
289
+ children: {},
290
+ tooltip: {},
291
+ measured: false,
292
+ });
201
293
  }, hoverEndDelay);
202
- };
294
+ }, [hoverEndDelay]);
203
295
 
204
296
  const mobilePressProps = {
205
- onPress: React.useCallback(() => {
206
- if (touched.current) {
207
- return null;
208
- } else {
209
- return children.props.onClick?.();
297
+ onPress: useCallback(() => {
298
+ if (!touched.current) {
299
+ children.props.onClick?.();
210
300
  }
211
301
  }, [children.props]),
212
302
  };
@@ -219,48 +309,75 @@ export const Tooltip = (props: TooltipProps) => {
219
309
  }
220
310
 
221
311
  return (
222
- <>
223
- {visible && (
224
- <Portal>
225
- <Pressable
226
- style={{
227
- alignSelf: "flex-start",
228
- justifyContent: "center",
229
- paddingHorizontal: 16,
230
- backgroundColor: theme[bgColor ?? "darkGray"],
231
- borderRadius: 16,
232
- paddingVertical: 8,
233
- display: "flex",
234
- flexShrink: 1,
235
- maxWidth: Math.max(Dimensions.get("window").width - 32, 300),
236
- ...getTooltipPosition({...(measurement as Measurement), idealDirection}),
237
- ...(measurement.measured ? {opacity: 1} : {opacity: 0}),
238
- }}
239
- testID="tooltip-container"
240
- onLayout={handleOnLayout}
241
- onPress={() => {
242
- setVisible(false);
243
- }}
244
- >
245
- <Text color="white">{text}</Text>
246
- </Pressable>
247
- </Portal>
248
- )}
312
+ <View>
249
313
  <View
250
- ref={childrenWrapperRef}
251
- onPointerEnter={() => {
252
- handleHoverIn();
253
- children.props.onHoverIn?.();
254
- }}
255
- onPointerLeave={() => {
256
- handleHoverOut();
257
- children.props.onHoverOut?.();
314
+ style={{
315
+ alignSelf: "flex-start",
258
316
  }}
259
- onTouchStart={handleTouchStart}
260
- {...(!isWeb && mobilePressProps)}
261
317
  >
262
- {children}
318
+ {visible && (
319
+ <Portal>
320
+ <View
321
+ style={{
322
+ position: "absolute",
323
+ zIndex: 999,
324
+ ...getTooltipPosition({...(measurement as Measurement), idealPosition}),
325
+ }}
326
+ onLayout={handleOnLayout}
327
+ >
328
+ {includeArrow && isWeb && (
329
+ <View style={arrowContainerStyles as ViewStyle}>
330
+ <Arrow color={theme.surface.secondaryExtraDark} position={finalPosition} />
331
+ </View>
332
+ )}
333
+ <View
334
+ style={{
335
+ backgroundColor: theme.surface.secondaryExtraDark,
336
+ borderRadius: theme.radius.default,
337
+ paddingVertical: 2,
338
+ paddingHorizontal: 8,
339
+ maxWidth: 320,
340
+ display: "flex",
341
+ flexShrink: 1,
342
+ opacity: measurement.measured ? 1 : 0,
343
+ }}
344
+ >
345
+ <Pressable
346
+ accessibilityHint="Tooltip information"
347
+ accessibilityLabel={text}
348
+ accessibilityRole="button"
349
+ style={{
350
+ backgroundColor: theme.surface.secondaryExtraDark,
351
+ borderRadius: theme.radius.default,
352
+ }}
353
+ testID="tooltip-container"
354
+ onPress={() => setVisible(false)}
355
+ >
356
+ <Text color="inverted" size="sm">
357
+ {text}
358
+ </Text>
359
+ </Pressable>
360
+ </View>
361
+ </View>
362
+ </Portal>
363
+ )}
364
+ <View
365
+ ref={childrenWrapperRef}
366
+ hitSlop={{top: 10, bottom: 10, left: 15, right: 15}}
367
+ onPointerEnter={() => {
368
+ handleHoverIn();
369
+ children.props.onHoverIn?.();
370
+ }}
371
+ onPointerLeave={() => {
372
+ handleHoverOut();
373
+ children.props.onHoverOut?.();
374
+ }}
375
+ onTouchStart={handleTouchStart}
376
+ {...(!isWeb && mobilePressProps)}
377
+ >
378
+ {children}
379
+ </View>
263
380
  </View>
264
- </>
381
+ </View>
265
382
  );
266
383
  };
@@ -52,13 +52,13 @@ export const UnifiedAddressAutoCompleteField = ({
52
52
  return (
53
53
  <TextField
54
54
  disabled={disabled}
55
- label="Street Address"
56
55
  placeholder="Enter an address"
57
56
  testID={testID}
57
+ title="Street Address"
58
58
  type="text"
59
59
  value={inputValue}
60
- onChange={({value}): void => {
61
- handleAddressChange({value});
60
+ onChange={(value): void => {
61
+ handleAddressChange(value);
62
62
  }}
63
63
  />
64
64
  );
package/src/Unifier.ts CHANGED
@@ -6,7 +6,7 @@ import * as Clipboard from "expo-clipboard";
6
6
  import * as Haptics from "expo-haptics";
7
7
  import {Dimensions, Keyboard, Linking, Platform, Vibration} from "react-native";
8
8
 
9
- import {PermissionKind, UnifiedTheme} from "./Common";
9
+ import {FernsTheme, PermissionKind} from "./Common";
10
10
  import {requestPermissions} from "./Permissions";
11
11
 
12
12
  declare global {
@@ -61,7 +61,7 @@ export function changeColorLuminance(hex: string, luminanceChange: Luminance) {
61
61
  }
62
62
 
63
63
  class UnifierClass {
64
- private _theme?: Partial<UnifiedTheme>;
64
+ private _theme?: Partial<FernsTheme>;
65
65
 
66
66
  private _web = false;
67
67
 
@@ -160,9 +160,9 @@ class UnifierClass {
160
160
  try {
161
161
  const jsonValue = JSON.stringify(item);
162
162
  await AsyncStorage.setItem(key, jsonValue);
163
- } catch (error) {
163
+ } catch (error: any) {
164
164
  console.error(`[storage] Error storing ${key}`, item, error);
165
- throw new Error(error as any);
165
+ throw new Error(error);
166
166
  }
167
167
  },
168
168
  };
package/src/Utilities.tsx CHANGED
@@ -294,14 +294,22 @@ export const isValidGoogleApiKey = (apiKey: string): boolean => {
294
294
 
295
295
  export function formattedCountyCode(state: string, countyName: string): string {
296
296
  // Remove whitespace and convert to lowercase for comparison
297
- const stateKey = state.replace(/\s+/g, "").toLowerCase();
297
+ const stateKey = state
298
+ .replace(/\s+/g, "")
299
+ .toLowerCase() as keyof typeof COUNTY_AND_COUNTY_EQUIVALENT_ENTITIES;
300
+
301
+ const stateData = COUNTY_AND_COUNTY_EQUIVALENT_ENTITIES[stateKey];
302
+
298
303
  // Remove whitespace, periods, apostrophes, and dashes for comparison
299
304
  const countyKey = countyName
300
305
  .trim()
301
306
  .toLowerCase()
302
- .replace(/[\s.'-]/g, "");
307
+ .replace(/[\s.'-]/g, "") as keyof typeof stateData;
303
308
 
304
- const countyData = COUNTY_AND_COUNTY_EQUIVALENT_ENTITIES[stateKey]?.[countyKey];
309
+ const countyData: {
310
+ stateFP: string;
311
+ countyFP: string;
312
+ } = stateData?.[countyKey];
305
313
  if (!countyData) {
306
314
  return "";
307
315
  }
@@ -73,12 +73,11 @@ export const WebAddressAutocomplete = ({
73
73
  <TextField
74
74
  disabled={disabled}
75
75
  inputRef={scriptLoaded ? (ref: any): void => (autocompleteInputRef.current = ref) : undefined}
76
- label="Street Address"
77
76
  placeholder="Enter an address"
78
77
  type="text"
79
78
  value={inputValue}
80
- onChange={({value}): void => {
81
- handleAddressChange({value});
79
+ onChange={(value): void => {
80
+ handleAddressChange(value);
82
81
  }}
83
82
  />
84
83
  );
@@ -0,0 +1,24 @@
1
+ // This component is intended to be used as an error message for form fields, specifically for text
2
+ // fields and text areas. It is not intended to be used as a standalone component.
3
+ import React, {FC} from "react";
4
+ import {Text, View} from "react-native";
5
+
6
+ import {Icon} from "../Icon";
7
+ import {useTheme} from "../Theme";
8
+
9
+ interface FieldErrorProps {
10
+ text: string;
11
+ }
12
+
13
+ export const FieldError: FC<FieldErrorProps> = ({text}) => {
14
+ const {theme} = useTheme();
15
+
16
+ return (
17
+ <View style={{flexDirection: "row", alignItems: "center", marginVertical: 2}}>
18
+ <Icon color="error" iconName="triangle-exclamation" size="sm" />
19
+ <View style={{marginLeft: 4}}>
20
+ <Text style={{color: theme.text.error, fontSize: 12}}>{text}</Text>
21
+ </View>
22
+ </View>
23
+ );
24
+ };
@@ -0,0 +1,20 @@
1
+ // This component is intended to be used as a helper text for form fields, specifically for text
2
+ // fields and text areas. It is not intended to be used as a standalone component.
3
+ import React, {FC} from "react";
4
+ import {Text, View} from "react-native";
5
+
6
+ import {useTheme} from "../Theme";
7
+
8
+ interface FieldHelperTextProps {
9
+ text: string;
10
+ }
11
+
12
+ export const FieldHelperText: FC<FieldHelperTextProps> = ({text}) => {
13
+ const {theme} = useTheme();
14
+
15
+ return (
16
+ <View style={{marginTop: 2}}>
17
+ <Text style={{fontSize: 12, color: theme.text.primary, lineHeight: 16}}>{text}</Text>
18
+ </View>
19
+ );
20
+ };
@@ -0,0 +1,31 @@
1
+ // This component is intended to be used as a title for form fields,
2
+ // specifically for text fields and text areas. It is not intended to be used as a standalone
3
+ // component.
4
+ import React, {FC} from "react";
5
+ import {Text} from "react-native";
6
+
7
+ import {isMobileDevice} from "../MediaQuery";
8
+ import {useTheme} from "../Theme";
9
+ import {isNative} from "../Utilities";
10
+
11
+ interface FieldTitleProps {
12
+ text: string;
13
+ }
14
+
15
+ export const FieldTitle: FC<FieldTitleProps> = ({text}) => {
16
+ const {theme} = useTheme();
17
+ const isMobileOrNative = isMobileDevice() || isNative();
18
+
19
+ return (
20
+ <Text
21
+ style={{
22
+ color: theme.text.primary,
23
+ fontSize: isMobileOrNative ? 14 : 16,
24
+ fontWeight: 600,
25
+ lineHeight: 22.4,
26
+ }}
27
+ >
28
+ {text}
29
+ </Text>
30
+ );
31
+ };
@@ -0,0 +1,3 @@
1
+ export * from "./FieldError";
2
+ export * from "./FieldHelperText";
3
+ export * from "./FieldTitle";