orn-ui 0.2.10 → 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 +66 -51
  2. package/README.md +3 -7
  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 +174 -154
  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 +176 -156
  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 +193 -164
  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,15 +1,27 @@
1
- import React, { memo, useState } from 'react';
2
- import { TextInput, TouchableOpacity, View, type StyleProp, type ViewStyle } from 'react-native';
1
+ import React, { memo, useRef, useState, type ComponentRef } from 'react';
2
+ import {
3
+ TextInput,
4
+ TouchableOpacity,
5
+ View,
6
+ type AccessibilityActionEvent,
7
+ type StyleProp,
8
+ type ViewStyle,
9
+ } from 'react-native';
3
10
  import { createStyles } from '../theme/createStyles';
4
- import { useAllowFontScaling, useColors, useTheme } from '../theme/UIProvider';
11
+ import { useAllowFontScaling, useColors, useLabels, useTheme } from '../theme/UIProvider';
12
+ import { useKeyboardField } from '../theme/useKeyboardField';
5
13
  import { Icon } from '../icons/Icon';
6
14
 
7
15
  export type StepperSize = 'sm' | 'md' | 'lg';
8
16
 
9
17
  export interface StepperProps {
18
+ /** Current value, as text (it may be mid-typing, e.g. "" or "1."). */
10
19
  value: string;
20
+ /** Receives the cleaned-up text while typing, and the clamped value on blur. */
11
21
  onChangeText: (text: string) => void;
22
+ /** "+" pressed (or swipe up with a screen reader). Do the arithmetic here. */
12
23
  onIncrement: () => void;
24
+ /** "-" pressed (or swipe down with a screen reader). */
13
25
  onDecrement: () => void;
14
26
  /** Scale of the control: height, buttons, icon and typography. @default 'md' */
15
27
  size?: StepperSize;
@@ -30,7 +42,11 @@ export interface StepperProps {
30
42
  /** Accepts a decimal separator, normalizing comma to dot. @default false */
31
43
  allowDecimals?: boolean;
32
44
  style?: StyleProp<ViewStyle>;
45
+ /** Accessible name of the numeric field. @default labels.quantity */
46
+ accessibilityLabel?: string;
47
+ /** Accessible name of the "+" button. @default labels.increment */
33
48
  incrementAccessibilityLabel?: string;
49
+ /** Accessible name of the "-" button. @default labels.decrement */
34
50
  decrementAccessibilityLabel?: string;
35
51
  testID?: string;
36
52
  }
@@ -41,6 +57,14 @@ const SIZES: Record<StepperSize, { height: number; icon: number; inputWidth: num
41
57
  lg: { height: 52, icon: 22, inputWidth: 64 },
42
58
  };
43
59
 
60
+ /** Minimum touch target (Fitts): smaller buttons reach it with hitSlop. */
61
+ const MIN_TOUCH = 44;
62
+
63
+ const ADJUST_ACTIONS = [
64
+ { name: 'increment' as const },
65
+ { name: 'decrement' as const },
66
+ ];
67
+
44
68
  const useStyles = createStyles((theme) => ({
45
69
  control: {
46
70
  flexDirection: 'row',
@@ -60,12 +84,12 @@ const useStyles = createStyles((theme) => ({
60
84
  borderRightWidth: 1,
61
85
  borderColor: theme.colors.border,
62
86
  },
63
- // El fondo distingue el campo de un valor de sólo lectura: es la única
64
- // señal de que ahí se puede tipear antes de tocarlo.
87
+ // The background tells the field apart from a read-only value: it is the
88
+ // only hint that you can type there before touching it.
65
89
  editable: { backgroundColor: theme.colors.inputBackground },
66
90
  }));
67
91
 
68
- /** Deja sólo lo que puede formar parte del número permitido por el rango. */
92
+ /** Keeps only what can be part of a number allowed by the range. */
69
93
  export function sanitizeNumeric(text: string, { allowDecimals = false, allowNegative = false } = {}): string {
70
94
  const normalized = allowDecimals ? text.replace(',', '.') : text;
71
95
  const negative = allowNegative && normalized.trimStart().startsWith('-');
@@ -77,12 +101,20 @@ export function sanitizeNumeric(text: string, { allowDecimals = false, allowNega
77
101
 
78
102
  /**
79
103
  * Stepper
80
- * Botón "-" + input numérico editable + botón "+". `size` controla sólo la
81
- * escala y `block` sólo el ancho, así que los dos ejes se combinan libremente.
104
+ * "-" button + editable numeric input + "+" button. `size` controls only the
105
+ * scale and `block` only the width, so both axes combine freely.
106
+ *
107
+ * The component doesn't do the buttons' arithmetic —that lives in
108
+ * `onIncrement`/`onDecrement`—, but it does clean up what is typed and signals
109
+ * when the value hit an end of the range by disabling the button that would pass it.
82
110
  *
83
- * El componente no hace la aritmética de los botones —eso vive en
84
- * `onIncrement`/`onDecrement`—, pero sí limpia lo que se tipea y avisa cuándo
85
- * el valor llegó a un extremo del rango deshabilitando el botón que lo pasaría.
111
+ * Gestalt, common region: the three parts share one border, so they read as a
112
+ * single control; the field is set apart by its fill (it can be typed into).
113
+ * Fitts: every button reaches 44pt, `sm` through hitSlop.
114
+ *
115
+ * Accessibility: the field is an adjustable element — VoiceOver/TalkBack users
116
+ * swipe up/down to step the value — and every name comes from `labels`. Like
117
+ * Input, it stays visible above the keyboard while typing.
86
118
  */
87
119
  export const Stepper = memo(
88
120
  ({
@@ -97,19 +129,25 @@ export const Stepper = memo(
97
129
  max,
98
130
  allowDecimals = false,
99
131
  style,
100
- incrementAccessibilityLabel = 'Increment',
101
- decrementAccessibilityLabel = 'Decrement',
132
+ accessibilityLabel,
133
+ incrementAccessibilityLabel,
134
+ decrementAccessibilityLabel,
102
135
  testID,
103
136
  }: StepperProps) => {
104
137
  const theme = useTheme();
105
138
  const colors = useColors();
106
139
  const styles = useStyles();
140
+ const labels = useLabels();
107
141
  const allowFontScaling = useAllowFontScaling();
108
142
  const [focused, setFocused] = useState(false);
143
+ const controlRef = useRef<ComponentRef<typeof View>>(null);
144
+ const keyboard = useKeyboardField(controlRef);
109
145
 
110
146
  const { height, icon, inputWidth } = SIZES[size];
111
147
  const fontSize =
112
148
  size === 'sm' ? theme.tokens.fontSize.md : size === 'md' ? theme.tokens.fontSize.lg : theme.tokens.fontSize.xl;
149
+ const slopV = Math.max(0, (MIN_TOUCH - height) / 2);
150
+ const hitSlop = slopV > 0 ? { top: slopV, bottom: slopV, left: slopV, right: slopV } : undefined;
113
151
 
114
152
  const allowNegative = min !== undefined && min < 0;
115
153
  const numeric = Number(value);
@@ -121,15 +159,22 @@ export const Stepper = memo(
121
159
  onChangeText(sanitizeNumeric(text, { allowDecimals, allowNegative }));
122
160
  };
123
161
 
124
- // El recorte al rango espera al blur: hacerlo mientras se tipea impide
125
- // llegar a "12" cuando el mínimo es 5, porque el "1" ya se corregiría.
162
+ // Clamping to the range waits for blur: doing it while typing makes it
163
+ // impossible to reach "12" when the minimum is 5, because the "1" would
164
+ // already be corrected.
126
165
  const handleBlur = () => {
127
166
  setFocused(false);
167
+ keyboard.blur();
128
168
  if (!isNumber) return;
129
169
  const clamped = Math.min(max ?? numeric, Math.max(min ?? numeric, numeric));
130
170
  if (clamped !== numeric) onChangeText(String(clamped));
131
171
  };
132
172
 
173
+ const handleAccessibilityAction = (e: AccessibilityActionEvent) => {
174
+ if (e.nativeEvent.actionName === 'increment' && !atMax) onIncrement();
175
+ if (e.nativeEvent.actionName === 'decrement' && !atMin) onDecrement();
176
+ };
177
+
133
178
  const stepButton = (
134
179
  direction: 'decrement' | 'increment',
135
180
  onPress: () => void,
@@ -139,6 +184,7 @@ export const Stepper = memo(
139
184
  <TouchableOpacity
140
185
  onPress={onPress}
141
186
  disabled={disabled}
187
+ hitSlop={hitSlop}
142
188
  style={[styles.btn, { width: height }]}
143
189
  accessibilityRole="button"
144
190
  accessibilityLabel={label}
@@ -155,6 +201,7 @@ export const Stepper = memo(
155
201
 
156
202
  return (
157
203
  <View
204
+ ref={controlRef}
158
205
  testID={testID}
159
206
  style={[
160
207
  styles.control,
@@ -164,7 +211,7 @@ export const Stepper = memo(
164
211
  style,
165
212
  ]}
166
213
  >
167
- {stepButton('decrement', onDecrement, atMin, decrementAccessibilityLabel)}
214
+ {stepButton('decrement', onDecrement, atMin, decrementAccessibilityLabel ?? labels.decrement)}
168
215
  <TextInput
169
216
  allowFontScaling={allowFontScaling}
170
217
  style={[
@@ -176,14 +223,21 @@ export const Stepper = memo(
176
223
  ]}
177
224
  value={value}
178
225
  onChangeText={handleChangeText}
179
- onFocus={() => setFocused(true)}
226
+ onFocus={() => {
227
+ setFocused(true);
228
+ keyboard.focus();
229
+ }}
180
230
  onBlur={handleBlur}
181
231
  editable={editable}
182
232
  keyboardType={allowDecimals ? 'decimal-pad' : 'number-pad'}
183
233
  selectTextOnFocus
184
- accessibilityLabel="Quantity"
234
+ accessibilityLabel={accessibilityLabel ?? labels.quantity}
235
+ accessibilityRole="adjustable"
236
+ accessibilityValue={{ text: value }}
237
+ accessibilityActions={ADJUST_ACTIONS}
238
+ onAccessibilityAction={handleAccessibilityAction}
185
239
  />
186
- {stepButton('increment', onIncrement, atMax, incrementAccessibilityLabel)}
240
+ {stepButton('increment', onIncrement, atMax, incrementAccessibilityLabel ?? labels.increment)}
187
241
  </View>
188
242
  );
189
243
  }
@@ -1,21 +1,33 @@
1
- import React, { memo } from 'react';
2
- import { ScrollView, Text, TouchableOpacity, View, type StyleProp, type ViewStyle } from 'react-native';
1
+ import React, { memo, useEffect, useRef, useState, type ComponentRef } from 'react';
2
+ import {
3
+ ScrollView,
4
+ Text,
5
+ TouchableOpacity,
6
+ View,
7
+ type LayoutChangeEvent,
8
+ type StyleProp,
9
+ type ViewStyle,
10
+ } from 'react-native';
11
+ import { useReduceMotion } from '../theme/useReduceMotion';
3
12
  import { createStyles } from '../theme/createStyles';
4
- import { useAllowFontScaling, useColors } from '../theme/UIProvider';
13
+ import { useAllowFontScaling, useColors, useLabels } from '../theme/UIProvider';
5
14
  import { Icon } from '../icons/Icon';
6
15
 
7
16
  export interface StepItem {
17
+ /** Short name of the step ("Payment"). */
8
18
  label: string;
19
+ /** Optional second line with a detail ("Card or cash"). */
9
20
  description?: string;
10
21
  }
11
22
 
12
23
  export type StepStatus = 'completed' | 'current' | 'pending';
13
24
 
14
25
  export interface StepsProps {
26
+ /** The sequence, in order. */
15
27
  steps: StepItem[];
16
28
  /** Index of the current step (0-based). Earlier steps become 'completed'. */
17
29
  current: number;
18
- /** @default 'horizontal' */
30
+ /** Lays the steps out in a row or in a column. @default 'horizontal' */
19
31
  orientation?: 'horizontal' | 'vertical';
20
32
  /**
21
33
  * What the circle of an already-completed step shows: a check, or its number.
@@ -25,51 +37,73 @@ export interface StepsProps {
25
37
  /** If provided, each step is tappable and reports its index. */
26
38
  onStepPress?: (index: number) => void;
27
39
  style?: StyleProp<ViewStyle>;
40
+ /** Root testID; each step gets `<testID>-<index>`. */
41
+ testID?: string;
28
42
  }
29
43
 
30
44
  const CIRCLE = 32;
31
- /** Ancho mínimo de una columna horizontal: por debajo, las etiquetas se parten. */
45
+ const CIRCLE_BORDER = 2;
46
+ const CHECK_SIZE = 18;
47
+ const CONNECTOR = 2;
48
+ /** Minimum width of a horizontal column: below it, labels break mid-word. */
32
49
  const STEP_MIN_WIDTH = 76;
50
+ /** Share of the row a horizontal connector takes next to a step (flex: 1). */
51
+ const CONNECTOR_FLEX = 0.3;
52
+ const PRESSED_OPACITY = 0.7;
33
53
 
34
54
  const useStyles = createStyles((theme) => ({
35
55
  rowContainer: { flexDirection: 'row', alignItems: 'flex-start' },
36
56
  columnContainer: { flexDirection: 'column' },
37
57
 
38
58
  // horizontal
39
- // ScrollView trae flexGrow: 1 de fábrica y se comía todo el alto disponible
40
- // del contenedor, dejando los pasos pegados arriba de una caja enorme.
59
+ // ScrollView ships with flexGrow: 1 and was eating all the available height
60
+ // of the container, leaving the steps stuck to the top of a huge box.
41
61
  hScrollView: { flexGrow: 0, flexShrink: 0 },
42
62
  hScroll: { flexGrow: 1, flexDirection: 'row', alignItems: 'flex-start' },
43
- // `minWidth` es lo que evita que RN parta palabras a la mitad
44
- // ("Almacé / n"): antes que apretar la columna por debajo de una palabra
45
- // corriente, la fila se vuelve scrollable.
63
+ // `minWidth` is what keeps RN from breaking words in half
64
+ // ("Almacé / n"): rather than squeezing the column below a regular
65
+ // word, the row becomes scrollable.
46
66
  hStep: { flex: 1, minWidth: STEP_MIN_WIDTH, alignItems: 'center', gap: theme.tokens.spacing.sm },
47
- hLabels: { alignItems: 'center', gap: 2, paddingHorizontal: 4 },
48
- // El conector toma una fracción chica del ancho: compitiendo de igual a
49
- // igual con los pasos (flex: 1) cada etiqueta se quedaba con 1/(2n-1) del
67
+ hLabels: { alignItems: 'center', gap: theme.tokens.spacing.xxs, paddingHorizontal: theme.tokens.spacing.xs },
68
+ // The connector takes a small fraction of the width: competing on equal
69
+ // terms with the steps (flex: 1), each label ended up with 1/(2n-1) of the
50
70
  // total.
51
- hConnector: { height: 2, flex: 0.3, minWidth: 12, marginTop: CIRCLE / 2 - 1 },
52
- hLabel: { fontSize: theme.tokens.fontSize.sm },
53
- hDescription: { fontSize: theme.tokens.fontSize.xs },
71
+ hConnector: {
72
+ height: CONNECTOR,
73
+ flex: CONNECTOR_FLEX,
74
+ minWidth: theme.tokens.spacing.md,
75
+ marginTop: CIRCLE / 2 - CONNECTOR / 2,
76
+ },
77
+ hLabel: { fontSize: theme.tokens.fontSize.sm, lineHeight: theme.tokens.lineHeight.sm },
78
+ hDescription: { fontSize: theme.tokens.fontSize.xs, lineHeight: theme.tokens.lineHeight.sm },
54
79
 
55
80
  // vertical
56
81
  vStep: { flexDirection: 'row', gap: theme.tokens.spacing.md },
57
82
  vIndicatorColumn: { alignItems: 'center' },
58
- vConnector: { width: 2, flex: 1, minHeight: 20, marginVertical: 4 },
59
- vLabels: { flex: 1, gap: 2, paddingBottom: theme.tokens.spacing.lg },
83
+ vConnector: { width: CONNECTOR, flex: 1, minHeight: theme.tokens.spacing.xl, marginVertical: theme.tokens.spacing.xs },
84
+ vLabels: { flex: 1, gap: theme.tokens.spacing.xxs, paddingBottom: theme.tokens.spacing.lg },
85
+ // The last step has no connector below: no trailing space either.
86
+ vLabelsLast: { paddingBottom: 0 },
60
87
 
61
88
  circle: {
62
89
  width: CIRCLE,
63
90
  height: CIRCLE,
64
91
  borderRadius: CIRCLE / 2,
65
- borderWidth: 2,
92
+ borderWidth: CIRCLE_BORDER,
66
93
  alignItems: 'center',
67
94
  justifyContent: 'center',
68
95
  },
69
96
  circleNumber: { fontSize: theme.tokens.fontSize.md, fontWeight: theme.tokens.fontWeight.semibold },
70
- label: { fontSize: theme.tokens.fontSize.md, fontWeight: theme.tokens.fontWeight.semibold, color: theme.colors.text },
97
+ label: {
98
+ fontSize: theme.tokens.fontSize.md,
99
+ lineHeight: theme.tokens.lineHeight.md,
100
+ fontWeight: theme.tokens.fontWeight.semibold,
101
+ color: theme.colors.text,
102
+ },
103
+ labelCurrent: { color: theme.colors.primaryText },
104
+ labelPending: { color: theme.colors.textLight, fontWeight: theme.tokens.fontWeight.medium },
71
105
  labelCentered: { textAlign: 'center' },
72
- description: { fontSize: theme.tokens.fontSize.sm, color: theme.colors.textLight },
106
+ description: { fontSize: theme.tokens.fontSize.sm, lineHeight: theme.tokens.lineHeight.sm, color: theme.colors.textLight },
73
107
  descriptionCentered: { textAlign: 'center' },
74
108
  }));
75
109
 
@@ -81,15 +115,51 @@ function statusOf(index: number, current: number): StepStatus {
81
115
 
82
116
  /**
83
117
  * Steps
84
- * Indicador de progreso multi-paso. Base visual de `Wizard`, pero utilizable
85
- * suelto para mostrar el avance de un flujo que se navega de otra forma.
118
+ * Multi-step progress indicator. The visual base of `Wizard`, but usable on
119
+ * its own to show progress through a flow that is navigated some other way.
120
+ *
121
+ * Gestalt, continuity: a connector line runs through the circles, so the steps
122
+ * read as one path; the stretch already walked is filled with the accent.
123
+ * Similarity: every step is the same circle + label, and the state only
124
+ * changes fill and color (done = filled, current = outlined accent, pending =
125
+ * grey). Von Restorff: the current step is the only accent-colored label.
126
+ *
127
+ * Accessibility: each step announces "Step 2 of 3: Payment, current", with
128
+ * every word from `labels`.
86
129
  */
87
130
  export const Steps = memo(
88
- ({ steps, current, orientation = 'horizontal', completedIndicator = 'check', onStepPress, style }: StepsProps) => {
131
+ ({
132
+ steps,
133
+ current,
134
+ orientation = 'horizontal',
135
+ completedIndicator = 'check',
136
+ onStepPress,
137
+ style,
138
+ testID,
139
+ }: StepsProps) => {
89
140
  const colors = useColors();
141
+ const labels = useLabels();
90
142
  const styles = useStyles();
91
143
  const allowFontScaling = useAllowFontScaling();
92
144
  const isVertical = orientation === 'vertical';
145
+ const reduceMotion = useReduceMotion();
146
+
147
+ // Horizontal overflow: when the steps don't fit, the row scrolls. A hidden
148
+ // step gave no hint of existing, so the current step is brought into view
149
+ // and the scroll bar flashes once (visibility of system status).
150
+ const scrollRef = useRef<ComponentRef<typeof ScrollView>>(null);
151
+ const [viewportWidth, setViewportWidth] = useState(0);
152
+ const [contentWidth, setContentWidth] = useState(0);
153
+ const stepX = useRef<number[]>([]);
154
+ const overflows = !isVertical && viewportWidth > 0 && contentWidth > viewportWidth + 1;
155
+
156
+ useEffect(() => {
157
+ if (!overflows) return;
158
+ const x = stepX.current[current] ?? 0;
159
+ // A quarter of the row of lead-in: the previous step stays partly visible.
160
+ scrollRef.current?.scrollTo({ x: Math.max(0, x - viewportWidth / 4), animated: !reduceMotion });
161
+ scrollRef.current?.flashScrollIndicators();
162
+ }, [overflows, current, viewportWidth, reduceMotion]);
93
163
 
94
164
  const colorsFor = (status: StepStatus) => {
95
165
  if (status === 'completed') return { bg: colors.primary, border: colors.primary, fg: colors.onPrimary };
@@ -103,7 +173,7 @@ export const Steps = memo(
103
173
  return (
104
174
  <View style={[styles.circle, { backgroundColor: c.bg, borderColor: c.border }]}>
105
175
  {showCheck ? (
106
- <Icon name="check" size={18} color={c.fg} />
176
+ <Icon name="check" size={CHECK_SIZE} color={c.fg} />
107
177
  ) : (
108
178
  <Text allowFontScaling={allowFontScaling} style={[styles.circleNumber, { color: c.fg }]}>
109
179
  {index + 1}
@@ -113,15 +183,16 @@ export const Steps = memo(
113
183
  );
114
184
  };
115
185
 
116
- const renderLabels = (step: StepItem, status: StepStatus, centered: boolean) => (
117
- <View style={centered ? styles.hLabels : styles.vLabels}>
186
+ const renderLabels = (step: StepItem, status: StepStatus, centered: boolean, isLast = false) => (
187
+ <View style={centered ? styles.hLabels : [styles.vLabels, isLast && styles.vLabelsLast]}>
118
188
  <Text
119
189
  allowFontScaling={allowFontScaling}
120
190
  style={[
121
191
  styles.label,
122
192
  centered && styles.labelCentered,
123
193
  centered && styles.hLabel,
124
- status === 'pending' && { color: colors.textLight },
194
+ status === 'current' && styles.labelCurrent,
195
+ status === 'pending' && styles.labelPending,
125
196
  ]}
126
197
  >
127
198
  {step.label}
@@ -137,23 +208,28 @@ export const Steps = memo(
137
208
  </View>
138
209
  );
139
210
 
211
+ const statusLabel = { completed: labels.stepCompleted, current: labels.stepCurrent, pending: labels.stepPending };
140
212
  const stepAccessibility = (index: number, step: StepItem, status: StepStatus) => ({
141
213
  accessibilityRole: (onStepPress ? 'button' : 'text') as 'button' | 'text',
142
- accessibilityLabel: `Step ${index + 1}: ${step.label}`,
214
+ accessibilityLabel: `${labels.stepOf
215
+ .replace('{n}', String(index + 1))
216
+ .replace('{total}', String(steps.length))
217
+ .replace('{label}', step.label)}, ${statusLabel[status]}`,
143
218
  accessibilityState: { selected: status === 'current', disabled: false },
219
+ testID: testID && `${testID}-${index}`,
144
220
  });
145
221
 
146
222
  if (isVertical) {
147
223
  return (
148
- <View style={[styles.columnContainer, style]}>
224
+ <View style={[styles.columnContainer, style]} testID={testID}>
149
225
  {steps.map((step, index) => {
150
226
  const status = statusOf(index, current);
151
227
  const isLast = index === steps.length - 1;
152
228
  const Wrapper = onStepPress ? TouchableOpacity : View;
153
- // Sólo tocable si hay onStepPress: pasarle onPress/activeOpacity
154
- // a un View plano no crashea, pero los deja como ruido silencioso.
229
+ // Only touchable when there is onStepPress: passing onPress/activeOpacity
230
+ // to a plain View doesn't crash, but leaves them as silent noise.
155
231
  const interactiveProps = onStepPress
156
- ? { onPress: () => onStepPress(index), activeOpacity: 0.7 }
232
+ ? { onPress: () => onStepPress(index), activeOpacity: PRESSED_OPACITY }
157
233
  : undefined;
158
234
  return (
159
235
  <Wrapper
@@ -173,7 +249,7 @@ export const Steps = memo(
173
249
  />
174
250
  )}
175
251
  </View>
176
- {renderLabels(step, status, false)}
252
+ {renderLabels(step, status, false, isLast)}
177
253
  </Wrapper>
178
254
  );
179
255
  })}
@@ -183,11 +259,14 @@ export const Steps = memo(
183
259
 
184
260
  return (
185
261
  <ScrollView
186
- testID="steps-row"
262
+ ref={scrollRef}
263
+ testID={testID}
187
264
  horizontal
188
- showsHorizontalScrollIndicator={false}
189
- // Con espacio de sobra los pasos se reparten la fila igual que antes
190
- // (flexGrow); cuando no entran, se desplaza en vez de apretar el texto.
265
+ showsHorizontalScrollIndicator={overflows}
266
+ onLayout={(e: LayoutChangeEvent) => setViewportWidth(e.nativeEvent.layout.width)}
267
+ onContentSizeChange={(width: number) => setContentWidth(width)}
268
+ // With room to spare the steps share the row just like before
269
+ // (flexGrow); when they don't fit, it scrolls instead of squeezing the text.
191
270
  style={[styles.hScrollView, style]}
192
271
  contentContainerStyle={styles.hScroll}
193
272
  >
@@ -196,12 +275,15 @@ export const Steps = memo(
196
275
  const isLast = index === steps.length - 1;
197
276
  const Wrapper = onStepPress ? TouchableOpacity : View;
198
277
  const interactiveProps = onStepPress
199
- ? { onPress: () => onStepPress(index), activeOpacity: 0.7 }
278
+ ? { onPress: () => onStepPress(index), activeOpacity: PRESSED_OPACITY }
200
279
  : undefined;
201
280
  return (
202
281
  <React.Fragment key={`${step.label}-${index}`}>
203
282
  <Wrapper
204
283
  style={styles.hStep}
284
+ onLayout={(e: LayoutChangeEvent) => {
285
+ stepX.current[index] = e.nativeEvent.layout.x;
286
+ }}
205
287
  {...interactiveProps}
206
288
  {...stepAccessibility(index, step, status)}
207
289
  >
@@ -1,10 +1,14 @@
1
1
  import React, { useMemo } from 'react';
2
2
  import { View, type StyleProp, type ViewStyle } from 'react-native';
3
3
  import { createStyles } from '../theme/createStyles';
4
+ import { useTheme } from '../theme/UIProvider';
4
5
 
5
6
  export interface SymmetricGridProps<T> {
7
+ /** Items to lay out, in reading order. */
6
8
  data: T[];
9
+ /** Renders one cell; it gets the full cell width. */
7
10
  renderItem: (item: T, index: number) => React.ReactElement;
11
+ /** Stable key per item. */
8
12
  keyExtractor: (item: T, index: number) => string;
9
13
  /** Columns per row. @default 2 */
10
14
  columns?: number;
@@ -16,11 +20,11 @@ export interface SymmetricGridProps<T> {
16
20
  */
17
21
  balanceLastRow?: boolean;
18
22
  style?: StyleProp<ViewStyle>;
23
+ testID?: string;
19
24
  }
20
25
 
21
- const useStyles = createStyles((theme) => ({
22
- grid: { gap: theme.tokens.spacing.md },
23
- row: { flexDirection: 'row', gap: theme.tokens.spacing.md },
26
+ const useStyles = createStyles(() => ({
27
+ row: { flexDirection: 'row' },
24
28
  rowBalanced: { justifyContent: 'center' },
25
29
  rowFull: { justifyContent: 'flex-start' },
26
30
  cell: { flexGrow: 0, flexShrink: 0 },
@@ -34,10 +38,16 @@ function chunk<T>(data: T[], size: number): T[][] {
34
38
 
35
39
  /**
36
40
  * SymmetricGrid
37
- * Ley de Prägnanz (buena forma): agrupa en filas parejas de N columnas.
38
- * La última fila, cuando queda incompleta, se centra por defecto en vez de
39
- * quedar pegada a un borde — eso es lo que la lee como "fila corta" y no
40
- * como un layout roto con un hueco a un lado.
41
+ * Law of Prägnanz (good form): groups items into even rows of N columns.
42
+ * The last row, when incomplete, is centered by default instead of sticking
43
+ * to one edge — that is what makes it read as a "short row" and not as a
44
+ * broken layout with a gap on one side.
45
+ *
46
+ * Gestalt, similarity: every cell has exactly the same width, also in the
47
+ * centered short row, so items read as peers. The horizontal gap is padding
48
+ * inside each cell (and a negative margin on the row), not flex `gap`: a
49
+ * `100 / columns %` width plus a gap made every row wider than the grid and
50
+ * pushed the right column out of the container.
41
51
  */
42
52
  export function SymmetricGrid<T>({
43
53
  data,
@@ -47,13 +57,16 @@ export function SymmetricGrid<T>({
47
57
  gap,
48
58
  balanceLastRow = true,
49
59
  style,
60
+ testID,
50
61
  }: SymmetricGridProps<T>) {
62
+ const theme = useTheme();
51
63
  const styles = useStyles();
52
64
  const rows = useMemo(() => chunk(data, columns), [data, columns]);
65
+ const space = gap ?? theme.tokens.spacing.md;
53
66
  const cellWidth = `${100 / columns}%` as const;
54
67
 
55
68
  return (
56
- <View style={[styles.grid, gap !== undefined && { gap }, style]}>
69
+ <View style={[{ gap: space }, style]} testID={testID}>
57
70
  {rows.map((row, rowIndex) => {
58
71
  const isLastRow = rowIndex === rows.length - 1;
59
72
  const isIncomplete = row.length < columns;
@@ -61,15 +74,18 @@ export function SymmetricGrid<T>({
61
74
 
62
75
  return (
63
76
  <View
64
- // `columns` en la key: si cambia, las filas no reusan nodos DOM
65
- // de una fila armada con otra cantidad de columnas.
77
+ // `columns` in the key: if it changes, rows don't reuse DOM nodes
78
+ // from a row built with a different number of columns.
66
79
  key={`row-${columns}-${rowIndex}`}
67
- style={[styles.row, centered ? styles.rowBalanced : styles.rowFull, gap !== undefined && { gap }]}
80
+ style={[styles.row, centered ? styles.rowBalanced : styles.rowFull, { marginHorizontal: -space / 2 }]}
68
81
  >
69
82
  {row.map((item, colIndex) => {
70
83
  const index = rowIndex * columns + colIndex;
71
84
  return (
72
- <View key={keyExtractor(item, index)} style={[styles.cell, { width: cellWidth }]}>
85
+ <View
86
+ key={keyExtractor(item, index)}
87
+ style={[styles.cell, { width: cellWidth, paddingHorizontal: space / 2 }]}
88
+ >
73
89
  {renderItem(item, index)}
74
90
  </View>
75
91
  );