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
@@ -1,5 +1,6 @@
1
- import React, { memo, useRef, useState } from 'react';
1
+ import React, { forwardRef, memo, useEffect, useImperativeHandle, useRef, useState, type ComponentRef } from 'react';
2
2
  import {
3
+ AccessibilityInfo,
3
4
  ActivityIndicator,
4
5
  Animated,
5
6
  Text,
@@ -11,21 +12,51 @@ import {
11
12
  type ViewStyle,
12
13
  } from 'react-native';
13
14
  import { createStyles } from '../theme/createStyles';
14
- import { useAllowFontScaling, useColors } from '../theme/UIProvider';
15
+ import { useAllowFontScaling, useColors, useLabels, useTheme } from '../theme/UIProvider';
15
16
  import { Icon } from '../icons/Icon';
16
17
  import type { IconName } from '../icons/types';
18
+ import { useKeyboardField } from '../theme/useKeyboardField';
19
+ import { validateInputValue, type InputRules } from './inputValidation';
20
+
21
+ export type { InputRules, InputRuleValue } from './inputValidation';
22
+
23
+ /** The TextInput instance, plus `validate()` to check the field on demand (e.g. on submit). */
24
+ export type InputHandle = ComponentRef<typeof TextInput> & {
25
+ /** Runs the rules, shows the error (if any) and returns it. */
26
+ validate: () => string | undefined;
27
+ };
17
28
 
18
29
  export interface InputProps extends Omit<TextInputProps, 'style'> {
30
+ /** Text above the field; also its accessible name (falls back to `placeholder`). */
19
31
  label?: string;
20
- /** Shows an asterisk next to the label. Purely visual, doesn't validate anything. */
32
+ /** Shows an asterisk next to the label, and an empty value fails validation (`labels.requiredError`). */
21
33
  required?: boolean;
34
+ /** Error shown under the field. Takes precedence over the built-in validation. */
22
35
  error?: string;
36
+ /** Built-in validation: length limits, a pattern and/or a custom check. */
37
+ rules?: InputRules;
38
+ /**
39
+ * When the rules run: on leaving the field, on every change, or only through
40
+ * `ref.validate()`. Once an error shows, it re-checks on every change so it
41
+ * clears as soon as the value is fixed. @default 'blur'
42
+ */
43
+ validateOn?: 'blur' | 'change' | 'submit';
44
+ /** Called with the error (or undefined) every time the rules run. */
45
+ onValidate?: (error: string | undefined) => void;
46
+ /** Style of the outer wrapper (label, field and error). */
23
47
  containerStyle?: StyleProp<ViewStyle>;
24
48
  style?: TextInputProps['style'];
49
+ /** Icon shown inside the field, to the left of the text. */
25
50
  leftIconName?: IconName;
51
+ /** Icon button inside the field, on the right. Ignored with `isPassword` or `isLoading`. */
26
52
  rightIconName?: IconName;
53
+ /** Called when the `rightIconName` button is pressed. Without it the button is disabled. */
27
54
  onRightIconPress?: () => void;
55
+ /** Accessible name of the `rightIconName` button. @default labels.clear */
56
+ rightIconAccessibilityLabel?: string;
57
+ /** Hides the text and adds an eye button to show or hide it. @default false */
28
58
  isPassword?: boolean;
59
+ /** Shows a small spinner on the right, in place of the right icon. @default false */
29
60
  isLoading?: boolean;
30
61
  }
31
62
 
@@ -54,25 +85,57 @@ const useStyles = createStyles((theme) => ({
54
85
  color: theme.colors.text,
55
86
  },
56
87
  leftIcon: { marginLeft: theme.tokens.spacing.lg, marginRight: -theme.tokens.spacing.xs },
57
- rightIcon: { padding: theme.tokens.spacing.sm + 2, marginRight: theme.tokens.spacing.xs },
88
+ // 20 icon + md padding (12) per side = 44pt touch area (Fitts).
89
+ rightIcon: { padding: theme.tokens.spacing.md, marginRight: theme.tokens.spacing.xxs },
90
+ // Read-only: no fill, so it doesn't look like a field you can tap
91
+ // (affordance), but the text keeps its contrast to stay readable.
92
+ readOnly: { backgroundColor: 'transparent' },
58
93
  errorText: { marginTop: theme.tokens.spacing.xs, fontSize: theme.tokens.fontSize.sm, color: theme.colors.errorText },
59
94
  }));
60
95
 
61
96
  /**
62
97
  * Input
63
- * El borde anima color entre border/primary/error con Animated (no
64
- * useNativeDriver: los navegadores de color en RN sin Fabric solo son
65
- * confiables en el hilo de JS; el costo es despreciable, se anima un borde).
98
+ * The border animates its color between border/primary/error with Animated
99
+ * (no useNativeDriver: color drivers in RN without Fabric are only reliable
100
+ * on the JS thread; the cost is negligible, it animates one border).
101
+ *
102
+ * Gestalt:
103
+ * - Proximity: label (`spacing.sm` above) and error (`spacing.xs` below) sit
104
+ * right next to the field and the next field is `spacing.lg` away: each
105
+ * label and its error read with their field, not with the neighbor.
106
+ * - Common region: left icon, text and right action share the same border
107
+ * and background, so they read as a single control.
108
+ * - Focal point: the border turns `primary` on focus and `error` on error;
109
+ * the error is also written out (not just color).
110
+ *
111
+ * Accessibility: the accessible name includes "required" when applicable, the
112
+ * error is announced as a hint, and the eye and right-action buttons have a
113
+ * 44pt touch area and texts from `labels` (translatable).
114
+ *
115
+ * Keyboard: on focus it registers with the root UIProvider's host, which
116
+ * lifts the app just enough for the whole field (label, field and error) to
117
+ * sit above the keyboard — without depending on Screen or a ScrollView. What
118
+ * you type is always visible.
119
+ *
120
+ * Validation: `required` and `rules` run when leaving the field (`validateOn`),
121
+ * the error appears in writing, is announced to the screen reader and, once
122
+ * visible, is revalidated on every change so it disappears as soon as it is
123
+ * fixed. An `error` passed by hand overrides the internal validation.
66
124
  */
67
125
  export const Input = memo(
68
- ({
126
+ forwardRef<InputHandle, InputProps>(({
69
127
  label,
70
128
  required = false,
71
- error,
129
+ error: errorProp,
130
+ rules,
131
+ validateOn = 'blur',
132
+ onValidate,
133
+ onChangeText,
72
134
  containerStyle,
73
135
  leftIconName,
74
136
  rightIconName,
75
137
  onRightIconPress,
138
+ rightIconAccessibilityLabel,
76
139
  isPassword = false,
77
140
  isLoading = false,
78
141
  style,
@@ -80,43 +143,85 @@ export const Input = memo(
80
143
  onBlur,
81
144
  testID,
82
145
  ...props
83
- }: InputProps) => {
146
+ }, ref) => {
84
147
  const colors = useColors();
85
148
  const styles = useStyles();
86
149
  const allowFontScaling = useAllowFontScaling();
150
+ const labels = useLabels();
151
+ const theme = useTheme();
152
+ const readOnly = props.editable === false;
87
153
  const [isFocused, setIsFocused] = useState(false);
88
154
  const [showPassword, setShowPassword] = useState(false);
89
155
  const focusProgress = useRef(new Animated.Value(0)).current;
156
+ const inputRef = useRef<ComponentRef<typeof TextInput>>(null);
157
+ const containerRef = useRef<ComponentRef<typeof View>>(null);
158
+ const [internalError, setInternalError] = useState<string | undefined>(undefined);
159
+ // Last known value: the controlled one (`value`) or what was typed (uncontrolled).
160
+ const valueRef = useRef(props.value ?? props.defaultValue ?? '');
161
+ if (props.value !== undefined) valueRef.current = props.value;
162
+ const error = errorProp ?? internalError;
163
+
164
+ const runValidation = () => {
165
+ const next = validateInputValue(valueRef.current, { required, rules }, labels);
166
+ setInternalError(next);
167
+ onValidate?.(next);
168
+ return next;
169
+ };
170
+
171
+ useImperativeHandle(ref, () => Object.assign(inputRef.current as ComponentRef<typeof TextInput>, { validate: runValidation }));
172
+
173
+ // The new error is announced right away, not only as a hint when returning to the field.
174
+ useEffect(() => {
175
+ if (internalError && errorProp === undefined) AccessibilityInfo.announceForAccessibility(internalError);
176
+ }, [internalError, errorProp]);
177
+
178
+ const keyboard = useKeyboardField(containerRef);
179
+
180
+ // If the error appears or changes while the field is focused, the block grows:
181
+ // a readjustment is requested so the error line isn't covered either.
182
+ useEffect(() => {
183
+ if (isFocused) keyboard.focus();
184
+ }, [error, isFocused, keyboard]);
90
185
 
91
186
  const handleFocus: TextInputProps['onFocus'] = (e) => {
92
187
  setIsFocused(true);
93
- Animated.timing(focusProgress, { toValue: 1, duration: 200, useNativeDriver: false }).start();
188
+ keyboard.focus();
189
+ Animated.timing(focusProgress, { toValue: 1, duration: theme.tokens.duration.base, useNativeDriver: false }).start();
94
190
  onFocus?.(e);
95
191
  };
96
192
 
97
193
  const handleBlur: TextInputProps['onBlur'] = (e) => {
98
194
  setIsFocused(false);
99
- Animated.timing(focusProgress, { toValue: 0, duration: 200, useNativeDriver: false }).start();
195
+ keyboard.blur();
196
+ if (validateOn === 'blur') runValidation();
197
+ Animated.timing(focusProgress, { toValue: 0, duration: theme.tokens.duration.base, useNativeDriver: false }).start();
100
198
  onBlur?.(e);
101
199
  };
102
200
 
201
+ const handleChangeText = (text: string) => {
202
+ valueRef.current = text;
203
+ onChangeText?.(text);
204
+ if (validateOn === 'change' || internalError) runValidation();
205
+ };
206
+
103
207
  const borderColor = error
104
208
  ? colors.error
105
209
  : focusProgress.interpolate({ outputRange: [colors.border, colors.primary], inputRange: [0, 1] });
106
210
 
107
211
  return (
108
- <View style={[styles.container, containerStyle]} testID={testID}>
109
- {label && (
212
+ <View ref={containerRef} style={[styles.container, containerStyle]} testID={testID}>
213
+ {!!label && (
110
214
  <Text allowFontScaling={allowFontScaling} style={styles.label}>
111
215
  {label}
112
216
  {required && <Text style={styles.required}> *</Text>}
113
217
  </Text>
114
218
  )}
115
219
 
116
- <Animated.View style={[styles.inputWrapper, { borderColor }]}>
220
+ <Animated.View style={[styles.inputWrapper, readOnly && styles.readOnly, { borderColor }]}>
117
221
  {leftIconName && <Icon name={leftIconName} size={20} color={colors.textLight} style={styles.leftIcon} />}
118
222
 
119
223
  <TextInput
224
+ ref={inputRef}
120
225
  style={[styles.input, style]}
121
226
  placeholderTextColor={colors.textLight}
122
227
  onFocus={handleFocus}
@@ -124,8 +229,13 @@ export const Input = memo(
124
229
  secureTextEntry={isPassword && !showPassword}
125
230
  allowFontScaling={allowFontScaling}
126
231
  textAlignVertical="center"
127
- accessibilityLabel={label ?? props.placeholder}
232
+ accessibilityLabel={
233
+ label || props.placeholder ? `${label ?? props.placeholder}${required ? `, ${labels.required}` : ''}` : undefined
234
+ }
235
+ accessibilityHint={error || undefined}
236
+ accessibilityState={{ disabled: readOnly, busy: isLoading }}
128
237
  {...props}
238
+ onChangeText={handleChangeText}
129
239
  />
130
240
 
131
241
  {isLoading ? (
@@ -137,7 +247,7 @@ export const Input = memo(
137
247
  onPress={() => setShowPassword((v) => !v)}
138
248
  style={styles.rightIcon}
139
249
  accessibilityRole="button"
140
- accessibilityLabel={showPassword ? 'Hide password' : 'Show password'}
250
+ accessibilityLabel={showPassword ? labels.hidePassword : labels.showPassword}
141
251
  >
142
252
  <Icon name={showPassword ? 'eye-off' : 'eye'} size={20} color={colors.textLight} />
143
253
  </TouchableOpacity>
@@ -147,7 +257,7 @@ export const Input = memo(
147
257
  style={styles.rightIcon}
148
258
  disabled={!onRightIconPress}
149
259
  accessibilityRole="button"
150
- accessibilityLabel="Clear"
260
+ accessibilityLabel={rightIconAccessibilityLabel ?? labels.clear}
151
261
  >
152
262
  <Icon name={rightIconName} size={20} color={colors.textLight} />
153
263
  </TouchableOpacity>
@@ -161,6 +271,6 @@ export const Input = memo(
161
271
  )}
162
272
  </View>
163
273
  );
164
- }
274
+ })
165
275
  );
166
276
  Input.displayName = 'Input';
@@ -4,45 +4,89 @@ import { createStyles } from '../theme/createStyles';
4
4
  import { useAllowFontScaling } from '../theme/UIProvider';
5
5
 
6
6
  export interface KeyValueRowProps {
7
+ /** Left side. A string or number gets the default label style; any other node renders as is. */
7
8
  label: React.ReactNode;
9
+ /** Right side. A string or number gets the default value style (tabular digits); any other node renders as is. */
8
10
  value: React.ReactNode;
9
11
  style?: StyleProp<ViewStyle>;
12
+ /** Only applies when `label` is a string or number. */
10
13
  labelStyle?: StyleProp<TextStyle>;
14
+ /** Only applies when `value` is a string or number. */
11
15
  valueStyle?: StyleProp<TextStyle>;
16
+ testID?: string;
12
17
  }
13
18
 
14
19
  const useStyles = createStyles((theme) => ({
15
- row: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },
16
- label: { fontSize: theme.tokens.fontSize.sm, fontWeight: theme.tokens.fontWeight.semibold, color: theme.colors.textLight },
17
- value: { fontSize: theme.tokens.fontSize.sm, textAlign: 'right', color: theme.colors.text },
20
+ row: {
21
+ flexDirection: 'row',
22
+ justifyContent: 'space-between',
23
+ alignItems: 'center',
24
+ gap: theme.tokens.spacing.md,
25
+ },
26
+ // Two texts: aligned on the first line, so a value that wraps onto
27
+ // several lines still reads next to its label.
28
+ rowText: { alignItems: 'baseline' },
29
+ // The label keeps its natural width up to half the row; the value
30
+ // shrinks and wraps instead of pushing the row off the screen.
31
+ label: {
32
+ flexShrink: 0,
33
+ maxWidth: '50%',
34
+ fontSize: theme.tokens.fontSize.sm,
35
+ lineHeight: theme.tokens.lineHeight.sm,
36
+ fontWeight: theme.tokens.fontWeight.semibold,
37
+ color: theme.colors.textLight,
38
+ },
39
+ value: {
40
+ flexShrink: 1,
41
+ fontSize: theme.tokens.fontSize.sm,
42
+ lineHeight: theme.tokens.lineHeight.sm,
43
+ textAlign: 'right',
44
+ color: theme.colors.text,
45
+ // Fixed-width digits: in a column of amounts the figures line up
46
+ // across rows.
47
+ fontVariant: ['tabular-nums'],
48
+ },
18
49
  }));
19
50
 
51
+ const isPrimitive = (node: React.ReactNode): node is string | number =>
52
+ typeof node === 'string' || typeof node === 'number';
53
+
20
54
  /**
21
55
  * KeyValueRow
22
- * Fila label (izquierda) / value (derecha). Si label/value son string o
23
- * number, se renderizan con el estilo default; si ya vienen envueltos en un
24
- * componente de texto propio, se respetan tal cual.
56
+ * Label (left) / value (right) row. If label/value are a string or number,
57
+ * they render with the default style; if they already come wrapped in a
58
+ * custom component, they are kept as is.
59
+ *
60
+ * Gestalt, alignment and similarity: labels share color and weight and values
61
+ * align to the right edge with tabular digits, so a stack of rows reads as
62
+ * two columns — what on the left, how much on the right.
63
+ * With a text label and value, the row is a single accessibility node
64
+ * ("Subtotal, $300.00"); if either is a custom node (a Badge, a button) it
65
+ * isn't merged, so as not to hide what that node announces or lets you tap.
25
66
  */
26
- export const KeyValueRow = memo(({ label, value, style, labelStyle, valueStyle }: KeyValueRowProps) => {
27
- const styles = useStyles();
28
- const allowFontScaling = useAllowFontScaling();
29
- return (
30
- <View style={[styles.row, style]}>
31
- {typeof label === 'string' || typeof label === 'number' ? (
32
- <Text allowFontScaling={allowFontScaling} style={[styles.label, labelStyle]}>
33
- {label}
34
- </Text>
35
- ) : (
36
- label
37
- )}
38
- {typeof value === 'string' || typeof value === 'number' ? (
39
- <Text allowFontScaling={allowFontScaling} style={[styles.value, valueStyle]}>
40
- {value}
41
- </Text>
42
- ) : (
43
- value
44
- )}
45
- </View>
46
- );
47
- });
67
+ export const KeyValueRow = memo(
68
+ ({ label, value, style, labelStyle, valueStyle, testID }: KeyValueRowProps) => {
69
+ const styles = useStyles();
70
+ const allowFontScaling = useAllowFontScaling();
71
+ const merge = isPrimitive(label) && isPrimitive(value);
72
+ return (
73
+ <View style={[styles.row, merge && styles.rowText, style]} accessible={merge || undefined} testID={testID}>
74
+ {isPrimitive(label) ? (
75
+ <Text allowFontScaling={allowFontScaling} style={[styles.label, labelStyle]}>
76
+ {label}
77
+ </Text>
78
+ ) : (
79
+ label
80
+ )}
81
+ {isPrimitive(value) ? (
82
+ <Text allowFontScaling={allowFontScaling} style={[styles.value, valueStyle]}>
83
+ {value}
84
+ </Text>
85
+ ) : (
86
+ value
87
+ )}
88
+ </View>
89
+ );
90
+ }
91
+ );
48
92
  KeyValueRow.displayName = 'KeyValueRow';
@@ -7,32 +7,54 @@ import {
7
7
  type StyleProp,
8
8
  type ViewStyle,
9
9
  } from 'react-native';
10
+ import { useReduceMotion } from './Transition';
10
11
 
11
- export interface PressableScaleProps extends Omit<PressableProps, 'style'> {
12
+ export interface PressableScaleProps extends Omit<PressableProps, 'style' | 'children'> {
12
13
  /** Target scale when pressed. @default 0.96 */
13
14
  scaleTo?: number;
14
15
  style?: StyleProp<ViewStyle>;
16
+ /** Pressable content. */
15
17
  children: React.ReactNode;
16
18
  }
17
19
 
20
+ /** Short spring with almost no bounce: feedback arrives in ~100 ms (Doherty). */
21
+ const PRESS_SPRING = { speed: 50, bounciness: 6 } as const;
22
+
18
23
  const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
19
24
 
20
25
  /**
21
26
  * PressableScale
22
- * Feedback táctil de "achicarse" al presionar, con Animated.spring de RN
23
- * (useNativeDriver: true — corre en el hilo nativo, sin coste de JS por frame).
24
- * No depende de reanimated: la librería entera es cero-dependencias.
27
+ * Tactile "shrink" feedback on press, with RN's Animated.spring
28
+ * (useNativeDriver: true — runs on the native thread, no JS cost per frame).
29
+ * Doesn't depend on reanimated: the whole library is zero-dependency.
30
+ *
31
+ * Gestalt, figure/ground: as it sinks, the pressed element separates for an
32
+ * instant from the rest and confirms what was touched (Doherty: immediate
33
+ * response). Announces itself as a button by default (`accessibilityRole` can
34
+ * be changed) and, when disabled, exposes `disabled` to the screen reader.
35
+ * With Reduce Motion it doesn't scale.
25
36
  */
26
37
  export const PressableScale = memo(
27
- ({ scaleTo = 0.96, style, children, onPressIn, onPressOut, disabled, ...props }: PressableScaleProps) => {
38
+ ({
39
+ scaleTo = 0.96,
40
+ style,
41
+ children,
42
+ onPressIn,
43
+ onPressOut,
44
+ disabled,
45
+ accessibilityRole = 'button',
46
+ accessibilityState,
47
+ ...props
48
+ }: PressableScaleProps) => {
28
49
  const scale = useRef(new Animated.Value(1)).current;
50
+ const reduceMotion = useReduceMotion();
29
51
 
30
52
  const animateTo = (value: number) => {
53
+ if (reduceMotion) return;
31
54
  Animated.spring(scale, {
32
55
  toValue: value,
33
56
  useNativeDriver: true,
34
- speed: 50,
35
- bounciness: 6,
57
+ ...PRESS_SPRING,
36
58
  }).start();
37
59
  };
38
60
 
@@ -49,6 +71,8 @@ export const PressableScale = memo(
49
71
  return (
50
72
  <AnimatedPressable
51
73
  {...props}
74
+ accessibilityRole={accessibilityRole}
75
+ accessibilityState={{ ...accessibilityState, disabled: !!disabled }}
52
76
  disabled={disabled}
53
77
  onPressIn={handlePressIn}
54
78
  onPressOut={handlePressOut}
@@ -26,11 +26,11 @@ export interface ShinyTextProps {
26
26
  spread?: number;
27
27
  /** When false it renders plain text in `shineColor`. @default true */
28
28
  animated?: boolean;
29
- /** Resting color of the characters. @default theme.colors.textLight */
29
+ /** Resting color of the characters. Keep it readable on its own (WCAG AA): the shine is decorative. @default theme.colors.textLight */
30
30
  color?: string;
31
31
  /** Color of the band that travels across. @default theme.colors.primary */
32
32
  shineColor?: string;
33
- /** @default 'left' */
33
+ /** Horizontal alignment of the line. @default 'left' */
34
34
  align?: 'left' | 'center' | 'right';
35
35
  /** Typography only: `color` and `shineColor` win over any color set here. */
36
36
  style?: StyleProp<TextStyle>;
@@ -49,11 +49,11 @@ const useStyles = createStyles((theme) => ({
49
49
  color: theme.colors.text,
50
50
  },
51
51
  row: { flexDirection: 'row', flexWrap: 'wrap' },
52
- // Sólo top/left: un absoluteFill estiraría la letra al ancho del grupo y la
53
- // volvería a alinear. Anclada a la esquina cae exactamente sobre la de abajo.
52
+ // Only top/left: an absoluteFill would stretch the letter to the group's width
53
+ // and realign it. Anchored to the corner it lands exactly on the one below.
54
54
  overlay: { position: 'absolute', top: 0, left: 0 },
55
- // Una palabra y los espacios que la siguen: el salto de línea ocurre entre
56
- // grupos, nunca entre las letras de una palabra.
55
+ // A word and the spaces that follow it: line breaks happen between
56
+ // groups, never between the letters of a word.
57
57
  group: { flexDirection: 'row' },
58
58
  }));
59
59
 
@@ -63,7 +63,7 @@ const ALIGN: Record<'left' | 'center' | 'right', ViewStyle['justifyContent']> =
63
63
  right: 'flex-end',
64
64
  };
65
65
 
66
- /** Una palabra con los espacios que la siguen, y el índice de su primera letra. */
66
+ /** A word with the spaces that follow it, and the index of its first letter. */
67
67
  interface Group {
68
68
  start: number;
69
69
  chars: string[];
@@ -79,8 +79,8 @@ function toGroups(text: string): Group[] {
79
79
  if (current.length === 0) start = index;
80
80
  current.push(char);
81
81
  const next = chars[index + 1];
82
- // Cierra el grupo cuando termina la racha de espacios que sigue a la
83
- // palabra: así el espacio viaja con ella y no abre línea por sí solo.
82
+ // Closes the group when the run of spaces following the word ends:
83
+ // that way the space travels with it and never starts a line on its own.
84
84
  const isSpace = /\s/.test(char);
85
85
  if (isSpace && next !== undefined && !/\s/.test(next)) {
86
86
  groups.push({ start, chars: current });
@@ -94,23 +94,23 @@ function toGroups(text: string): Group[] {
94
94
 
95
95
  /**
96
96
  * ShinyText
97
- * Una banda de luz recorre el texto de izquierda a derecha. Sin
98
- * `background-clip: text` ni máscaras —que React Native no tiene en el rango
99
- * soportado— el brillo se compone letra por letra: cada una lleva su color de
100
- * reposo y encima, superpuesta, la misma letra en el color del brillo con la
101
- * opacidad animada. La banda es una ventana de interpolación que se desplaza:
102
- * lo que cambia por frame es sólo `opacity`, o sea que la animación entera
103
- * corre en el hilo nativo y JS no participa de ningún frame.
97
+ * A band of light sweeps across the text from left to right. Without
98
+ * `background-clip: text` or masks —which React Native lacks in the supported
99
+ * range— the shine is composed letter by letter: each one carries its resting
100
+ * color and, overlaid on top, the same letter in the shine color with animated
101
+ * opacity. The band is a moving interpolation window: the only thing that
102
+ * changes per frame is `opacity`, which means the whole animation runs on the
103
+ * native thread and JS takes part in no frame.
104
104
  *
105
- * Gestalt, destino común: las letras se encienden en secuencia y con el mismo
106
- * ritmo, así que se leen como una sola cosa que se mueve —una palabra
107
- * iluminándose— y no como N letras parpadeando por su cuenta. Por eso el ancho
108
- * de banda es relativo al texto y no una cantidad fija de píxeles: un título
109
- * largo y uno corto tardan lo mismo y se perciben igual.
105
+ * Gestalt, common fate: the letters light up in sequence and at the same
106
+ * rhythm, so they read as one moving thing —a word lighting up— and not as N
107
+ * letters blinking on their own. That is why the band width is relative to
108
+ * the text and not a fixed number of pixels: a long title and a short one take
109
+ * the same time and are perceived the same.
110
110
  *
111
- * Con "reducir movimiento" activo, o con `animated={false}`, el texto se
112
- * renderiza plano en `shineColor` —legible, un solo nodo y seleccionable—
113
- * porque el efecto es decorativo y nada de lo que comunica está en el brillo.
111
+ * With "reduce motion" on, or with `animated={false}`, the text renders flat
112
+ * in `shineColor` —legible, a single node and selectable— because the effect
113
+ * is decorative and nothing it communicates lives in the shine.
114
114
  */
115
115
  export const ShinyText = memo(
116
116
  ({
@@ -132,9 +132,9 @@ export const ShinyText = memo(
132
132
  const progress = useRef(new Animated.Value(0)).current;
133
133
 
134
134
  const base = color ?? theme.colors.textLight;
135
- // El acento, no `text`: contra `textLight` la diferencia es sólo de
136
- // luminancia y el barrido casi no se ve. El brillo cambia tono además de
137
- // claridad, que es lo que hace legible el movimiento.
135
+ // The accent, not `text`: against `textLight` the difference is only in
136
+ // luminance and the sweep is barely visible. The shine changes hue as well
137
+ // as lightness, which is what makes the motion readable.
138
138
  const shine = shineColor ?? theme.colors.primary;
139
139
  const running = animated && !reduceMotion && text.length > 0;
140
140
 
@@ -170,9 +170,9 @@ export const ShinyText = memo(
170
170
  }
171
171
 
172
172
  const total = Array.from(text).length;
173
- // La banda entra por la izquierda y sale por la derecha, así que el
174
- // recorrido normalizado mide 1 + 2·spread. `half` es media banda en esa
175
- // escala: el tramo de progreso que una letra tarda en encenderse.
173
+ // The band enters on the left and exits on the right, so the normalized
174
+ // path measures 1 + 2·spread. `half` is half a band on that scale: the
175
+ // stretch of progress a letter takes to light up.
176
176
  const half = spread / (1 + 2 * spread);
177
177
 
178
178
  return (
@@ -188,7 +188,7 @@ export const ShinyText = memo(
188
188
  {group.chars.map((char, offset) => {
189
189
  const index = group.start + offset;
190
190
  const position = total === 1 ? 0.5 : index / (total - 1);
191
- // Progreso en el que el centro de la banda cae sobre esta letra.
191
+ // Progress at which the center of the band falls on this letter.
192
192
  const peak = (position + spread) / (1 + 2 * spread);
193
193
  const charStyle: StyleProp<TextStyle> = [styles.text, style];
194
194