@multiplatform.one/forms 7.7.6 → 7.10.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 (497) hide show
  1. package/dist/cjs/Button/index.cjs +1 -4
  2. package/dist/cjs/Button/index.native.js +5 -6
  3. package/dist/cjs/Button/index.native.js.map +1 -1
  4. package/dist/cjs/Chip/index.cjs +1 -1
  5. package/dist/cjs/Chip/index.native.js +1 -1
  6. package/dist/cjs/Chip/index.native.js.map +1 -1
  7. package/dist/cjs/FloatingPanel/index.cjs +59 -14
  8. package/dist/cjs/FloatingPanel/index.native.js +16 -7
  9. package/dist/cjs/FloatingPanel/index.native.js.map +1 -1
  10. package/dist/cjs/FloatingPanel/nestedAction.cjs +37 -0
  11. package/dist/cjs/FloatingPanel/nestedAction.native.js +42 -0
  12. package/dist/cjs/FloatingPanel/nestedAction.native.js.map +1 -0
  13. package/dist/cjs/InputParts/index.cjs +19 -8
  14. package/dist/cjs/InputParts/index.native.js +20 -11
  15. package/dist/cjs/InputParts/index.native.js.map +1 -1
  16. package/dist/cjs/Wheel/index.cjs +3 -3
  17. package/dist/cjs/Wheel/index.native.js +3 -3
  18. package/dist/cjs/Wheel/index.native.js.map +1 -1
  19. package/dist/cjs/fieldLayout.cjs +3 -3
  20. package/dist/cjs/fieldLayout.native.js +3 -3
  21. package/dist/cjs/fieldLayout.native.js.map +1 -1
  22. package/dist/cjs/fields/Checkbox/CheckboxFieldFrame.cjs +9 -2
  23. package/dist/cjs/fields/Checkbox/CheckboxFieldFrame.native.js +10 -1
  24. package/dist/cjs/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  25. package/dist/cjs/fields/Combobox/index.cjs +36 -29
  26. package/dist/cjs/fields/Combobox/index.native.js +38 -38
  27. package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
  28. package/dist/cjs/fields/DatePicker/Calendar.cjs +6 -1
  29. package/dist/cjs/fields/DatePicker/Calendar.native.js +6 -1
  30. package/dist/cjs/fields/DatePicker/Calendar.native.js.map +1 -1
  31. package/dist/cjs/fields/DatePicker/DateRangePicker.cjs +2 -2
  32. package/dist/cjs/fields/DatePicker/DateRangePicker.native.js +2 -2
  33. package/dist/cjs/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  34. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.cjs +15 -12
  35. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js +16 -12
  36. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  37. package/dist/cjs/fields/DatePicker/DatetimePicker.native.js +39 -14
  38. package/dist/cjs/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  39. package/dist/cjs/fields/DatePicker/MonthPicker.cjs +10 -3
  40. package/dist/cjs/fields/DatePicker/MonthPicker.native.js +10 -3
  41. package/dist/cjs/fields/DatePicker/MonthPicker.native.js.map +1 -1
  42. package/dist/cjs/fields/DatePicker/MultiDatePicker.cjs +2 -2
  43. package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js +2 -2
  44. package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  45. package/dist/cjs/fields/DatePicker/index.native.js +3 -0
  46. package/dist/cjs/fields/DatePicker/index.native.js.map +1 -1
  47. package/dist/cjs/fields/DatePicker/parts.cjs +26 -14
  48. package/dist/cjs/fields/DatePicker/parts.native.js +28 -14
  49. package/dist/cjs/fields/DatePicker/parts.native.js.map +1 -1
  50. package/dist/cjs/fields/FileUpload/index.cjs +6 -0
  51. package/dist/cjs/fields/FileUpload/index.native.js +6 -0
  52. package/dist/cjs/fields/FileUpload/index.native.js.map +1 -1
  53. package/dist/cjs/fields/Geolocation/GeolocationMap.native.js.map +1 -1
  54. package/dist/cjs/fields/Geolocation/geocoder.cjs +63 -0
  55. package/dist/cjs/fields/Geolocation/geocoder.native.js +68 -0
  56. package/dist/cjs/fields/Geolocation/geocoder.native.js.map +1 -0
  57. package/dist/cjs/fields/Geolocation/index.cjs +801 -152
  58. package/dist/cjs/fields/Geolocation/index.native.js +856 -167
  59. package/dist/cjs/fields/Geolocation/index.native.js.map +1 -1
  60. package/dist/cjs/fields/Geolocation/nativeSearchFocus.cjs +44 -0
  61. package/dist/cjs/fields/Geolocation/nativeSearchFocus.native.js +47 -0
  62. package/dist/cjs/fields/Geolocation/nativeSearchFocus.native.js.map +1 -0
  63. package/dist/cjs/fields/Icon/drawnSet.cjs +16 -3
  64. package/dist/cjs/fields/Icon/drawnSet.native.js +20 -3
  65. package/dist/cjs/fields/Icon/drawnSet.native.js.map +1 -1
  66. package/dist/cjs/fields/Icon/index.cjs +102 -27
  67. package/dist/cjs/fields/Icon/index.native.js +115 -31
  68. package/dist/cjs/fields/Icon/index.native.js.map +1 -1
  69. package/dist/cjs/fields/Input/index.cjs +5 -12
  70. package/dist/cjs/fields/Input/index.native.js +5 -13
  71. package/dist/cjs/fields/Input/index.native.js.map +1 -1
  72. package/dist/cjs/fields/PhoneInput/index.cjs +2 -2
  73. package/dist/cjs/fields/PhoneInput/index.native.js +2 -2
  74. package/dist/cjs/fields/PhoneInput/index.native.js.map +1 -1
  75. package/dist/cjs/fields/RadioGroup/index.cjs +34 -5
  76. package/dist/cjs/fields/RadioGroup/index.native.js +49 -7
  77. package/dist/cjs/fields/RadioGroup/index.native.js.map +1 -1
  78. package/dist/cjs/fields/SearchInput/index.cjs +8 -9
  79. package/dist/cjs/fields/SearchInput/index.native.js +8 -9
  80. package/dist/cjs/fields/SearchInput/index.native.js.map +1 -1
  81. package/dist/cjs/fields/Select/index.cjs +42 -11
  82. package/dist/cjs/fields/Select/index.native.js +52 -20
  83. package/dist/cjs/fields/Select/index.native.js.map +1 -1
  84. package/dist/cjs/fields/Stepper/index.cjs +144 -31
  85. package/dist/cjs/fields/Stepper/index.native.js +151 -31
  86. package/dist/cjs/fields/Stepper/index.native.js.map +1 -1
  87. package/dist/cjs/fields/ToggleGroup/index.cjs +35 -2
  88. package/dist/cjs/fields/ToggleGroup/index.native.js +42 -2
  89. package/dist/cjs/fields/ToggleGroup/index.native.js.map +1 -1
  90. package/dist/cjs/index.cjs +2 -0
  91. package/dist/cjs/index.native.js +2 -0
  92. package/dist/cjs/index.native.js.map +1 -1
  93. package/dist/cjs/shared/focusManagement.cjs +24 -11
  94. package/dist/cjs/shared/focusManagement.native.js +24 -11
  95. package/dist/cjs/shared/focusManagement.native.js.map +1 -1
  96. package/dist/cjs/shared/nativeA11y.cjs +57 -0
  97. package/dist/cjs/shared/nativeA11y.native.js +61 -0
  98. package/dist/cjs/shared/nativeA11y.native.js.map +1 -0
  99. package/dist/esm/Button/index.mjs +1 -4
  100. package/dist/esm/Button/index.mjs.map +1 -1
  101. package/dist/esm/Button/index.native.js +5 -6
  102. package/dist/esm/Button/index.native.js.map +1 -1
  103. package/dist/esm/Chip/index.mjs +1 -1
  104. package/dist/esm/Chip/index.mjs.map +1 -1
  105. package/dist/esm/Chip/index.native.js +1 -1
  106. package/dist/esm/Chip/index.native.js.map +1 -1
  107. package/dist/esm/FloatingPanel/index.mjs +58 -15
  108. package/dist/esm/FloatingPanel/index.mjs.map +1 -1
  109. package/dist/esm/FloatingPanel/index.native.js +15 -8
  110. package/dist/esm/FloatingPanel/index.native.js.map +1 -1
  111. package/dist/esm/FloatingPanel/nestedAction.mjs +11 -0
  112. package/dist/esm/FloatingPanel/nestedAction.mjs.map +1 -0
  113. package/dist/esm/FloatingPanel/nestedAction.native.js +13 -0
  114. package/dist/esm/FloatingPanel/nestedAction.native.js.map +1 -0
  115. package/dist/esm/InputParts/index.mjs +20 -9
  116. package/dist/esm/InputParts/index.mjs.map +1 -1
  117. package/dist/esm/InputParts/index.native.js +21 -12
  118. package/dist/esm/InputParts/index.native.js.map +1 -1
  119. package/dist/esm/Wheel/index.mjs +3 -3
  120. package/dist/esm/Wheel/index.mjs.map +1 -1
  121. package/dist/esm/Wheel/index.native.js +3 -3
  122. package/dist/esm/Wheel/index.native.js.map +1 -1
  123. package/dist/esm/fieldLayout.mjs +3 -3
  124. package/dist/esm/fieldLayout.mjs.map +1 -1
  125. package/dist/esm/fieldLayout.native.js +3 -3
  126. package/dist/esm/fieldLayout.native.js.map +1 -1
  127. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.mjs +8 -1
  128. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.mjs.map +1 -1
  129. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.native.js +10 -1
  130. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  131. package/dist/esm/fields/Combobox/index.mjs +36 -29
  132. package/dist/esm/fields/Combobox/index.mjs.map +1 -1
  133. package/dist/esm/fields/Combobox/index.native.js +38 -38
  134. package/dist/esm/fields/Combobox/index.native.js.map +1 -1
  135. package/dist/esm/fields/DatePicker/Calendar.mjs +6 -1
  136. package/dist/esm/fields/DatePicker/Calendar.mjs.map +1 -1
  137. package/dist/esm/fields/DatePicker/Calendar.native.js +6 -1
  138. package/dist/esm/fields/DatePicker/Calendar.native.js.map +1 -1
  139. package/dist/esm/fields/DatePicker/DateRangePicker.mjs +2 -2
  140. package/dist/esm/fields/DatePicker/DateRangePicker.mjs.map +1 -1
  141. package/dist/esm/fields/DatePicker/DateRangePicker.native.js +2 -2
  142. package/dist/esm/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  143. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.mjs +15 -12
  144. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.mjs.map +1 -1
  145. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.native.js +16 -12
  146. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  147. package/dist/esm/fields/DatePicker/DatetimePicker.native.js +39 -14
  148. package/dist/esm/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  149. package/dist/esm/fields/DatePicker/MonthPicker.mjs +10 -3
  150. package/dist/esm/fields/DatePicker/MonthPicker.mjs.map +1 -1
  151. package/dist/esm/fields/DatePicker/MonthPicker.native.js +10 -3
  152. package/dist/esm/fields/DatePicker/MonthPicker.native.js.map +1 -1
  153. package/dist/esm/fields/DatePicker/MultiDatePicker.mjs +2 -2
  154. package/dist/esm/fields/DatePicker/MultiDatePicker.mjs.map +1 -1
  155. package/dist/esm/fields/DatePicker/MultiDatePicker.native.js +2 -2
  156. package/dist/esm/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  157. package/dist/esm/fields/DatePicker/index.native.js +3 -0
  158. package/dist/esm/fields/DatePicker/index.native.js.map +1 -1
  159. package/dist/esm/fields/DatePicker/parts.mjs +28 -16
  160. package/dist/esm/fields/DatePicker/parts.mjs.map +1 -1
  161. package/dist/esm/fields/DatePicker/parts.native.js +30 -16
  162. package/dist/esm/fields/DatePicker/parts.native.js.map +1 -1
  163. package/dist/esm/fields/FileUpload/index.mjs +6 -0
  164. package/dist/esm/fields/FileUpload/index.mjs.map +1 -1
  165. package/dist/esm/fields/FileUpload/index.native.js +6 -0
  166. package/dist/esm/fields/FileUpload/index.native.js.map +1 -1
  167. package/dist/esm/fields/Geolocation/GeolocationMap.mjs.map +1 -1
  168. package/dist/esm/fields/Geolocation/GeolocationMap.native.js.map +1 -1
  169. package/dist/esm/fields/Geolocation/geocoder.mjs +33 -0
  170. package/dist/esm/fields/Geolocation/geocoder.mjs.map +1 -0
  171. package/dist/esm/fields/Geolocation/geocoder.native.js +35 -0
  172. package/dist/esm/fields/Geolocation/geocoder.native.js.map +1 -0
  173. package/dist/esm/fields/Geolocation/index.mjs +792 -149
  174. package/dist/esm/fields/Geolocation/index.mjs.map +1 -1
  175. package/dist/esm/fields/Geolocation/index.native.js +847 -164
  176. package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
  177. package/dist/esm/fields/Geolocation/nativeSearchFocus.mjs +19 -0
  178. package/dist/esm/fields/Geolocation/nativeSearchFocus.mjs.map +1 -0
  179. package/dist/esm/fields/Geolocation/nativeSearchFocus.native.js +19 -0
  180. package/dist/esm/fields/Geolocation/nativeSearchFocus.native.js.map +1 -0
  181. package/dist/esm/fields/Icon/drawnSet.mjs +16 -3
  182. package/dist/esm/fields/Icon/drawnSet.mjs.map +1 -1
  183. package/dist/esm/fields/Icon/drawnSet.native.js +20 -3
  184. package/dist/esm/fields/Icon/drawnSet.native.js.map +1 -1
  185. package/dist/esm/fields/Icon/index.mjs +93 -18
  186. package/dist/esm/fields/Icon/index.mjs.map +1 -1
  187. package/dist/esm/fields/Icon/index.native.js +106 -22
  188. package/dist/esm/fields/Icon/index.native.js.map +1 -1
  189. package/dist/esm/fields/Input/index.mjs +5 -12
  190. package/dist/esm/fields/Input/index.mjs.map +1 -1
  191. package/dist/esm/fields/Input/index.native.js +5 -13
  192. package/dist/esm/fields/Input/index.native.js.map +1 -1
  193. package/dist/esm/fields/PhoneInput/index.mjs +2 -2
  194. package/dist/esm/fields/PhoneInput/index.mjs.map +1 -1
  195. package/dist/esm/fields/PhoneInput/index.native.js +2 -2
  196. package/dist/esm/fields/PhoneInput/index.native.js.map +1 -1
  197. package/dist/esm/fields/RadioGroup/index.mjs +34 -5
  198. package/dist/esm/fields/RadioGroup/index.mjs.map +1 -1
  199. package/dist/esm/fields/RadioGroup/index.native.js +49 -7
  200. package/dist/esm/fields/RadioGroup/index.native.js.map +1 -1
  201. package/dist/esm/fields/SearchInput/index.mjs +9 -10
  202. package/dist/esm/fields/SearchInput/index.mjs.map +1 -1
  203. package/dist/esm/fields/SearchInput/index.native.js +9 -10
  204. package/dist/esm/fields/SearchInput/index.native.js.map +1 -1
  205. package/dist/esm/fields/Select/index.mjs +42 -11
  206. package/dist/esm/fields/Select/index.mjs.map +1 -1
  207. package/dist/esm/fields/Select/index.native.js +52 -20
  208. package/dist/esm/fields/Select/index.native.js.map +1 -1
  209. package/dist/esm/fields/Stepper/index.mjs +145 -32
  210. package/dist/esm/fields/Stepper/index.mjs.map +1 -1
  211. package/dist/esm/fields/Stepper/index.native.js +152 -32
  212. package/dist/esm/fields/Stepper/index.native.js.map +1 -1
  213. package/dist/esm/fields/ToggleGroup/index.mjs +35 -2
  214. package/dist/esm/fields/ToggleGroup/index.mjs.map +1 -1
  215. package/dist/esm/fields/ToggleGroup/index.native.js +42 -2
  216. package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
  217. package/dist/esm/index.mjs +2 -1
  218. package/dist/esm/index.mjs.map +1 -1
  219. package/dist/esm/index.native.js +2 -1
  220. package/dist/esm/index.native.js.map +1 -1
  221. package/dist/esm/shared/focusManagement.mjs +24 -11
  222. package/dist/esm/shared/focusManagement.mjs.map +1 -1
  223. package/dist/esm/shared/focusManagement.native.js +24 -11
  224. package/dist/esm/shared/focusManagement.native.js.map +1 -1
  225. package/dist/esm/shared/nativeA11y.mjs +31 -0
  226. package/dist/esm/shared/nativeA11y.mjs.map +1 -0
  227. package/dist/esm/shared/nativeA11y.native.js +32 -0
  228. package/dist/esm/shared/nativeA11y.native.js.map +1 -0
  229. package/dist/jsx/Button/index.mjs +1 -4
  230. package/dist/jsx/Button/index.mjs.map +1 -1
  231. package/dist/jsx/Button/index.native.js +5 -6
  232. package/dist/jsx/Button/index.native.js.map +1 -1
  233. package/dist/jsx/Chip/index.mjs +1 -1
  234. package/dist/jsx/Chip/index.mjs.map +1 -1
  235. package/dist/jsx/Chip/index.native.js +1 -1
  236. package/dist/jsx/Chip/index.native.js.map +1 -1
  237. package/dist/jsx/FloatingPanel/index.mjs +58 -15
  238. package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
  239. package/dist/jsx/FloatingPanel/index.native.js +16 -7
  240. package/dist/jsx/FloatingPanel/index.native.js.map +1 -1
  241. package/dist/jsx/FloatingPanel/nestedAction.mjs +11 -0
  242. package/dist/jsx/FloatingPanel/nestedAction.mjs.map +1 -0
  243. package/dist/jsx/FloatingPanel/nestedAction.native.js +42 -0
  244. package/dist/jsx/FloatingPanel/nestedAction.native.js.map +1 -0
  245. package/dist/jsx/InputParts/index.mjs +20 -9
  246. package/dist/jsx/InputParts/index.mjs.map +1 -1
  247. package/dist/jsx/InputParts/index.native.js +20 -11
  248. package/dist/jsx/InputParts/index.native.js.map +1 -1
  249. package/dist/jsx/Wheel/index.mjs +3 -3
  250. package/dist/jsx/Wheel/index.mjs.map +1 -1
  251. package/dist/jsx/Wheel/index.native.js +3 -3
  252. package/dist/jsx/Wheel/index.native.js.map +1 -1
  253. package/dist/jsx/fieldLayout.mjs +3 -3
  254. package/dist/jsx/fieldLayout.mjs.map +1 -1
  255. package/dist/jsx/fieldLayout.native.js +3 -3
  256. package/dist/jsx/fieldLayout.native.js.map +1 -1
  257. package/dist/jsx/fields/Checkbox/CheckboxFieldFrame.mjs +8 -1
  258. package/dist/jsx/fields/Checkbox/CheckboxFieldFrame.mjs.map +1 -1
  259. package/dist/jsx/fields/Checkbox/CheckboxFieldFrame.native.js +10 -1
  260. package/dist/jsx/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  261. package/dist/jsx/fields/Combobox/index.mjs +36 -29
  262. package/dist/jsx/fields/Combobox/index.mjs.map +1 -1
  263. package/dist/jsx/fields/Combobox/index.native.js +38 -38
  264. package/dist/jsx/fields/Combobox/index.native.js.map +1 -1
  265. package/dist/jsx/fields/DatePicker/Calendar.mjs +6 -1
  266. package/dist/jsx/fields/DatePicker/Calendar.mjs.map +1 -1
  267. package/dist/jsx/fields/DatePicker/Calendar.native.js +6 -1
  268. package/dist/jsx/fields/DatePicker/Calendar.native.js.map +1 -1
  269. package/dist/jsx/fields/DatePicker/DateRangePicker.mjs +2 -2
  270. package/dist/jsx/fields/DatePicker/DateRangePicker.mjs.map +1 -1
  271. package/dist/jsx/fields/DatePicker/DateRangePicker.native.js +2 -2
  272. package/dist/jsx/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  273. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.mjs +15 -12
  274. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.mjs.map +1 -1
  275. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.native.js +16 -12
  276. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  277. package/dist/jsx/fields/DatePicker/DatetimePicker.native.js +39 -14
  278. package/dist/jsx/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  279. package/dist/jsx/fields/DatePicker/MonthPicker.mjs +10 -3
  280. package/dist/jsx/fields/DatePicker/MonthPicker.mjs.map +1 -1
  281. package/dist/jsx/fields/DatePicker/MonthPicker.native.js +10 -3
  282. package/dist/jsx/fields/DatePicker/MonthPicker.native.js.map +1 -1
  283. package/dist/jsx/fields/DatePicker/MultiDatePicker.mjs +2 -2
  284. package/dist/jsx/fields/DatePicker/MultiDatePicker.mjs.map +1 -1
  285. package/dist/jsx/fields/DatePicker/MultiDatePicker.native.js +2 -2
  286. package/dist/jsx/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  287. package/dist/jsx/fields/DatePicker/index.native.js +3 -0
  288. package/dist/jsx/fields/DatePicker/index.native.js.map +1 -1
  289. package/dist/jsx/fields/DatePicker/parts.mjs +28 -16
  290. package/dist/jsx/fields/DatePicker/parts.mjs.map +1 -1
  291. package/dist/jsx/fields/DatePicker/parts.native.js +28 -14
  292. package/dist/jsx/fields/DatePicker/parts.native.js.map +1 -1
  293. package/dist/jsx/fields/FileUpload/index.mjs +6 -0
  294. package/dist/jsx/fields/FileUpload/index.mjs.map +1 -1
  295. package/dist/jsx/fields/FileUpload/index.native.js +6 -0
  296. package/dist/jsx/fields/FileUpload/index.native.js.map +1 -1
  297. package/dist/jsx/fields/Geolocation/GeolocationMap.mjs.map +1 -1
  298. package/dist/jsx/fields/Geolocation/GeolocationMap.native.js.map +1 -1
  299. package/dist/jsx/fields/Geolocation/geocoder.mjs +33 -0
  300. package/dist/jsx/fields/Geolocation/geocoder.mjs.map +1 -0
  301. package/dist/jsx/fields/Geolocation/geocoder.native.js +68 -0
  302. package/dist/jsx/fields/Geolocation/geocoder.native.js.map +1 -0
  303. package/dist/jsx/fields/Geolocation/index.mjs +792 -149
  304. package/dist/jsx/fields/Geolocation/index.mjs.map +1 -1
  305. package/dist/jsx/fields/Geolocation/index.native.js +856 -167
  306. package/dist/jsx/fields/Geolocation/index.native.js.map +1 -1
  307. package/dist/jsx/fields/Geolocation/nativeSearchFocus.mjs +19 -0
  308. package/dist/jsx/fields/Geolocation/nativeSearchFocus.mjs.map +1 -0
  309. package/dist/jsx/fields/Geolocation/nativeSearchFocus.native.js +47 -0
  310. package/dist/jsx/fields/Geolocation/nativeSearchFocus.native.js.map +1 -0
  311. package/dist/jsx/fields/Icon/drawnSet.mjs +16 -3
  312. package/dist/jsx/fields/Icon/drawnSet.mjs.map +1 -1
  313. package/dist/jsx/fields/Icon/drawnSet.native.js +20 -3
  314. package/dist/jsx/fields/Icon/drawnSet.native.js.map +1 -1
  315. package/dist/jsx/fields/Icon/index.mjs +93 -18
  316. package/dist/jsx/fields/Icon/index.mjs.map +1 -1
  317. package/dist/jsx/fields/Icon/index.native.js +115 -31
  318. package/dist/jsx/fields/Icon/index.native.js.map +1 -1
  319. package/dist/jsx/fields/Input/index.mjs +5 -12
  320. package/dist/jsx/fields/Input/index.mjs.map +1 -1
  321. package/dist/jsx/fields/Input/index.native.js +5 -13
  322. package/dist/jsx/fields/Input/index.native.js.map +1 -1
  323. package/dist/jsx/fields/PhoneInput/index.mjs +2 -2
  324. package/dist/jsx/fields/PhoneInput/index.mjs.map +1 -1
  325. package/dist/jsx/fields/PhoneInput/index.native.js +2 -2
  326. package/dist/jsx/fields/PhoneInput/index.native.js.map +1 -1
  327. package/dist/jsx/fields/RadioGroup/index.mjs +34 -5
  328. package/dist/jsx/fields/RadioGroup/index.mjs.map +1 -1
  329. package/dist/jsx/fields/RadioGroup/index.native.js +49 -7
  330. package/dist/jsx/fields/RadioGroup/index.native.js.map +1 -1
  331. package/dist/jsx/fields/SearchInput/index.mjs +9 -10
  332. package/dist/jsx/fields/SearchInput/index.mjs.map +1 -1
  333. package/dist/jsx/fields/SearchInput/index.native.js +8 -9
  334. package/dist/jsx/fields/SearchInput/index.native.js.map +1 -1
  335. package/dist/jsx/fields/Select/index.mjs +42 -11
  336. package/dist/jsx/fields/Select/index.mjs.map +1 -1
  337. package/dist/jsx/fields/Select/index.native.js +52 -20
  338. package/dist/jsx/fields/Select/index.native.js.map +1 -1
  339. package/dist/jsx/fields/Stepper/index.mjs +145 -32
  340. package/dist/jsx/fields/Stepper/index.mjs.map +1 -1
  341. package/dist/jsx/fields/Stepper/index.native.js +151 -31
  342. package/dist/jsx/fields/Stepper/index.native.js.map +1 -1
  343. package/dist/jsx/fields/ToggleGroup/index.mjs +35 -2
  344. package/dist/jsx/fields/ToggleGroup/index.mjs.map +1 -1
  345. package/dist/jsx/fields/ToggleGroup/index.native.js +42 -2
  346. package/dist/jsx/fields/ToggleGroup/index.native.js.map +1 -1
  347. package/dist/jsx/index.js +2 -1
  348. package/dist/jsx/index.js.map +1 -1
  349. package/dist/jsx/index.mjs +2 -1
  350. package/dist/jsx/index.mjs.map +1 -1
  351. package/dist/jsx/index.native.js +2 -0
  352. package/dist/jsx/index.native.js.map +1 -1
  353. package/dist/jsx/shared/focusManagement.mjs +24 -11
  354. package/dist/jsx/shared/focusManagement.mjs.map +1 -1
  355. package/dist/jsx/shared/focusManagement.native.js +24 -11
  356. package/dist/jsx/shared/focusManagement.native.js.map +1 -1
  357. package/dist/jsx/shared/nativeA11y.mjs +31 -0
  358. package/dist/jsx/shared/nativeA11y.mjs.map +1 -0
  359. package/dist/jsx/shared/nativeA11y.native.js +61 -0
  360. package/dist/jsx/shared/nativeA11y.native.js.map +1 -0
  361. package/package.json +9 -7
  362. package/src/Button/Button.fontWeight.spec.tsx +75 -0
  363. package/src/Button/Button.labelInk.spec.tsx +21 -18
  364. package/src/Button/Button.outlinedChannel.spec.tsx +46 -0
  365. package/src/Button/Button.sizeLadder.spec.tsx +4 -3
  366. package/src/Button/Button.stories.tsx +20 -0
  367. package/src/Button/index.tsx +30 -7
  368. package/src/Chip/Chip.spec.tsx +3 -1
  369. package/src/Chip/index.tsx +1 -5
  370. package/src/FieldGroup.stories.tsx +3 -7
  371. package/src/FieldLayout.stories.tsx +75 -12
  372. package/src/Fieldset.stories.tsx +3 -7
  373. package/src/FloatingPanel/FloatingPanel.native.spec.tsx +54 -0
  374. package/src/FloatingPanel/FloatingPanel.spec.tsx +109 -0
  375. package/src/FloatingPanel/index.native.tsx +24 -7
  376. package/src/FloatingPanel/index.tsx +80 -13
  377. package/src/FloatingPanel/nestedAction.spec.ts +36 -0
  378. package/src/FloatingPanel/nestedAction.ts +15 -0
  379. package/src/FloatingPanel/panelWidthContract.spec.ts +12 -15
  380. package/src/FormGrid.stories.tsx +5 -11
  381. package/src/FormsIntegration.stories.tsx +2 -6
  382. package/src/InputParts/InputButton.spec.tsx +16 -0
  383. package/src/InputParts/index.tsx +34 -7
  384. package/src/InputParts/layoutGap.spec.tsx +43 -0
  385. package/src/Wheel/Wheel.spec.tsx +16 -0
  386. package/src/Wheel/index.tsx +3 -3
  387. package/src/fieldFamilyStories.radius.spec.tsx +118 -0
  388. package/src/fieldLayout.spec.tsx +42 -1
  389. package/src/fieldLayout.tsx +9 -9
  390. package/src/fields/Barcode/Barcode.spec.tsx +2 -0
  391. package/src/fields/Checkbox/CheckboxFieldFrame.spec.tsx +18 -0
  392. package/src/fields/Checkbox/CheckboxFieldFrame.tsx +6 -1
  393. package/src/fields/Combobox/Combobox.spec.tsx +48 -1
  394. package/src/fields/Combobox/index.tsx +53 -39
  395. package/src/fields/DatePicker/Calendar.tsx +4 -1
  396. package/src/fields/DatePicker/DatePicker.stories.tsx +22 -1
  397. package/src/fields/DatePicker/DateRangePicker.tsx +4 -2
  398. package/src/fields/DatePicker/DatetimePicker.catalog.tsx +21 -19
  399. package/src/fields/DatePicker/DatetimePicker.native.spec.tsx +144 -0
  400. package/src/fields/DatePicker/DatetimePicker.native.tsx +57 -32
  401. package/src/fields/DatePicker/DatetimePicker.stories.tsx +22 -0
  402. package/src/fields/DatePicker/MonthPicker.tsx +8 -3
  403. package/src/fields/DatePicker/MultiDatePicker.tsx +4 -2
  404. package/src/fields/DatePicker/index.native.tsx +1 -0
  405. package/src/fields/DatePicker/parts.spec.tsx +56 -0
  406. package/src/fields/DatePicker/parts.tsx +33 -12
  407. package/src/fields/FileUpload/FileUpload.spec.tsx +29 -0
  408. package/src/fields/FileUpload/index.tsx +6 -0
  409. package/src/fields/Geolocation/Geolocation.spec.tsx +287 -35
  410. package/src/fields/Geolocation/Geolocation.stories.tsx +141 -7
  411. package/src/fields/Geolocation/GeolocationMap.native.tsx +3 -0
  412. package/src/fields/Geolocation/GeolocationMap.tsx +4 -0
  413. package/src/fields/Geolocation/geocoder.spec.ts +59 -0
  414. package/src/fields/Geolocation/geocoder.ts +84 -0
  415. package/src/fields/Geolocation/geocoderSeam.spec.tsx +203 -0
  416. package/src/fields/Geolocation/index.tsx +912 -180
  417. package/src/fields/Geolocation/nativeSearchFocus.spec.ts +34 -0
  418. package/src/fields/Geolocation/nativeSearchFocus.ts +19 -0
  419. package/src/fields/Geolocation/salvage.spec.tsx +398 -0
  420. package/src/fields/Geolocation/storyProviders.spec.tsx +44 -0
  421. package/src/fields/Icon/Icon.spec.tsx +215 -1
  422. package/src/fields/Icon/Icon.stories.tsx +9 -1
  423. package/src/fields/Icon/drawnSet.tsx +44 -4
  424. package/src/fields/Icon/index.tsx +118 -18
  425. package/src/fields/Input/Input.copy.spec.tsx +1 -0
  426. package/src/fields/Input/Input.spec.tsx +50 -0
  427. package/src/fields/Input/Input.stories.tsx +1 -1
  428. package/src/fields/Input/index.tsx +7 -13
  429. package/src/fields/PhoneInput/index.tsx +2 -2
  430. package/src/fields/RadioGroup/RadioGroup.native.spec.tsx +67 -0
  431. package/src/fields/RadioGroup/index.tsx +82 -8
  432. package/src/fields/SearchInput/SearchInput.spec.tsx +14 -0
  433. package/src/fields/SearchInput/index.tsx +5 -6
  434. package/src/fields/Select/Select.spec.tsx +54 -0
  435. package/src/fields/Select/index.tsx +52 -17
  436. package/src/fields/Stepper/Stepper.spec.tsx +34 -1
  437. package/src/fields/Stepper/index.tsx +193 -33
  438. package/src/fields/ToggleGroup/ToggleGroup.native.spec.tsx +73 -0
  439. package/src/fields/ToggleGroup/ToggleGroup.spec.tsx +49 -0
  440. package/src/fields/ToggleGroup/index.tsx +76 -1
  441. package/src/index.ts +9 -0
  442. package/src/shared/focusManagement.spec.tsx +68 -0
  443. package/src/shared/focusManagement.ts +20 -10
  444. package/src/shared/nativeA11y.spec.ts +64 -0
  445. package/src/shared/nativeA11y.ts +80 -0
  446. package/types/Button/index.d.ts +22 -3
  447. package/types/Button/index.d.ts.map +1 -1
  448. package/types/Chip/index.d.ts.map +1 -1
  449. package/types/FloatingPanel/index.d.ts +11 -1
  450. package/types/FloatingPanel/index.d.ts.map +1 -1
  451. package/types/FloatingPanel/index.native.d.ts +2 -1
  452. package/types/FloatingPanel/index.native.d.ts.map +1 -1
  453. package/types/FloatingPanel/nestedAction.d.ts +13 -0
  454. package/types/FloatingPanel/nestedAction.d.ts.map +1 -0
  455. package/types/InputParts/index.d.ts.map +1 -1
  456. package/types/fields/Checkbox/CheckboxFieldFrame.d.ts +46 -2
  457. package/types/fields/Checkbox/CheckboxFieldFrame.d.ts.map +1 -1
  458. package/types/fields/Checkbox/index.d.ts +3 -3
  459. package/types/fields/Combobox/index.d.ts +3 -1
  460. package/types/fields/Combobox/index.d.ts.map +1 -1
  461. package/types/fields/DatePicker/Calendar.d.ts.map +1 -1
  462. package/types/fields/DatePicker/DateRangePicker.d.ts.map +1 -1
  463. package/types/fields/DatePicker/DatetimePicker.catalog.d.ts.map +1 -1
  464. package/types/fields/DatePicker/DatetimePicker.native.d.ts.map +1 -1
  465. package/types/fields/DatePicker/MonthPicker.d.ts.map +1 -1
  466. package/types/fields/DatePicker/MultiDatePicker.d.ts.map +1 -1
  467. package/types/fields/DatePicker/index.native.d.ts.map +1 -1
  468. package/types/fields/DatePicker/parts.d.ts.map +1 -1
  469. package/types/fields/FileUpload/index.d.ts.map +1 -1
  470. package/types/fields/Geolocation/GeolocationMap.d.ts +4 -0
  471. package/types/fields/Geolocation/GeolocationMap.d.ts.map +1 -1
  472. package/types/fields/Geolocation/GeolocationMap.native.d.ts +3 -0
  473. package/types/fields/Geolocation/GeolocationMap.native.d.ts.map +1 -1
  474. package/types/fields/Geolocation/geocoder.d.ts +53 -0
  475. package/types/fields/Geolocation/geocoder.d.ts.map +1 -0
  476. package/types/fields/Geolocation/index.d.ts +18 -2
  477. package/types/fields/Geolocation/index.d.ts.map +1 -1
  478. package/types/fields/Geolocation/nativeSearchFocus.d.ts +8 -0
  479. package/types/fields/Geolocation/nativeSearchFocus.d.ts.map +1 -0
  480. package/types/fields/Icon/drawnSet.d.ts.map +1 -1
  481. package/types/fields/Icon/index.d.ts.map +1 -1
  482. package/types/fields/Input/index.d.ts.map +1 -1
  483. package/types/fields/PhoneInput/index.d.ts.map +1 -1
  484. package/types/fields/RadioGroup/index.d.ts +30 -3
  485. package/types/fields/RadioGroup/index.d.ts.map +1 -1
  486. package/types/fields/SearchInput/index.d.ts.map +1 -1
  487. package/types/fields/Select/index.d.ts.map +1 -1
  488. package/types/fields/Stepper/index.d.ts.map +1 -1
  489. package/types/fields/ToggleGroup/index.d.ts +31 -2
  490. package/types/fields/ToggleGroup/index.d.ts.map +1 -1
  491. package/types/index.d.ts +2 -0
  492. package/types/index.d.ts.map +1 -1
  493. package/types/shared/focusManagement.d.ts +2 -2
  494. package/types/shared/focusManagement.d.ts.map +1 -1
  495. package/types/shared/nativeA11y.d.ts +61 -0
  496. package/types/shared/nativeA11y.d.ts.map +1 -0
  497. package/src/router.d.ts +0 -16
@@ -1,7 +1,8 @@
1
1
  import type { ComponentProps, ReactElement, ReactNode } from "react";
2
2
  import { useCallback, useRef } from "react";
3
- import { ClipboardIcon, WarningCircleIcon } from "@phosphor-icons/react";
3
+ import { writeToClipboard } from "@multiplatform.one/platform";
4
4
  import { MIN_PRESS_TARGET, pressTargetHitSlop } from "@multiplatform.one/theme";
5
+ import { ClipboardIcon, WarningCircleIcon } from "@phosphor-icons/react";
5
6
  import type {
6
7
  InputKeyboardType,
7
8
  InputTextContentType,
@@ -119,16 +120,6 @@ export interface InputProps {
119
120
 
120
121
  const COPY_LABEL = "Copy to clipboard";
121
122
 
122
- async function writeClipboard(text: string): Promise<boolean> {
123
- try {
124
- if (typeof navigator === "undefined" || !navigator.clipboard?.writeText) return false;
125
- await navigator.clipboard.writeText(text);
126
- return true;
127
- } catch {
128
- return false;
129
- }
130
- }
131
-
132
123
  export function Input({
133
124
  name,
134
125
  form: formProp,
@@ -247,7 +238,7 @@ export function Input({
247
238
 
248
239
  const handleCopy = useCallback(
249
240
  async (text: string) => {
250
- const ok = await writeClipboard(text);
241
+ const ok = await writeToClipboard(text);
251
242
  onCopyResult?.(ok);
252
243
  },
253
244
  [onCopyResult],
@@ -361,7 +352,9 @@ export function Input({
361
352
  {...(placeholder !== undefined ? { placeholder } : undefined)}
362
353
  disabled={disabled}
363
354
  id={id}
364
- {...(handleChange ? { value: inputValue ?? "" } : { defaultValue: inputValue })}
355
+ {...(handleChange || value !== undefined
356
+ ? { value: inputValue ?? "" }
357
+ : { defaultValue: inputValue })}
365
358
  aria-required={required || undefined}
366
359
  aria-invalid={hasError || undefined}
367
360
  {...areaName}
@@ -381,6 +374,7 @@ export function Input({
381
374
  disabled={disabled}
382
375
  tabIndex={disabled ? -1 : 0}
383
376
  aria-label={COPY_LABEL}
377
+ accessibilityLabel={COPY_LABEL}
384
378
  hitSlop={belowFloor ? pressTargetHitSlop(visualHeight) : undefined}
385
379
  onPress={disabled ? undefined : activateCopy}
386
380
  onKeyDown={
@@ -43,8 +43,6 @@ const phoneInputCss = `/* LC-71: flag+dial are adornments of one control. Ring l
43
43
  .mp-phone-input [data-testid="combobox-trigger"] {
44
44
  outline: none !important;
45
45
  box-shadow: none !important;
46
- width: auto !important;
47
- flex: 0 0 auto;
48
46
  }
49
47
  .mp-phone-input [data-testid="combobox-trigger"]:focus,
50
48
  .mp-phone-input [data-testid="combobox-trigger"]:focus-visible {
@@ -329,9 +327,11 @@ export function PhoneInput<
329
327
  alignItems="stretch"
330
328
  flexGrow={0}
331
329
  flexShrink={0}
330
+ gap="$1.5"
332
331
  {...(readOnly ? { pointerEvents: "none" as const } : undefined)}
333
332
  >
334
333
  <Combobox
334
+ triggerSizing="content"
335
335
  options={countryOptions}
336
336
  value={regionCode}
337
337
  onChange={(val) => handleRegionChange(typeof val === "string" ? val : (val[0] ?? ""))}
@@ -0,0 +1,67 @@
1
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
2
+ import { describe, expect, it, vi } from "vitest";
3
+ import { RadioGroup } from "./index";
4
+
5
+ // MPO-283. Mock tamagui's isWeb so the native branch runs on the test host
6
+ // renderer, then read the React Native prop names back off the DOM. The state
7
+ // object itself is pinned in shared/nativeA11y.spec.ts — the host stringifies
8
+ // it — so what this file proves is that the component reaches the helper with
9
+ // the right role and the right name.
10
+ vi.mock("tamagui", async (importOriginal) => ({
11
+ ...(await importOriginal<typeof import("tamagui")>()),
12
+ isWeb: false,
13
+ }));
14
+
15
+ const phase = [
16
+ { label: "CREDITS", value: "CREDITS" },
17
+ { label: "DEBITS", value: "DEBITS" },
18
+ { label: "DISCRETIONARY", value: "DISCRETIONARY", disabled: true },
19
+ ];
20
+
21
+ const names = (container: HTMLElement) =>
22
+ Array.from(container.querySelectorAll("[accessibilityrole]")).map((el) => [
23
+ el.getAttribute("accessibilityrole"),
24
+ el.getAttribute("accessibilitylabel"),
25
+ ]);
26
+
27
+ describe("native RadioGroup accessibility contract", () => {
28
+ it("makes every option a named control instead of bare StaticText", () => {
29
+ const { container } = renderWithProviders(
30
+ <RadioGroup label="Phase" options={phase} value="DEBITS" />,
31
+ );
32
+ expect(names(container)).toEqual([
33
+ ["button", "CREDITS"],
34
+ ["button", "DEBITS"],
35
+ ["button", "DISCRETIONARY"],
36
+ ]);
37
+ });
38
+
39
+ it("prefixes a group accessibilityLabel onto each option, because iOS never reads a container", () => {
40
+ const { container } = renderWithProviders(
41
+ <RadioGroup accessibilityLabel="Phase" options={phase} value="DEBITS" />,
42
+ );
43
+ expect(names(container)).toContainEqual(["button", "Phase, DEBITS"]);
44
+ });
45
+
46
+ it("takes aria-label as an alias, since tamagui never maps it onto native", () => {
47
+ const { container } = renderWithProviders(
48
+ <RadioGroup aria-label="Phase" options={phase} value="DEBITS" />,
49
+ );
50
+ expect(names(container)).toContainEqual(["button", "Phase, DEBITS"]);
51
+ });
52
+
53
+ it("lets an option override its own name", () => {
54
+ const { container } = renderWithProviders(
55
+ <RadioGroup
56
+ options={[{ label: "▲", value: "up", accessibilityLabel: "Increasing" }]}
57
+ value="up"
58
+ />,
59
+ );
60
+ expect(names(container)).toEqual([["button", "Increasing"]]);
61
+ });
62
+
63
+ // The sibling Label is also told to stay out of the native tree so an option
64
+ // is not read twice. It cannot be asserted here — the web renderer drops the
65
+ // React Native accessibility props off Label entirely — so that one is
66
+ // measured on device instead.
67
+ });
@@ -28,6 +28,7 @@ import { getSize } from "@tamagui/get-token";
28
28
  import { Skeleton } from "../../Skeleton";
29
29
  import { Field, FieldLayout } from "../../fieldLayout";
30
30
  import { formControlColors, formSelectedColors } from "../../shared/colorRamps";
31
+ import { choiceItemA11y, composeA11yName } from "../../shared/nativeA11y";
31
32
  import {
32
33
  getElevationWrapperProps,
33
34
  getFieldError,
@@ -131,6 +132,14 @@ export interface RadioGroupOption {
131
132
  disabled?: boolean;
132
133
  /** Muted secondary line under the label; rendered in `card` mode. */
133
134
  description?: string;
135
+ /**
136
+ * MPO-283 — accessible name for THIS option, overriding `label`. Use it
137
+ * when the option carries meaning the label text does not: a glyph, or a
138
+ * state encoded in fill/weight/position rather than words.
139
+ */
140
+ accessibilityLabel?: string;
141
+ /** Extra spoken context for this option (native `accessibilityHint`). */
142
+ accessibilityHint?: string;
134
143
  }
135
144
 
136
145
  export interface RadioGroupProps {
@@ -179,11 +188,33 @@ export interface RadioGroupProps {
179
188
  * primitives (same anatomy as `CheckboxGroup card`).
180
189
  */
181
190
  card?: boolean;
191
+ /**
192
+ * MPO-283 — accessible name for the whole group.
193
+ *
194
+ * tamagui does not map `aria-label` onto React Native's
195
+ * `accessibilityLabel`, so the web attribute is inert on native; this prop
196
+ * is the native channel and `aria-label` is accepted as an alias.
197
+ *
198
+ * iOS speaks elements, never non-element containers, so a name set here is
199
+ * PREFIXED onto each option's accessible name ("Phase, CREDITS") instead of
200
+ * sitting on the frame where nothing reads it. Options stay individually
201
+ * reachable and keep their own checked state.
202
+ */
203
+ accessibilityLabel?: string;
204
+ /** Alias for `accessibilityLabel`; also emitted as the web attribute. */
205
+ "aria-label"?: string;
206
+ /** Web-only name reference. Native has no id-based equivalent. */
207
+ "aria-labelledby"?: string;
208
+ /** Extra spoken context for the group (native `accessibilityHint`). */
209
+ accessibilityHint?: string;
182
210
  }
183
211
 
184
212
  interface RadioOptionItemProps {
185
213
  option: RadioGroupOption;
186
214
  itemId: string;
215
+ /** MPO-283 — the resolved native accessible name for this option. */
216
+ nativeLabel: string;
217
+ nativeHint?: string;
187
218
  a11y?: { "aria-labelledby"?: string; "aria-describedby"?: string };
188
219
  selected: boolean;
189
220
  isTabStop?: boolean;
@@ -203,6 +234,8 @@ interface RadioOptionItemProps {
203
234
  function RadioOptionItem({
204
235
  option,
205
236
  itemId,
237
+ nativeLabel,
238
+ nativeHint,
206
239
  a11y,
207
240
  selected,
208
241
  isTabStop,
@@ -277,15 +310,22 @@ function RadioOptionItem({
277
310
  {...(groupDisabled || option.disabled ? disabledChrome : undefined)}
278
311
  pointerEvents={readOnly ? "none" : undefined}
279
312
  {...a11y}
280
- // RN only exposes the radio to the a11y tree when `accessible` is set;
281
- // web keeps Tamagui's role=radio + label association untouched.
313
+ // MPO-283. RN only exposes the radio when `accessible` is set, and the
314
+ // aria-* spellings this block used to carry never reached iOS at all:
315
+ // tamagui does not map them onto React Native's accessibility props, so
316
+ // options came back as bare StaticText with no role and no checked
317
+ // state. The RN prop names are the ones iOS actually reads.
282
318
  {...(!isWeb
283
- ? {
284
- accessible: true,
285
- "aria-label": typeof option.label === "string" ? option.label : String(option.value),
286
- "aria-checked": selected,
287
- }
288
- : {})}
319
+ ? choiceItemA11y({
320
+ kind: "radio",
321
+ name: nativeLabel,
322
+ selected,
323
+ disabled: Boolean(groupDisabled || option.disabled),
324
+ hint: nativeHint,
325
+ })
326
+ : option.accessibilityLabel
327
+ ? { "aria-label": option.accessibilityLabel }
328
+ : {})}
289
329
  {...(hoverProps && {
290
330
  hoverStyle: {
291
331
  ...hoverProps,
@@ -344,6 +384,10 @@ export function RadioGroup({
344
384
  skeleton,
345
385
  compact,
346
386
  card,
387
+ accessibilityLabel,
388
+ accessibilityHint,
389
+ "aria-label": ariaLabel,
390
+ "aria-labelledby": ariaLabelledBy,
347
391
  }: RadioGroupProps) {
348
392
  // Canonical `onChange` and the alias `onValueChange` both fire from the
349
393
  // single emit site below (same reconciliation as Switch).
@@ -351,6 +395,17 @@ export function RadioGroup({
351
395
  onChange?.(val);
352
396
  onValueChange?.(val);
353
397
  };
398
+ // MPO-283: one name, two channels — tamagui drops `aria-label` on native, so
399
+ // the prop and the attribute are reconciled here.
400
+ const groupA11yName = accessibilityLabel ?? ariaLabel;
401
+ // iOS reads elements, not containers, so an explicit group name rides in
402
+ // front of each option's own name rather than sitting on the frame.
403
+ const optionA11yName = (option: RadioGroupOption) =>
404
+ composeA11yName(
405
+ groupA11yName,
406
+ option.accessibilityLabel ??
407
+ (typeof option.label === "string" ? option.label : String(option.value)),
408
+ );
354
409
  const { resolvedForm, knobProps, control, text, elevation, disabledState, id } = useFormField({
355
410
  form: formProp,
356
411
  id: idProp,
@@ -440,6 +495,8 @@ export function RadioGroup({
440
495
  <RadioOptionItem
441
496
  option={option}
442
497
  itemId={itemId}
498
+ nativeLabel={optionA11yName(option)}
499
+ nativeHint={option.accessibilityHint ?? accessibilityHint}
443
500
  a11y={a11y}
444
501
  selected={!!selected}
445
502
  isTabStop={isTabStop}
@@ -541,6 +598,15 @@ export function RadioGroup({
541
598
  )}
542
599
  <Label
543
600
  htmlFor={itemId}
601
+ // MPO-283: on native the radio itself now carries this text as
602
+ // its accessible name, so leaving the Label in the tree reads
603
+ // every option twice. Web keeps the label/control association.
604
+ {...(!isWeb
605
+ ? {
606
+ accessibilityElementsHidden: true,
607
+ importantForAccessibility: "no-hide-descendants" as const,
608
+ }
609
+ : undefined)}
544
610
  size={(size || knobProps.sizeToken) as FontSizeTokens}
545
611
  {...knobProps.body}
546
612
  color={knobProps.textAccentColor}
@@ -615,6 +681,14 @@ export function RadioGroup({
615
681
  aria-required={required || undefined}
616
682
  aria-invalid={hasError || undefined}
617
683
  aria-readonly={readOnly || undefined}
684
+ // MPO-283: web reads the attribute, Android reads the RN prop off the
685
+ // container. iOS reads neither, which is why the name is also prefixed
686
+ // onto every option above.
687
+ {...(groupA11yName ? { "aria-label": groupA11yName } : undefined)}
688
+ {...(ariaLabelledBy ? { "aria-labelledby": ariaLabelledBy } : undefined)}
689
+ {...(!isWeb && groupA11yName
690
+ ? { accessibilityLabel: groupA11yName, accessibilityRole: "radiogroup" as const }
691
+ : undefined)}
618
692
  >
619
693
  {renderItems(radioValue, emit)}
620
694
  </TamaguiRadioGroup>
@@ -5,6 +5,7 @@ import { fireEvent } from "@testing-library/react";
5
5
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
6
6
  import { SIZE_RECIPE_TOKENS, sizeRecipeForToken } from "@multiplatform.one/theme";
7
7
  import { renderWithProviders } from "@multiplatform.one/test-utils";
8
+ import { useTheme } from "tamagui";
8
9
  import { Form } from "../../Form";
9
10
  import { SearchInput } from "./index";
10
11
 
@@ -31,6 +32,19 @@ describe("SearchInput", () => {
31
32
  expect(result.container.querySelector("svg")).toBeTruthy();
32
33
  });
33
34
 
35
+ it("uses readable glyph ink for search and clear rather than the boundary ramp", () => {
36
+ let expectedInk = "";
37
+ function Sample() {
38
+ const theme = useTheme();
39
+ expectedInk = String(theme.color11?.val);
40
+ return <SearchInput placeholder="Search things" defaultValue="corp" />;
41
+ }
42
+ const { container } = renderWithProviders(<Sample />);
43
+ const glyphs = container.querySelectorAll("svg");
44
+ expect(glyphs).toHaveLength(2);
45
+ for (const glyph of glyphs) expect(glyph.getAttribute("fill")).toBe(expectedInk);
46
+ });
47
+
34
48
  it("bidi-isolates the default placeholder (LC-58) and passes explicit ones through", () => {
35
49
  // Default: FSI…PDI framing so the trailing "..." cannot reorder to
36
50
  // "…Search" under RTL; the visible run stays byte-identical inside.
@@ -28,7 +28,7 @@ import { View, isWeb } from "tamagui";
28
28
  import { Skeleton } from "../../Skeleton";
29
29
  import { Field, FieldLayout } from "../../fieldLayout";
30
30
  import { Input as InputParts } from "../../InputParts";
31
- import { formControlColors } from "../../shared/colorRamps";
31
+ import { formCommonColors } from "../../shared/colorRamps";
32
32
  import { bidiIsolate, t } from "../../shared/t";
33
33
  import type { AnyFormApi } from "../../types";
34
34
  import {
@@ -339,7 +339,7 @@ export function SearchInput({
339
339
  >
340
340
  <InputParts.Icon
341
341
  adornment="leading"
342
- color={formControlColors.boundary}
342
+ color={formCommonColors.muted}
343
343
  className={isWeb ? "mp-search-leading" : undefined}
344
344
  {...leadingWebProps}
345
345
  >
@@ -363,11 +363,8 @@ export function SearchInput({
363
363
  justifyContent="center"
364
364
  cursor="pointer"
365
365
  outlineWidth={0}
366
- hoverStyle={{ opacity: 1 }}
367
- pressStyle={{ opacity: 0.9 }}
368
366
  focusStyle={{ outlineWidth: 0 }}
369
367
  focusVisibleStyle={{ outlineWidth: 0 }}
370
- opacity={0.85}
371
368
  flexShrink={0}
372
369
  hitSlop={belowFloor ? pressTargetHitSlop(visualHeight) : undefined}
373
370
  onPress={() => clearText(fieldChange)}
@@ -385,8 +382,10 @@ export function SearchInput({
385
382
  className={isWeb ? "mp-chip-dismiss-ring" : undefined}
386
383
  alignItems="center"
387
384
  justifyContent="center"
385
+ hoverStyle={{ backgroundColor: "$color4" }}
386
+ pressStyle={{ backgroundColor: "$color5" }}
388
387
  >
389
- <InputParts.Icon aria-hidden color={formControlColors.boundary}>
388
+ <InputParts.Icon aria-hidden color={formCommonColors.muted}>
390
389
  <XIcon size={resolvedIconSize} />
391
390
  </InputParts.Icon>
392
391
  </View>
@@ -334,3 +334,57 @@ describe("Select Components", () => {
334
334
  });
335
335
  });
336
336
  });
337
+
338
+ describe("Select pointer intent", () => {
339
+ it("commits a deliberate cross-row release immediately after keyboard open", async () => {
340
+ const onChange = vi.fn();
341
+ const result = renderWithProviders(<Select options={mockOptions} onChange={onChange} />);
342
+ const trigger = result.getByTestId("select-trigger");
343
+ fireEvent.keyDown(trigger, { key: "Enter" });
344
+ const options = await result.findAllByRole("option");
345
+ fireEvent.pointerDown(options[0], { button: 0, pointerId: 1 });
346
+ fireEvent.mouseDown(options[0]);
347
+ fireEvent.mouseUp(options[1]);
348
+ expect(onChange).toHaveBeenCalledExactlyOnceWith("option2");
349
+ expect(trigger).toHaveAttribute("aria-expanded", "false");
350
+ });
351
+
352
+ it("consumes the opening gesture release over the covered row", async () => {
353
+ const onChange = vi.fn();
354
+ const result = renderWithProviders(<Select options={mockOptions} onChange={onChange} />);
355
+ const trigger = result.getByTestId("select-trigger");
356
+ fireEvent.mouseDown(trigger);
357
+ const options = await result.findAllByRole("option");
358
+ fireEvent.mouseUp(options[0]);
359
+ expect(onChange).not.toHaveBeenCalled();
360
+ expect(trigger).toHaveAttribute("aria-expanded", "true");
361
+ });
362
+
363
+ it("does not select when a background drag releases over an option", async () => {
364
+ const onChange = vi.fn();
365
+ const result = renderWithProviders(<Select options={mockOptions} onChange={onChange} />);
366
+ fireEvent.mouseDown(result.getByTestId("select-trigger"));
367
+ const options = await result.findAllByRole("option");
368
+ fireEvent.mouseUp(options[0]);
369
+ const panel = result.getByTestId("select-dropdown");
370
+ fireEvent.pointerDown(panel, { button: 0, clientY: 10 });
371
+ fireEvent.pointerMove(document, { clientY: 50 });
372
+ fireEvent.pointerUp(document);
373
+ fireEvent.mouseUp(options[1]);
374
+ expect(onChange).not.toHaveBeenCalled();
375
+ });
376
+
377
+ it("toggles a multiple option exactly once on an immediate click", async () => {
378
+ const onChange = vi.fn();
379
+ const result = renderWithProviders(
380
+ <Select options={mockOptions} multiple onChange={onChange} />,
381
+ );
382
+ fireEvent.keyDown(result.getByTestId("select-trigger"), { key: "Enter" });
383
+ const options = await result.findAllByRole("option");
384
+ fireEvent.pointerDown(options[0], { button: 0, pointerId: 1 });
385
+ fireEvent.mouseDown(options[0]);
386
+ fireEvent.mouseUp(options[0]);
387
+ fireEvent.click(options[0]);
388
+ expect(onChange).toHaveBeenCalledExactlyOnceWith(["option1"]);
389
+ });
390
+ });
@@ -125,10 +125,13 @@ export interface SelectProps {
125
125
  // LC-71: Tamagui maps `focusVisibleStyle` onto mouse/:focus, so the ring is
126
126
  // painted from `wasKeyboardFocus()` (inset — overlay overflow clips it).
127
127
  // LC-72 CONTAINER-CLIP: rows stay square; the panel radius cuts the corners.
128
- const selectRowOutlineRest = {
128
+ const selectOutlineRest = {
129
129
  outlineWidth: 0,
130
130
  outlineStyle: "solid" as const,
131
131
  outlineColor: "transparent",
132
+ };
133
+ const selectRowOutlineRest = {
134
+ ...selectOutlineRest,
132
135
  borderRadius: 0,
133
136
  };
134
137
 
@@ -266,7 +269,8 @@ function selectTriggerRingProps(kbTrigger: boolean, open: boolean) {
266
269
  if (kbTrigger && !open) {
267
270
  return { ...keyboardFocusRingProps, "data-kb-ring": "true" as const };
268
271
  }
269
- return { ...selectRowOutlineRest, "data-kb-ring": undefined };
272
+ // Focus modality owns the outline; the control recipe owns trigger shape.
273
+ return { ...selectOutlineRest, "data-kb-ring": undefined };
270
274
  }
271
275
 
272
276
  function selectItemRingProps(isActive: boolean, kbNav: boolean) {
@@ -398,6 +402,10 @@ const SelectItem = memo(function SelectItem({
398
402
  },
399
403
  onPointerDown() {
400
404
  ctx.setKbNav(false);
405
+ // A press on a mounted row is a new gesture, not the release that
406
+ // opened this covering panel. Arm immediately, regardless of time.
407
+ ctx.allowMouseUpRef.current = true;
408
+ ctx.allowSelectRef.current = true;
401
409
  },
402
410
  onMouseUp() {
403
411
  if (!ctx.allowMouseUpRef.current) {
@@ -598,6 +606,16 @@ function FloatingSelectCore({
598
606
 
599
607
  const { scrollRef: dragScrollRef, dragProps } = useDragScroll({
600
608
  direction: "vertical",
609
+ onDragEnd: () => {
610
+ // The following mouseup finishes scrolling; it must not pick a row.
611
+ allowSelectRef.current = false;
612
+ allowMouseUpRef.current = false;
613
+ if (selectTimeoutRef.current) clearTimeout(selectTimeoutRef.current);
614
+ selectTimeoutRef.current = setTimeout(() => {
615
+ allowSelectRef.current = true;
616
+ allowMouseUpRef.current = true;
617
+ });
618
+ },
601
619
  });
602
620
 
603
621
  // Sync drag scroll ref with floating ref
@@ -1006,6 +1024,7 @@ function FloatingSelectCore({
1006
1024
  suppressFocusRing={open}
1007
1025
  size={knobProps.sizeToken}
1008
1026
  {...pickerTriggerContract(knobProps.control.height)}
1027
+ paddingHorizontal={knobProps.panelPadding.padding}
1009
1028
  {...(inTableCell
1010
1029
  ? // Chromeless in cells.
1011
1030
  {}
@@ -1017,9 +1036,8 @@ function FloatingSelectCore({
1017
1036
  <SyncKeyboardFocusToBox active={kbTrigger && !open} />
1018
1037
  <View
1019
1038
  flex={1}
1020
- // LC-18 (UX-021): trigger inset rides the space knob so trigger text
1021
- // stays column-aligned with the menu rows at every density.
1022
- paddingHorizontal={knobProps.panelPadding.padding}
1039
+ // The Box owns the same horizontal inset as the option rows.
1040
+ minWidth={0}
1023
1041
  paddingVertical="$2"
1024
1042
  justifyContent={multiple && selectedValues.length > 0 ? "center" : "flex-start"}
1025
1043
  alignItems={multiple && selectedValues.length > 0 ? "center" : "flex-start"}
@@ -1061,7 +1079,7 @@ function FloatingSelectCore({
1061
1079
  </Text>
1062
1080
  )}
1063
1081
  </View>
1064
- <View paddingInlineEnd="$2" alignSelf="center">
1082
+ <View flexShrink={0} alignSelf="center">
1065
1083
  <CaretDownIcon size={16} color={glyphColor} />
1066
1084
  </View>
1067
1085
  </InputParts.Box>
@@ -1221,6 +1239,8 @@ function NativeSelectCore({
1221
1239
  const [open, setOpen] = useState(false);
1222
1240
  const [activeIndex, setActiveIndex] = useState<number | null>(0);
1223
1241
  const listRef = useRef<HTMLElement | null>(null);
1242
+ const listboxId = `${id}-listbox`;
1243
+ const optionId = (index: number) => `${listboxId}-option-${index}`;
1224
1244
  const { kbTrigger, kbNav, setKbNav, onTriggerFocus, onTriggerBlur, onTriggerPointerDown } =
1225
1245
  useSelectKeyboardRing();
1226
1246
 
@@ -1332,12 +1352,22 @@ function NativeSelectCore({
1332
1352
  // VoiceOver blob.
1333
1353
  <View
1334
1354
  ref={listRef as any}
1355
+ // React Native's Role type omits listbox; these are DOM-only attributes.
1335
1356
  {...(isWeb
1336
- ? {
1337
- tabIndex: 0,
1357
+ ? ({
1358
+ id: listboxId,
1359
+ role: "listbox" as const,
1360
+ "aria-label": ariaLabel ?? fieldA11y?.label ?? placeholder,
1361
+ "aria-multiselectable": multiple || undefined,
1362
+ "aria-hidden": !open,
1363
+ "aria-activedescendant":
1364
+ activeIndex != null && displayOptions[activeIndex]
1365
+ ? optionId(activeIndex)
1366
+ : undefined,
1367
+ tabIndex: open ? 0 : -1,
1338
1368
  onKeyDown: handleListKeyDown,
1339
1369
  onFocus: () => setKbNav(wasKeyboardFocus()),
1340
- }
1370
+ } as Record<string, unknown>)
1341
1371
  : undefined)}
1342
1372
  outlineStyle="none"
1343
1373
  >
@@ -1360,6 +1390,9 @@ function NativeSelectCore({
1360
1390
  const row = (
1361
1391
  <View
1362
1392
  key={isWeb ? option.value : undefined}
1393
+ {...(isWeb
1394
+ ? { id: optionId(i), role: "option" as const, "aria-selected": selected }
1395
+ : undefined)}
1363
1396
  flexDirection="row"
1364
1397
  alignItems="center"
1365
1398
  borderRadius={0}
@@ -1465,6 +1498,7 @@ function NativeSelectCore({
1465
1498
  disabled={disabled}
1466
1499
  size={knobProps.sizeToken}
1467
1500
  {...pickerTriggerContract(knobProps.control.height)}
1501
+ paddingHorizontal={knobProps.panelPadding.padding}
1468
1502
  pointerEvents="none"
1469
1503
  {...(inTableCell
1470
1504
  ? {}
@@ -1477,7 +1511,7 @@ function NativeSelectCore({
1477
1511
  >
1478
1512
  <View
1479
1513
  flex={1}
1480
- paddingHorizontal={knobProps.panelPadding.padding}
1514
+ minWidth={0}
1481
1515
  paddingVertical="$2"
1482
1516
  justifyContent="flex-start"
1483
1517
  alignItems="flex-start"
@@ -1492,7 +1526,7 @@ function NativeSelectCore({
1492
1526
  {triggerValueText}
1493
1527
  </Text>
1494
1528
  </View>
1495
- <View paddingInlineEnd="$2" alignSelf="center">
1529
+ <View flexShrink={0} alignSelf="center">
1496
1530
  <CaretDownIcon size={16} />
1497
1531
  </View>
1498
1532
  </InputParts.Box>
@@ -1518,6 +1552,7 @@ function NativeSelectCore({
1518
1552
  disabled={disabled}
1519
1553
  size={knobProps.sizeToken}
1520
1554
  {...pickerTriggerContract(knobProps.control.height)}
1555
+ paddingHorizontal={knobProps.panelPadding.padding}
1521
1556
  {...(inTableCell
1522
1557
  ? {}
1523
1558
  : {
@@ -1537,6 +1572,7 @@ function NativeSelectCore({
1537
1572
  role: "combobox" as const,
1538
1573
  "aria-haspopup": "listbox",
1539
1574
  "aria-expanded": open,
1575
+ "aria-controls": open ? listboxId : undefined,
1540
1576
  "aria-autocomplete": "none",
1541
1577
  // Standalone (no label): fall back to placeholder so the
1542
1578
  // trigger still has a name (axe button-name). Labelled: the
@@ -1547,8 +1583,8 @@ function NativeSelectCore({
1547
1583
  tabIndex: disabled ? -1 : 0,
1548
1584
  }
1549
1585
  : { importantForAccessibility: "no" as const })}
1550
- // Sheet capture opens first on web. Keep this opener idempotent;
1551
- // native delegates the gesture to FloatingPanel's Pressable.
1586
+ // The web sheet shares this gesture with FloatingPanel's capture
1587
+ // opener. Both must open idempotently. Native owns its own press.
1552
1588
  onPress={isWeb && !disabled ? () => setOpen(true) : undefined}
1553
1589
  onFocus={isWeb ? onTriggerFocus : undefined}
1554
1590
  onBlur={isWeb ? onTriggerBlur : undefined}
@@ -1567,9 +1603,8 @@ function NativeSelectCore({
1567
1603
  <SyncKeyboardFocusToBox active={kbTrigger && !open} />
1568
1604
  <View
1569
1605
  flex={1}
1570
- // LC-18 (UX-021): trigger inset rides the space knob (matches the
1571
- // floating trigger and sheet rows).
1572
- paddingHorizontal={knobProps.panelPadding.padding}
1606
+ // The Box owns the same horizontal inset as the option rows.
1607
+ minWidth={0}
1573
1608
  paddingVertical="$2"
1574
1609
  justifyContent={multiple && selectedValues.length > 0 ? "center" : "flex-start"}
1575
1610
  alignItems={multiple && selectedValues.length > 0 ? "center" : "flex-start"}
@@ -1610,7 +1645,7 @@ function NativeSelectCore({
1610
1645
  </Text>
1611
1646
  )}
1612
1647
  </View>
1613
- <View paddingInlineEnd="$2" alignSelf="center">
1648
+ <View flexShrink={0} alignSelf="center">
1614
1649
  <CaretDownIcon size={16} color={glyphColor} />
1615
1650
  </View>
1616
1651
  </InputParts.Box>