orn-ui 0.2.9 → 0.3.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 (552) hide show
  1. package/AGENTS.md +67 -52
  2. package/README.md +5 -9
  3. package/lib/commonjs/atoms/Avatar.js +77 -5
  4. package/lib/commonjs/atoms/Avatar.js.map +1 -1
  5. package/lib/commonjs/atoms/Badge.js +17 -8
  6. package/lib/commonjs/atoms/Badge.js.map +1 -1
  7. package/lib/commonjs/atoms/Button.js +108 -39
  8. package/lib/commonjs/atoms/Button.js.map +1 -1
  9. package/lib/commonjs/atoms/Card.js +24 -2
  10. package/lib/commonjs/atoms/Card.js.map +1 -1
  11. package/lib/commonjs/atoms/Checkbox.js +41 -10
  12. package/lib/commonjs/atoms/Checkbox.js.map +1 -1
  13. package/lib/commonjs/atoms/Divider.js +30 -5
  14. package/lib/commonjs/atoms/Divider.js.map +1 -1
  15. package/lib/commonjs/atoms/EmptyState.js +58 -20
  16. package/lib/commonjs/atoms/EmptyState.js.map +1 -1
  17. package/lib/commonjs/atoms/Fab.js +32 -12
  18. package/lib/commonjs/atoms/Fab.js.map +1 -1
  19. package/lib/commonjs/atoms/Gradient.js +102 -36
  20. package/lib/commonjs/atoms/Gradient.js.map +1 -1
  21. package/lib/commonjs/atoms/IconButton.js +25 -4
  22. package/lib/commonjs/atoms/IconButton.js.map +1 -1
  23. package/lib/commonjs/atoms/Image.js +61 -25
  24. package/lib/commonjs/atoms/Image.js.map +1 -1
  25. package/lib/commonjs/atoms/Input.js +105 -17
  26. package/lib/commonjs/atoms/Input.js.map +1 -1
  27. package/lib/commonjs/atoms/KeyValueRow.js +37 -9
  28. package/lib/commonjs/atoms/KeyValueRow.js.map +1 -1
  29. package/lib/commonjs/atoms/PressableScale.js +25 -5
  30. package/lib/commonjs/atoms/PressableScale.js.map +1 -1
  31. package/lib/commonjs/atoms/ShinyText.js +29 -29
  32. package/lib/commonjs/atoms/Skeleton.js +28 -13
  33. package/lib/commonjs/atoms/Skeleton.js.map +1 -1
  34. package/lib/commonjs/atoms/Spinner.js +81 -22
  35. package/lib/commonjs/atoms/Spinner.js.map +1 -1
  36. package/lib/commonjs/atoms/Text.js +56 -5
  37. package/lib/commonjs/atoms/Text.js.map +1 -1
  38. package/lib/commonjs/atoms/Transition.js +46 -43
  39. package/lib/commonjs/atoms/Transition.js.map +1 -1
  40. package/lib/commonjs/atoms/index.js +6 -0
  41. package/lib/commonjs/atoms/index.js.map +1 -1
  42. package/lib/commonjs/atoms/inputValidation.js +56 -0
  43. package/lib/commonjs/atoms/inputValidation.js.map +1 -0
  44. package/lib/commonjs/icons/Icon.js +4 -4
  45. package/lib/commonjs/icons/defaultIcons.js +576 -24
  46. package/lib/commonjs/icons/defaultIcons.js.map +1 -1
  47. package/lib/commonjs/icons/index.js +6 -0
  48. package/lib/commonjs/icons/index.js.map +1 -1
  49. package/lib/commonjs/molecules/AvatarHeader.js +47 -14
  50. package/lib/commonjs/molecules/AvatarHeader.js.map +1 -1
  51. package/lib/commonjs/molecules/FormActions.js +25 -9
  52. package/lib/commonjs/molecules/FormActions.js.map +1 -1
  53. package/lib/commonjs/molecules/InfoRow.js +30 -14
  54. package/lib/commonjs/molecules/InfoRow.js.map +1 -1
  55. package/lib/commonjs/molecules/OptionCard.js +37 -22
  56. package/lib/commonjs/molecules/OptionCard.js.map +1 -1
  57. package/lib/commonjs/molecules/SegmentedControl.js +103 -14
  58. package/lib/commonjs/molecules/SegmentedControl.js.map +1 -1
  59. package/lib/commonjs/molecules/Stepper.js +61 -16
  60. package/lib/commonjs/molecules/Stepper.js.map +1 -1
  61. package/lib/commonjs/molecules/Steps.js +105 -41
  62. package/lib/commonjs/molecules/Steps.js.map +1 -1
  63. package/lib/commonjs/molecules/SymmetricGrid.js +26 -18
  64. package/lib/commonjs/molecules/SymmetricGrid.js.map +1 -1
  65. package/lib/commonjs/organisms/Alert.js +49 -35
  66. package/lib/commonjs/organisms/Alert.js.map +1 -1
  67. package/lib/commonjs/organisms/AlertProvider.js +10 -10
  68. package/lib/commonjs/organisms/BottomSheet.js +137 -85
  69. package/lib/commonjs/organisms/BottomSheet.js.map +1 -1
  70. package/lib/commonjs/organisms/Chart.js +197 -156
  71. package/lib/commonjs/organisms/Chart.js.map +1 -1
  72. package/lib/commonjs/organisms/DateField.js +36 -20
  73. package/lib/commonjs/organisms/DateField.js.map +1 -1
  74. package/lib/commonjs/organisms/DatePicker.js +56 -33
  75. package/lib/commonjs/organisms/DatePicker.js.map +1 -1
  76. package/lib/commonjs/organisms/List.js +62 -34
  77. package/lib/commonjs/organisms/List.js.map +1 -1
  78. package/lib/commonjs/organisms/Modal.js +120 -82
  79. package/lib/commonjs/organisms/Modal.js.map +1 -1
  80. package/lib/commonjs/organisms/NavigationBar.js +63 -24
  81. package/lib/commonjs/organisms/NavigationBar.js.map +1 -1
  82. package/lib/commonjs/organisms/OptionWheel.js +64 -64
  83. package/lib/commonjs/organisms/OptionWheel.js.map +1 -1
  84. package/lib/commonjs/organisms/ReorderableList.js +48 -27
  85. package/lib/commonjs/organisms/ReorderableList.js.map +1 -1
  86. package/lib/commonjs/organisms/Screen.js +68 -35
  87. package/lib/commonjs/organisms/Screen.js.map +1 -1
  88. package/lib/commonjs/organisms/SearchList.js +56 -26
  89. package/lib/commonjs/organisms/SearchList.js.map +1 -1
  90. package/lib/commonjs/organisms/Select.js +45 -24
  91. package/lib/commonjs/organisms/Select.js.map +1 -1
  92. package/lib/commonjs/organisms/Slides.js +36 -23
  93. package/lib/commonjs/organisms/Slides.js.map +1 -1
  94. package/lib/commonjs/organisms/ThemeToggle.js +10 -9
  95. package/lib/commonjs/organisms/ThemeToggle.js.map +1 -1
  96. package/lib/commonjs/organisms/Timeline.js +73 -56
  97. package/lib/commonjs/organisms/Timeline.js.map +1 -1
  98. package/lib/commonjs/organisms/Toast.js +46 -15
  99. package/lib/commonjs/organisms/Toast.js.map +1 -1
  100. package/lib/commonjs/organisms/ToastProvider.js +14 -10
  101. package/lib/commonjs/organisms/ToastProvider.js.map +1 -1
  102. package/lib/commonjs/organisms/Wizard.js +40 -15
  103. package/lib/commonjs/organisms/Wizard.js.map +1 -1
  104. package/lib/commonjs/organisms/chart/frame.js +25 -25
  105. package/lib/commonjs/organisms/chart/frame.js.map +1 -1
  106. package/lib/commonjs/organisms/chart/marks.js +42 -42
  107. package/lib/commonjs/organisms/chart/math.js +84 -85
  108. package/lib/commonjs/organisms/chart/math.js.map +1 -1
  109. package/lib/commonjs/organisms/chart/palette.js +28 -28
  110. package/lib/commonjs/organisms/imperativeBridge.js +5 -5
  111. package/lib/commonjs/organisms/imperativeBridge.js.map +1 -1
  112. package/lib/commonjs/organisms/useSlides.js +53 -21
  113. package/lib/commonjs/organisms/useSlides.js.map +1 -1
  114. package/lib/commonjs/safe-area/SafeAreaUIProvider.js +9 -66
  115. package/lib/commonjs/safe-area/SafeAreaUIProvider.js.map +1 -1
  116. package/lib/commonjs/safe-area/index.js.map +1 -1
  117. package/lib/commonjs/theme/KeyboardAvoidance.js +206 -0
  118. package/lib/commonjs/theme/KeyboardAvoidance.js.map +1 -0
  119. package/lib/commonjs/theme/NativeOverlay.js +263 -0
  120. package/lib/commonjs/theme/NativeOverlay.js.map +1 -0
  121. package/lib/commonjs/theme/UIProvider.js +86 -33
  122. package/lib/commonjs/theme/UIProvider.js.map +1 -1
  123. package/lib/commonjs/theme/colors.js +17 -17
  124. package/lib/commonjs/theme/colors.js.map +1 -1
  125. package/lib/commonjs/theme/createStyles.js +19 -16
  126. package/lib/commonjs/theme/createStyles.js.map +1 -1
  127. package/lib/commonjs/theme/createTheme.js +6 -6
  128. package/lib/commonjs/theme/index.js +6 -0
  129. package/lib/commonjs/theme/index.js.map +1 -1
  130. package/lib/commonjs/theme/insets.js +1 -1
  131. package/lib/commonjs/theme/labels.js +29 -1
  132. package/lib/commonjs/theme/labels.js.map +1 -1
  133. package/lib/commonjs/theme/palettes.js +25 -23
  134. package/lib/commonjs/theme/palettes.js.map +1 -1
  135. package/lib/commonjs/theme/tokens.js +28 -14
  136. package/lib/commonjs/theme/tokens.js.map +1 -1
  137. package/lib/commonjs/theme/useKeyboardField.js +36 -0
  138. package/lib/commonjs/theme/useKeyboardField.js.map +1 -0
  139. package/lib/commonjs/theme/useReduceMotion.js +31 -0
  140. package/lib/commonjs/theme/useReduceMotion.js.map +1 -0
  141. package/lib/module/atoms/Avatar.js +79 -8
  142. package/lib/module/atoms/Avatar.js.map +1 -1
  143. package/lib/module/atoms/Badge.js +17 -8
  144. package/lib/module/atoms/Badge.js.map +1 -1
  145. package/lib/module/atoms/Button.js +110 -41
  146. package/lib/module/atoms/Button.js.map +1 -1
  147. package/lib/module/atoms/Card.js +24 -2
  148. package/lib/module/atoms/Card.js.map +1 -1
  149. package/lib/module/atoms/Checkbox.js +42 -11
  150. package/lib/module/atoms/Checkbox.js.map +1 -1
  151. package/lib/module/atoms/Divider.js +31 -6
  152. package/lib/module/atoms/Divider.js.map +1 -1
  153. package/lib/module/atoms/EmptyState.js +58 -20
  154. package/lib/module/atoms/EmptyState.js.map +1 -1
  155. package/lib/module/atoms/Fab.js +33 -13
  156. package/lib/module/atoms/Fab.js.map +1 -1
  157. package/lib/module/atoms/Gradient.js +103 -37
  158. package/lib/module/atoms/Gradient.js.map +1 -1
  159. package/lib/module/atoms/IconButton.js +25 -4
  160. package/lib/module/atoms/IconButton.js.map +1 -1
  161. package/lib/module/atoms/Image.js +61 -25
  162. package/lib/module/atoms/Image.js.map +1 -1
  163. package/lib/module/atoms/Input.js +108 -20
  164. package/lib/module/atoms/Input.js.map +1 -1
  165. package/lib/module/atoms/KeyValueRow.js +37 -9
  166. package/lib/module/atoms/KeyValueRow.js.map +1 -1
  167. package/lib/module/atoms/PressableScale.js +25 -5
  168. package/lib/module/atoms/PressableScale.js.map +1 -1
  169. package/lib/module/atoms/ShinyText.js +29 -29
  170. package/lib/module/atoms/Skeleton.js +30 -13
  171. package/lib/module/atoms/Skeleton.js.map +1 -1
  172. package/lib/module/atoms/Spinner.js +82 -23
  173. package/lib/module/atoms/Spinner.js.map +1 -1
  174. package/lib/module/atoms/Text.js +56 -5
  175. package/lib/module/atoms/Text.js.map +1 -1
  176. package/lib/module/atoms/Transition.js +41 -42
  177. package/lib/module/atoms/Transition.js.map +1 -1
  178. package/lib/module/atoms/index.js +1 -1
  179. package/lib/module/atoms/index.js.map +1 -1
  180. package/lib/module/atoms/inputValidation.js +52 -0
  181. package/lib/module/atoms/inputValidation.js.map +1 -0
  182. package/lib/module/icons/Icon.js +4 -4
  183. package/lib/module/icons/defaultIcons.js +574 -24
  184. package/lib/module/icons/defaultIcons.js.map +1 -1
  185. package/lib/module/icons/index.js +1 -1
  186. package/lib/module/icons/index.js.map +1 -1
  187. package/lib/module/molecules/AvatarHeader.js +47 -14
  188. package/lib/module/molecules/AvatarHeader.js.map +1 -1
  189. package/lib/module/molecules/FormActions.js +25 -9
  190. package/lib/module/molecules/FormActions.js.map +1 -1
  191. package/lib/module/molecules/InfoRow.js +30 -14
  192. package/lib/module/molecules/InfoRow.js.map +1 -1
  193. package/lib/module/molecules/OptionCard.js +37 -22
  194. package/lib/module/molecules/OptionCard.js.map +1 -1
  195. package/lib/module/molecules/SegmentedControl.js +107 -18
  196. package/lib/module/molecules/SegmentedControl.js.map +1 -1
  197. package/lib/module/molecules/Stepper.js +63 -18
  198. package/lib/module/molecules/Stepper.js.map +1 -1
  199. package/lib/module/molecules/Steps.js +107 -43
  200. package/lib/module/molecules/Steps.js.map +1 -1
  201. package/lib/module/molecules/SymmetricGrid.js +26 -18
  202. package/lib/module/molecules/SymmetricGrid.js.map +1 -1
  203. package/lib/module/organisms/Alert.js +51 -37
  204. package/lib/module/organisms/Alert.js.map +1 -1
  205. package/lib/module/organisms/AlertProvider.js +10 -10
  206. package/lib/module/organisms/BottomSheet.js +142 -88
  207. package/lib/module/organisms/BottomSheet.js.map +1 -1
  208. package/lib/module/organisms/Chart.js +199 -158
  209. package/lib/module/organisms/Chart.js.map +1 -1
  210. package/lib/module/organisms/DateField.js +36 -20
  211. package/lib/module/organisms/DateField.js.map +1 -1
  212. package/lib/module/organisms/DatePicker.js +56 -33
  213. package/lib/module/organisms/DatePicker.js.map +1 -1
  214. package/lib/module/organisms/List.js +62 -34
  215. package/lib/module/organisms/List.js.map +1 -1
  216. package/lib/module/organisms/Modal.js +122 -84
  217. package/lib/module/organisms/Modal.js.map +1 -1
  218. package/lib/module/organisms/NavigationBar.js +64 -25
  219. package/lib/module/organisms/NavigationBar.js.map +1 -1
  220. package/lib/module/organisms/OptionWheel.js +64 -64
  221. package/lib/module/organisms/OptionWheel.js.map +1 -1
  222. package/lib/module/organisms/ReorderableList.js +48 -27
  223. package/lib/module/organisms/ReorderableList.js.map +1 -1
  224. package/lib/module/organisms/Screen.js +70 -37
  225. package/lib/module/organisms/Screen.js.map +1 -1
  226. package/lib/module/organisms/SearchList.js +56 -26
  227. package/lib/module/organisms/SearchList.js.map +1 -1
  228. package/lib/module/organisms/Select.js +46 -25
  229. package/lib/module/organisms/Select.js.map +1 -1
  230. package/lib/module/organisms/Slides.js +37 -24
  231. package/lib/module/organisms/Slides.js.map +1 -1
  232. package/lib/module/organisms/ThemeToggle.js +11 -10
  233. package/lib/module/organisms/ThemeToggle.js.map +1 -1
  234. package/lib/module/organisms/Timeline.js +73 -56
  235. package/lib/module/organisms/Timeline.js.map +1 -1
  236. package/lib/module/organisms/Toast.js +47 -16
  237. package/lib/module/organisms/Toast.js.map +1 -1
  238. package/lib/module/organisms/ToastProvider.js +15 -11
  239. package/lib/module/organisms/ToastProvider.js.map +1 -1
  240. package/lib/module/organisms/Wizard.js +41 -16
  241. package/lib/module/organisms/Wizard.js.map +1 -1
  242. package/lib/module/organisms/chart/frame.js +25 -25
  243. package/lib/module/organisms/chart/frame.js.map +1 -1
  244. package/lib/module/organisms/chart/marks.js +42 -42
  245. package/lib/module/organisms/chart/math.js +84 -85
  246. package/lib/module/organisms/chart/math.js.map +1 -1
  247. package/lib/module/organisms/chart/palette.js +28 -28
  248. package/lib/module/organisms/imperativeBridge.js +5 -5
  249. package/lib/module/organisms/imperativeBridge.js.map +1 -1
  250. package/lib/module/organisms/useSlides.js +53 -21
  251. package/lib/module/organisms/useSlides.js.map +1 -1
  252. package/lib/module/safe-area/SafeAreaUIProvider.js +10 -65
  253. package/lib/module/safe-area/SafeAreaUIProvider.js.map +1 -1
  254. package/lib/module/safe-area/index.js +1 -0
  255. package/lib/module/safe-area/index.js.map +1 -1
  256. package/lib/module/theme/KeyboardAvoidance.js +198 -0
  257. package/lib/module/theme/KeyboardAvoidance.js.map +1 -0
  258. package/lib/module/theme/NativeOverlay.js +257 -0
  259. package/lib/module/theme/NativeOverlay.js.map +1 -0
  260. package/lib/module/theme/UIProvider.js +88 -35
  261. package/lib/module/theme/UIProvider.js.map +1 -1
  262. package/lib/module/theme/colors.js +17 -17
  263. package/lib/module/theme/colors.js.map +1 -1
  264. package/lib/module/theme/createStyles.js +20 -16
  265. package/lib/module/theme/createStyles.js.map +1 -1
  266. package/lib/module/theme/createTheme.js +6 -6
  267. package/lib/module/theme/index.js +1 -1
  268. package/lib/module/theme/index.js.map +1 -1
  269. package/lib/module/theme/insets.js +1 -1
  270. package/lib/module/theme/labels.js +29 -1
  271. package/lib/module/theme/labels.js.map +1 -1
  272. package/lib/module/theme/palettes.js +25 -23
  273. package/lib/module/theme/palettes.js.map +1 -1
  274. package/lib/module/theme/tokens.js +27 -13
  275. package/lib/module/theme/tokens.js.map +1 -1
  276. package/lib/module/theme/useKeyboardField.js +33 -0
  277. package/lib/module/theme/useKeyboardField.js.map +1 -0
  278. package/lib/module/theme/useReduceMotion.js +28 -0
  279. package/lib/module/theme/useReduceMotion.js.map +1 -0
  280. package/lib/typescript/atoms/Avatar.d.ts +35 -5
  281. package/lib/typescript/atoms/Avatar.d.ts.map +1 -1
  282. package/lib/typescript/atoms/Badge.d.ts +14 -3
  283. package/lib/typescript/atoms/Badge.d.ts.map +1 -1
  284. package/lib/typescript/atoms/Button.d.ts +34 -3
  285. package/lib/typescript/atoms/Button.d.ts.map +1 -1
  286. package/lib/typescript/atoms/Card.d.ts +13 -2
  287. package/lib/typescript/atoms/Card.d.ts.map +1 -1
  288. package/lib/typescript/atoms/Checkbox.d.ts +26 -1
  289. package/lib/typescript/atoms/Checkbox.d.ts.map +1 -1
  290. package/lib/typescript/atoms/Divider.d.ts +18 -1
  291. package/lib/typescript/atoms/Divider.d.ts.map +1 -1
  292. package/lib/typescript/atoms/EmptyState.d.ts +30 -3
  293. package/lib/typescript/atoms/EmptyState.d.ts.map +1 -1
  294. package/lib/typescript/atoms/Fab.d.ts +24 -4
  295. package/lib/typescript/atoms/Fab.d.ts.map +1 -1
  296. package/lib/typescript/atoms/Gradient.d.ts +21 -15
  297. package/lib/typescript/atoms/Gradient.d.ts.map +1 -1
  298. package/lib/typescript/atoms/IconButton.d.ts +18 -4
  299. package/lib/typescript/atoms/IconButton.d.ts.map +1 -1
  300. package/lib/typescript/atoms/Image.d.ts +39 -17
  301. package/lib/typescript/atoms/Image.d.ts.map +1 -1
  302. package/lib/typescript/atoms/Input.d.ts +57 -7
  303. package/lib/typescript/atoms/Input.d.ts.map +1 -1
  304. package/lib/typescript/atoms/KeyValueRow.d.ts +16 -4
  305. package/lib/typescript/atoms/KeyValueRow.d.ts.map +1 -1
  306. package/lib/typescript/atoms/PressableScale.d.ts +12 -5
  307. package/lib/typescript/atoms/PressableScale.d.ts.map +1 -1
  308. package/lib/typescript/atoms/ShinyText.d.ts +17 -17
  309. package/lib/typescript/atoms/ShinyText.d.ts.map +1 -1
  310. package/lib/typescript/atoms/Skeleton.d.ts +12 -7
  311. package/lib/typescript/atoms/Skeleton.d.ts.map +1 -1
  312. package/lib/typescript/atoms/Spinner.d.ts +29 -1
  313. package/lib/typescript/atoms/Spinner.d.ts.map +1 -1
  314. package/lib/typescript/atoms/Text.d.ts +46 -0
  315. package/lib/typescript/atoms/Text.d.ts.map +1 -1
  316. package/lib/typescript/atoms/Transition.d.ts +19 -15
  317. package/lib/typescript/atoms/Transition.d.ts.map +1 -1
  318. package/lib/typescript/atoms/index.d.ts +3 -3
  319. package/lib/typescript/atoms/index.d.ts.map +1 -1
  320. package/lib/typescript/atoms/inputValidation.d.ts +29 -0
  321. package/lib/typescript/atoms/inputValidation.d.ts.map +1 -0
  322. package/lib/typescript/icons/Icon.d.ts +4 -4
  323. package/lib/typescript/icons/defaultIcons.d.ts +19 -2
  324. package/lib/typescript/icons/defaultIcons.d.ts.map +1 -1
  325. package/lib/typescript/icons/index.d.ts +2 -2
  326. package/lib/typescript/icons/index.d.ts.map +1 -1
  327. package/lib/typescript/icons/types.d.ts +13 -3
  328. package/lib/typescript/icons/types.d.ts.map +1 -1
  329. package/lib/typescript/molecules/AvatarHeader.d.ts +23 -4
  330. package/lib/typescript/molecules/AvatarHeader.d.ts.map +1 -1
  331. package/lib/typescript/molecules/FormActions.d.ts +21 -4
  332. package/lib/typescript/molecules/FormActions.d.ts.map +1 -1
  333. package/lib/typescript/molecules/InfoRow.d.ts +17 -3
  334. package/lib/typescript/molecules/InfoRow.d.ts.map +1 -1
  335. package/lib/typescript/molecules/OptionCard.d.ts +20 -5
  336. package/lib/typescript/molecules/OptionCard.d.ts.map +1 -1
  337. package/lib/typescript/molecules/SegmentedControl.d.ts +18 -2
  338. package/lib/typescript/molecules/SegmentedControl.d.ts.map +1 -1
  339. package/lib/typescript/molecules/Stepper.d.ts +23 -7
  340. package/lib/typescript/molecules/Stepper.d.ts.map +1 -1
  341. package/lib/typescript/molecules/Steps.d.ts +18 -4
  342. package/lib/typescript/molecules/Steps.d.ts.map +1 -1
  343. package/lib/typescript/molecules/SymmetricGrid.d.ts +15 -5
  344. package/lib/typescript/molecules/SymmetricGrid.d.ts.map +1 -1
  345. package/lib/typescript/organisms/Alert.d.ts +28 -2
  346. package/lib/typescript/organisms/Alert.d.ts.map +1 -1
  347. package/lib/typescript/organisms/AlertProvider.d.ts +10 -10
  348. package/lib/typescript/organisms/AlertProvider.d.ts.map +1 -1
  349. package/lib/typescript/organisms/BottomSheet.d.ts +20 -5
  350. package/lib/typescript/organisms/BottomSheet.d.ts.map +1 -1
  351. package/lib/typescript/organisms/Chart.d.ts +86 -75
  352. package/lib/typescript/organisms/Chart.d.ts.map +1 -1
  353. package/lib/typescript/organisms/DateField.d.ts +17 -3
  354. package/lib/typescript/organisms/DateField.d.ts.map +1 -1
  355. package/lib/typescript/organisms/DatePicker.d.ts +7 -11
  356. package/lib/typescript/organisms/DatePicker.d.ts.map +1 -1
  357. package/lib/typescript/organisms/List.d.ts +30 -3
  358. package/lib/typescript/organisms/List.d.ts.map +1 -1
  359. package/lib/typescript/organisms/Modal.d.ts +30 -3
  360. package/lib/typescript/organisms/Modal.d.ts.map +1 -1
  361. package/lib/typescript/organisms/NavigationBar.d.ts +26 -7
  362. package/lib/typescript/organisms/NavigationBar.d.ts.map +1 -1
  363. package/lib/typescript/organisms/OptionWheel.d.ts +20 -16
  364. package/lib/typescript/organisms/OptionWheel.d.ts.map +1 -1
  365. package/lib/typescript/organisms/ReorderableList.d.ts +20 -11
  366. package/lib/typescript/organisms/ReorderableList.d.ts.map +1 -1
  367. package/lib/typescript/organisms/Screen.d.ts +27 -8
  368. package/lib/typescript/organisms/Screen.d.ts.map +1 -1
  369. package/lib/typescript/organisms/SearchList.d.ts +46 -3
  370. package/lib/typescript/organisms/SearchList.d.ts.map +1 -1
  371. package/lib/typescript/organisms/Select.d.ts +26 -6
  372. package/lib/typescript/organisms/Select.d.ts.map +1 -1
  373. package/lib/typescript/organisms/Slides.d.ts +44 -26
  374. package/lib/typescript/organisms/Slides.d.ts.map +1 -1
  375. package/lib/typescript/organisms/ThemeToggle.d.ts +6 -2
  376. package/lib/typescript/organisms/ThemeToggle.d.ts.map +1 -1
  377. package/lib/typescript/organisms/Timeline.d.ts +26 -9
  378. package/lib/typescript/organisms/Timeline.d.ts.map +1 -1
  379. package/lib/typescript/organisms/Toast.d.ts +19 -4
  380. package/lib/typescript/organisms/Toast.d.ts.map +1 -1
  381. package/lib/typescript/organisms/ToastProvider.d.ts +8 -8
  382. package/lib/typescript/organisms/ToastProvider.d.ts.map +1 -1
  383. package/lib/typescript/organisms/Wizard.d.ts +24 -6
  384. package/lib/typescript/organisms/Wizard.d.ts.map +1 -1
  385. package/lib/typescript/organisms/chart/frame.d.ts +21 -21
  386. package/lib/typescript/organisms/chart/frame.d.ts.map +1 -1
  387. package/lib/typescript/organisms/chart/marks.d.ts +28 -28
  388. package/lib/typescript/organisms/chart/marks.d.ts.map +1 -1
  389. package/lib/typescript/organisms/chart/math.d.ts +69 -70
  390. package/lib/typescript/organisms/chart/math.d.ts.map +1 -1
  391. package/lib/typescript/organisms/chart/palette.d.ts +2 -2
  392. package/lib/typescript/organisms/chart/palette.d.ts.map +1 -1
  393. package/lib/typescript/organisms/imperativeBridge.d.ts +4 -4
  394. package/lib/typescript/organisms/useSlides.d.ts +8 -16
  395. package/lib/typescript/organisms/useSlides.d.ts.map +1 -1
  396. package/lib/typescript/safe-area/SafeAreaUIProvider.d.ts +9 -7
  397. package/lib/typescript/safe-area/SafeAreaUIProvider.d.ts.map +1 -1
  398. package/lib/typescript/safe-area/index.d.ts.map +1 -1
  399. package/lib/typescript/theme/KeyboardAvoidance.d.ts +62 -0
  400. package/lib/typescript/theme/KeyboardAvoidance.d.ts.map +1 -0
  401. package/lib/typescript/theme/NativeOverlay.d.ts +43 -0
  402. package/lib/typescript/theme/NativeOverlay.d.ts.map +1 -0
  403. package/lib/typescript/theme/UIProvider.d.ts +38 -20
  404. package/lib/typescript/theme/UIProvider.d.ts.map +1 -1
  405. package/lib/typescript/theme/colors.d.ts +13 -13
  406. package/lib/typescript/theme/colors.d.ts.map +1 -1
  407. package/lib/typescript/theme/createStyles.d.ts +20 -14
  408. package/lib/typescript/theme/createStyles.d.ts.map +1 -1
  409. package/lib/typescript/theme/createTheme.d.ts +5 -5
  410. package/lib/typescript/theme/index.d.ts +1 -1
  411. package/lib/typescript/theme/index.d.ts.map +1 -1
  412. package/lib/typescript/theme/insets.d.ts +1 -1
  413. package/lib/typescript/theme/insets.d.ts.map +1 -1
  414. package/lib/typescript/theme/labels.d.ts +57 -2
  415. package/lib/typescript/theme/labels.d.ts.map +1 -1
  416. package/lib/typescript/theme/palettes.d.ts +25 -19
  417. package/lib/typescript/theme/palettes.d.ts.map +1 -1
  418. package/lib/typescript/theme/tokens.d.ts +15 -8
  419. package/lib/typescript/theme/tokens.d.ts.map +1 -1
  420. package/lib/typescript/theme/types.d.ts +7 -7
  421. package/lib/typescript/theme/types.d.ts.map +1 -1
  422. package/lib/typescript/theme/useKeyboardField.d.ts +17 -0
  423. package/lib/typescript/theme/useKeyboardField.d.ts.map +1 -0
  424. package/lib/typescript/theme/useReduceMotion.d.ts +7 -0
  425. package/lib/typescript/theme/useReduceMotion.d.ts.map +1 -0
  426. package/llms.txt +4 -4
  427. package/package.json +15 -14
  428. package/registry/alert-provider.json +4 -3
  429. package/registry/alert.json +3 -2
  430. package/registry/avatar-header.json +1 -1
  431. package/registry/avatar.json +3 -2
  432. package/registry/badge.json +1 -1
  433. package/registry/bottom-sheet.json +1 -1
  434. package/registry/button.json +3 -2
  435. package/registry/card.json +1 -1
  436. package/registry/chart.json +5 -5
  437. package/registry/checkbox.json +3 -2
  438. package/registry/core.json +31 -15
  439. package/registry/date-field.json +1 -1
  440. package/registry/date-picker.json +3 -2
  441. package/registry/divider.json +1 -1
  442. package/registry/empty-state.json +4 -2
  443. package/registry/fab.json +3 -2
  444. package/registry/form-actions.json +3 -2
  445. package/registry/gradient.json +1 -1
  446. package/registry/icon-button.json +3 -2
  447. package/registry/image.json +1 -1
  448. package/registry/index.json +79 -61
  449. package/registry/info-row.json +1 -1
  450. package/registry/input.json +5 -1
  451. package/registry/key-value-row.json +1 -1
  452. package/registry/list.json +3 -1
  453. package/registry/manifest.json +3 -1
  454. package/registry/modal.json +1 -1
  455. package/registry/navigation-bar.json +1 -1
  456. package/registry/option-card.json +3 -2
  457. package/registry/option-wheel.json +1 -1
  458. package/registry/pressable-scale.json +3 -2
  459. package/registry/reorderable-list.json +1 -1
  460. package/registry/screen.json +1 -1
  461. package/registry/search-list.json +7 -1
  462. package/registry/segmented-control.json +1 -1
  463. package/registry/select.json +1 -1
  464. package/registry/shiny-text.json +1 -1
  465. package/registry/skeleton.json +3 -2
  466. package/registry/slides.json +2 -2
  467. package/registry/spinner.json +1 -1
  468. package/registry/stepper.json +1 -1
  469. package/registry/steps.json +1 -1
  470. package/registry/symmetric-grid.json +1 -1
  471. package/registry/theme-toggle.json +1 -1
  472. package/registry/timeline.json +1 -1
  473. package/registry/title.json +1 -1
  474. package/registry/toast-provider.json +2 -2
  475. package/registry/toast.json +1 -1
  476. package/registry/transition.json +1 -1
  477. package/registry/wizard.json +1 -1
  478. package/src/atoms/Avatar.tsx +117 -26
  479. package/src/atoms/Badge.tsx +20 -9
  480. package/src/atoms/Button.tsx +102 -30
  481. package/src/atoms/Card.tsx +23 -3
  482. package/src/atoms/Checkbox.tsx +49 -12
  483. package/src/atoms/Divider.tsx +34 -4
  484. package/src/atoms/EmptyState.tsx +63 -16
  485. package/src/atoms/Fab.tsx +56 -9
  486. package/src/atoms/Gradient.tsx +92 -41
  487. package/src/atoms/IconButton.tsx +27 -4
  488. package/src/atoms/Image.tsx +74 -28
  489. package/src/atoms/Input.tsx +129 -19
  490. package/src/atoms/KeyValueRow.tsx +72 -28
  491. package/src/atoms/PressableScale.tsx +31 -7
  492. package/src/atoms/ShinyText.tsx +31 -31
  493. package/src/atoms/Skeleton.tsx +37 -17
  494. package/src/atoms/Spinner.tsx +87 -24
  495. package/src/atoms/Text.tsx +66 -6
  496. package/src/atoms/Transition.tsx +40 -44
  497. package/src/atoms/index.ts +3 -3
  498. package/src/atoms/inputValidation.ts +59 -0
  499. package/src/icons/Icon.tsx +4 -4
  500. package/src/icons/defaultIcons.tsx +445 -22
  501. package/src/icons/index.ts +2 -2
  502. package/src/icons/types.ts +26 -4
  503. package/src/molecules/AvatarHeader.tsx +88 -34
  504. package/src/molecules/FormActions.tsx +36 -6
  505. package/src/molecules/InfoRow.tsx +39 -12
  506. package/src/molecules/OptionCard.tsx +55 -20
  507. package/src/molecules/SegmentedControl.tsx +135 -15
  508. package/src/molecules/Stepper.tsx +73 -19
  509. package/src/molecules/Steps.tsx +121 -39
  510. package/src/molecules/SymmetricGrid.tsx +28 -12
  511. package/src/organisms/Alert.tsx +97 -26
  512. package/src/organisms/AlertProvider.tsx +13 -13
  513. package/src/organisms/BottomSheet.tsx +115 -43
  514. package/src/organisms/Chart.tsx +223 -165
  515. package/src/organisms/DateField.tsx +40 -15
  516. package/src/organisms/DatePicker.tsx +53 -32
  517. package/src/organisms/List.tsx +64 -15
  518. package/src/organisms/Modal.tsx +122 -63
  519. package/src/organisms/NavigationBar.tsx +73 -23
  520. package/src/organisms/OptionWheel.tsx +70 -66
  521. package/src/organisms/ReorderableList.tsx +49 -27
  522. package/src/organisms/Screen.tsx +79 -42
  523. package/src/organisms/SearchList.tsx +84 -20
  524. package/src/organisms/Select.tsx +63 -29
  525. package/src/organisms/Slides.tsx +63 -44
  526. package/src/organisms/ThemeToggle.tsx +15 -6
  527. package/src/organisms/Timeline.tsx +79 -62
  528. package/src/organisms/Toast.tsx +50 -15
  529. package/src/organisms/ToastProvider.tsx +17 -13
  530. package/src/organisms/Wizard.tsx +58 -21
  531. package/src/organisms/chart/frame.tsx +35 -35
  532. package/src/organisms/chart/marks.tsx +53 -53
  533. package/src/organisms/chart/math.ts +93 -94
  534. package/src/organisms/chart/palette.ts +28 -28
  535. package/src/organisms/imperativeBridge.ts +5 -5
  536. package/src/organisms/useSlides.ts +66 -31
  537. package/src/safe-area/SafeAreaUIProvider.tsx +9 -70
  538. package/src/safe-area/index.ts +1 -0
  539. package/src/theme/KeyboardAvoidance.tsx +216 -0
  540. package/src/theme/NativeOverlay.tsx +269 -0
  541. package/src/theme/UIProvider.tsx +109 -46
  542. package/src/theme/colors.ts +21 -21
  543. package/src/theme/createStyles.ts +23 -19
  544. package/src/theme/createTheme.ts +6 -6
  545. package/src/theme/index.ts +1 -1
  546. package/src/theme/insets.ts +1 -1
  547. package/src/theme/labels.ts +85 -2
  548. package/src/theme/palettes.ts +33 -25
  549. package/src/theme/tokens.ts +27 -13
  550. package/src/theme/types.ts +7 -7
  551. package/src/theme/useKeyboardField.ts +33 -0
  552. package/src/theme/useReduceMotion.ts +27 -0
package/src/atoms/Fab.tsx CHANGED
@@ -2,22 +2,43 @@ import React, { memo } from 'react';
2
2
  import { type GestureResponderEvent, type StyleProp, type ViewStyle } from 'react-native';
3
3
  import { PressableScale } from './PressableScale';
4
4
  import { Icon } from '../icons/Icon';
5
+ import { onColor } from '../icons/defaultIcons';
5
6
  import type { IconName } from '../icons/types';
6
7
  import { createStyles } from '../theme/createStyles';
7
- import { useColors } from '../theme/UIProvider';
8
+ import { useColors, useInsets, useTheme } from '../theme/UIProvider';
8
9
 
9
10
  export interface FabProps {
11
+ /** Called when the button is pressed. */
10
12
  onPress: (e: GestureResponderEvent) => void;
13
+ /** Built-in or custom icon name. Ignored when `icon` is passed. @default 'plus' */
11
14
  iconName?: IconName;
15
+ /** Any node in place of the icon. */
12
16
  icon?: React.ReactNode;
17
+ /** Diameter in pt. @default 60 */
13
18
  size?: number;
19
+ /** Distance from the bottom edge, on top of the safe area. @default tokens.spacing.xl (20) */
14
20
  bottom?: number;
21
+ /** Distance from the right edge, on top of the safe area. @default tokens.spacing.xl (20) */
15
22
  right?: number;
23
+ /**
24
+ * Adds the safe-area insets to `bottom`/`right`, so the button clears the
25
+ * home indicator. Pass false above a NavigationBar or tab bar, which
26
+ * already covers that edge. @default true
27
+ */
28
+ safeArea?: boolean;
29
+ /** Fill color. The icon switches to black or white for contrast. @default theme.colors.primary */
16
30
  color?: string;
17
31
  style?: StyleProp<ViewStyle>;
32
+ /** Required: the button has no visible text. */
18
33
  accessibilityLabel: string;
34
+ testID?: string;
19
35
  }
20
36
 
37
+ /** Default diameter: comfortably above the 44pt touch minimum (Fitts). */
38
+ const DEFAULT_SIZE = 60;
39
+ /** The glyph takes up half the circle. */
40
+ const ICON_RATIO = 0.5;
41
+
21
42
  const useStyles = createStyles((theme) => ({
22
43
  fab: {
23
44
  position: 'absolute',
@@ -29,14 +50,39 @@ const useStyles = createStyles((theme) => ({
29
50
 
30
51
  /**
31
52
  * Fab
32
- * Botón flotante circular. `bottom`/`right` en vez del `tabBarHeight`
33
- * obligatorio de la versión original — el consumidor decide su propio
34
- * offset (con o sin tab bar).
53
+ * Circular floating button for the screen's main action.
54
+ * `bottom`/`right` instead of the required `tabBarHeight` of the original
55
+ * version — the consumer decides its own offset (with or without a tab bar).
56
+ *
57
+ * Gestalt, figure/ground: it is the only thing that floats (`lg` shadow) and
58
+ * carries the accent, so it stands apart from the content passing beneath it
59
+ * (Von Restorff: one per screen). Fitts: large and in the thumb's corner,
60
+ * above the safe area so it doesn't compete with the home gesture.
35
61
  */
36
62
  export const Fab = memo(
37
- ({ onPress, iconName = 'plus', icon, size = 60, bottom = 20, right = 20, color, style, accessibilityLabel }: FabProps) => {
63
+ ({
64
+ onPress,
65
+ iconName = 'plus',
66
+ icon,
67
+ size = DEFAULT_SIZE,
68
+ bottom,
69
+ right,
70
+ safeArea = true,
71
+ color,
72
+ style,
73
+ accessibilityLabel,
74
+ testID,
75
+ }: FabProps) => {
38
76
  const styles = useStyles();
39
77
  const colors = useColors();
78
+ const theme = useTheme();
79
+ const insets = useInsets();
80
+ const fill = color ?? colors.primary;
81
+ // With the theme color, its `onPrimary`; with a custom one, black or white
82
+ // depending on contrast (a cyan with a white icon was unreadable).
83
+ const glyph = color ? onColor(color) : colors.onPrimary;
84
+ const edge = theme.tokens.spacing.xl;
85
+
40
86
  return (
41
87
  <PressableScale
42
88
  onPress={onPress}
@@ -46,16 +92,17 @@ export const Fab = memo(
46
92
  width: size,
47
93
  height: size,
48
94
  borderRadius: size / 2,
49
- bottom,
50
- right,
51
- backgroundColor: color ?? colors.primary,
95
+ bottom: (bottom ?? edge) + (safeArea ? insets.bottom : 0),
96
+ right: (right ?? edge) + (safeArea ? insets.right : 0),
97
+ backgroundColor: fill,
52
98
  },
53
99
  style,
54
100
  ]}
55
101
  accessibilityRole="button"
56
102
  accessibilityLabel={accessibilityLabel}
103
+ testID={testID}
57
104
  >
58
- {icon ?? <Icon name={iconName} size={size * 0.5} color={colors.onPrimary} />}
105
+ {icon ?? <Icon name={iconName} size={size * ICON_RATIO} color={glyph} />}
59
106
  </PressableScale>
60
107
  );
61
108
  }
@@ -1,60 +1,98 @@
1
- import React, { memo, useMemo } from 'react';
2
- import { StyleSheet, View, type StyleProp, type ViewStyle } from 'react-native';
1
+ import React, { memo, useMemo, useState } from 'react';
2
+ import { StyleSheet, View, type LayoutChangeEvent, type StyleProp, type ViewStyle } from 'react-native';
3
3
 
4
4
  export type GradientDirection = 'vertical' | 'horizontal' | 'diagonal' | 'diagonal-reverse';
5
5
 
6
6
  export interface GradientProps {
7
- /** Paradas del degradado. Uno solo pinta plano; ninguno no pinta nada. */
7
+ /** Gradient stops. A single color paints flat; none paints nothing. */
8
8
  colors: string[];
9
9
  /**
10
- * 'vertical' va de arriba a abajo, 'horizontal' de izquierda a derecha,
11
- * 'diagonal' de arriba-izquierda a abajo-derecha y 'diagonal-reverse' de
12
- * arriba-derecha a abajo-izquierda.
10
+ * 'vertical' runs top to bottom, 'horizontal' left to right, 'diagonal'
11
+ * top-left to bottom-right and 'diagonal-reverse' top-right to bottom-left.
13
12
  * @default 'vertical'
14
13
  */
15
14
  direction?: GradientDirection;
16
15
  /**
17
- * Bandas por tramo (un tramo = un par de colores consecutivos). Más bandas
18
- * = transición más suave y más vistas en el árbol.
19
- * @default 24
16
+ * Bands per segment (a segment = a pair of consecutive colors). More bands
17
+ * = a smoother transition and more views in the tree.
18
+ * @default 48
20
19
  */
21
20
  steps?: number;
22
- /** Contenido por encima del degradado. */
21
+ /** Content rendered on top of the gradient. */
23
22
  children?: React.ReactNode;
24
23
  style?: StyleProp<ViewStyle>;
25
24
  testID?: string;
26
25
  }
27
26
 
28
- const DEFAULT_STEPS = 24;
27
+ const DEFAULT_STEPS = 48;
29
28
 
30
29
  const styles = StyleSheet.create({
31
- // Recorta el plano rotado de las diagonales y el degradado al borderRadius.
30
+ // Clips the rotated plane of the diagonals and the gradient to the borderRadius.
32
31
  root: { overflow: 'hidden' },
33
- segment: { flex: 1 },
34
- band: { flex: 1 },
35
- // Plano √2 centrado: rotado 45° cubre las esquinas sin medir el contenedor.
32
+ // Centered √2 plane: covers the corners of a SQUARE container without
33
+ // measuring it. Only used until the first onLayout; after that the plane is
34
+ // sized with the real diagonal (see `diagonalBox`).
36
35
  diagonalPlane: { position: 'absolute', top: '-21%', left: '-21%', width: '142%', height: '142%' },
37
36
  });
38
37
 
38
+ /**
39
+ * Opacities of stacked layers: layer k (from 1 to n-1) starts at k/n and
40
+ * runs to the end of the segment; stacked with "over", the total opacity in
41
+ * band k is k/(n-1), same as side-by-side bands. The difference: no layer
42
+ * edge sits next to a gap, so the antialiasing of an edge (especially when
43
+ * rotated) blends with the color of the layer below and not with what is
44
+ * behind the gradient — without the thin lines between bands.
45
+ */
46
+ function layerOpacities(n: number): number[] {
47
+ const out: number[] = [];
48
+ let prev = 0;
49
+ for (let k = 1; k < n; k += 1) {
50
+ const total = k / (n - 1);
51
+ out.push(prev >= 1 ? 1 : 1 - (1 - total) / (1 - prev));
52
+ prev = total;
53
+ }
54
+ return out;
55
+ }
56
+
57
+ /** Square with the diagonal as its side, centered: rotated 45° it covers any rectangle. */
58
+ function diagonalBox(width: number, height: number): ViewStyle {
59
+ const side = Math.hypot(width, height);
60
+ return { position: 'absolute', width: side, height: side, left: (width - side) / 2, top: (height - side) / 2 };
61
+ }
62
+
39
63
  /**
40
64
  * Gradient
41
- * Degradado lineal sin dependencias: React Native no trae uno en el rango
42
- * soportado (Expo SDK 54–57) y `experimental_backgroundImage` no está en toda
43
- * esa ventana, así que se compone con bandas.
65
+ * Dependency-free linear gradient: React Native doesn't ship one in the
66
+ * supported range (Expo SDK 54–57) and `experimental_backgroundImage` isn't
67
+ * available across that whole window, so it is composed from bands.
68
+ *
69
+ * Each segment paints the start color and, on top, layers of the end color
70
+ * that accumulate (see `layerOpacities`). The compositor blends alpha linearly:
71
+ * the result is the sRGB interpolation between stops without parsing the
72
+ * color, which is why any format RN accepts works (hex, `rgba()`, name). The
73
+ * layers run to the end of the plane so no thin lines are left between
74
+ * bands, and the diagonals rotate a square the size of the measured diagonal
75
+ * to cover any rectangle, not just squares.
44
76
  *
45
- * Cada tramo pinta el color inicial y encima N bandas del final con opacidad
46
- * de 0 a 1. El compositor mezcla alpha linealmente: el resultado es la
47
- * interpolación sRGB entre paradas sin parsear el color, y por eso vale
48
- * cualquier formato que acepte RN (hex, `rgba()`, nombre).
77
+ * Gestalt, figure and ground: content on top must contrast with ALL the
78
+ * stops, not just the first — white text that reads well over the blue at
79
+ * the start can get lost over the light blue at the end.
49
80
  */
50
81
  export const Gradient = memo(
51
82
  ({ colors, direction = 'vertical', steps = DEFAULT_STEPS, children, style, testID }: GradientProps) => {
52
83
  const isRow = direction === 'horizontal';
53
84
  const isDiagonal = direction === 'diagonal' || direction === 'diagonal-reverse';
54
- // rotate positivo gira en horario (Y crece hacia abajo): -45° manda el eje
55
- // del degradado hacia abajo-derecha.
85
+ // positive rotate turns clockwise (Y grows downward): -45° sends the
86
+ // gradient axis down-right.
56
87
  const rotate = direction === 'diagonal' ? '-45deg' : '45deg';
57
88
  const bandCount = Math.max(2, Math.floor(steps));
89
+ const [size, setSize] = useState<{ width: number; height: number } | null>(null);
90
+ const onLayout = isDiagonal
91
+ ? (e: LayoutChangeEvent) => {
92
+ const { width, height } = e.nativeEvent.layout;
93
+ setSize((prev) => (prev && prev.width === width && prev.height === height ? prev : { width, height }));
94
+ }
95
+ : undefined;
58
96
 
59
97
  const painted = useMemo(() => {
60
98
  if (colors.length === 0) return null;
@@ -62,32 +100,45 @@ export const Gradient = memo(
62
100
  return <View style={[StyleSheet.absoluteFill, { backgroundColor: colors[0] }]} />;
63
101
  }
64
102
 
65
- const segments = colors.slice(0, -1).map((from, index) => {
103
+ const segmentCount = colors.length - 1;
104
+ const opacities = layerOpacities(bandCount);
105
+ // From `start` (fraction of the axis) to the end of the plane.
106
+ const from = (start: number): ViewStyle =>
107
+ isRow
108
+ ? { position: 'absolute', top: 0, bottom: 0, right: 0, left: `${start * 100}%` }
109
+ : { position: 'absolute', left: 0, right: 0, bottom: 0, top: `${start * 100}%` };
110
+
111
+ // Segments are stacked too: each one covers the previous from its start,
112
+ // and since it begins with the color the previous one ended with, the
113
+ // edge between segments doesn't show the background.
114
+ const segments = colors.slice(0, -1).map((start, index) => {
66
115
  const to = colors[index + 1] as string;
116
+ const segStart = index / segmentCount;
117
+ const segLength = 1 / segmentCount;
118
+ // The segment runs from segStart to the END of the plane; its layers
119
+ // sit at fractions of that remaining length.
120
+ const rest = 1 - segStart;
67
121
  return (
68
- <View
69
- key={`${from}-${to}-${index}`}
70
- style={[styles.segment, { backgroundColor: from, flexDirection: isRow ? 'row' : 'column' }]}
71
- >
72
- {Array.from({ length: bandCount }, (_, band) => (
73
- <View key={band} style={[styles.band, { backgroundColor: to, opacity: band / (bandCount - 1) }]} />
122
+ <View key={`${start}-${to}-${index}`} style={[from(segStart), { backgroundColor: start }]}>
123
+ {opacities.map((opacity, k) => (
124
+ <View
125
+ key={k}
126
+ style={[from((((k + 1) / bandCount) * segLength) / rest), { backgroundColor: to, opacity }]}
127
+ />
74
128
  ))}
75
129
  </View>
76
130
  );
77
131
  });
78
132
 
79
- const stack = (
80
- <View style={[StyleSheet.absoluteFill, { flexDirection: isRow ? 'row' : 'column' }]}>{segments}</View>
81
- );
82
-
83
- if (!isDiagonal) return stack;
84
- return <View style={[styles.diagonalPlane, { transform: [{ rotate }] }]}>{segments}</View>;
85
- }, [colors, isRow, isDiagonal, rotate, bandCount]);
133
+ if (!isDiagonal) return <View style={StyleSheet.absoluteFill}>{segments}</View>;
134
+ const plane = size ? diagonalBox(size.width, size.height) : styles.diagonalPlane;
135
+ return <View style={[plane, { transform: [{ rotate }] }]}>{segments}</View>;
136
+ }, [colors, isRow, isDiagonal, rotate, bandCount, size]);
86
137
 
87
138
  return (
88
- <View testID={testID} style={[styles.root, style]}>
89
- {/* pointerEvents va en el pintado, no en la raíz: el degradado no debe
90
- robarle los toques a lo que el consumidor ponga encima. */}
139
+ <View testID={testID} style={[styles.root, style]} onLayout={onLayout}>
140
+ {/* pointerEvents goes on the painted layer, not the root: the gradient
141
+ must not steal touches from whatever the consumer places on top. */}
91
142
  <View style={StyleSheet.absoluteFill} pointerEvents="none">
92
143
  {painted}
93
144
  </View>
@@ -4,15 +4,23 @@ import { PressableScale } from './PressableScale';
4
4
  import { Icon } from '../icons/Icon';
5
5
  import type { IconName } from '../icons/types';
6
6
  import { createStyles } from '../theme/createStyles';
7
+ import { useTheme } from '../theme/UIProvider';
7
8
 
8
9
  export interface IconButtonProps {
10
+ /** Icon from the library's set. Ignored when `icon` is passed. */
9
11
  iconName?: IconName;
12
+ /** Custom node in place of the icon. Takes precedence over `iconName`. */
10
13
  icon?: React.ReactNode;
14
+ /** Called on press. Not called while `disabled`. */
11
15
  onPress?: (e: GestureResponderEvent) => void;
16
+ /** Icon size in pt. The touch area is padded up to 44pt with `hitSlop`. @default 24 */
12
17
  size?: number;
18
+ /** Icon color. Defaults to `colors.text`. */
13
19
  color?: string;
20
+ /** Dims the button by half and ignores presses. */
14
21
  disabled?: boolean;
15
22
  style?: StyleProp<ViewStyle>;
23
+ /** Required: the button has no visible text, so this is all a screen reader announces. */
16
24
  accessibilityLabel: string;
17
25
  testID?: string;
18
26
  }
@@ -25,20 +33,35 @@ const useStyles = createStyles((theme) => ({
25
33
  },
26
34
  }));
27
35
 
36
+ /** Minimum touch area recommended by Apple (44pt) and Material (48dp ≈ 44pt). */
37
+ const MIN_TOUCH = 44;
38
+
28
39
  /**
29
40
  * IconButton
30
- * Botón de solo ícono con área táctil mínima de 44x44 garantizada por el
31
- * padding (icon 24 + padding 8*2 = 40; sube a 44 con size>=24 default RN).
32
- * `accessibilityLabel` es obligatorio: sin texto visible, es la única forma
33
- * de que un lector de pantalla anuncie qué hace el botón.
41
+ * Icon-only button. `accessibilityLabel` is required: with no visible text,
42
+ * it is the only way for a screen reader to announce what it does.
43
+ *
44
+ * Fitts: the visible area is icon + `spacing.sm` per side (24 + 16 = 40pt
45
+ * with the default size, 32pt with `size={16}`). `hitSlop` makes up the
46
+ * rest up to 44pt without enlarging the layout, so a row of icons keeps its
47
+ * rhythm and each one is still easy to tap.
48
+ *
49
+ * Gestalt, figure and ground: it has no background of its own, the icon is
50
+ * the figure over whatever is behind it; that is why the default color is
51
+ * `colors.text` (guaranteed AA contrast) and `disabled` dims it by half.
34
52
  */
35
53
  export const IconButton = memo(
36
54
  ({ iconName, icon, onPress, size = 24, color, disabled, style, accessibilityLabel, testID }: IconButtonProps) => {
37
55
  const styles = useStyles();
56
+ const theme = useTheme();
57
+ const visible = size + theme.tokens.spacing.sm * 2;
58
+ const extra = Math.max(0, Math.ceil((MIN_TOUCH - visible) / 2));
59
+ const hitSlop = extra > 0 ? { top: extra, bottom: extra, left: extra, right: extra } : undefined;
38
60
  return (
39
61
  <PressableScale
40
62
  onPress={onPress}
41
63
  disabled={disabled}
64
+ hitSlop={hitSlop}
42
65
  style={[styles.hitArea, { opacity: disabled ? 0.5 : 1 }, style]}
43
66
  accessibilityRole="button"
44
67
  accessibilityLabel={accessibilityLabel}
@@ -4,27 +4,38 @@ import {
4
4
  Platform,
5
5
  StyleSheet,
6
6
  View,
7
- type ImageErrorEventData,
7
+ type ImageProps as RNImageProps,
8
8
  type ImageResizeMode,
9
9
  type ImageSourcePropType,
10
- type NativeSyntheticEvent,
11
10
  type StyleProp,
12
11
  type ViewStyle,
13
12
  } from 'react-native';
14
13
  import { createStyles } from '../theme/createStyles';
14
+ import { useColors, useTheme } from '../theme/UIProvider';
15
+ import { Icon } from '../icons/Icon';
15
16
  import { Spinner } from './Spinner';
16
17
 
18
+ /**
19
+ * The event RN's Image passes to `onError`. Taken from its own prop type:
20
+ * react-native 0.88 (Expo SDK 58) renamed the exported name
21
+ * (`ImageErrorEventData` -> `ImageErrorEvent`).
22
+ */
23
+ type ImageErrorEvent = Parameters<NonNullable<RNImageProps['onError']>>[0];
24
+
17
25
  export interface ImageProps {
26
+ /** Image to load (same as React Native's `source`). */
18
27
  source: ImageSourcePropType;
28
+ /** Width of the image slot, in pt. */
19
29
  width?: number;
30
+ /** Height of the image slot, in pt. */
20
31
  height?: number;
21
- /** @default 'cover' */
32
+ /** How the image fits its slot (same as React Native). @default 'cover' */
22
33
  resizeMode?: ImageResizeMode;
23
34
  /** Corner radius, same pattern as Avatar/Card. @default 0 */
24
35
  radius?: number;
25
36
  /** What to show while loading. `false` to show nothing. @default true (small spinner) */
26
37
  loading?: React.ReactNode | boolean;
27
- /** What to show if loading fails. @default a gray placeholder, no content */
38
+ /** What to show if loading fails. @default placeholder with a warning icon */
28
39
  fallback?: React.ReactNode;
29
40
  /**
30
41
  * 'high' triggers Image.prefetch() on mount, before <Image> starts
@@ -34,15 +45,22 @@ export interface ImageProps {
34
45
  */
35
46
  priority?: 'low' | 'normal' | 'high';
36
47
  style?: StyleProp<ViewStyle>;
48
+ /** Called when loading finishes, successfully or not (same as RN). */
37
49
  onLoadEnd?: () => void;
38
- onError?: (error: NativeSyntheticEvent<ImageErrorEventData>) => void;
50
+ /** Describes the image for screen readers. Without it the image is decorative. */
51
+ accessibilityLabel?: string;
52
+ /** Called when loading fails; the `fallback` is shown. */
53
+ onError?: (error: ImageErrorEvent) => void;
39
54
  testID?: string;
40
55
  }
41
56
 
42
57
  const useStyles = createStyles((theme) => ({
43
- container: { overflow: 'hidden', backgroundColor: theme.colors.skeleton },
58
+ container: { overflow: 'hidden' },
59
+ // Only while loading or on failure: once the image has loaded, a PNG with
60
+ // transparency (a logo) let this gray show through.
61
+ placeholder: { backgroundColor: theme.colors.skeleton },
44
62
  overlay: { alignItems: 'center', justifyContent: 'center' },
45
- fallback: { flex: 1, backgroundColor: theme.colors.skeleton },
63
+ fallback: { flex: 1, backgroundColor: theme.colors.skeleton, alignItems: 'center', justifyContent: 'center' },
46
64
  }));
47
65
 
48
66
  function sourceUri(source: ImageSourcePropType): string | undefined {
@@ -51,14 +69,22 @@ function sourceUri(source: ImageSourcePropType): string | undefined {
51
69
 
52
70
  /**
53
71
  * Image
54
- * Wrapper cero-dependencias sobre <Image> de RN: agrega estado de carga y
55
- * error (con los mismos placeholders que el resto de la librería), y expone
56
- * `priority="high"` para adelantar la descarga vía Image.prefetch(). El
57
- * cache real (disco/memoria) lo maneja el motor de imágenes nativo de RN —
58
- * esto no lo reimplementa, solo no lo deja apagado por accidente: en iOS
59
- * fuerza `cache="force-cache"` (usa el disco aunque el header HTTP no lo
60
- * pida); en Android el cache de disco de la imagen nativa ya está siempre
61
- * activo, no hay knob equivalente que tocar.
72
+ * Zero-dependency wrapper over RN's <Image>: adds loading and error state
73
+ * (with the same placeholders as the rest of the library), and exposes
74
+ * `priority="high"` to start the download early via Image.prefetch(). The
75
+ * actual cache (disk/memory) is handled by RN's native image engine — this
76
+ * doesn't reimplement it, it just keeps it from being accidentally turned off:
77
+ * on iOS it forces `cache="force-cache"` (uses the disk even when the HTTP
78
+ * header doesn't ask for it); on Android the native image's disk cache is
79
+ * always on, there is no equivalent knob to touch.
80
+ *
81
+ * Gestalt, closure: the container takes its final size from the first frame
82
+ * (`skeleton` background), so the layout doesn't jump when the image arrives
83
+ * and the eye completes the shape it will fill. If loading fails, the same
84
+ * slot shows a warning icon: the state is visible, not a silent gray.
85
+ *
86
+ * Success is detected with `onLoad`, not `onLoadEnd`: RN also calls
87
+ * `onLoadEnd` on failure, and using it for "loaded" overwrote the error.
62
88
  */
63
89
  export const Image = memo(
64
90
  ({
@@ -74,14 +100,17 @@ export const Image = memo(
74
100
  onLoadEnd,
75
101
  onError,
76
102
  testID,
103
+ accessibilityLabel,
77
104
  }: ImageProps) => {
78
105
  const styles = useStyles();
106
+ const colors = useColors();
107
+ const theme = useTheme();
79
108
  const [status, setStatus] = useState<'loading' | 'loaded' | 'error'>('loading');
80
109
  const uri = sourceUri(source);
81
110
 
82
111
  useEffect(() => {
83
- // Resetea el estado si cambia la imagen (misma instancia de Image,
84
- // source distinto: p.ej. avatar de un usuario a otro en la misma fila).
112
+ // Resets the state if the image changes (same Image instance, different
113
+ // source: e.g. one user's avatar to another's in the same row).
85
114
  setStatus('loading');
86
115
  }, [uri ?? source]);
87
116
 
@@ -92,28 +121,34 @@ export const Image = memo(
92
121
  }, [priority, uri]);
93
122
 
94
123
  const handleError = useCallback(
95
- (e: NativeSyntheticEvent<ImageErrorEventData>) => {
124
+ (e: ImageErrorEvent) => {
96
125
  setStatus('error');
97
126
  onError?.(e);
98
127
  },
99
128
  [onError]
100
129
  );
101
130
 
102
- const handleLoadEnd = useCallback(() => {
131
+ const handleLoad = useCallback(() => {
103
132
  setStatus('loaded');
104
- onLoadEnd?.();
105
- }, [onLoadEnd]);
133
+ }, []);
106
134
 
107
135
  return (
108
- <View style={[styles.container, { width, height, borderRadius: radius }, style]} testID={testID}>
136
+ <View
137
+ style={[styles.container, status !== 'loaded' && styles.placeholder, { width, height, borderRadius: radius }, style]}
138
+ testID={testID}
139
+ accessible={!!accessibilityLabel}
140
+ accessibilityRole={accessibilityLabel ? 'image' : undefined}
141
+ accessibilityLabel={accessibilityLabel}
142
+ >
109
143
  {status !== 'error' && (
110
144
  <RNImage
111
145
  source={source}
112
146
  resizeMode={resizeMode}
113
147
  style={StyleSheet.absoluteFill}
114
- fadeDuration={Platform.OS === 'android' ? 150 : undefined}
148
+ fadeDuration={Platform.OS === 'android' ? theme.tokens.duration.fast : undefined}
115
149
  {...(Platform.OS === 'ios' ? { cache: 'force-cache' as const } : null)}
116
- onLoadEnd={handleLoadEnd}
150
+ onLoad={handleLoad}
151
+ onLoadEnd={onLoadEnd}
117
152
  onError={handleError}
118
153
  />
119
154
  )}
@@ -122,7 +157,18 @@ export const Image = memo(
122
157
  {loading === true ? <Spinner size="small" fullscreen={false} /> : loading}
123
158
  </View>
124
159
  )}
125
- {status === 'error' && (fallback ?? <View style={styles.fallback} />)}
160
+ {status === 'error' && (
161
+ // Custom fallback or the default: always centered in the slot.
162
+ <View style={styles.fallback}>
163
+ {fallback ?? (
164
+ <Icon
165
+ name="warning"
166
+ size={Math.max(16, Math.min(32, Math.round(Math.min(width ?? 64, height ?? 64) * 0.3)))}
167
+ color={colors.textLight}
168
+ />
169
+ )}
170
+ </View>
171
+ )}
126
172
  </View>
127
173
  );
128
174
  }
@@ -130,8 +176,8 @@ export const Image = memo(
130
176
  Image.displayName = 'Image';
131
177
 
132
178
  /**
133
- * Precarga una URL antes de montar el componente (p.ej. al recibir la
134
- * respuesta de un listado, antes de navegar al detalle). Re-exporta
135
- * Image.prefetch de RN — no hay nada zero-dep que agregarle encima.
179
+ * Preloads a URL before mounting the component (e.g. on receiving a list
180
+ * response, before navigating to the detail). Re-exports RN's
181
+ * Image.prefetch — there is nothing zero-dep to add on top.
136
182
  */
137
183
  export const prefetchImage = RNImage.prefetch;