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
@@ -22,16 +22,26 @@ export interface SearchListProps<T> {
22
22
  /** Optional chrome above the search bar (e.g. back button + title). */
23
23
  header?: React.ReactNode;
24
24
 
25
+ /** Text of the search box (controlled). */
25
26
  searchValue: string;
27
+ /** Called with the new text; the clear button calls it with an empty string. */
26
28
  onSearchChange: (text: string) => void;
29
+ /** Placeholder of the search box. @default labels.search */
27
30
  searchPlaceholder?: string;
31
+ /** Shows a spinner inside the search box. @default false */
28
32
  searchIsLoading?: boolean;
33
+ /** Shows a button next to the search box and is called when it is pressed. */
29
34
  onScanPress?: () => void;
35
+ /** Accessible name of the `onScanPress` button. @default labels.scan */
30
36
  scanAccessibilityLabel?: string;
37
+ /** Extra nodes at the end of the search row. */
31
38
  extraActions?: React.ReactNode;
32
39
 
40
+ /** Items to render. */
33
41
  data: T[];
42
+ /** Stable key per item. */
34
43
  keyExtractor: (item: T, index: number) => string;
44
+ /** Renders each row (same as FlatList's `renderItem`). */
35
45
  renderItem: FlatListProps<T>['renderItem'];
36
46
 
37
47
  /** Initial load: while true and there's no data, placeholders are shown. */
@@ -40,12 +50,23 @@ export interface SearchListProps<T> {
40
50
  loadingMode?: 'replace' | 'overlay';
41
51
  /** Reload with data already on screen (pull-to-refresh). @default false */
42
52
  isRefreshing?: boolean;
53
+ /** Shows a spinner in the footer while the next page loads. @default false */
43
54
  isLoadingMore?: boolean;
44
55
  /** Controlled by the consumer: while false, a fullscreen spinner is shown. @default true */
45
56
  isReady?: boolean;
57
+ /**
58
+ * Text of the spinner shown while `isReady` is false and of the `overlay` loading. @default
59
+ * labels.loading
60
+ */
46
61
  loadingText?: string;
62
+ /** Text of the footer spinner shown with `isLoadingMore`. @default labels.loadingMore */
47
63
  loadingMoreText?: string;
64
+ /**
65
+ * Whether more pages remain. While false, `noMoreText` shows at the end of a non-empty list.
66
+ * @default false
67
+ */
48
68
  hasMore?: boolean;
69
+ /** Text shown at the end of the list when `hasMore` is false. */
49
70
  noMoreText?: string;
50
71
 
51
72
  /** Ghost rows for the initial load. @default 6 */
@@ -53,31 +74,43 @@ export interface SearchListProps<T> {
53
74
  /** Custom placeholder, to match the real shape of the item. */
54
75
  renderSkeletonItem?: () => React.ReactElement;
55
76
 
77
+ /** Called when scrolling gets close to the end. Takes precedence over `onEndReached`. */
56
78
  onLoadMore?: () => void;
79
+ /** Called when scrolling gets close to the end. Ignored when `onLoadMore` is passed. */
57
80
  onEndReached?: () => void;
81
+ /** How close to the end `onEndReached` fires, in visible lengths of the list. @default 0.3 */
58
82
  onEndReachedThreshold?: number;
83
+ /** Enables pull-to-refresh and is called when the user pulls. */
59
84
  onRefresh?: () => void;
60
85
 
86
+ /** Title of the empty state. @default labels.noResultsTitle */
61
87
  emptyTitle?: string;
88
+ /** Supporting line of the empty state. @default labels.noResultsDescription */
62
89
  emptyDescription?: string;
90
+ /** Icon of the empty state. @default 'search' */
63
91
  emptyIconName?: IconName;
64
92
 
93
+ /** Rendered above the items, inside the scroll. */
65
94
  ListHeaderComponent?: FlatListProps<T>['ListHeaderComponent'];
95
+ /** Rendered below the items, before the pagination loader and `noMoreText`. */
66
96
  ListFooterComponent?: FlatListProps<T>['ListFooterComponent'];
67
97
 
98
+ /** Style of the list's content container (also used by the skeleton). */
68
99
  contentContainerStyle?: StyleProp<ViewStyle>;
100
+ /** Style of the outer wrapper. */
69
101
  containerStyle?: ViewStyle;
70
102
 
71
103
  /** List component to use (FlashList, etc). @default FlatList */
72
104
  ListComponent?: React.ComponentType<any>;
105
+ /** Extra props passed to `ListComponent`; they override the ones set here. */
73
106
  listProps?: Record<string, unknown>;
74
107
  }
75
108
 
76
109
  const useStyles = createStyles((theme) => ({
77
110
  container: { flex: 1 },
78
- searchRow: { flexDirection: 'row', alignItems: 'center', marginBottom: theme.tokens.spacing.lg - 1, gap: theme.tokens.spacing.sm + 2 },
111
+ searchRow: { flexDirection: 'row', alignItems: 'center', marginBottom: theme.tokens.spacing.lg, gap: theme.tokens.spacing.md },
79
112
  searchInput: { flex: 1, marginBottom: 0 },
80
- scanButton: { backgroundColor: theme.colors.primary, width: 50, height: 50, borderRadius: theme.tokens.radius.lg, ...theme.tokens.shadow.sm },
113
+ scanButton: { backgroundColor: theme.colors.primary, width: SCAN_SIZE, height: SCAN_SIZE, borderRadius: theme.tokens.radius.lg, ...theme.tokens.shadow.sm },
81
114
  listArea: { flex: 1 },
82
115
  listContent: { paddingBottom: theme.tokens.spacing.xl },
83
116
  loadingOverlay: {
@@ -99,14 +132,30 @@ const useStyles = createStyles((theme) => ({
99
132
  gap: theme.tokens.spacing.md,
100
133
  padding: theme.tokens.spacing.md,
101
134
  },
102
- skeletonText: { flex: 1, gap: theme.tokens.spacing.sm },
135
+ skeletonText: { flex: 1 },
136
+ empty: { marginTop: theme.tokens.spacing.xxxl },
103
137
  }));
104
138
 
139
+ /** The scan button is square and as tall as the search Input beside it. */
140
+ const SCAN_SIZE = 50;
141
+ /** Same as Avatar's default size: the placeholder row matches a typical avatar row. */
142
+ const SKELETON_AVATAR = 44;
143
+
105
144
  /**
106
145
  * SearchList
107
- * Buscador + lista + estados de carga/paginación/vacío. El contenido de
108
- * cada ítem (renderItem) queda a cargo de quien la usa, ya que difiere por
109
- * completo entre casos de uso.
146
+ * Search box + list + loading/pagination/empty states. The content of each
147
+ * item (renderItem) is up to whoever uses it, since it differs completely
148
+ * between use cases.
149
+ *
150
+ * Design:
151
+ * - Proximity + common region: the search row (box, scan, extra actions)
152
+ * sits right on top of the results it filters.
153
+ * - Doherty threshold: every wait has immediate feedback (placeholders, a
154
+ * spinner in the box while searching, a footer loader while paging), and
155
+ * "no results" only appears once it is known there is nothing.
156
+ * - Jakob's law: the clear (×) inside the box, pull-to-refresh, the keyboard
157
+ * dismissed when the list is dragged.
158
+ * - Fitts's law: the scan button is as tall as the box, a 50pt target.
110
159
  */
111
160
  export function SearchList<T>({
112
161
  header,
@@ -115,7 +164,7 @@ export function SearchList<T>({
115
164
  searchPlaceholder,
116
165
  searchIsLoading = false,
117
166
  onScanPress,
118
- scanAccessibilityLabel = 'Scan',
167
+ scanAccessibilityLabel,
119
168
  extraActions,
120
169
  data,
121
170
  keyExtractor,
@@ -154,8 +203,8 @@ export function SearchList<T>({
154
203
 
155
204
  const handleEndReached = onLoadMore ?? onEndReached;
156
205
 
157
- // El footer propio y el loader de paginación conviven: antes el primero
158
- // tapaba al segundo y la lista dejaba de avisar que estaba trayendo más.
206
+ // The custom footer and the pagination loader coexist: previously the first
207
+ // covered the second and the list stopped signaling it was fetching more.
159
208
  const renderFooter = useCallback(() => {
160
209
  const custom =
161
210
  typeof ListFooterComponent === 'function' ? (
@@ -181,12 +230,12 @@ export function SearchList<T>({
181
230
  );
182
231
  }, [ListFooterComponent, isLoadingMore, resolvedLoadingMoreText, noMoreText, hasMore, data.length, styles.footer, styles.footerText]);
183
232
 
184
- // Vacío sólo cuando ya se sabe que no hay nada: durante la carga inicial se
185
- // muestran placeholders, no "sin resultados".
233
+ // Empty only once it is known there is nothing: during the initial load
234
+ // placeholders are shown, not "no results".
186
235
  const renderEmpty = useCallback(() => {
187
236
  if (isLoading || isRefreshing) return null;
188
- return <EmptyState title={emptyTitle} description={emptyDescription} iconName={emptyIconName} style={{ marginTop: 50 }} />;
189
- }, [isLoading, isRefreshing, emptyTitle, emptyDescription, emptyIconName]);
237
+ return <EmptyState title={emptyTitle} description={emptyDescription} iconName={emptyIconName} style={styles.empty} />;
238
+ }, [isLoading, isRefreshing, emptyTitle, emptyDescription, emptyIconName, styles.empty]);
190
239
 
191
240
  if (!isReady) {
192
241
  return (
@@ -216,11 +265,11 @@ export function SearchList<T>({
216
265
  />
217
266
  {onScanPress && (
218
267
  <IconButton
219
- iconName="search"
268
+ iconName="scan"
220
269
  onPress={onScanPress}
221
270
  color={colors.onPrimary}
222
271
  style={styles.scanButton}
223
- accessibilityLabel={scanAccessibilityLabel}
272
+ accessibilityLabel={scanAccessibilityLabel ?? labels.scan}
224
273
  />
225
274
  )}
226
275
  {extraActions}
@@ -228,22 +277,37 @@ export function SearchList<T>({
228
277
 
229
278
  <View style={styles.listArea}>
230
279
  {showOverlayLoading && (
231
- <View style={styles.loadingOverlay}>
280
+ <View
281
+ style={styles.loadingOverlay}
282
+ accessible
283
+ accessibilityRole="progressbar"
284
+ accessibilityLabel={resolvedLoadingText}
285
+ accessibilityState={{ busy: true }}
286
+ >
232
287
  <ActivityIndicator size="large" color={colors.primary} />
233
288
  <Text style={styles.footerText}>{resolvedLoadingText}</Text>
234
289
  </View>
235
290
  )}
236
291
 
237
292
  {isInitialLoading ? (
238
- <View testID="list-skeleton" style={[styles.listContent, contentContainerStyle]}>
293
+ <View
294
+ testID="list-skeleton"
295
+ style={[styles.listContent, contentContainerStyle]}
296
+ // The placeholders are hidden from screen readers: the group
297
+ // announces that the list is loading instead of silence.
298
+ accessible
299
+ accessibilityRole="progressbar"
300
+ accessibilityLabel={resolvedLoadingText}
301
+ accessibilityState={{ busy: true }}
302
+ >
239
303
  {Array.from({ length: skeletonCount }, (_, i) => (
240
304
  <React.Fragment key={i}>
241
305
  {renderSkeletonItem?.() ?? (
242
306
  <View style={styles.skeletonRow}>
243
- <Skeleton variant="circle" width={40} />
307
+ <Skeleton variant="circle" width={SKELETON_AVATAR} />
244
308
  <View style={styles.skeletonText}>
245
- <Skeleton width="60%" height={14} />
246
- <Skeleton width="35%" height={12} />
309
+ <Skeleton variant="text" width="60%" />
310
+ <Skeleton variant="text" width="35%" />
247
311
  </View>
248
312
  </View>
249
313
  )}
@@ -1,8 +1,7 @@
1
- import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
1
+ import React, { useCallback, useEffect, useMemo, useRef, useState, type ComponentRef } from 'react';
2
2
  import {
3
3
  ActivityIndicator,
4
4
  Keyboard,
5
- Modal,
6
5
  Platform,
7
6
  Pressable,
8
7
  ScrollView,
@@ -14,6 +13,7 @@ import {
14
13
  type ViewStyle,
15
14
  } from 'react-native';
16
15
  import { createStyles } from '../theme/createStyles';
16
+ import { NativeOverlay } from '../theme/NativeOverlay';
17
17
  import { useAllowFontScaling, useColors, useLabels } from '../theme/UIProvider';
18
18
  import { Icon } from '../icons/Icon';
19
19
  import type { IconName } from '../icons/types';
@@ -21,37 +21,53 @@ import type { IconName } from '../icons/types';
21
21
  export interface SelectOption<T> {
22
22
  label: string;
23
23
  value: T;
24
- /** Glifo del set de la librería, a la izquierda del label. */
24
+ /** Glyph from the library's icon set, left of the label. */
25
25
  iconName?: IconName;
26
- /** Emoji a la izquierda del label. Gana sobre `iconName`. */
26
+ /** Emoji left of the label. Takes precedence over `iconName`. */
27
27
  emoji?: string;
28
28
  disabled?: boolean;
29
29
  }
30
30
 
31
31
  export interface SelectProps<T> {
32
+ /** Text above the field; also its accessible name. */
32
33
  label?: string;
34
+ /** Shows an asterisk next to the label. @default false */
33
35
  required?: boolean;
36
+ /** Options of the dropdown: label, value and, optionally, icon, emoji or disabled. */
34
37
  options: SelectOption<T>[];
38
+ /** Value of the selected option (controlled). `undefined` shows the placeholder. */
35
39
  selectedValue: T | undefined;
40
+ /** Called with the value of the chosen option; the dropdown then closes. */
36
41
  onSelect: (value: T) => void;
42
+ /** Text while nothing is selected. @default labels.selectPlaceholder */
37
43
  placeholder?: string;
44
+ /** Error shown under the field. */
38
45
  error?: string;
46
+ /** Shows a spinner in place of the chevron and blocks opening. @default false */
39
47
  isLoading?: boolean;
48
+ /** Dims the field and blocks opening. @default false */
40
49
  disabled?: boolean;
41
50
  /** Adds a search box inside the dropdown. @default false */
42
51
  searchable?: boolean;
52
+ /** Placeholder of the search box (with `searchable`). @default labels.search */
43
53
  searchPlaceholder?: string;
44
54
  /** Maximum height of the dropdown, if the available space allows it. @default 280 */
45
55
  maxHeight?: number;
56
+ /** Called with `true` when the dropdown opens and `false` when it closes. */
46
57
  onOpenChange?: (open: boolean) => void;
58
+ /** Style of the outer wrapper (label, field and error). */
47
59
  containerStyle?: StyleProp<ViewStyle>;
48
60
  testID?: string;
49
61
  }
50
62
 
51
- /** Aire entre el campo y el desplegable. */
63
+ /** Room between the field and the dropdown. */
52
64
  const GAP = 8;
53
- /** Por debajo de esto el desplegable no muestra ni dos filas. */
65
+ /** Below this the dropdown can't even show two rows. */
54
66
  const MIN_HEIGHT = 120;
67
+ /** Same height as Input and DateField, so a form's fields line up. */
68
+ const FIELD_MIN_HEIGHT = 50;
69
+ const ICON_SIZE = 20;
70
+ const CHECK_SIZE = 18;
55
71
 
56
72
  const useStyles = createStyles((theme) => ({
57
73
  container: { gap: theme.tokens.spacing.sm },
@@ -65,10 +81,11 @@ const useStyles = createStyles((theme) => ({
65
81
  borderColor: theme.colors.border,
66
82
  borderRadius: theme.tokens.radius.lg,
67
83
  backgroundColor: theme.colors.inputBackground,
68
- minHeight: 50,
84
+ minHeight: FIELD_MIN_HEIGHT,
69
85
  paddingHorizontal: theme.tokens.spacing.lg,
70
86
  },
71
87
  fieldOpen: { borderColor: theme.colors.primary },
88
+ fieldError: { borderColor: theme.colors.error },
72
89
  fieldDisabled: { opacity: 0.5 },
73
90
  fieldValue: { flexDirection: 'row', alignItems: 'center', gap: theme.tokens.spacing.sm, flexShrink: 1 },
74
91
  fieldText: { fontSize: theme.tokens.fontSize.lg, color: theme.colors.text, flexShrink: 1 },
@@ -79,7 +96,7 @@ const useStyles = createStyles((theme) => ({
79
96
  borderWidth: 2,
80
97
  borderColor: theme.colors.border,
81
98
  borderRadius: theme.tokens.radius.lg,
82
- backgroundColor: theme.colors.surface,
99
+ backgroundColor: theme.colors.surfaceRaised,
83
100
  overflow: 'hidden',
84
101
  ...theme.tokens.shadow.md,
85
102
  },
@@ -96,7 +113,7 @@ const useStyles = createStyles((theme) => ({
96
113
  alignItems: 'center',
97
114
  justifyContent: 'space-between',
98
115
  paddingHorizontal: theme.tokens.spacing.lg,
99
- paddingVertical: theme.tokens.spacing.md + 2,
116
+ paddingVertical: theme.tokens.spacing.md + theme.tokens.spacing.xxs,
100
117
  borderBottomWidth: 1,
101
118
  borderBottomColor: theme.colors.border,
102
119
  },
@@ -104,7 +121,7 @@ const useStyles = createStyles((theme) => ({
104
121
  optionRowSelected: { backgroundColor: theme.colors.primarySoft },
105
122
  optionRowDisabled: { opacity: 0.4 },
106
123
  optionLabel: { flexDirection: 'row', alignItems: 'center', gap: theme.tokens.spacing.sm, flexShrink: 1 },
107
- optionText: { fontSize: theme.tokens.fontSize.lg - 1, color: theme.colors.text },
124
+ optionText: { fontSize: theme.tokens.fontSize.lg, color: theme.colors.text },
108
125
  optionTextSelected: { fontWeight: theme.tokens.fontWeight.semibold, color: theme.colors.primaryText },
109
126
  emoji: { fontSize: theme.tokens.fontSize.lg },
110
127
  empty: {
@@ -125,10 +142,18 @@ interface Anchor {
125
142
 
126
143
  /**
127
144
  * Select
128
- * Dropdown de una sola opción. La lista se mide contra la ventana y se dibuja
129
- * dentro de un Modal, no en el árbol del campo: así ningún `overflow: hidden`
130
- * la recorta, no depende del zIndex (poco confiable en Android) y el fondo del
131
- * Modal resuelve cerrar tocando afuera y con el botón atrás.
145
+ * Single-option dropdown. The list is measured against the window and drawn
146
+ * inside a Modal, not in the field's tree: that way no `overflow: hidden`
147
+ * clips it, it doesn't depend on zIndex (unreliable on Android) and the
148
+ * Modal's backdrop handles closing by tapping outside and with the back button.
149
+ *
150
+ * Design:
151
+ * - Proximity + continuity: the list opens right against the field, toward
152
+ * wherever there is more room, so the eye goes from field to options.
153
+ * - Von Restorff: the picked option alone has the accent fill and a check.
154
+ * - Jakob's law: same field as Input and DateField (height, border, label,
155
+ * red border with an error); tap outside or Android back closes it.
156
+ * - Hick's law: past a handful of options, `searchable` narrows the list.
132
157
  */
133
158
  export function Select<T extends string | number>({
134
159
  label,
@@ -153,12 +178,13 @@ export function Select<T extends string | number>({
153
178
  const allowFontScaling = useAllowFontScaling();
154
179
  const { height: windowHeight } = useWindowDimensions();
155
180
 
156
- const fieldRef = useRef<View>(null);
181
+ const fieldRef = useRef<ComponentRef<typeof View>>(null);
157
182
  const [open, setOpen] = useState(false);
158
183
  const [anchor, setAnchor] = useState<Anchor | null>(null);
159
184
  const [query, setQuery] = useState('');
160
185
  const [keyboardHeight, setKeyboardHeight] = useState(0);
161
186
  const isDisabled = disabled || isLoading;
187
+ const fieldName = label ?? placeholder ?? labels.selectPlaceholder;
162
188
  const selectedOption = options.find((o) => o.value === selectedValue);
163
189
 
164
190
  const close = useCallback(() => {
@@ -168,16 +194,16 @@ export function Select<T extends string | number>({
168
194
  onOpenChange?.(false);
169
195
  }, [onOpenChange]);
170
196
 
171
- // Abrir no espera a la medición: si `measureInWindow` no responde, la lista
172
- // igual aparece (centrada) en vez de que el campo deje de funcionar.
197
+ // Opening doesn't wait for the measurement: if `measureInWindow` doesn't
198
+ // respond, the list still appears (centered) instead of the field ceasing to work.
173
199
  const openList = () => {
174
200
  fieldRef.current?.measureInWindow((x, y, width, height) => setAnchor({ x, y, width, height }));
175
201
  setOpen(true);
176
202
  onOpenChange?.(true);
177
203
  };
178
204
 
179
- // El buscador abre el teclado encima del desplegable: sin descontarlo, la
180
- // lista se dibuja donde ya no se ve.
205
+ // The search box opens the keyboard over the dropdown: without subtracting
206
+ // it, the list is drawn where it can no longer be seen.
181
207
  useEffect(() => {
182
208
  if (!open) return;
183
209
  setKeyboardHeight(Keyboard.metrics()?.height ?? 0);
@@ -196,8 +222,8 @@ export function Select<T extends string | number>({
196
222
  return options.filter((option) => option.label.toLowerCase().includes(needle));
197
223
  }, [options, query, searchable]);
198
224
 
199
- // Se abre hacia donde haya más aire: contra el borde inferior de la pantalla,
200
- // hacia arriba es la única forma de que entre.
225
+ // It opens toward wherever there is more room: against the bottom edge of
226
+ // the screen, upward is the only way for it to fit.
201
227
  const placement = useMemo((): ViewStyle => {
202
228
  if (!anchor) return { left: GAP * 2, right: GAP * 2, top: windowHeight * 0.25, maxHeight };
203
229
  const usableHeight = windowHeight - keyboardHeight;
@@ -221,7 +247,7 @@ export function Select<T extends string | number>({
221
247
  </Text>
222
248
  );
223
249
  }
224
- return option.iconName ? <Icon name={option.iconName} size={20} color={color} /> : null;
250
+ return option.iconName ? <Icon name={option.iconName} size={ICON_SIZE} color={color} /> : null;
225
251
  };
226
252
 
227
253
  return (
@@ -235,11 +261,12 @@ export function Select<T extends string | number>({
235
261
 
236
262
  <Pressable
237
263
  ref={fieldRef}
238
- style={[styles.field, open && styles.fieldOpen, isDisabled && styles.fieldDisabled]}
264
+ style={[styles.field, !!error && styles.fieldError, open && styles.fieldOpen, isDisabled && styles.fieldDisabled]}
239
265
  onPress={openList}
240
266
  disabled={isDisabled}
241
267
  accessibilityRole="combobox"
242
- accessibilityLabel={label ?? placeholder ?? labels.selectPlaceholder}
268
+ accessibilityLabel={required ? `${fieldName}, ${labels.required}` : fieldName}
269
+ accessibilityHint={error || undefined}
243
270
  accessibilityValue={{ text: selectedOption?.label ?? '' }}
244
271
  accessibilityState={{ expanded: open, disabled: isDisabled }}
245
272
  >
@@ -256,15 +283,22 @@ export function Select<T extends string | number>({
256
283
  {isLoading ? (
257
284
  <ActivityIndicator size="small" color={colors.primary} />
258
285
  ) : (
259
- <Icon name={open ? 'chevron-up' : 'chevron-down'} size={20} color={colors.textLight} />
286
+ <Icon name={open ? 'chevron-up' : 'chevron-down'} size={ICON_SIZE} color={colors.textLight} />
260
287
  )}
261
288
  </Pressable>
262
289
 
263
290
  {open && (
264
- <Modal visible transparent animationType="fade" statusBarTranslucent onRequestClose={close}>
291
+ <NativeOverlay transparent animationType="fade" statusBarTranslucent onRequestClose={close}>
265
292
  <Pressable style={styles.backdrop} onPress={close} testID="select-backdrop" />
266
293
 
267
- <View style={[styles.sheet, placement]} accessibilityRole="radiogroup" testID="select-list">
294
+ <View
295
+ style={[styles.sheet, placement]}
296
+ accessibilityRole="radiogroup"
297
+ // On iOS it may be drawn inside another open overlay: the reader stays in the list.
298
+ accessibilityViewIsModal
299
+ onAccessibilityEscape={close}
300
+ testID="select-list"
301
+ >
268
302
  {searchable && (
269
303
  <TextInput
270
304
  allowFontScaling={allowFontScaling}
@@ -309,7 +343,7 @@ export function Select<T extends string | number>({
309
343
  {option.label}
310
344
  </Text>
311
345
  </View>
312
- {isSelected && <Icon name="check" size={18} color={colors.primary} />}
346
+ {isSelected && <Icon name="check" size={CHECK_SIZE} color={colors.primary} />}
313
347
  </Pressable>
314
348
  );
315
349
  })}
@@ -321,7 +355,7 @@ export function Select<T extends string | number>({
321
355
  )}
322
356
  </ScrollView>
323
357
  </View>
324
- </Modal>
358
+ </NativeOverlay>
325
359
  )}
326
360
 
327
361
  {!!error && (