@terreno/ui 0.0.1

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 (446) hide show
  1. package/LICENSE +203 -0
  2. package/README.md +160 -0
  3. package/dist/Accordion.d.ts +3 -0
  4. package/dist/Accordion.js +30 -0
  5. package/dist/Accordion.js.map +1 -0
  6. package/dist/ActionSheet.d.ts +169 -0
  7. package/dist/ActionSheet.js +637 -0
  8. package/dist/ActionSheet.js.map +1 -0
  9. package/dist/AddressField.d.ts +3 -0
  10. package/dist/AddressField.js +18 -0
  11. package/dist/AddressField.js.map +1 -0
  12. package/dist/Avatar.d.ts +3 -0
  13. package/dist/Avatar.js +189 -0
  14. package/dist/Avatar.js.map +1 -0
  15. package/dist/Badge.d.ts +3 -0
  16. package/dist/Badge.js +100 -0
  17. package/dist/Badge.js.map +1 -0
  18. package/dist/Banner.d.ts +4 -0
  19. package/dist/Banner.js +103 -0
  20. package/dist/Banner.js.map +1 -0
  21. package/dist/Body.d.ts +3 -0
  22. package/dist/Body.js +17 -0
  23. package/dist/Body.js.map +1 -0
  24. package/dist/BooleanField.d.ts +3 -0
  25. package/dist/BooleanField.js +89 -0
  26. package/dist/BooleanField.js.map +1 -0
  27. package/dist/Box.d.ts +3 -0
  28. package/dist/Box.js +289 -0
  29. package/dist/Box.js.map +1 -0
  30. package/dist/Button.d.ts +3 -0
  31. package/dist/Button.js +105 -0
  32. package/dist/Button.js.map +1 -0
  33. package/dist/Card.d.ts +2 -0
  34. package/dist/Card.js +18 -0
  35. package/dist/Card.js.map +1 -0
  36. package/dist/CheckBox.d.ts +3 -0
  37. package/dist/CheckBox.js +28 -0
  38. package/dist/CheckBox.js.map +1 -0
  39. package/dist/Common.d.ts +2325 -0
  40. package/dist/Common.js +47 -0
  41. package/dist/Common.js.map +1 -0
  42. package/dist/CommonIconTypes.d.ts +3 -0
  43. package/dist/CommonIconTypes.js +2 -0
  44. package/dist/CommonIconTypes.js.map +1 -0
  45. package/dist/Constants.d.ts +12685 -0
  46. package/dist/Constants.js +3310 -0
  47. package/dist/Constants.js.map +1 -0
  48. package/dist/CustomSelectField.d.ts +3 -0
  49. package/dist/CustomSelectField.js +59 -0
  50. package/dist/CustomSelectField.js.map +1 -0
  51. package/dist/DataTable.d.ts +3 -0
  52. package/dist/DataTable.js +190 -0
  53. package/dist/DataTable.js.map +1 -0
  54. package/dist/DateTimeActionSheet.d.ts +2 -0
  55. package/dist/DateTimeActionSheet.js +270 -0
  56. package/dist/DateTimeActionSheet.js.map +1 -0
  57. package/dist/DateTimeField.d.ts +3 -0
  58. package/dist/DateTimeField.js +514 -0
  59. package/dist/DateTimeField.js.map +1 -0
  60. package/dist/DateUtilities.d.ts +57 -0
  61. package/dist/DateUtilities.js +308 -0
  62. package/dist/DateUtilities.js.map +1 -0
  63. package/dist/DecimalRangeActionSheet.d.ts +6 -0
  64. package/dist/DecimalRangeActionSheet.js +45 -0
  65. package/dist/DecimalRangeActionSheet.js.map +1 -0
  66. package/dist/DismissButton.d.ts +3 -0
  67. package/dist/DismissButton.js +12 -0
  68. package/dist/DismissButton.js.map +1 -0
  69. package/dist/EmailField.d.ts +3 -0
  70. package/dist/EmailField.js +48 -0
  71. package/dist/EmailField.js.map +1 -0
  72. package/dist/EmojiSelector.d.ts +113 -0
  73. package/dist/EmojiSelector.js +322 -0
  74. package/dist/EmojiSelector.js.map +1 -0
  75. package/dist/ErrorBoundary.d.ts +19 -0
  76. package/dist/ErrorBoundary.js +30 -0
  77. package/dist/ErrorBoundary.js.map +1 -0
  78. package/dist/ErrorPage.d.ts +6 -0
  79. package/dist/ErrorPage.js +15 -0
  80. package/dist/ErrorPage.js.map +1 -0
  81. package/dist/Field.d.ts +3 -0
  82. package/dist/Field.js +80 -0
  83. package/dist/Field.js.map +1 -0
  84. package/dist/FlatList.d.ts +2 -0
  85. package/dist/FlatList.js +3 -0
  86. package/dist/FlatList.js.map +1 -0
  87. package/dist/Heading.d.ts +3 -0
  88. package/dist/Heading.js +43 -0
  89. package/dist/Heading.js.map +1 -0
  90. package/dist/HeightActionSheet.d.ts +11 -0
  91. package/dist/HeightActionSheet.js +46 -0
  92. package/dist/HeightActionSheet.js.map +1 -0
  93. package/dist/Hyperlink.d.ts +30 -0
  94. package/dist/Hyperlink.js +144 -0
  95. package/dist/Hyperlink.js.map +1 -0
  96. package/dist/Icon.d.ts +3 -0
  97. package/dist/Icon.js +15 -0
  98. package/dist/Icon.js.map +1 -0
  99. package/dist/IconButton.d.ts +3 -0
  100. package/dist/IconButton.js +111 -0
  101. package/dist/IconButton.js.map +1 -0
  102. package/dist/Image.d.ts +8 -0
  103. package/dist/Image.js +37 -0
  104. package/dist/Image.js.map +1 -0
  105. package/dist/ImageBackground.d.ts +10 -0
  106. package/dist/ImageBackground.js +9 -0
  107. package/dist/ImageBackground.js.map +1 -0
  108. package/dist/InfoModalIcon.d.ts +3 -0
  109. package/dist/InfoModalIcon.js +10 -0
  110. package/dist/InfoModalIcon.js.map +1 -0
  111. package/dist/InfoTooltipButton.d.ts +3 -0
  112. package/dist/InfoTooltipButton.js +6 -0
  113. package/dist/InfoTooltipButton.js.map +1 -0
  114. package/dist/Link.d.ts +3 -0
  115. package/dist/Link.js +10 -0
  116. package/dist/Link.js.map +1 -0
  117. package/dist/MarkdownView.d.ts +5 -0
  118. package/dist/MarkdownView.js +44 -0
  119. package/dist/MarkdownView.js.map +1 -0
  120. package/dist/MediaQuery.d.ts +4 -0
  121. package/dist/MediaQuery.js +52 -0
  122. package/dist/MediaQuery.js.map +1 -0
  123. package/dist/MobileAddressAutoComplete.d.ts +2 -0
  124. package/dist/MobileAddressAutoComplete.js +54 -0
  125. package/dist/MobileAddressAutoComplete.js.map +1 -0
  126. package/dist/Modal.d.ts +3 -0
  127. package/dist/Modal.js +127 -0
  128. package/dist/Modal.js.map +1 -0
  129. package/dist/ModalSheet.d.ts +6 -0
  130. package/dist/ModalSheet.js +42 -0
  131. package/dist/ModalSheet.js.map +1 -0
  132. package/dist/MultiselectField.d.ts +3 -0
  133. package/dist/MultiselectField.js +45 -0
  134. package/dist/MultiselectField.js.map +1 -0
  135. package/dist/NumberField.d.ts +3 -0
  136. package/dist/NumberField.js +60 -0
  137. package/dist/NumberField.js.map +1 -0
  138. package/dist/NumberPickerActionSheet.d.ts +7 -0
  139. package/dist/NumberPickerActionSheet.js +22 -0
  140. package/dist/NumberPickerActionSheet.js.map +1 -0
  141. package/dist/OpenAPIContext.d.ts +4 -0
  142. package/dist/OpenAPIContext.js +53 -0
  143. package/dist/OpenAPIContext.js.map +1 -0
  144. package/dist/Page.d.ts +7 -0
  145. package/dist/Page.js +24 -0
  146. package/dist/Page.js.map +1 -0
  147. package/dist/Pagination.d.ts +3 -0
  148. package/dist/Pagination.js +106 -0
  149. package/dist/Pagination.js.map +1 -0
  150. package/dist/PasswordField.d.ts +2 -0
  151. package/dist/PasswordField.js +6 -0
  152. package/dist/PasswordField.js.map +1 -0
  153. package/dist/Permissions.d.ts +2 -0
  154. package/dist/Permissions.js +35 -0
  155. package/dist/Permissions.js.map +1 -0
  156. package/dist/PhoneNumberField.d.ts +3 -0
  157. package/dist/PhoneNumberField.js +83 -0
  158. package/dist/PhoneNumberField.js.map +1 -0
  159. package/dist/PickerSelect.d.ts +46 -0
  160. package/dist/PickerSelect.js +306 -0
  161. package/dist/PickerSelect.js.map +1 -0
  162. package/dist/Radio.d.ts +3 -0
  163. package/dist/Radio.js +21 -0
  164. package/dist/Radio.js.map +1 -0
  165. package/dist/RadioField.d.ts +3 -0
  166. package/dist/RadioField.js +16 -0
  167. package/dist/RadioField.js.map +1 -0
  168. package/dist/ScrollView.d.ts +2 -0
  169. package/dist/ScrollView.js +3 -0
  170. package/dist/ScrollView.js.map +1 -0
  171. package/dist/SectionDivider.d.ts +2 -0
  172. package/dist/SectionDivider.js +12 -0
  173. package/dist/SectionDivider.js.map +1 -0
  174. package/dist/SegmentedControl.d.ts +3 -0
  175. package/dist/SegmentedControl.js +65 -0
  176. package/dist/SegmentedControl.js.map +1 -0
  177. package/dist/SelectBadge.d.ts +3 -0
  178. package/dist/SelectBadge.js +166 -0
  179. package/dist/SelectBadge.js.map +1 -0
  180. package/dist/SelectField.d.ts +3 -0
  181. package/dist/SelectField.js +16 -0
  182. package/dist/SelectField.js.map +1 -0
  183. package/dist/SideDrawer.d.ts +3 -0
  184. package/dist/SideDrawer.js +32 -0
  185. package/dist/SideDrawer.js.map +1 -0
  186. package/dist/Signature.d.ts +8 -0
  187. package/dist/Signature.js +21 -0
  188. package/dist/Signature.js.map +1 -0
  189. package/dist/Signature.native.d.ts +8 -0
  190. package/dist/Signature.native.js +26 -0
  191. package/dist/Signature.native.js.map +1 -0
  192. package/dist/SignatureField.d.ts +3 -0
  193. package/dist/SignatureField.js +42 -0
  194. package/dist/SignatureField.js.map +1 -0
  195. package/dist/Slider.d.ts +3 -0
  196. package/dist/Slider.js +78 -0
  197. package/dist/Slider.js.map +1 -0
  198. package/dist/Spinner.d.ts +3 -0
  199. package/dist/Spinner.js +33 -0
  200. package/dist/Spinner.js.map +1 -0
  201. package/dist/SplitPage.d.ts +2 -0
  202. package/dist/SplitPage.js +139 -0
  203. package/dist/SplitPage.js.map +1 -0
  204. package/dist/SplitPage.native.d.ts +2 -0
  205. package/dist/SplitPage.native.js +75 -0
  206. package/dist/SplitPage.native.js.map +1 -0
  207. package/dist/TapToEdit.d.ts +4 -0
  208. package/dist/TapToEdit.js +170 -0
  209. package/dist/TapToEdit.js.map +1 -0
  210. package/dist/TerrenoProvider.d.ts +6 -0
  211. package/dist/TerrenoProvider.js +10 -0
  212. package/dist/TerrenoProvider.js.map +1 -0
  213. package/dist/Text.d.ts +3 -0
  214. package/dist/Text.js +95 -0
  215. package/dist/Text.js.map +1 -0
  216. package/dist/TextArea.d.ts +3 -0
  217. package/dist/TextArea.js +6 -0
  218. package/dist/TextArea.js.map +1 -0
  219. package/dist/TextField.d.ts +3 -0
  220. package/dist/TextField.js +144 -0
  221. package/dist/TextField.js.map +1 -0
  222. package/dist/TextFieldNumberActionSheet.d.ts +7 -0
  223. package/dist/TextFieldNumberActionSheet.js +20 -0
  224. package/dist/TextFieldNumberActionSheet.js.map +1 -0
  225. package/dist/Theme.d.ts +96 -0
  226. package/dist/Theme.js +213 -0
  227. package/dist/Theme.js.map +1 -0
  228. package/dist/TimezonePicker.d.ts +11 -0
  229. package/dist/TimezonePicker.js +27 -0
  230. package/dist/TimezonePicker.js.map +1 -0
  231. package/dist/Toast.d.ts +23 -0
  232. package/dist/Toast.js +157 -0
  233. package/dist/Toast.js.map +1 -0
  234. package/dist/Tooltip.d.ts +3 -0
  235. package/dist/Tooltip.js +289 -0
  236. package/dist/Tooltip.js.map +1 -0
  237. package/dist/UnifiedAddressAutoComplete.d.ts +2 -0
  238. package/dist/UnifiedAddressAutoComplete.js +23 -0
  239. package/dist/UnifiedAddressAutoComplete.js.map +1 -0
  240. package/dist/Unifier.d.ts +43 -0
  241. package/dist/Unifier.js +154 -0
  242. package/dist/Unifier.js.map +1 -0
  243. package/dist/Utilities.d.ts +56 -0
  244. package/dist/Utilities.js +193 -0
  245. package/dist/Utilities.js.map +1 -0
  246. package/dist/WebAddressAutocomplete.d.ts +3 -0
  247. package/dist/WebAddressAutocomplete.js +61 -0
  248. package/dist/WebAddressAutocomplete.js.map +1 -0
  249. package/dist/fieldElements/FieldError.d.ts +6 -0
  250. package/dist/fieldElements/FieldError.js +9 -0
  251. package/dist/fieldElements/FieldError.js.map +1 -0
  252. package/dist/fieldElements/FieldHelperText.d.ts +6 -0
  253. package/dist/fieldElements/FieldHelperText.js +8 -0
  254. package/dist/fieldElements/FieldHelperText.js.map +1 -0
  255. package/dist/fieldElements/FieldTitle.d.ts +6 -0
  256. package/dist/fieldElements/FieldTitle.js +16 -0
  257. package/dist/fieldElements/FieldTitle.js.map +1 -0
  258. package/dist/fieldElements/index.d.ts +3 -0
  259. package/dist/fieldElements/index.js +4 -0
  260. package/dist/fieldElements/index.js.map +1 -0
  261. package/dist/icons/MobileIcon.d.ts +2 -0
  262. package/dist/icons/MobileIcon.js +18 -0
  263. package/dist/icons/MobileIcon.js.map +1 -0
  264. package/dist/icons/OfflineIcon.d.ts +2 -0
  265. package/dist/icons/OfflineIcon.js +18 -0
  266. package/dist/icons/OfflineIcon.js.map +1 -0
  267. package/dist/icons/OnlineIcon.d.ts +2 -0
  268. package/dist/icons/OnlineIcon.js +19 -0
  269. package/dist/icons/OnlineIcon.js.map +1 -0
  270. package/dist/icons/OutOfficeIcon.d.ts +2 -0
  271. package/dist/icons/OutOfficeIcon.js +18 -0
  272. package/dist/icons/OutOfficeIcon.js.map +1 -0
  273. package/dist/icons/index.d.ts +4 -0
  274. package/dist/icons/index.js +5 -0
  275. package/dist/icons/index.js.map +1 -0
  276. package/dist/index.d.ts +1328 -0
  277. package/dist/index.js +89 -0
  278. package/dist/index.js.map +1 -0
  279. package/dist/table/Table.d.ts +3 -0
  280. package/dist/table/Table.js +53 -0
  281. package/dist/table/Table.js.map +1 -0
  282. package/dist/table/TableBadge.d.ts +6 -0
  283. package/dist/table/TableBadge.js +23 -0
  284. package/dist/table/TableBadge.js.map +1 -0
  285. package/dist/table/TableBoolean.d.ts +6 -0
  286. package/dist/table/TableBoolean.js +37 -0
  287. package/dist/table/TableBoolean.js.map +1 -0
  288. package/dist/table/TableDate.d.ts +3 -0
  289. package/dist/table/TableDate.js +27 -0
  290. package/dist/table/TableDate.js.map +1 -0
  291. package/dist/table/TableHeader.d.ts +6 -0
  292. package/dist/table/TableHeader.js +10 -0
  293. package/dist/table/TableHeader.js.map +1 -0
  294. package/dist/table/TableHeaderCell.d.ts +6 -0
  295. package/dist/table/TableHeaderCell.js +54 -0
  296. package/dist/table/TableHeaderCell.js.map +1 -0
  297. package/dist/table/TableIconButton.d.ts +3 -0
  298. package/dist/table/TableIconButton.js +39 -0
  299. package/dist/table/TableIconButton.js.map +1 -0
  300. package/dist/table/TableNumber.d.ts +3 -0
  301. package/dist/table/TableNumber.js +18 -0
  302. package/dist/table/TableNumber.js.map +1 -0
  303. package/dist/table/TableRow.d.ts +6 -0
  304. package/dist/table/TableRow.js +22 -0
  305. package/dist/table/TableRow.js.map +1 -0
  306. package/dist/table/TableText.d.ts +3 -0
  307. package/dist/table/TableText.js +18 -0
  308. package/dist/table/TableText.js.map +1 -0
  309. package/dist/table/TableTitle.d.ts +3 -0
  310. package/dist/table/TableTitle.js +21 -0
  311. package/dist/table/TableTitle.js.map +1 -0
  312. package/dist/table/tableContext.d.ts +5 -0
  313. package/dist/table/tableContext.js +38 -0
  314. package/dist/table/tableContext.js.map +1 -0
  315. package/dist/useStoredState.d.ts +1 -0
  316. package/dist/useStoredState.js +49 -0
  317. package/dist/useStoredState.js.map +1 -0
  318. package/package.json +123 -0
  319. package/src/Accordion.test.tsx +104 -0
  320. package/src/Accordion.tsx +81 -0
  321. package/src/ActionSheet.tsx +881 -0
  322. package/src/AddressField.test.tsx +120 -0
  323. package/src/AddressField.tsx +122 -0
  324. package/src/Avatar.test.tsx +163 -0
  325. package/src/Avatar.tsx +298 -0
  326. package/src/Badge.test.tsx +116 -0
  327. package/src/Badge.tsx +136 -0
  328. package/src/Banner.tsx +200 -0
  329. package/src/Body.tsx +34 -0
  330. package/src/BooleanField.tsx +141 -0
  331. package/src/Box.test.tsx +662 -0
  332. package/src/Box.tsx +368 -0
  333. package/src/Button.tsx +196 -0
  334. package/src/Card.tsx +19 -0
  335. package/src/CheckBox.tsx +45 -0
  336. package/src/Common.ts +2787 -0
  337. package/src/CommonIconTypes.ts +2030 -0
  338. package/src/Constants.ts +3311 -0
  339. package/src/CustomSelectField.tsx +115 -0
  340. package/src/DataTable.tsx +674 -0
  341. package/src/DateTimeActionSheet.tsx +559 -0
  342. package/src/DateTimeField.test.tsx +393 -0
  343. package/src/DateTimeField.tsx +777 -0
  344. package/src/DateUtilities.test.ts +440 -0
  345. package/src/DateUtilities.tsx +370 -0
  346. package/src/DecimalRangeActionSheet.tsx +85 -0
  347. package/src/DismissButton.tsx +31 -0
  348. package/src/EmailField.tsx +66 -0
  349. package/src/EmojiSelector.test.tsx +61 -0
  350. package/src/EmojiSelector.tsx +510 -0
  351. package/src/ErrorBoundary.tsx +37 -0
  352. package/src/ErrorPage.tsx +41 -0
  353. package/src/Field.tsx +101 -0
  354. package/src/FlatList.tsx +2 -0
  355. package/src/Heading.tsx +66 -0
  356. package/src/HeightActionSheet.tsx +91 -0
  357. package/src/Hyperlink.tsx +179 -0
  358. package/src/Icon.tsx +36 -0
  359. package/src/IconButton.tsx +217 -0
  360. package/src/Image.tsx +51 -0
  361. package/src/ImageBackground.tsx +14 -0
  362. package/src/InfoModalIcon.tsx +42 -0
  363. package/src/InfoTooltipButton.tsx +16 -0
  364. package/src/Link.tsx +22 -0
  365. package/src/MarkdownView.tsx +67 -0
  366. package/src/MediaQuery.ts +46 -0
  367. package/src/MobileAddressAutoComplete.tsx +126 -0
  368. package/src/Modal.tsx +300 -0
  369. package/src/ModalSheet.tsx +58 -0
  370. package/src/MultiselectField.tsx +112 -0
  371. package/src/NumberField.tsx +67 -0
  372. package/src/NumberPickerActionSheet.tsx +51 -0
  373. package/src/OpenAPIContext.tsx +74 -0
  374. package/src/Page.tsx +105 -0
  375. package/src/Pagination.tsx +169 -0
  376. package/src/PasswordField.tsx +7 -0
  377. package/src/Permissions.ts +43 -0
  378. package/src/PhoneNumberField.tsx +109 -0
  379. package/src/PickerSelect.tsx +571 -0
  380. package/src/Radio.tsx +33 -0
  381. package/src/RadioField.tsx +43 -0
  382. package/src/ScrollView.tsx +2 -0
  383. package/src/SectionDivider.tsx +18 -0
  384. package/src/SegmentedControl.tsx +126 -0
  385. package/src/SelectBadge.tsx +280 -0
  386. package/src/SelectField.tsx +41 -0
  387. package/src/SideDrawer.tsx +56 -0
  388. package/src/Signature.native.tsx +57 -0
  389. package/src/Signature.tsx +44 -0
  390. package/src/SignatureField.tsx +92 -0
  391. package/src/Slider.tsx +199 -0
  392. package/src/Spinner.tsx +35 -0
  393. package/src/SplitPage.native.tsx +163 -0
  394. package/src/SplitPage.tsx +304 -0
  395. package/src/TapToEdit.tsx +292 -0
  396. package/src/TerrenoProvider.tsx +31 -0
  397. package/src/Text.tsx +123 -0
  398. package/src/TextArea.test.tsx +255 -0
  399. package/src/TextArea.tsx +8 -0
  400. package/src/TextField.test.tsx +487 -0
  401. package/src/TextField.tsx +260 -0
  402. package/src/TextFieldNumberActionSheet.tsx +46 -0
  403. package/src/Theme.tsx +248 -0
  404. package/src/TimezonePicker.tsx +45 -0
  405. package/src/Toast.tsx +234 -0
  406. package/src/Tooltip.tsx +407 -0
  407. package/src/UnifiedAddressAutoComplete.tsx +66 -0
  408. package/src/Unifier.ts +172 -0
  409. package/src/Utilities.tsx +329 -0
  410. package/src/WebAddressAutocomplete.tsx +84 -0
  411. package/src/__snapshots__/Accordion.test.tsx.snap +126 -0
  412. package/src/__snapshots__/AddressField.test.tsx.snap +1197 -0
  413. package/src/__snapshots__/Avatar.test.tsx.snap +57 -0
  414. package/src/__snapshots__/Badge.test.tsx.snap +55 -0
  415. package/src/__snapshots__/Box.test.tsx.snap +162 -0
  416. package/src/__snapshots__/EmojiSelector.test.tsx.snap +422 -0
  417. package/src/__snapshots__/TextArea.test.tsx.snap +521 -0
  418. package/src/__snapshots__/TextField.test.tsx.snap +569 -0
  419. package/src/bunSetup.ts +1235 -0
  420. package/src/fieldElements/FieldError.tsx +24 -0
  421. package/src/fieldElements/FieldHelperText.tsx +20 -0
  422. package/src/fieldElements/FieldTitle.tsx +31 -0
  423. package/src/fieldElements/index.tsx +3 -0
  424. package/src/icons/MobileIcon.tsx +40 -0
  425. package/src/icons/OfflineIcon.tsx +37 -0
  426. package/src/icons/OnlineIcon.tsx +39 -0
  427. package/src/icons/OutOfficeIcon.tsx +36 -0
  428. package/src/icons/index.ts +4 -0
  429. package/src/index.tsx +1375 -0
  430. package/src/polyfill.d.ts +11 -0
  431. package/src/table/Table.tsx +109 -0
  432. package/src/table/TableBadge.tsx +46 -0
  433. package/src/table/TableBoolean.tsx +70 -0
  434. package/src/table/TableDate.tsx +38 -0
  435. package/src/table/TableHeader.tsx +20 -0
  436. package/src/table/TableHeaderCell.tsx +94 -0
  437. package/src/table/TableIconButton.tsx +61 -0
  438. package/src/table/TableNumber.tsx +29 -0
  439. package/src/table/TableRow.tsx +67 -0
  440. package/src/table/TableText.tsx +29 -0
  441. package/src/table/TableTitle.tsx +31 -0
  442. package/src/table/tableContext.tsx +67 -0
  443. package/src/test-utils.tsx +27 -0
  444. package/src/types/react-native-swiper-flatlist.d.ts +56 -0
  445. package/src/useStoredState.test.tsx +143 -0
  446. package/src/useStoredState.ts +56 -0
@@ -0,0 +1,120 @@
1
+ import {afterEach, beforeEach, describe, expect, it, mock} from "bun:test";
2
+ import {fireEvent} from "@testing-library/react-native";
3
+
4
+ import {AddressField} from "./AddressField";
5
+ import {renderWithTheme} from "./test-utils";
6
+
7
+ describe("AddressField", () => {
8
+ let mockOnChange: ReturnType<typeof mock>;
9
+ let mockOnBlur: ReturnType<typeof mock>;
10
+
11
+ const defaultValue = {
12
+ address1: "123 Main St",
13
+ address2: "Apt 4B",
14
+ city: "Springfield",
15
+ countyCode: "17167",
16
+ countyName: "Sangamon",
17
+ state: "IL",
18
+ zipcode: "62701",
19
+ };
20
+
21
+ beforeEach(() => {
22
+ mockOnChange = mock(() => {});
23
+ mockOnBlur = mock(() => {});
24
+ });
25
+
26
+ afterEach(() => {
27
+ // Reset mocks after each test
28
+ });
29
+
30
+ const defaultProps = {
31
+ onBlur: mockOnBlur,
32
+ onChange: mockOnChange,
33
+ testID: "test-address",
34
+ value: defaultValue,
35
+ };
36
+
37
+ it("renders correctly with default props", () => {
38
+ const {toJSON} = renderWithTheme(
39
+ <AddressField {...defaultProps} onBlur={mockOnBlur} onChange={mockOnChange} />
40
+ );
41
+ expect(toJSON()).toMatchSnapshot();
42
+ });
43
+
44
+ it("renders all address fields", () => {
45
+ const {getByTestId} = renderWithTheme(
46
+ <AddressField {...defaultProps} onBlur={mockOnBlur} onChange={mockOnChange} />
47
+ );
48
+
49
+ expect(getByTestId("test-address-address1")).toBeTruthy();
50
+ expect(getByTestId("test-address-address2")).toBeTruthy();
51
+ expect(getByTestId("test-address-city")).toBeTruthy();
52
+ expect(getByTestId("test-address-zip")).toBeTruthy();
53
+ });
54
+
55
+ it("calls onChange when address fields are updated", () => {
56
+ const {getByTestId} = renderWithTheme(
57
+ <AddressField {...defaultProps} onBlur={mockOnBlur} onChange={mockOnChange} />
58
+ );
59
+
60
+ const cityInput = getByTestId("test-address-city");
61
+ fireEvent.changeText(cityInput, "New City");
62
+
63
+ expect(mockOnChange).toHaveBeenCalledWith({
64
+ ...defaultValue,
65
+ city: "New City",
66
+ });
67
+ });
68
+
69
+ it("calls onBlur when a field is blurred", () => {
70
+ const {getByTestId} = renderWithTheme(
71
+ <AddressField {...defaultProps} onBlur={mockOnBlur} onChange={mockOnChange} />
72
+ );
73
+ // Reset mock since it was called during render
74
+ mockOnBlur.mockClear();
75
+ const zipInput = getByTestId("test-address-zip");
76
+ fireEvent.changeText(zipInput, "90210");
77
+ fireEvent(zipInput, "blur");
78
+
79
+ expect(mockOnBlur).toHaveBeenCalledWith({
80
+ ...defaultValue,
81
+ zipcode: "90210",
82
+ });
83
+ });
84
+
85
+ it("renders county fields when includeCounty is true", () => {
86
+ const {getByTestId} = renderWithTheme(
87
+ <AddressField {...defaultProps} includeCounty onBlur={mockOnBlur} onChange={mockOnChange} />
88
+ );
89
+
90
+ expect(getByTestId("test-address-county")).toBeTruthy();
91
+ expect(getByTestId("test-address-county-code")).toBeTruthy();
92
+ });
93
+
94
+ it("does not render county fields when includeCounty is false", () => {
95
+ const {queryByTestId} = renderWithTheme(
96
+ <AddressField
97
+ {...defaultProps}
98
+ includeCounty={false}
99
+ onBlur={mockOnBlur}
100
+ onChange={mockOnChange}
101
+ />
102
+ );
103
+
104
+ expect(queryByTestId("test-address-county")).toBeNull();
105
+ expect(queryByTestId("test-address-county-code")).toBeNull();
106
+ });
107
+
108
+ it("disables all fields when disabled prop is true", () => {
109
+ const {getByTestId} = renderWithTheme(
110
+ <AddressField {...defaultProps} disabled onBlur={mockOnBlur} onChange={mockOnChange} />
111
+ );
112
+
113
+ const address1Input = getByTestId("test-address-address1");
114
+ const cityInput = getByTestId("test-address-city");
115
+
116
+ // Check that the disabled prop is passed down to the inputs
117
+ expect(address1Input.props.accessibilityState.disabled).toBe(true);
118
+ expect(cityInput.props.accessibilityState.disabled).toBe(true);
119
+ });
120
+ });
@@ -0,0 +1,122 @@
1
+ import type {FC} from "react";
2
+ import {View} from "react-native";
3
+
4
+ import type {AddressFieldProps, AddressInterface} from "./Common";
5
+ import {USSTATESLIST} from "./Constants";
6
+ import {SelectField} from "./SelectField";
7
+ import {TextField} from "./TextField";
8
+ import {UnifiedAddressAutoCompleteField} from "./UnifiedAddressAutoComplete";
9
+
10
+ export const AddressField: FC<AddressFieldProps> = ({
11
+ disabled,
12
+ googleMapsApiKey,
13
+ googlePlacesMobileStyles,
14
+ includeCounty,
15
+ value,
16
+ testID,
17
+ onChange,
18
+ onBlur,
19
+ }) => {
20
+ const handleAddressChange = (field: string, newValue: string) => {
21
+ onChange({...value, [field]: newValue});
22
+ onBlur?.({...value, [field]: newValue});
23
+ };
24
+
25
+ const handleAutoCompleteChange = (newValue: AddressInterface) => {
26
+ onChange({...value, ...newValue});
27
+ };
28
+
29
+ const {
30
+ address1 = "",
31
+ address2 = "",
32
+ city = "",
33
+ state = "",
34
+ zipcode = "",
35
+ countyName = "",
36
+ countyCode = "",
37
+ }: AddressInterface = value ?? ({} as AddressInterface);
38
+
39
+ return (
40
+ <>
41
+ <View style={{marginBottom: 16}}>
42
+ <UnifiedAddressAutoCompleteField
43
+ disabled={disabled}
44
+ googleMapsApiKey={googleMapsApiKey}
45
+ googlePlacesMobileStyles={googlePlacesMobileStyles}
46
+ handleAddressChange={(result) => handleAddressChange("address1", result)}
47
+ handleAutoCompleteChange={(result) => handleAutoCompleteChange(result)}
48
+ includeCounty={includeCounty}
49
+ inputValue={address1}
50
+ testID={`${testID}-address1`}
51
+ />
52
+ </View>
53
+ <View style={{marginBottom: 16}}>
54
+ <TextField
55
+ disabled={disabled}
56
+ id="address2"
57
+ onChange={(result) => handleAddressChange("address2", result)}
58
+ testID={`${testID}-address2`}
59
+ title="Apt, suite, etc"
60
+ type="text"
61
+ value={address2}
62
+ />
63
+ </View>
64
+ <View style={{marginBottom: 16}}>
65
+ <TextField
66
+ disabled={disabled}
67
+ id="city"
68
+ onChange={(result) => handleAddressChange("city", result)}
69
+ testID={`${testID}-city`}
70
+ title="City"
71
+ type="text"
72
+ value={city}
73
+ />
74
+ </View>
75
+ <View style={{marginBottom: 16}}>
76
+ <SelectField
77
+ onChange={(result) => handleAddressChange("state", result!)}
78
+ options={USSTATESLIST}
79
+ title="State"
80
+ value={state}
81
+ />
82
+ </View>
83
+ <View style={{marginBottom: 16}}>
84
+ <TextField
85
+ disabled={disabled}
86
+ id="zipcode"
87
+ onChange={(result) => handleAddressChange("zipcode", result)}
88
+ testID={`${testID}-zip`}
89
+ title="Zipcode"
90
+ type="text"
91
+ value={zipcode}
92
+ />
93
+ </View>
94
+ {includeCounty && (
95
+ <>
96
+ <View style={{marginBottom: 16}}>
97
+ <TextField
98
+ disabled={disabled}
99
+ id="countyName"
100
+ onChange={(result) => handleAddressChange("countyName", result)}
101
+ testID={`${testID}-county`}
102
+ title="County Name"
103
+ type="text"
104
+ value={countyName}
105
+ />
106
+ </View>
107
+ <View style={{marginBottom: 16}}>
108
+ <TextField
109
+ disabled={disabled}
110
+ id="countyCode"
111
+ onChange={(result) => handleAddressChange("countyCode", result)}
112
+ testID={`${testID}-county-code`}
113
+ title="County Code"
114
+ type="text"
115
+ value={countyCode}
116
+ />
117
+ </View>
118
+ </>
119
+ )}
120
+ </>
121
+ );
122
+ };
@@ -0,0 +1,163 @@
1
+ import {beforeEach, describe, expect, it, mock, spyOn} from "bun:test";
2
+ import {act, fireEvent} from "@testing-library/react-native";
3
+ import * as ImageManipulator from "expo-image-manipulator";
4
+
5
+ import {Avatar} from "./Avatar";
6
+ import {renderWithTheme} from "./test-utils";
7
+
8
+ // Mock functions for image manipulation chain
9
+ const mockSaveAsync = mock(() =>
10
+ Promise.resolve({
11
+ base64: "test-base64",
12
+ uri: "test-uri",
13
+ })
14
+ );
15
+ const mockRenderAsync = mock(() =>
16
+ Promise.resolve({
17
+ saveAsync: mockSaveAsync,
18
+ })
19
+ );
20
+ const mockResize = mock(() => ({
21
+ renderAsync: mockRenderAsync,
22
+ }));
23
+
24
+ // Mock expo-image-manipulator
25
+ mock.module("expo-image-manipulator", () => ({
26
+ ImageManipulator: {
27
+ manipulate: mock(() => ({
28
+ resize: mockResize,
29
+ })),
30
+ },
31
+ SaveFormat: {
32
+ JPEG: "jpeg",
33
+ PNG: "png",
34
+ },
35
+ }));
36
+
37
+ // Mock expo-image-picker
38
+ mock.module("expo-image-picker", () => ({
39
+ launchImageLibraryAsync: mock(() =>
40
+ Promise.resolve({
41
+ assets: [
42
+ {
43
+ height: 100,
44
+ uri: "test-uri",
45
+ width: 100,
46
+ },
47
+ ],
48
+ canceled: false,
49
+ })
50
+ ),
51
+ }));
52
+
53
+ // Mock expo-linear-gradient
54
+ mock.module("expo-linear-gradient", () => ({
55
+ LinearGradient: "LinearGradient",
56
+ }));
57
+
58
+ describe("Avatar", () => {
59
+ const defaultProps = {
60
+ name: "John Doe",
61
+ src: "https://example.com/avatar.jpg",
62
+ testID: "avatar",
63
+ };
64
+
65
+ beforeEach(() => {
66
+ // Reset mocks
67
+ mockSaveAsync.mockClear();
68
+ mockRenderAsync.mockClear();
69
+ mockResize.mockClear();
70
+ });
71
+
72
+ it("renders correctly with default props", () => {
73
+ const {toJSON} = renderWithTheme(<Avatar {...defaultProps} />);
74
+ expect(toJSON()).toMatchSnapshot();
75
+ });
76
+
77
+ it("renders initials when no image is provided", () => {
78
+ const {getByText} = renderWithTheme(<Avatar name="John Doe" testID="avatar" />);
79
+ expect(getByText("JD")).toBeTruthy();
80
+ });
81
+
82
+ it("renders image when src is provided", () => {
83
+ const {getByTestId} = renderWithTheme(<Avatar {...defaultProps} />);
84
+ const image = getByTestId("avatar-image");
85
+ expect(image).toBeTruthy();
86
+ });
87
+
88
+ it("shows initials when image fails to load", () => {
89
+ const {getByText, getByTestId} = renderWithTheme(<Avatar {...defaultProps} name="John Doe" />);
90
+
91
+ // Simulate image load error
92
+ fireEvent(getByTestId("avatar-image"), "onError");
93
+
94
+ expect(getByText("JD")).toBeTruthy();
95
+ });
96
+
97
+ it("applies correct size class", () => {
98
+ const size = "lg";
99
+ const {getByTestId} = renderWithTheme(<Avatar {...defaultProps} size={size} />);
100
+ const avatar = getByTestId("avatar-image");
101
+ // Check if the style contains the expected size
102
+ expect(avatar.props.style).toMatchObject({
103
+ height: 72, // lg size from the sizes object
104
+ });
105
+ });
106
+
107
+ it("shows status indicator when status is provided", () => {
108
+ const {getByTestId} = renderWithTheme(<Avatar {...defaultProps} status="online" />);
109
+ expect(getByTestId("status-indicator")).toBeTruthy();
110
+ });
111
+
112
+ it("shows edit icon when status is imagePicker and size is xl", () => {
113
+ const {getByText} = renderWithTheme(
114
+ <Avatar {...defaultProps} size="xl" status="imagePicker" />
115
+ );
116
+ expect(getByText("Upload Image")).toBeTruthy();
117
+ });
118
+
119
+ it("calls onChange when edit icon is pressed", async () => {
120
+ const mockOnChange = mock(() => {});
121
+ const {getByText} = renderWithTheme(
122
+ <Avatar {...defaultProps} onChange={mockOnChange} size="xl" status="imagePicker" />
123
+ );
124
+
125
+ await act(async () => {
126
+ fireEvent.press(getByText("Upload Image"));
127
+ });
128
+
129
+ // The onChange should be called with the processed image
130
+ expect(mockOnChange).toHaveBeenCalledWith({
131
+ avatarImageFormat: "png",
132
+ base64: "test-base64",
133
+ uri: "data:image/png;base64,test-base64",
134
+ });
135
+ expect(ImageManipulator.ImageManipulator.manipulate).toHaveBeenCalled();
136
+ expect(mockResize).toHaveBeenCalled();
137
+ expect(mockRenderAsync).toHaveBeenCalled();
138
+ expect(mockSaveAsync).toHaveBeenCalledWith({
139
+ base64: true,
140
+ format: "png",
141
+ });
142
+ });
143
+
144
+ it("applies border when hasBorder is true", () => {
145
+ const {getByTestId} = renderWithTheme(<Avatar {...defaultProps} hasBorder />);
146
+ const avatar = getByTestId("avatar-image");
147
+ // Check if the style contains border properties
148
+ expect(avatar.props.style).toMatchObject({
149
+ borderColor: expect.any(String),
150
+ borderWidth: expect.any(Number),
151
+ });
152
+ });
153
+
154
+ it("shows warning when imagePicker status is used with non-xl size", () => {
155
+ const consoleWarnSpy = spyOn(console, "warn").mockImplementation(() => {});
156
+ renderWithTheme(<Avatar {...defaultProps} size="lg" status="imagePicker" />);
157
+
158
+ expect(consoleWarnSpy).toHaveBeenCalledWith(
159
+ "Avatars with the status of 'imagePicker' should also have an onChange property."
160
+ );
161
+ consoleWarnSpy.mockRestore();
162
+ });
163
+ });
package/src/Avatar.tsx ADDED
@@ -0,0 +1,298 @@
1
+ import {ImageManipulator, type ImageResult, SaveFormat} from "expo-image-manipulator";
2
+ import {launchImageLibraryAsync} from "expo-image-picker";
3
+ import {LinearGradient} from "expo-linear-gradient";
4
+ import type React from "react";
5
+ import {type FC, useState} from "react";
6
+ import {Image, Pressable, Text, View} from "react-native";
7
+
8
+ import type {AvatarProps, CustomSvgProps} from "./Common";
9
+ import {Icon} from "./Icon";
10
+ import {MobileIcon, OfflineIcon, OnlineIcon, OutOfOfficeIcon} from "./icons";
11
+ import {isMobileDevice} from "./MediaQuery";
12
+ import {useTheme} from "./Theme";
13
+ import {Tooltip} from "./Tooltip";
14
+
15
+ const sizes = {
16
+ lg: 72,
17
+ md: 56,
18
+ sm: 38,
19
+ xl: 120,
20
+ xs: 28,
21
+ };
22
+
23
+ const initialsFontSizes = {
24
+ lg: 32,
25
+ md: 24,
26
+ sm: 16,
27
+ xl: 60,
28
+ xs: 12,
29
+ };
30
+
31
+ const iconSizeScale = {
32
+ lg: 1.1,
33
+ md: 0.9,
34
+ sm: 0.7,
35
+ xl: 1.5,
36
+ xs: 0.5,
37
+ };
38
+
39
+ const sizeIconPadding = {
40
+ lg: 7,
41
+ md: 9,
42
+ sm: 10,
43
+ xl: 0,
44
+ xs: 12,
45
+ };
46
+
47
+ export const Avatar: FC<AvatarProps> = ({
48
+ name,
49
+ hasBorder = false,
50
+ size = "md",
51
+ src,
52
+ onChange,
53
+ status,
54
+ doNotDisturb = false,
55
+ }) => {
56
+ const {theme} = useTheme();
57
+ const [isImageLoaded, setIsImageLoaded] = useState(true);
58
+ const avatarImageFormat = SaveFormat.PNG;
59
+ const avatarImageDiameter = sizes[size];
60
+ const showEditIcon = status === "imagePicker";
61
+
62
+ const avatarRadius = avatarImageDiameter / 2;
63
+ const computedInitials =
64
+ (name.match(/(^\S\S?|\s\S)?/g) ?? []) // Use nullish coalescing to handle the case where match returns null
65
+ .map((v) => v.trim())
66
+ .join("")
67
+ .match(/(^\S|\S$)?/g) ??
68
+ [] // Use nullish coalescing to handle the case where match returns null
69
+ .join("")
70
+ .toLocaleUpperCase();
71
+ const statusIcons: {
72
+ [id: string]: {
73
+ icon: (props: CustomSvgProps) => React.ReactElement;
74
+ label: string;
75
+ };
76
+ } = {
77
+ activeMobile: {
78
+ icon: MobileIcon,
79
+
80
+ label: "Active on Mobile",
81
+ },
82
+ offline: {icon: OfflineIcon, label: "Offline"},
83
+ online: {icon: OnlineIcon, label: "Online"},
84
+ outOfOffice: {icon: OutOfOfficeIcon, label: "Out of Office"},
85
+ };
86
+
87
+ if (showEditIcon && !onChange) {
88
+ console.warn("Avatars with the status of 'imagePicker' should also have an onChange property.");
89
+ }
90
+
91
+ const handleImageError = (event: any) => {
92
+ setIsImageLoaded(false);
93
+ console.warn("Image load error: ", event);
94
+ };
95
+
96
+ const pickImage = async () => {
97
+ // TODO: Add permission request to use camera to take a picture
98
+ const result = await launchImageLibraryAsync({
99
+ allowsEditing: true,
100
+ base64: true,
101
+ mediaTypes: "images",
102
+ });
103
+
104
+ if (!result.canceled && result.assets) {
105
+ const resizedImage = await resizeAndFormatImage(result.assets[0].uri);
106
+ // convert base64 to data uri
107
+ resizedImage.uri = `data:image/${avatarImageFormat.toLowerCase()};base64,${resizedImage.base64}`;
108
+ if (onChange) {
109
+ onChange({avatarImageFormat, ...resizedImage});
110
+ }
111
+ }
112
+ };
113
+
114
+ const resizeAndFormatImage = async (imageUri: string): Promise<ImageResult> => {
115
+ const imageContext = await ImageManipulator.manipulate(imageUri);
116
+ const resizedImage = await imageContext.resize({
117
+ height: avatarImageDiameter,
118
+ });
119
+ const renderedImage = await resizedImage.renderAsync();
120
+ return await renderedImage.saveAsync({base64: true, format: avatarImageFormat});
121
+ };
122
+
123
+ const renderEditIcon = () => {
124
+ if (size !== "xl") {
125
+ console.error(`Avatar: "imagePicker" status is only supported for size "xl"`);
126
+ return null;
127
+ }
128
+
129
+ return (
130
+ <Pressable
131
+ aria-role="button"
132
+ onPress={pickImage}
133
+ style={{
134
+ alignItems: "center",
135
+ backgroundColor: "rgba(255,255,255,0.75)",
136
+ borderRadius: avatarRadius,
137
+ height: avatarImageDiameter,
138
+ justifyContent: "center",
139
+ position: "absolute",
140
+ width: avatarImageDiameter,
141
+ zIndex: 5,
142
+ }}
143
+ >
144
+ <Icon color="primary" iconName="pen-to-square" size="2xl" type="regular" />
145
+ <Text
146
+ style={{
147
+ fontSize: 12,
148
+ fontWeight: "bold",
149
+ marginTop: 10,
150
+ textAlign: "center",
151
+ }}
152
+ >
153
+ Upload Image
154
+ </Text>
155
+ </Pressable>
156
+ );
157
+ };
158
+
159
+ const renderStatusIcon = () => {
160
+ if (!status || showEditIcon) {
161
+ return null;
162
+ }
163
+ const {icon} = statusIcons[status];
164
+
165
+ if (!icon) {
166
+ console.warn(`Avatar: Invalid status ${status}`);
167
+ return null;
168
+ }
169
+
170
+ return (
171
+ <View
172
+ style={{
173
+ bottom: 0,
174
+ position: "absolute",
175
+ right: 0,
176
+ zIndex: 5,
177
+ }}
178
+ testID="status-indicator"
179
+ >
180
+ {icon({
181
+ doNotDisturb,
182
+ transform: [{scale: iconSizeScale[size]}],
183
+ })}
184
+ </View>
185
+ );
186
+ };
187
+
188
+ let avatar = (
189
+ <View
190
+ accessibilityHint={showEditIcon ? "Opens file explorer" : "Avatar image"}
191
+ aria-label={`${name}'s avatar`}
192
+ aria-role="image"
193
+ style={{height: avatarImageDiameter, position: "relative", width: avatarImageDiameter}}
194
+ >
195
+ <Pressable
196
+ aria-role="button"
197
+ style={{
198
+ borderRadius: 1,
199
+ cursor: showEditIcon ? "pointer" : "auto",
200
+ overflow: "hidden",
201
+ position: "relative",
202
+ }}
203
+ >
204
+ {src && isImageLoaded ? (
205
+ // TODO: Make our Image component rounding work so that we can use it for Avatar.
206
+ // Currently it creates an unrounded box around the Image.
207
+ <Image
208
+ accessibilityIgnoresInvertColors
209
+ onError={handleImageError}
210
+ source={{cache: "force-cache", uri: src}}
211
+ style={{
212
+ borderColor: hasBorder ? "white" : "transparent",
213
+ borderRadius: avatarRadius,
214
+ borderWidth: hasBorder && status !== "imagePicker" ? avatarImageDiameter * 0.04 : 0,
215
+ height: avatarImageDiameter,
216
+ overflow: "hidden",
217
+ }}
218
+ testID="avatar-image"
219
+ />
220
+ ) : (
221
+ <View
222
+ style={{
223
+ alignItems: "center",
224
+ backgroundColor: theme.surface.secondaryDark,
225
+ borderColor: hasBorder && status !== "imagePicker" ? "white" : "transparent",
226
+ borderRadius: avatarRadius,
227
+ borderWidth: hasBorder && status !== "imagePicker" ? avatarImageDiameter * 0.04 : 0,
228
+ display: "flex",
229
+ height: avatarImageDiameter,
230
+ justifyContent: "center",
231
+ width: avatarImageDiameter,
232
+ }}
233
+ >
234
+ <Text
235
+ style={{
236
+ color: theme.text.inverted,
237
+ fontSize: initialsFontSizes[size],
238
+ fontWeight: 500,
239
+ }}
240
+ >
241
+ {computedInitials}
242
+ </Text>
243
+ </View>
244
+ )}
245
+ </Pressable>
246
+ {/* Needs to come after the image so it renders on top. */}
247
+ {showEditIcon && renderEditIcon()}
248
+ </View>
249
+ );
250
+
251
+ if (hasBorder && status !== "imagePicker") {
252
+ const gradientDiameter = avatarImageDiameter * 1.1;
253
+ const gradientStartColor = "#FFC947";
254
+ const gradientEndColor = "#EA9095";
255
+ // Start the first color in the top left corner and end the second color in the bottom
256
+ // right corner.
257
+
258
+ avatar = (
259
+ <LinearGradient
260
+ colors={[gradientStartColor, gradientEndColor]}
261
+ end={{x: 1, y: 1}}
262
+ start={{x: 0, y: 0}}
263
+ style={{
264
+ alignItems: "center",
265
+ borderRadius: gradientDiameter / 2,
266
+ height: gradientDiameter,
267
+ justifyContent: "center",
268
+ width: gradientDiameter,
269
+ }}
270
+ >
271
+ {avatar}
272
+ </LinearGradient>
273
+ );
274
+ }
275
+
276
+ if (status) {
277
+ // Need to wrap the tooltip so it doesn't expand to 100% width and render the tooltip off.
278
+ // Don't show the tooltips on mobile because they intercept the edit avatar clicks.
279
+ const widthPlusPadding = avatarImageDiameter + sizeIconPadding[size];
280
+
281
+ avatar = (
282
+ <View
283
+ style={{
284
+ paddingBottom: sizeIconPadding[size],
285
+ paddingRight: sizeIconPadding[size],
286
+ width: widthPlusPadding,
287
+ }}
288
+ >
289
+ <Tooltip idealPosition="top" text={isMobileDevice() ? undefined : status}>
290
+ {avatar}
291
+ </Tooltip>
292
+ {renderStatusIcon()}
293
+ </View>
294
+ );
295
+ }
296
+
297
+ return avatar;
298
+ };