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,49 +1,65 @@
1
1
  import React, { memo, useEffect, useState } from 'react';
2
2
  import {
3
- Dimensions,
4
3
  KeyboardAvoidingView,
5
- Modal as RNModal,
6
4
  Platform,
7
5
  Pressable,
8
6
  ScrollView,
9
7
  View,
8
+ useWindowDimensions,
10
9
  type ModalProps as RNModalProps,
11
10
  type ViewStyle,
12
11
  } from 'react-native';
13
12
  import { createStyles } from '../theme/createStyles';
14
- import { useColors, useModalSafeAreaBoundary } from '../theme/UIProvider';
13
+ import { useLabels, useModalSafeAreaBoundary, useTheme } from '../theme/UIProvider';
14
+ import { NativeOverlay } from '../theme/NativeOverlay';
15
+ import { KeyboardHandled } from '../theme/KeyboardAvoidance';
15
16
  import type { EdgeInsets } from '../theme/insets';
16
17
  import { Title } from '../atoms/Text';
17
18
  import { IconButton } from '../atoms/IconButton';
18
19
  import { Transition, type TransitionPreset } from '../atoms/Transition';
19
20
 
20
- const { height: SCREEN_HEIGHT } = Dimensions.get('window');
21
-
22
21
  export type ModalVariant = 'full' | 'overlay' | 'fullScreen';
23
22
 
24
23
  export interface ModalProps
25
24
  extends Pick<RNModalProps, 'statusBarTranslucent' | 'onRequestClose' | 'hardwareAccelerated'> {
25
+ /** Shows or hides the modal. The animated variants play their exit before unmounting. */
26
26
  visible: boolean;
27
+ /**
28
+ * Shows the close button in the header and is called by it, by a tap on the backdrop (`overlay`) and
29
+ * by Android's back button.
30
+ */
27
31
  onClose?: () => void;
32
+ /** Header title, on a single line. */
28
33
  title?: string;
34
+ /** Accessible name of the close button. @default labels.close */
29
35
  closeAccessibilityLabel?: string;
36
+ /** Body of the modal. */
30
37
  children: React.ReactNode;
38
+ /** Fixed area below the content (e.g. actions); it doesn't scroll. */
31
39
  footer?: React.ReactNode;
40
+ /** Style of the card (`overlay`) or the full-screen wrapper. */
32
41
  containerStyle?: ViewStyle;
42
+ /** Style of the content area (the scroll container when `scrollable`). */
33
43
  contentStyle?: ViewStyle;
44
+ /**
45
+ * 'full' slides up a full page, 'overlay' a centered card over a dimmed backdrop, 'fullScreen' uses
46
+ * the native full-screen presentation. @default 'full'
47
+ */
34
48
  variant?: ModalVariant;
49
+ /** Wraps the content in a ScrollView. @default true */
35
50
  scrollable?: boolean;
36
51
  }
37
52
 
38
53
  const useStyles = createStyles((theme) => ({
39
54
  flex1: { flex: 1 },
40
- fullWrapper: { flex: 1, backgroundColor: theme.colors.background },
41
- overlayContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: theme.tokens.spacing.xxl - 4 },
55
+ fullWrapper: { flex: 1, backgroundColor: theme.colors.surface },
56
+ overlayContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: theme.tokens.spacing.xl },
42
57
  backdrop: { backgroundColor: theme.colors.overlay },
43
58
  overlayCard: {
44
59
  width: '100%',
45
60
  maxHeight: '85%',
46
- backgroundColor: theme.colors.surface,
61
+ // Raised: in dark mode the plain surface sank into the dimmed backdrop.
62
+ backgroundColor: theme.colors.surfaceRaised,
47
63
  borderRadius: theme.tokens.radius.xxl,
48
64
  overflow: 'hidden',
49
65
  ...theme.tokens.shadow.lg,
@@ -55,11 +71,11 @@ const useStyles = createStyles((theme) => ({
55
71
  padding: theme.tokens.spacing.xl,
56
72
  borderBottomWidth: 1,
57
73
  borderBottomColor: theme.colors.border,
58
- backgroundColor: theme.colors.surface,
59
74
  },
60
75
  title: { fontSize: theme.tokens.fontSize.xl, fontWeight: theme.tokens.fontWeight.bold, flex: 1 },
61
76
  closeButton: { marginLeft: theme.tokens.spacing.md },
62
- contentWrapper: { flexShrink: 1, backgroundColor: theme.colors.surface },
77
+ cardInner: { flexShrink: 1 },
78
+ contentWrapper: { flexShrink: 1 },
63
79
  scrollWrapper: { flexShrink: 1 },
64
80
  scrollContent: { padding: theme.tokens.spacing.xl, flexGrow: 1 },
65
81
  scrollContentFull: { padding: 0, flexGrow: 1 },
@@ -67,22 +83,38 @@ const useStyles = createStyles((theme) => ({
67
83
  padding: theme.tokens.spacing.xl,
68
84
  borderTopWidth: 1,
69
85
  borderTopColor: theme.colors.border,
70
- backgroundColor: theme.colors.surface,
71
86
  },
72
87
  }));
73
88
 
89
+ /** Close glyph: the same size BottomSheet uses; IconButton pads it to 44pt. */
90
+ const CLOSE_ICON_SIZE = 24;
91
+ /** How far the `overlay` card drops in while it scales up. */
92
+ const OVERLAY_ENTER_DISTANCE = 40;
93
+
94
+
74
95
  /**
75
96
  * Modal
76
- * Un solo componente para todos los modales de la app: maneja scroll,
77
- * teclado, insets y layout según `variant`. Para una hoja desde abajo está
78
- * BottomSheet, que además trae arrastre para cerrar.
97
+ * A single component for all of the app's modals: handles scroll, keyboard,
98
+ * insets and layout according to `variant`. For a sheet from the bottom there
99
+ * is BottomSheet, which also comes with drag to close.
100
+ *
101
+ * Design:
102
+ * - Figure and ground (Gestalt): `overlay` dims the screen behind a raised
103
+ * card, so the task in front is the only figure.
104
+ * - Common region: header, content and footer share one surface, split by
105
+ * hairlines; the footer stays fixed so its actions are always in reach.
106
+ * - Jakob's law: title on the left, close at the top right, Android back and
107
+ * the VoiceOver escape gesture close it, like the system's own sheets.
108
+ * - Fitts's law: the close button is a 44pt target.
109
+ * - Screen readers stay inside the modal (`accessibilityViewIsModal`), which
110
+ * matters on iOS when it is drawn inside another open overlay.
79
111
  */
80
112
  export const Modal = memo(
81
113
  ({
82
114
  visible,
83
115
  onClose,
84
116
  title,
85
- closeAccessibilityLabel = 'Close',
117
+ closeAccessibilityLabel,
86
118
  children,
87
119
  footer,
88
120
  containerStyle,
@@ -98,8 +130,12 @@ export const Modal = memo(
98
130
  const isFullScreen = variant === 'fullScreen';
99
131
  const isAnimatedVariant = isOverlay || isFull;
100
132
  const ModalSafeAreaBoundary = useModalSafeAreaBoundary();
101
- const colors = useColors();
133
+ const theme = useTheme();
134
+ const { colors } = theme;
102
135
  const styles = useStyles();
136
+ const labels = useLabels();
137
+ const closeLabel = closeAccessibilityLabel ?? labels.close;
138
+ const { height: windowHeight } = useWindowDimensions();
103
139
 
104
140
  const [mounted, setMounted] = useState(!isAnimatedVariant && visible);
105
141
 
@@ -108,10 +144,10 @@ export const Modal = memo(
108
144
  else if (visible) setMounted(true);
109
145
  }, [visible, isAnimatedVariant]);
110
146
 
111
- // La tarjeta nunca anima opacity: hacerlo dispara un bug de Android donde
112
- // los hijos con elevation parpadean. El fondo semitransparente sí.
147
+ // The card never animates opacity: doing so triggers an Android bug where
148
+ // children with elevation flicker. The semi-transparent backdrop does.
113
149
  const cardPreset: TransitionPreset[] = isFull ? ['slide-up'] : ['slide-down', 'scale'];
114
- const cardDistance = isFull ? SCREEN_HEIGHT : 40;
150
+ const cardDistance = isFull ? windowHeight : OVERLAY_ENTER_DISTANCE;
115
151
 
116
152
  const behavior = Platform.OS === 'ios' ? (isFull ? undefined : 'padding') : 'height';
117
153
  const keyboardOffset = Platform.OS === 'ios' ? 0 : 20;
@@ -127,7 +163,14 @@ export const Modal = memo(
127
163
  )}
128
164
  {!title && <View style={styles.flex1} />}
129
165
  {!!onClose && (
130
- <IconButton iconName="close" size={24} color={colors.text} onPress={onClose} accessibilityLabel={closeAccessibilityLabel} style={styles.closeButton} />
166
+ <IconButton
167
+ iconName="close"
168
+ size={CLOSE_ICON_SIZE}
169
+ color={colors.text}
170
+ onPress={onClose}
171
+ accessibilityLabel={closeLabel}
172
+ style={styles.closeButton}
173
+ />
131
174
  )}
132
175
  </View>
133
176
  );
@@ -156,42 +199,17 @@ export const Modal = memo(
156
199
 
157
200
  const renderFooter = () => (footer ? <View style={styles.footer}>{footer}</View> : null);
158
201
 
159
- if (!mounted) return null;
160
-
161
- return (
162
- <RNModal
163
- visible
164
- onRequestClose={onRequestClose ?? onClose}
165
- animationType={isAnimatedVariant ? 'none' : 'slide'}
166
- // `full` anima su propia entrada (translateY) con animationType="none"
167
- // y necesita `transparent` para que no se vea un fondo negro detrás
168
- // mientras desliza. RN sólo admite `transparent` junto a
169
- // 'overFullScreen' — con 'pageSheet' avisa que la combinación no está
170
- // soportada. Por eso `full` usa overFullScreen: la presentación nativa
171
- // de pageSheet sería redundante con nuestra animación de todos modos.
172
- presentationStyle={
173
- Platform.OS === 'ios' ? (isFullScreen ? 'fullScreen' : 'overFullScreen') : undefined
174
- }
175
- transparent={isOverlay || isFull}
176
- statusBarTranslucent={statusBarTranslucent}
177
- hardwareAccelerated={hardwareAccelerated}
178
- >
179
- <KeyboardAvoidingView behavior={behavior} keyboardVerticalOffset={keyboardOffset} style={styles.flex1}>
180
- {/* Insets medidos dentro de esta ventana nativa del Modal, no los de
181
- la raíz de la app — pueden diferir (Android siempre abre una
182
- ventana propia; iOS según `presentationStyle`). */}
183
- <ModalSafeAreaBoundary>
184
- {(insets: EdgeInsets) =>
202
+ const renderBody = (insets: EdgeInsets) =>
185
203
  isOverlay ? (
186
204
  <View style={styles.overlayContainer}>
187
- {/* Sin accessibilityLabel propio: el header ya expone un botón "Close"
188
- accesible; duplicar el label aquí generaría dos elementos con el
189
- mismo nombre para lectores de pantalla. Tocar afuera es un atajo
190
- puramente táctil. */}
205
+ {/* No accessibilityLabel of its own: the header already exposes an
206
+ accessible "Close" button; duplicating the label here would create
207
+ two elements with the same name for screen readers. Tapping
208
+ outside is a purely tactile shortcut. */}
191
209
  <Transition
192
210
  visible={visible}
193
211
  preset="fade"
194
- duration={200}
212
+ duration={theme.tokens.duration.base}
195
213
  keepMounted
196
214
  style={[{ ...StyleSheetAbsoluteFill }, styles.backdrop]}
197
215
  >
@@ -202,13 +220,15 @@ export const Modal = memo(
202
220
  visible={visible}
203
221
  preset={cardPreset}
204
222
  distance={cardDistance}
205
- duration={250}
223
+ duration={theme.tokens.duration.slow}
206
224
  onExited={() => setMounted(false)}
207
225
  style={[styles.overlayCard, containerStyle]}
208
226
  >
209
- {renderHeader()}
210
- {renderMainContent()}
211
- {renderFooter()}
227
+ <View style={styles.cardInner} accessibilityViewIsModal onAccessibilityEscape={onClose}>
228
+ {renderHeader()}
229
+ {renderMainContent()}
230
+ {renderFooter()}
231
+ </View>
212
232
  </Transition>
213
233
  </View>
214
234
  ) : isFull ? (
@@ -216,29 +236,68 @@ export const Modal = memo(
216
236
  visible={visible}
217
237
  preset={cardPreset}
218
238
  distance={cardDistance}
219
- duration={250}
239
+ duration={theme.tokens.duration.slow}
220
240
  onExited={() => setMounted(false)}
221
241
  style={[styles.fullWrapper, containerStyle]}
222
242
  >
223
- <View style={[styles.flex1, { paddingTop: insets.top, paddingBottom: insets.bottom }]}>
243
+ <View
244
+ style={[styles.flex1, { paddingTop: insets.top, paddingBottom: insets.bottom }]}
245
+ accessibilityViewIsModal
246
+ onAccessibilityEscape={onClose}
247
+ >
224
248
  {renderHeader()}
225
249
  {renderMainContent()}
226
250
  {renderFooter()}
227
251
  </View>
228
252
  </Transition>
229
253
  ) : (
230
- <View style={[styles.fullWrapper, containerStyle]}>
231
- <View style={[styles.flex1, { paddingTop: insets.top, paddingBottom: insets.bottom }]}>
254
+ <View
255
+ style={[styles.fullWrapper, containerStyle]}
256
+ >
257
+ <View
258
+ style={[styles.flex1, { paddingTop: insets.top, paddingBottom: insets.bottom }]}
259
+ accessibilityViewIsModal
260
+ onAccessibilityEscape={onClose}
261
+ >
232
262
  {renderHeader()}
233
263
  {renderMainContent()}
234
264
  {renderFooter()}
235
265
  </View>
236
266
  </View>
237
- )
238
- }
239
- </ModalSafeAreaBoundary>
267
+ );
268
+
269
+ if (!mounted) return null;
270
+
271
+
272
+ return (
273
+ <NativeOverlay
274
+ // closing: while the exit animation plays, no other overlay layers into it.
275
+ closing={!visible}
276
+ onRequestClose={onRequestClose ?? onClose}
277
+ animationType={isAnimatedVariant ? 'none' : 'slide'}
278
+ // `full` animates its own entrance (translateY) with animationType="none"
279
+ // and needs `transparent` so no black background shows behind it
280
+ // while sliding. RN only allows `transparent` together with
281
+ // 'overFullScreen' — with 'pageSheet' it warns that the combination
282
+ // isn't supported. That's why `full` uses overFullScreen: pageSheet's
283
+ // native presentation would be redundant with our animation anyway.
284
+ presentationStyle={
285
+ Platform.OS === 'ios' ? (isFullScreen ? 'fullScreen' : 'overFullScreen') : undefined
286
+ }
287
+ transparent={isOverlay || isFull}
288
+ statusBarTranslucent={statusBarTranslucent}
289
+ hardwareAccelerated={hardwareAccelerated}
290
+ >
291
+ {/* Its own native window: its KeyboardAvoidingView compensates for it, not the root host. */}
292
+ <KeyboardHandled>
293
+ <KeyboardAvoidingView behavior={behavior} keyboardVerticalOffset={keyboardOffset} style={styles.flex1}>
294
+ {/* Insets measured inside this native Modal window, not the app
295
+ root's — they may differ (Android always opens its own window;
296
+ iOS depending on `presentationStyle`). */}
297
+ <ModalSafeAreaBoundary>{renderBody}</ModalSafeAreaBoundary>
240
298
  </KeyboardAvoidingView>
241
- </RNModal>
299
+ </KeyboardHandled>
300
+ </NativeOverlay>
242
301
  );
243
302
  }
244
303
  );
@@ -1,6 +1,8 @@
1
1
  import React, { memo, useEffect, useRef, useState } from 'react';
2
2
  import {
3
3
  Animated,
4
+ Keyboard,
5
+ Platform,
4
6
  StyleSheet,
5
7
  Text,
6
8
  TouchableOpacity,
@@ -11,6 +13,7 @@ import {
11
13
  } from 'react-native';
12
14
  import { createStyles } from '../theme/createStyles';
13
15
  import { useAllowFontScaling, useColors, useInsets, useTheme } from '../theme/UIProvider';
16
+ import { useReduceMotion } from '../theme/useReduceMotion';
14
17
  import { Icon } from '../icons/Icon';
15
18
  import type { IconName } from '../icons/types';
16
19
 
@@ -18,24 +21,40 @@ export interface NavigationBarItem {
18
21
  key: string;
19
22
  label: string;
20
23
  iconName?: IconName;
21
- /** Contador sobre el ícono. `true` pinta sólo el punto. */
24
+ /** Counter over the icon, also read by screen readers. `true` shows only the dot. */
22
25
  badge?: number | string | true;
23
26
  }
24
27
 
25
28
  export interface NavigationBarProps {
29
+ /** The destinations: key, label, and optionally an icon and a badge. */
26
30
  items: NavigationBarItem[];
31
+ /** Key of the selected item (controlled). */
27
32
  activeKey: string;
33
+ /** Called with the key of the pressed item. */
28
34
  onChange: (key: string) => void;
29
35
  /** Screen edge where the bar lives. @default 'bottom' */
30
36
  position?: 'bottom' | 'top';
31
- /** @default true */
37
+ /** Shows the label under each icon. @default true */
32
38
  showLabels?: boolean;
33
39
  /** Adds the safe area inset for the edge where the bar lives. @default true */
34
40
  safeArea?: boolean;
41
+ /**
42
+ * Hides a bottom bar while the keyboard is open, like native tab bars, so
43
+ * it doesn't sit between the field and the keyboard. Only Android needs it:
44
+ * on iOS the keyboard already covers the bar. @default true
45
+ */
46
+ hideOnKeyboard?: boolean;
35
47
  style?: StyleProp<ViewStyle>;
36
48
  testID?: string;
37
49
  }
38
50
 
51
+ /** Counter badge: a pill that still fits two digits over a 22pt icon. */
52
+ const BADGE_SIZE = 16;
53
+ const BADGE_DOT_SIZE = 10;
54
+ const BADGE_FONT_SIZE = 10;
55
+ /** Indicator spring: settles fast without bouncing past the tab. */
56
+ const INDICATOR_SPRING = { friction: 9, tension: 90 };
57
+
39
58
  const useStyles = createStyles((theme) => ({
40
59
  bar: {
41
60
  flexDirection: 'row',
@@ -50,32 +69,32 @@ const useStyles = createStyles((theme) => ({
50
69
  position: 'absolute',
51
70
  top: theme.tokens.spacing.xs,
52
71
  bottom: theme.tokens.spacing.xs,
53
- // El indicador se posiciona contra el borde de la barra, no contra su caja
54
- // interna: al `left` hay que sumarle el padding horizontal para que quede
55
- // centrado sobre la pestaña y no corrido hacia la izquierda.
72
+ // The indicator is positioned against the bar's edge, not its inner box:
73
+ // the horizontal padding has to be added to `left` so it sits centered
74
+ // over the tab and not shifted to the left.
56
75
  left: theme.tokens.spacing.xs + theme.tokens.spacing.sm,
57
76
  borderRadius: theme.tokens.radius.lg,
58
77
  backgroundColor: theme.colors.primarySoft,
59
78
  },
60
79
  item: { flex: 1, paddingVertical: theme.tokens.spacing.xs },
61
- itemContent: { alignItems: 'center', justifyContent: 'center', gap: 2 },
80
+ itemContent: { alignItems: 'center', justifyContent: 'center', gap: theme.tokens.spacing.xxs },
62
81
  label: { fontSize: theme.tokens.fontSize.xs, fontWeight: theme.tokens.fontWeight.medium },
63
82
  badge: {
64
83
  position: 'absolute',
65
- top: -4,
84
+ top: -theme.tokens.spacing.xs,
66
85
  left: '50%',
67
- marginLeft: 4,
68
- minWidth: 16,
69
- height: 16,
70
- paddingHorizontal: 4,
86
+ marginLeft: theme.tokens.spacing.xs,
87
+ minWidth: BADGE_SIZE,
88
+ height: BADGE_SIZE,
89
+ paddingHorizontal: theme.tokens.spacing.xs,
71
90
  borderRadius: theme.tokens.radius.full,
72
91
  backgroundColor: theme.colors.error,
73
92
  alignItems: 'center',
74
93
  justifyContent: 'center',
75
94
  },
76
- badgeDot: { minWidth: 10, height: 10, top: -2, paddingHorizontal: 0 },
95
+ badgeDot: { minWidth: BADGE_DOT_SIZE, height: BADGE_DOT_SIZE, top: -theme.tokens.spacing.xxs, paddingHorizontal: 0 },
77
96
  badgeText: {
78
- fontSize: 10,
97
+ fontSize: BADGE_FONT_SIZE,
79
98
  fontWeight: theme.tokens.fontWeight.bold,
80
99
  color: theme.colors.onError,
81
100
  },
@@ -85,10 +104,20 @@ const ICON_SIZE = 22;
85
104
 
86
105
  /**
87
106
  * NavigationBar
88
- * Barra de navegación por pestañas con la misma apariencia y las mismas
89
- * transiciones en iOS y Android: el indicador se desliza hasta la pestaña
90
- * activa y su contenido crece y toma el color de acento con un cross-fade.
91
- * No navega por su cuenta — reporta la pestaña tocada y el consumidor decide.
107
+ * Tab navigation bar with the same look and the same transitions on iOS and
108
+ * Android: the indicator slides to the active tab and its content grows and
109
+ * takes the accent color with a cross-fade.
110
+ * It doesn't navigate on its own — it reports the tapped tab and the consumer decides.
111
+ *
112
+ * Design:
113
+ * - Jakob's law: the tab bar people know from every app, at the bottom by
114
+ * default, icon over label.
115
+ * - Similarity + Von Restorff: every tab looks the same except the active
116
+ * one, which alone gets the accent and the indicator.
117
+ * - Continuity: the indicator slides from tab to tab instead of jumping
118
+ * (in place with Reduce Motion).
119
+ * - Fitts's law: the whole column is the target, not just the icon.
120
+ * - Hick's law: meant for 3–5 destinations.
92
121
  */
93
122
  export const NavigationBar = memo(
94
123
  ({
@@ -98,6 +127,7 @@ export const NavigationBar = memo(
98
127
  position = 'bottom',
99
128
  showLabels = true,
100
129
  safeArea = true,
130
+ hideOnKeyboard = true,
101
131
  style,
102
132
  testID,
103
133
  }: NavigationBarProps) => {
@@ -106,8 +136,23 @@ export const NavigationBar = memo(
106
136
  const styles = useStyles();
107
137
  const insets = useInsets();
108
138
  const allowFontScaling = useAllowFontScaling();
139
+ const reduceMotion = useReduceMotion();
109
140
 
110
141
  const [barWidth, setBarWidth] = useState(0);
142
+ const [keyboardOpen, setKeyboardOpen] = useState(false);
143
+
144
+ // On Android the window shrinks with the keyboard and the bar would end up
145
+ // floating above it, between the field and the keys. On iOS the keyboard
146
+ // covers it: no need (and hiding it would move the layout midway through
147
+ // the keyboard animation).
148
+ useEffect(() => {
149
+ if (!hideOnKeyboard || position !== 'bottom' || Platform.OS !== 'android') return;
150
+ const subs = [
151
+ Keyboard.addListener('keyboardDidShow', () => setKeyboardOpen(true)),
152
+ Keyboard.addListener('keyboardDidHide', () => setKeyboardOpen(false)),
153
+ ];
154
+ return () => subs.forEach((sub) => sub.remove());
155
+ }, [hideOnKeyboard, position]);
111
156
  const slide = useRef(new Animated.Value(0)).current;
112
157
  const placed = useRef(false);
113
158
 
@@ -120,15 +165,16 @@ export const NavigationBar = memo(
120
165
  useEffect(() => {
121
166
  if (itemWidth <= 0) return;
122
167
  const to = activeIndex * itemWidth;
123
- // En el primer layout el indicador aparece en su lugar; animarlo desde 0
124
- // sería un deslizamiento que el usuario no pidió.
125
- if (!placed.current) {
168
+ // On the first layout the indicator appears in place; animating it from 0
169
+ // would be a slide the user didn't ask for.
170
+ // With Reduce Motion it moves without the slide, too.
171
+ if (!placed.current || reduceMotion) {
126
172
  placed.current = true;
127
173
  slide.setValue(to);
128
174
  return;
129
175
  }
130
- Animated.spring(slide, { toValue: to, useNativeDriver: true, friction: 9, tension: 90 }).start();
131
- }, [activeIndex, itemWidth, slide]);
176
+ Animated.spring(slide, { toValue: to, useNativeDriver: true, ...INDICATOR_SPRING }).start();
177
+ }, [activeIndex, itemWidth, slide, reduceMotion]);
132
178
 
133
179
  const onLayout = (e: LayoutChangeEvent) => {
134
180
  const next = e.nativeEvent.layout.width - theme.tokens.spacing.xs * 2;
@@ -146,6 +192,8 @@ export const NavigationBar = memo(
146
192
  </>
147
193
  );
148
194
 
195
+ if (keyboardOpen) return null;
196
+
149
197
  return (
150
198
  <View
151
199
  testID={testID}
@@ -196,10 +244,12 @@ export const NavigationBar = memo(
196
244
  accessibilityRole="tab"
197
245
  accessibilityLabel={item.label}
198
246
  accessibilityState={{ selected: active }}
247
+ // The badge is drawn, not text the reader reaches: its count goes in the value.
248
+ accessibilityValue={typeof item.badge === 'number' || typeof item.badge === 'string' ? { text: String(item.badge) } : undefined}
199
249
  >
200
250
  <Animated.View style={[styles.itemContent, { transform: [{ scale }] }]}>
201
251
  {renderContent(item, colors.textLight)}
202
- {/* Copia decorativa: sin ocultarla, el lector lee el label dos veces. */}
252
+ {/* Decorative copy: if it weren't hidden, the reader would read the label twice. */}
203
253
  <Animated.View
204
254
  pointerEvents="none"
205
255
  accessibilityElementsHidden