@multiplatform.one/forms 7.46.0 → 7.47.1

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 (541) hide show
  1. package/dist/cjs/Button/index.cjs +14 -3
  2. package/dist/cjs/Button/index.native.js +18 -7
  3. package/dist/cjs/Button/index.native.js.map +1 -1
  4. package/dist/cjs/ErrorSummary.cjs +1 -1
  5. package/dist/cjs/ErrorSummary.native.js +1 -1
  6. package/dist/cjs/ErrorSummary.native.js.map +1 -1
  7. package/dist/cjs/FloatingPanel/PanelPortal.cjs +1 -1
  8. package/dist/cjs/FloatingPanel/index.cjs +13 -4
  9. package/dist/cjs/FloatingPanel/index.native.js +9 -2
  10. package/dist/cjs/FloatingPanel/index.native.js.map +1 -1
  11. package/dist/cjs/FloatingPanel/trailingAction.cjs +59 -0
  12. package/dist/cjs/FloatingPanel/trailingAction.native.js +64 -0
  13. package/dist/cjs/FloatingPanel/trailingAction.native.js.map +1 -0
  14. package/dist/cjs/FormGrid.cjs +1 -0
  15. package/dist/cjs/FormGrid.native.js +1 -0
  16. package/dist/cjs/FormGrid.native.js.map +1 -1
  17. package/dist/cjs/InputParts/PasswordReveal.cjs +96 -0
  18. package/dist/cjs/InputParts/PasswordReveal.native.js +104 -0
  19. package/dist/cjs/InputParts/PasswordReveal.native.js.map +1 -0
  20. package/dist/cjs/InputParts/index.cjs +95 -5
  21. package/dist/cjs/InputParts/index.native.js +99 -5
  22. package/dist/cjs/InputParts/index.native.js.map +1 -1
  23. package/dist/cjs/fields/ColorPicker/index.cjs +8 -17
  24. package/dist/cjs/fields/ColorPicker/index.native.js +9 -18
  25. package/dist/cjs/fields/ColorPicker/index.native.js.map +1 -1
  26. package/dist/cjs/fields/Combobox/index.cjs +28 -44
  27. package/dist/cjs/fields/Combobox/index.native.js +30 -45
  28. package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
  29. package/dist/cjs/fields/DatePicker/Calendar.cjs +3 -4
  30. package/dist/cjs/fields/DatePicker/Calendar.native.js +3 -4
  31. package/dist/cjs/fields/DatePicker/Calendar.native.js.map +1 -1
  32. package/dist/cjs/fields/DatePicker/parts.cjs +5 -9
  33. package/dist/cjs/fields/DatePicker/parts.native.js +5 -9
  34. package/dist/cjs/fields/DatePicker/parts.native.js.map +1 -1
  35. package/dist/cjs/fields/Duration/durationMath.cjs +1 -1
  36. package/dist/cjs/fields/Duration/durationMath.native.js +1 -1
  37. package/dist/cjs/fields/Duration/durationMath.native.js.map +1 -1
  38. package/dist/cjs/fields/Duration/index.cjs +100 -90
  39. package/dist/cjs/fields/Duration/index.native.js +108 -98
  40. package/dist/cjs/fields/Duration/index.native.js.map +1 -1
  41. package/dist/cjs/fields/FileUpload/index.cjs +134 -24
  42. package/dist/cjs/fields/FileUpload/index.native.js +149 -34
  43. package/dist/cjs/fields/FileUpload/index.native.js.map +1 -1
  44. package/dist/cjs/fields/Geolocation/GeolocationMap.cjs +2 -1
  45. package/dist/cjs/fields/Geolocation/GeolocationMap.native.js +3 -2
  46. package/dist/cjs/fields/Geolocation/GeolocationMap.native.js.map +1 -1
  47. package/dist/cjs/fields/Geolocation/index.cjs +10 -8
  48. package/dist/cjs/fields/Geolocation/index.native.js +10 -8
  49. package/dist/cjs/fields/Geolocation/index.native.js.map +1 -1
  50. package/dist/cjs/fields/Icon/index.cjs +6 -13
  51. package/dist/cjs/fields/Icon/index.native.js +6 -13
  52. package/dist/cjs/fields/Icon/index.native.js.map +1 -1
  53. package/dist/cjs/fields/ImageField/index.cjs +5 -5
  54. package/dist/cjs/fields/ImageField/index.native.js +5 -5
  55. package/dist/cjs/fields/ImageField/index.native.js.map +1 -1
  56. package/dist/cjs/fields/Input/index.cjs +27 -21
  57. package/dist/cjs/fields/Input/index.native.js +28 -21
  58. package/dist/cjs/fields/Input/index.native.js.map +1 -1
  59. package/dist/cjs/fields/MentionInput/index.cjs +7 -8
  60. package/dist/cjs/fields/MentionInput/index.native.js +7 -8
  61. package/dist/cjs/fields/MentionInput/index.native.js.map +1 -1
  62. package/dist/cjs/fields/OTPInput/index.cjs +1 -1
  63. package/dist/cjs/fields/OTPInput/index.native.js +1 -1
  64. package/dist/cjs/fields/OTPInput/index.native.js.map +1 -1
  65. package/dist/cjs/fields/PhoneInput/index.cjs +3 -3
  66. package/dist/cjs/fields/PhoneInput/index.native.js +3 -3
  67. package/dist/cjs/fields/PhoneInput/index.native.js.map +1 -1
  68. package/dist/cjs/fields/RadioGroup/index.cjs +1 -0
  69. package/dist/cjs/fields/RadioGroup/index.native.js +1 -0
  70. package/dist/cjs/fields/RadioGroup/index.native.js.map +1 -1
  71. package/dist/cjs/fields/SearchInput/index.cjs +4 -48
  72. package/dist/cjs/fields/SearchInput/index.native.js +4 -46
  73. package/dist/cjs/fields/SearchInput/index.native.js.map +1 -1
  74. package/dist/cjs/fields/Select/index.cjs +14 -12
  75. package/dist/cjs/fields/Select/index.native.js +14 -12
  76. package/dist/cjs/fields/Select/index.native.js.map +1 -1
  77. package/dist/cjs/fields/Signature/index.cjs +1 -1
  78. package/dist/cjs/fields/Signature/index.native.js +1 -1
  79. package/dist/cjs/fields/Signature/index.native.js.map +1 -1
  80. package/dist/cjs/fields/Slider/index.cjs +1 -1
  81. package/dist/cjs/fields/Slider/index.native.js +1 -1
  82. package/dist/cjs/fields/Slider/index.native.js.map +1 -1
  83. package/dist/cjs/fields/TimePicker/parts.cjs +5 -9
  84. package/dist/cjs/fields/TimePicker/parts.native.js +5 -9
  85. package/dist/cjs/fields/TimePicker/parts.native.js.map +1 -1
  86. package/dist/cjs/fields/TimeRangeScrubber/index.cjs +14 -9
  87. package/dist/cjs/fields/TimeRangeScrubber/index.native.js +14 -9
  88. package/dist/cjs/fields/TimeRangeScrubber/index.native.js.map +1 -1
  89. package/dist/cjs/fields/ToggleGroup/index.cjs +1 -1
  90. package/dist/cjs/fields/ToggleGroup/index.native.js +1 -1
  91. package/dist/cjs/fields/ToggleGroup/index.native.js.map +1 -1
  92. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.cjs +5 -5
  93. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js +5 -5
  94. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  95. package/dist/cjs/hooks/useFocusManagement.cjs +3 -2
  96. package/dist/cjs/hooks/useFocusManagement.native.js +3 -2
  97. package/dist/cjs/hooks/useFocusManagement.native.js.map +1 -1
  98. package/dist/cjs/index.cjs +7 -0
  99. package/dist/cjs/index.native.js +7 -0
  100. package/dist/cjs/index.native.js.map +1 -1
  101. package/dist/cjs/shared/focusManagement.cjs +1 -1
  102. package/dist/cjs/shared/focusManagement.native.js +1 -1
  103. package/dist/cjs/shared/panelPortal.cjs +1 -1
  104. package/dist/cjs/shared/panelPortal.native.js +1 -1
  105. package/dist/cjs/shared/panelPortal.native.js.map +1 -1
  106. package/dist/cjs/shared/useDragScroll.cjs +2 -2
  107. package/dist/cjs/shared/useDragScroll.native.js +2 -2
  108. package/dist/cjs/shared/useDragScroll.native.js.map +1 -1
  109. package/dist/esm/Button/index.mjs +17 -6
  110. package/dist/esm/Button/index.mjs.map +1 -1
  111. package/dist/esm/Button/index.native.js +21 -10
  112. package/dist/esm/Button/index.native.js.map +1 -1
  113. package/dist/esm/ErrorSummary.mjs +2 -2
  114. package/dist/esm/ErrorSummary.mjs.map +1 -1
  115. package/dist/esm/ErrorSummary.native.js +2 -2
  116. package/dist/esm/ErrorSummary.native.js.map +1 -1
  117. package/dist/esm/FloatingPanel/PanelPortal.mjs +1 -1
  118. package/dist/esm/FloatingPanel/PanelPortal.mjs.map +1 -1
  119. package/dist/esm/FloatingPanel/index.mjs +13 -4
  120. package/dist/esm/FloatingPanel/index.mjs.map +1 -1
  121. package/dist/esm/FloatingPanel/index.native.js +9 -2
  122. package/dist/esm/FloatingPanel/index.native.js.map +1 -1
  123. package/dist/esm/FloatingPanel/trailingAction.mjs +33 -0
  124. package/dist/esm/FloatingPanel/trailingAction.mjs.map +1 -0
  125. package/dist/esm/FloatingPanel/trailingAction.native.js +35 -0
  126. package/dist/esm/FloatingPanel/trailingAction.native.js.map +1 -0
  127. package/dist/esm/FormGrid.mjs +1 -0
  128. package/dist/esm/FormGrid.mjs.map +1 -1
  129. package/dist/esm/FormGrid.native.js +1 -0
  130. package/dist/esm/FormGrid.native.js.map +1 -1
  131. package/dist/esm/InputParts/PasswordReveal.mjs +68 -0
  132. package/dist/esm/InputParts/PasswordReveal.mjs.map +1 -0
  133. package/dist/esm/InputParts/PasswordReveal.native.js +73 -0
  134. package/dist/esm/InputParts/PasswordReveal.native.js.map +1 -0
  135. package/dist/esm/InputParts/index.mjs +97 -8
  136. package/dist/esm/InputParts/index.mjs.map +1 -1
  137. package/dist/esm/InputParts/index.native.js +101 -8
  138. package/dist/esm/InputParts/index.native.js.map +1 -1
  139. package/dist/esm/fields/ColorPicker/index.mjs +8 -17
  140. package/dist/esm/fields/ColorPicker/index.mjs.map +1 -1
  141. package/dist/esm/fields/ColorPicker/index.native.js +9 -18
  142. package/dist/esm/fields/ColorPicker/index.native.js.map +1 -1
  143. package/dist/esm/fields/Combobox/index.mjs +29 -45
  144. package/dist/esm/fields/Combobox/index.mjs.map +1 -1
  145. package/dist/esm/fields/Combobox/index.native.js +31 -46
  146. package/dist/esm/fields/Combobox/index.native.js.map +1 -1
  147. package/dist/esm/fields/DatePicker/Calendar.mjs +4 -5
  148. package/dist/esm/fields/DatePicker/Calendar.mjs.map +1 -1
  149. package/dist/esm/fields/DatePicker/Calendar.native.js +4 -5
  150. package/dist/esm/fields/DatePicker/Calendar.native.js.map +1 -1
  151. package/dist/esm/fields/DatePicker/parts.mjs +5 -9
  152. package/dist/esm/fields/DatePicker/parts.mjs.map +1 -1
  153. package/dist/esm/fields/DatePicker/parts.native.js +5 -9
  154. package/dist/esm/fields/DatePicker/parts.native.js.map +1 -1
  155. package/dist/esm/fields/Duration/durationMath.mjs +1 -1
  156. package/dist/esm/fields/Duration/durationMath.mjs.map +1 -1
  157. package/dist/esm/fields/Duration/durationMath.native.js +1 -1
  158. package/dist/esm/fields/Duration/index.mjs +100 -90
  159. package/dist/esm/fields/Duration/index.mjs.map +1 -1
  160. package/dist/esm/fields/Duration/index.native.js +108 -98
  161. package/dist/esm/fields/Duration/index.native.js.map +1 -1
  162. package/dist/esm/fields/FileUpload/index.mjs +135 -25
  163. package/dist/esm/fields/FileUpload/index.mjs.map +1 -1
  164. package/dist/esm/fields/FileUpload/index.native.js +150 -35
  165. package/dist/esm/fields/FileUpload/index.native.js.map +1 -1
  166. package/dist/esm/fields/Geolocation/GeolocationMap.mjs +2 -1
  167. package/dist/esm/fields/Geolocation/GeolocationMap.mjs.map +1 -1
  168. package/dist/esm/fields/Geolocation/GeolocationMap.native.js +2 -1
  169. package/dist/esm/fields/Geolocation/GeolocationMap.native.js.map +1 -1
  170. package/dist/esm/fields/Geolocation/index.mjs +13 -11
  171. package/dist/esm/fields/Geolocation/index.mjs.map +1 -1
  172. package/dist/esm/fields/Geolocation/index.native.js +13 -11
  173. package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
  174. package/dist/esm/fields/Icon/index.mjs +8 -15
  175. package/dist/esm/fields/Icon/index.mjs.map +1 -1
  176. package/dist/esm/fields/Icon/index.native.js +8 -15
  177. package/dist/esm/fields/Icon/index.native.js.map +1 -1
  178. package/dist/esm/fields/ImageField/index.mjs +7 -7
  179. package/dist/esm/fields/ImageField/index.mjs.map +1 -1
  180. package/dist/esm/fields/ImageField/index.native.js +7 -7
  181. package/dist/esm/fields/ImageField/index.native.js.map +1 -1
  182. package/dist/esm/fields/Input/index.mjs +28 -22
  183. package/dist/esm/fields/Input/index.mjs.map +1 -1
  184. package/dist/esm/fields/Input/index.native.js +29 -22
  185. package/dist/esm/fields/Input/index.native.js.map +1 -1
  186. package/dist/esm/fields/MentionInput/index.mjs +13 -14
  187. package/dist/esm/fields/MentionInput/index.mjs.map +1 -1
  188. package/dist/esm/fields/MentionInput/index.native.js +13 -14
  189. package/dist/esm/fields/MentionInput/index.native.js.map +1 -1
  190. package/dist/esm/fields/OTPInput/index.mjs +2 -2
  191. package/dist/esm/fields/OTPInput/index.mjs.map +1 -1
  192. package/dist/esm/fields/OTPInput/index.native.js +2 -2
  193. package/dist/esm/fields/OTPInput/index.native.js.map +1 -1
  194. package/dist/esm/fields/PhoneInput/index.mjs +5 -5
  195. package/dist/esm/fields/PhoneInput/index.mjs.map +1 -1
  196. package/dist/esm/fields/PhoneInput/index.native.js +5 -5
  197. package/dist/esm/fields/PhoneInput/index.native.js.map +1 -1
  198. package/dist/esm/fields/RadioGroup/index.mjs +1 -0
  199. package/dist/esm/fields/RadioGroup/index.mjs.map +1 -1
  200. package/dist/esm/fields/RadioGroup/index.native.js +1 -0
  201. package/dist/esm/fields/RadioGroup/index.native.js.map +1 -1
  202. package/dist/esm/fields/SearchInput/index.mjs +5 -49
  203. package/dist/esm/fields/SearchInput/index.mjs.map +1 -1
  204. package/dist/esm/fields/SearchInput/index.native.js +5 -47
  205. package/dist/esm/fields/SearchInput/index.native.js.map +1 -1
  206. package/dist/esm/fields/Select/index.mjs +15 -13
  207. package/dist/esm/fields/Select/index.mjs.map +1 -1
  208. package/dist/esm/fields/Select/index.native.js +15 -13
  209. package/dist/esm/fields/Select/index.native.js.map +1 -1
  210. package/dist/esm/fields/Signature/index.mjs +2 -2
  211. package/dist/esm/fields/Signature/index.mjs.map +1 -1
  212. package/dist/esm/fields/Signature/index.native.js +2 -2
  213. package/dist/esm/fields/Signature/index.native.js.map +1 -1
  214. package/dist/esm/fields/Slider/index.mjs +2 -2
  215. package/dist/esm/fields/Slider/index.mjs.map +1 -1
  216. package/dist/esm/fields/Slider/index.native.js +2 -2
  217. package/dist/esm/fields/Slider/index.native.js.map +1 -1
  218. package/dist/esm/fields/TimePicker/parts.mjs +5 -9
  219. package/dist/esm/fields/TimePicker/parts.mjs.map +1 -1
  220. package/dist/esm/fields/TimePicker/parts.native.js +5 -9
  221. package/dist/esm/fields/TimePicker/parts.native.js.map +1 -1
  222. package/dist/esm/fields/TimeRangeScrubber/index.mjs +20 -15
  223. package/dist/esm/fields/TimeRangeScrubber/index.mjs.map +1 -1
  224. package/dist/esm/fields/TimeRangeScrubber/index.native.js +20 -15
  225. package/dist/esm/fields/TimeRangeScrubber/index.native.js.map +1 -1
  226. package/dist/esm/fields/ToggleGroup/index.mjs +3 -3
  227. package/dist/esm/fields/ToggleGroup/index.mjs.map +1 -1
  228. package/dist/esm/fields/ToggleGroup/index.native.js +3 -3
  229. package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
  230. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs +2 -2
  231. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
  232. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js +2 -2
  233. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  234. package/dist/esm/hooks/useFocusManagement.mjs +3 -2
  235. package/dist/esm/hooks/useFocusManagement.mjs.map +1 -1
  236. package/dist/esm/hooks/useFocusManagement.native.js +3 -2
  237. package/dist/esm/hooks/useFocusManagement.native.js.map +1 -1
  238. package/dist/esm/index.mjs +3 -1
  239. package/dist/esm/index.mjs.map +1 -1
  240. package/dist/esm/index.native.js +3 -1
  241. package/dist/esm/index.native.js.map +1 -1
  242. package/dist/esm/shared/focusManagement.mjs +1 -1
  243. package/dist/esm/shared/focusManagement.mjs.map +1 -1
  244. package/dist/esm/shared/focusManagement.native.js +1 -1
  245. package/dist/esm/shared/panelPortal.mjs +1 -1
  246. package/dist/esm/shared/panelPortal.mjs.map +1 -1
  247. package/dist/esm/shared/panelPortal.native.js +1 -1
  248. package/dist/esm/shared/panelPortal.native.js.map +1 -1
  249. package/dist/esm/shared/useDragScroll.mjs +2 -2
  250. package/dist/esm/shared/useDragScroll.mjs.map +1 -1
  251. package/dist/esm/shared/useDragScroll.native.js +2 -2
  252. package/dist/esm/shared/useDragScroll.native.js.map +1 -1
  253. package/dist/jsx/Button/index.mjs +17 -6
  254. package/dist/jsx/Button/index.mjs.map +1 -1
  255. package/dist/jsx/Button/index.native.js +18 -7
  256. package/dist/jsx/Button/index.native.js.map +1 -1
  257. package/dist/jsx/ErrorSummary.mjs +2 -2
  258. package/dist/jsx/ErrorSummary.mjs.map +1 -1
  259. package/dist/jsx/ErrorSummary.native.js +1 -1
  260. package/dist/jsx/ErrorSummary.native.js.map +1 -1
  261. package/dist/jsx/FloatingPanel/PanelPortal.mjs +1 -1
  262. package/dist/jsx/FloatingPanel/PanelPortal.mjs.map +1 -1
  263. package/dist/jsx/FloatingPanel/index.mjs +13 -4
  264. package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
  265. package/dist/jsx/FloatingPanel/index.native.js +9 -2
  266. package/dist/jsx/FloatingPanel/index.native.js.map +1 -1
  267. package/dist/jsx/FloatingPanel/trailingAction.mjs +33 -0
  268. package/dist/jsx/FloatingPanel/trailingAction.mjs.map +1 -0
  269. package/dist/jsx/FloatingPanel/trailingAction.native.js +64 -0
  270. package/dist/jsx/FloatingPanel/trailingAction.native.js.map +1 -0
  271. package/dist/jsx/FormGrid.mjs +1 -0
  272. package/dist/jsx/FormGrid.mjs.map +1 -1
  273. package/dist/jsx/FormGrid.native.js +1 -0
  274. package/dist/jsx/FormGrid.native.js.map +1 -1
  275. package/dist/jsx/InputParts/PasswordReveal.mjs +68 -0
  276. package/dist/jsx/InputParts/PasswordReveal.mjs.map +1 -0
  277. package/dist/jsx/InputParts/PasswordReveal.native.js +104 -0
  278. package/dist/jsx/InputParts/PasswordReveal.native.js.map +1 -0
  279. package/dist/jsx/InputParts/index.mjs +97 -8
  280. package/dist/jsx/InputParts/index.mjs.map +1 -1
  281. package/dist/jsx/InputParts/index.native.js +99 -5
  282. package/dist/jsx/InputParts/index.native.js.map +1 -1
  283. package/dist/jsx/fields/ColorPicker/index.mjs +8 -17
  284. package/dist/jsx/fields/ColorPicker/index.mjs.map +1 -1
  285. package/dist/jsx/fields/ColorPicker/index.native.js +9 -18
  286. package/dist/jsx/fields/ColorPicker/index.native.js.map +1 -1
  287. package/dist/jsx/fields/Combobox/index.mjs +29 -45
  288. package/dist/jsx/fields/Combobox/index.mjs.map +1 -1
  289. package/dist/jsx/fields/Combobox/index.native.js +30 -45
  290. package/dist/jsx/fields/Combobox/index.native.js.map +1 -1
  291. package/dist/jsx/fields/DatePicker/Calendar.mjs +4 -5
  292. package/dist/jsx/fields/DatePicker/Calendar.mjs.map +1 -1
  293. package/dist/jsx/fields/DatePicker/Calendar.native.js +3 -4
  294. package/dist/jsx/fields/DatePicker/Calendar.native.js.map +1 -1
  295. package/dist/jsx/fields/DatePicker/parts.mjs +5 -9
  296. package/dist/jsx/fields/DatePicker/parts.mjs.map +1 -1
  297. package/dist/jsx/fields/DatePicker/parts.native.js +5 -9
  298. package/dist/jsx/fields/DatePicker/parts.native.js.map +1 -1
  299. package/dist/jsx/fields/Duration/durationMath.mjs +1 -1
  300. package/dist/jsx/fields/Duration/durationMath.mjs.map +1 -1
  301. package/dist/jsx/fields/Duration/durationMath.native.js +1 -1
  302. package/dist/jsx/fields/Duration/durationMath.native.js.map +1 -1
  303. package/dist/jsx/fields/Duration/index.mjs +100 -90
  304. package/dist/jsx/fields/Duration/index.mjs.map +1 -1
  305. package/dist/jsx/fields/Duration/index.native.js +108 -98
  306. package/dist/jsx/fields/Duration/index.native.js.map +1 -1
  307. package/dist/jsx/fields/FileUpload/index.mjs +135 -25
  308. package/dist/jsx/fields/FileUpload/index.mjs.map +1 -1
  309. package/dist/jsx/fields/FileUpload/index.native.js +149 -34
  310. package/dist/jsx/fields/FileUpload/index.native.js.map +1 -1
  311. package/dist/jsx/fields/Geolocation/GeolocationMap.mjs +2 -1
  312. package/dist/jsx/fields/Geolocation/GeolocationMap.mjs.map +1 -1
  313. package/dist/jsx/fields/Geolocation/GeolocationMap.native.js +3 -2
  314. package/dist/jsx/fields/Geolocation/GeolocationMap.native.js.map +1 -1
  315. package/dist/jsx/fields/Geolocation/index.mjs +13 -11
  316. package/dist/jsx/fields/Geolocation/index.mjs.map +1 -1
  317. package/dist/jsx/fields/Geolocation/index.native.js +10 -8
  318. package/dist/jsx/fields/Geolocation/index.native.js.map +1 -1
  319. package/dist/jsx/fields/Icon/index.mjs +8 -15
  320. package/dist/jsx/fields/Icon/index.mjs.map +1 -1
  321. package/dist/jsx/fields/Icon/index.native.js +6 -13
  322. package/dist/jsx/fields/Icon/index.native.js.map +1 -1
  323. package/dist/jsx/fields/ImageField/index.mjs +7 -7
  324. package/dist/jsx/fields/ImageField/index.mjs.map +1 -1
  325. package/dist/jsx/fields/ImageField/index.native.js +5 -5
  326. package/dist/jsx/fields/ImageField/index.native.js.map +1 -1
  327. package/dist/jsx/fields/Input/index.mjs +28 -22
  328. package/dist/jsx/fields/Input/index.mjs.map +1 -1
  329. package/dist/jsx/fields/Input/index.native.js +28 -21
  330. package/dist/jsx/fields/Input/index.native.js.map +1 -1
  331. package/dist/jsx/fields/MentionInput/index.mjs +13 -14
  332. package/dist/jsx/fields/MentionInput/index.mjs.map +1 -1
  333. package/dist/jsx/fields/MentionInput/index.native.js +7 -8
  334. package/dist/jsx/fields/MentionInput/index.native.js.map +1 -1
  335. package/dist/jsx/fields/OTPInput/index.mjs +2 -2
  336. package/dist/jsx/fields/OTPInput/index.mjs.map +1 -1
  337. package/dist/jsx/fields/OTPInput/index.native.js +1 -1
  338. package/dist/jsx/fields/OTPInput/index.native.js.map +1 -1
  339. package/dist/jsx/fields/PhoneInput/index.mjs +5 -5
  340. package/dist/jsx/fields/PhoneInput/index.mjs.map +1 -1
  341. package/dist/jsx/fields/PhoneInput/index.native.js +3 -3
  342. package/dist/jsx/fields/PhoneInput/index.native.js.map +1 -1
  343. package/dist/jsx/fields/RadioGroup/index.mjs +1 -0
  344. package/dist/jsx/fields/RadioGroup/index.mjs.map +1 -1
  345. package/dist/jsx/fields/RadioGroup/index.native.js +1 -0
  346. package/dist/jsx/fields/RadioGroup/index.native.js.map +1 -1
  347. package/dist/jsx/fields/SearchInput/index.mjs +5 -49
  348. package/dist/jsx/fields/SearchInput/index.mjs.map +1 -1
  349. package/dist/jsx/fields/SearchInput/index.native.js +4 -46
  350. package/dist/jsx/fields/SearchInput/index.native.js.map +1 -1
  351. package/dist/jsx/fields/Select/index.mjs +15 -13
  352. package/dist/jsx/fields/Select/index.mjs.map +1 -1
  353. package/dist/jsx/fields/Select/index.native.js +14 -12
  354. package/dist/jsx/fields/Select/index.native.js.map +1 -1
  355. package/dist/jsx/fields/Signature/index.mjs +2 -2
  356. package/dist/jsx/fields/Signature/index.mjs.map +1 -1
  357. package/dist/jsx/fields/Signature/index.native.js +1 -1
  358. package/dist/jsx/fields/Signature/index.native.js.map +1 -1
  359. package/dist/jsx/fields/Slider/index.mjs +2 -2
  360. package/dist/jsx/fields/Slider/index.mjs.map +1 -1
  361. package/dist/jsx/fields/Slider/index.native.js +1 -1
  362. package/dist/jsx/fields/Slider/index.native.js.map +1 -1
  363. package/dist/jsx/fields/TimePicker/parts.mjs +5 -9
  364. package/dist/jsx/fields/TimePicker/parts.mjs.map +1 -1
  365. package/dist/jsx/fields/TimePicker/parts.native.js +5 -9
  366. package/dist/jsx/fields/TimePicker/parts.native.js.map +1 -1
  367. package/dist/jsx/fields/TimeRangeScrubber/index.mjs +20 -15
  368. package/dist/jsx/fields/TimeRangeScrubber/index.mjs.map +1 -1
  369. package/dist/jsx/fields/TimeRangeScrubber/index.native.js +14 -9
  370. package/dist/jsx/fields/TimeRangeScrubber/index.native.js.map +1 -1
  371. package/dist/jsx/fields/ToggleGroup/index.mjs +3 -3
  372. package/dist/jsx/fields/ToggleGroup/index.mjs.map +1 -1
  373. package/dist/jsx/fields/ToggleGroup/index.native.js +1 -1
  374. package/dist/jsx/fields/ToggleGroup/index.native.js.map +1 -1
  375. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs +2 -2
  376. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
  377. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js +5 -5
  378. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  379. package/dist/jsx/hooks/useFocusManagement.mjs +3 -2
  380. package/dist/jsx/hooks/useFocusManagement.mjs.map +1 -1
  381. package/dist/jsx/hooks/useFocusManagement.native.js +3 -2
  382. package/dist/jsx/hooks/useFocusManagement.native.js.map +1 -1
  383. package/dist/jsx/index.js +3 -1
  384. package/dist/jsx/index.js.map +1 -1
  385. package/dist/jsx/index.mjs +3 -1
  386. package/dist/jsx/index.mjs.map +1 -1
  387. package/dist/jsx/index.native.js +7 -0
  388. package/dist/jsx/index.native.js.map +1 -1
  389. package/dist/jsx/shared/focusManagement.mjs +1 -1
  390. package/dist/jsx/shared/focusManagement.mjs.map +1 -1
  391. package/dist/jsx/shared/focusManagement.native.js +1 -1
  392. package/dist/jsx/shared/focusManagement.native.js.map +1 -1
  393. package/dist/jsx/shared/panelPortal.mjs +1 -1
  394. package/dist/jsx/shared/panelPortal.mjs.map +1 -1
  395. package/dist/jsx/shared/panelPortal.native.js +1 -1
  396. package/dist/jsx/shared/panelPortal.native.js.map +1 -1
  397. package/dist/jsx/shared/useDragScroll.mjs +2 -2
  398. package/dist/jsx/shared/useDragScroll.mjs.map +1 -1
  399. package/dist/jsx/shared/useDragScroll.native.js +2 -2
  400. package/dist/jsx/shared/useDragScroll.native.js.map +1 -1
  401. package/package.json +8 -8
  402. package/src/AdaptivePopup/AdaptivePopup.stories.tsx +2 -1
  403. package/src/Button/Button.borderLadder.spec.tsx +32 -7
  404. package/src/Button/Button.edge.spec.tsx +68 -0
  405. package/src/Button/Button.stories.tsx +2 -1
  406. package/src/Button/index.tsx +37 -11
  407. package/src/Chip/Chip.stories.tsx +2 -1
  408. package/src/ContextualSaveBar/ContextualSaveBar.stories.tsx +2 -1
  409. package/src/ContextualSaveBar/UnsavedChangesDialog.stories.tsx +2 -1
  410. package/src/ControlGroup/ControlGroup.stories.tsx +2 -1
  411. package/src/DescriptionList/DescriptionList.stories.tsx +2 -1
  412. package/src/ErrorSummary.stories.tsx +2 -1
  413. package/src/ErrorSummary.tsx +2 -2
  414. package/src/FieldDisplay/FieldDisplay.stories.tsx +2 -1
  415. package/src/FieldLayout.stories.tsx +2 -2
  416. package/src/FloatingPanel/FloatingPanel.stories.tsx +2 -2
  417. package/src/FloatingPanel/PanelPortal.tsx +1 -0
  418. package/src/FloatingPanel/index.native.tsx +4 -2
  419. package/src/FloatingPanel/index.tsx +14 -4
  420. package/src/FloatingPanel/trailingAction.tsx +37 -0
  421. package/src/Form/Form.stories.tsx +2 -1
  422. package/src/FormGrid.stories.tsx +2 -1
  423. package/src/FormGrid.tsx +1 -0
  424. package/src/FormsIntegration.stories.tsx +4 -18
  425. package/src/InputParts/InputParts.stories.tsx +11 -11
  426. package/src/InputParts/PasswordReveal.tsx +94 -0
  427. package/src/InputParts/index.tsx +144 -2
  428. package/src/InputParts/inputPartsStories.spec.tsx +3 -1
  429. package/src/Skeleton/Skeleton.stories.tsx +2 -2
  430. package/src/Spinner/Spinner.stories.tsx +2 -2
  431. package/src/Wheel/Wheel.stories.tsx +2 -2
  432. package/src/fieldTrailingAction.spec.tsx +188 -0
  433. package/src/fields/Barcode/Barcode.stories.tsx +2 -1
  434. package/src/fields/Barcode/BarcodePreview.stories.tsx +2 -1
  435. package/src/fields/Checkbox/Checkbox.stories.tsx +3 -1
  436. package/src/fields/Checkbox/CheckboxGroup.stories.tsx +2 -2
  437. package/src/fields/Checkbox/Checkboxes.stories.tsx +2 -1
  438. package/src/fields/ColorPicker/PresetSwatches.stories.tsx +2 -1
  439. package/src/fields/ColorPicker/index.tsx +6 -12
  440. package/src/fields/Combobox/Combobox.stories.tsx +2 -1
  441. package/src/fields/Combobox/index.tsx +39 -41
  442. package/src/fields/DatePicker/Calendar.stories.tsx +2 -1
  443. package/src/fields/DatePicker/Calendar.tsx +4 -5
  444. package/src/fields/DatePicker/DatePicker.spec.tsx +2 -2
  445. package/src/fields/DatePicker/DatePicker.stories.tsx +2 -1
  446. package/src/fields/DatePicker/DateRangePicker.stories.tsx +2 -1
  447. package/src/fields/DatePicker/DatetimePicker.stories.tsx +2 -1
  448. package/src/fields/DatePicker/MonthPicker.stories.tsx +2 -1
  449. package/src/fields/DatePicker/MultiDatePicker.spec.tsx +1 -1
  450. package/src/fields/DatePicker/MultiDatePicker.stories.tsx +2 -1
  451. package/src/fields/DatePicker/parts.tsx +6 -10
  452. package/src/fields/Duration/Duration.spec.tsx +25 -1
  453. package/src/fields/Duration/Duration.stories.tsx +6 -1
  454. package/src/fields/Duration/durationMath.spec.ts +2 -2
  455. package/src/fields/Duration/durationMath.ts +1 -1
  456. package/src/fields/Duration/index.tsx +91 -70
  457. package/src/fields/FileUpload/FileUpload.spec.tsx +86 -3
  458. package/src/fields/FileUpload/FileUpload.stories.tsx +15 -0
  459. package/src/fields/FileUpload/index.tsx +170 -50
  460. package/src/fields/Geolocation/Geolocation.stories.tsx +2 -1
  461. package/src/fields/Geolocation/GeolocationMap.native.tsx +2 -1
  462. package/src/fields/Geolocation/GeolocationMap.tsx +2 -1
  463. package/src/fields/Geolocation/index.tsx +39 -16
  464. package/src/fields/Icon/index.tsx +9 -15
  465. package/src/fields/ImageField/index.tsx +9 -8
  466. package/src/fields/Input/Input.stories.tsx +39 -1
  467. package/src/fields/Input/index.tsx +45 -25
  468. package/src/fields/MentionInput/index.tsx +17 -18
  469. package/src/fields/OTPInput/OtpInput.stories.tsx +2 -1
  470. package/src/fields/OTPInput/index.tsx +2 -2
  471. package/src/fields/PhoneInput/PhoneInput.stories.tsx +2 -1
  472. package/src/fields/PhoneInput/index.tsx +10 -6
  473. package/src/fields/Progress/Progress.stories.tsx +2 -1
  474. package/src/fields/RadioGroup/RadioGroup.stories.tsx +3 -2
  475. package/src/fields/RadioGroup/index.tsx +1 -0
  476. package/src/fields/Rating/Rating.stories.tsx +2 -1
  477. package/src/fields/SearchInput/SearchInput.stories.tsx +2 -1
  478. package/src/fields/SearchInput/index.tsx +8 -45
  479. package/src/fields/Select/Select.stories.tsx +2 -2
  480. package/src/fields/Select/index.tsx +18 -12
  481. package/src/fields/Signature/Signature.stories.tsx +2 -1
  482. package/src/fields/Signature/index.tsx +6 -1
  483. package/src/fields/Slider/Slider.stories.tsx +2 -1
  484. package/src/fields/Slider/index.tsx +6 -2
  485. package/src/fields/Stepper/Stepper.stories.tsx +2 -1
  486. package/src/fields/Switch/Switch.stories.tsx +3 -1
  487. package/src/fields/TextArea/TextArea.stories.tsx +2 -1
  488. package/src/fields/TimePicker/TimePicker.stories.tsx +2 -1
  489. package/src/fields/TimePicker/parts.tsx +6 -10
  490. package/src/fields/TimeRangeScrubber/index.tsx +20 -18
  491. package/src/fields/ToggleGroup/ToggleGroup.stories.tsx +2 -8
  492. package/src/fields/ToggleGroup/index.tsx +10 -4
  493. package/src/fields/nativeDateTime/OsDateTimeSheet.tsx +2 -2
  494. package/src/fields/pickerActivation.spec.tsx +7 -3
  495. package/src/hooks/useFocusManagement.ts +3 -2
  496. package/src/index.ts +9 -0
  497. package/src/shared/focusManagement.ts +1 -1
  498. package/src/shared/panelPortal.ts +2 -1
  499. package/src/shared/useDragScroll.ts +2 -2
  500. package/types/Button/index.d.ts +9 -1
  501. package/types/Button/index.d.ts.map +1 -1
  502. package/types/FloatingPanel/PanelPortal.d.ts.map +1 -1
  503. package/types/FloatingPanel/index.d.ts.map +1 -1
  504. package/types/FloatingPanel/index.native.d.ts.map +1 -1
  505. package/types/FloatingPanel/trailingAction.d.ts +16 -0
  506. package/types/FloatingPanel/trailingAction.d.ts.map +1 -0
  507. package/types/InputParts/PasswordReveal.d.ts +28 -0
  508. package/types/InputParts/PasswordReveal.d.ts.map +1 -0
  509. package/types/InputParts/index.d.ts +34 -2
  510. package/types/InputParts/index.d.ts.map +1 -1
  511. package/types/fields/Checkbox/index.d.ts +4 -4
  512. package/types/fields/ColorPicker/index.d.ts.map +1 -1
  513. package/types/fields/Combobox/index.d.ts.map +1 -1
  514. package/types/fields/DatePicker/Calendar.d.ts.map +1 -1
  515. package/types/fields/DatePicker/parts.d.ts.map +1 -1
  516. package/types/fields/Duration/index.d.ts.map +1 -1
  517. package/types/fields/FileUpload/index.d.ts +1 -0
  518. package/types/fields/FileUpload/index.d.ts.map +1 -1
  519. package/types/fields/Geolocation/GeolocationMap.d.ts.map +1 -1
  520. package/types/fields/Geolocation/GeolocationMap.native.d.ts.map +1 -1
  521. package/types/fields/Geolocation/index.d.ts.map +1 -1
  522. package/types/fields/Icon/index.d.ts.map +1 -1
  523. package/types/fields/ImageField/index.d.ts.map +1 -1
  524. package/types/fields/Input/index.d.ts +9 -3
  525. package/types/fields/Input/index.d.ts.map +1 -1
  526. package/types/fields/MentionInput/index.d.ts.map +1 -1
  527. package/types/fields/PhoneInput/index.d.ts.map +1 -1
  528. package/types/fields/RadioGroup/index.d.ts +2 -2
  529. package/types/fields/RadioGroup/index.d.ts.map +1 -1
  530. package/types/fields/SearchInput/index.d.ts.map +1 -1
  531. package/types/fields/Select/index.d.ts.map +1 -1
  532. package/types/fields/Signature/index.d.ts.map +1 -1
  533. package/types/fields/Slider/index.d.ts.map +1 -1
  534. package/types/fields/TimePicker/parts.d.ts.map +1 -1
  535. package/types/fields/TimeRangeScrubber/index.d.ts.map +1 -1
  536. package/types/fields/ToggleGroup/index.d.ts +1 -1
  537. package/types/fields/ToggleGroup/index.d.ts.map +1 -1
  538. package/types/hooks/useFocusManagement.d.ts.map +1 -1
  539. package/types/index.d.ts +4 -0
  540. package/types/index.d.ts.map +1 -1
  541. package/types/shared/panelPortal.d.ts.map +1 -1
@@ -62,6 +62,62 @@ async function pickFile(container: Element, file: File) {
62
62
  }
63
63
 
64
64
  describe("FileUpload", () => {
65
+ it("shows a stored image with Replace and Remove instead of empty source choices", () => {
66
+ const remove = vi.fn();
67
+ const result = renderWithProviders(
68
+ <FileUpload existing={{ src: "/files/sprite.png" }} onExistingRemove={remove} />,
69
+ );
70
+ expect(result.container.textContent).toContain("Replace");
71
+ expect(result.container.textContent).not.toContain("Choose File");
72
+ expect(result.container.textContent).not.toContain("Drag a file");
73
+ expect(result.container.querySelector('[data-file-upload="preview"] img')).toBeTruthy();
74
+ fireEvent.click(result.getButton("Remove sprite.png")!);
75
+ expect(remove).toHaveBeenCalledTimes(1);
76
+ });
77
+
78
+ it("opens replacement sources and cancels without changing the stored attachment", async () => {
79
+ const onChange = vi.fn();
80
+ const result = renderWithProviders(
81
+ <FileUpload existing={{ src: "/files/sprite.png" }} onChange={onChange} />,
82
+ );
83
+ await act(async () => {
84
+ fireEvent.click(result.container.querySelector('[aria-label="Replace"]')!);
85
+ });
86
+ expect(result.container.textContent).toContain("Choose File");
87
+ expect(result.container.querySelector('[data-file-upload="preview"] img')).toBeTruthy();
88
+ await act(async () => {
89
+ fireEvent.click(result.container.querySelector('[aria-label="Cancel replacement"]')!);
90
+ });
91
+ expect(result.container.textContent).not.toContain("Choose File");
92
+ expect(onChange).not.toHaveBeenCalled();
93
+ });
94
+
95
+ it("renders a stored document as a file name without a broken image", () => {
96
+ const result = renderWithProviders(<FileUpload existing={{ src: "/files/report.pdf" }} />);
97
+ expect(result.container.textContent).toContain("report.pdf");
98
+ expect(result.container.querySelector("img")).toBeNull();
99
+ });
100
+
101
+ it("lets an empty dropzone follow its content height", () => {
102
+ const result = renderWithProviders(<FileUpload />);
103
+ expect(getZone(result.container).className).not.toMatch(/_minH-/);
104
+ expect(result.container.querySelector('[data-file-upload="sources"]')).toBeTruthy();
105
+ });
106
+
107
+ it("retains the stored preview when a replacement upload fails", async () => {
108
+ const result = renderWithProviders(
109
+ <FileUpload
110
+ existing={{ src: "/files/original.png" }}
111
+ onUpload={async () => {
112
+ throw new Error("Offline");
113
+ }}
114
+ />,
115
+ );
116
+ await pickFile(result.container, new File(["new"], "new.png", { type: "image/png" }));
117
+ await waitFor(() => expect(result.container.textContent).toContain("Offline"));
118
+ expect(result.container.querySelector('img[src="/files/original.png"]')).toBeTruthy();
119
+ });
120
+
65
121
  it("should render placeholder and upload button text", () => {
66
122
  const result = renderWithProviders(
67
123
  <FileUpload
@@ -290,7 +346,7 @@ describe("FileUpload bento-derived dropzone (MPO-57)", () => {
290
346
 
291
347
  it("renders picked files as in-zone rows: name, bold size line, filled $color12 remove disc (29 painted, hitSlop 44)", async () => {
292
348
  const { container } = renderWithHouseThemes(
293
- <FileUpload label="Attachment" name="attachment" />,
349
+ <FileUpload label="Attachment" name="attachment" multiple />,
294
350
  );
295
351
  await pickFile(container, new File(["hello"], "hello.txt", { type: "text/plain" }));
296
352
 
@@ -327,7 +383,7 @@ describe("FileUpload bento-derived dropzone (MPO-57)", () => {
327
383
 
328
384
  it("hangs the file list off ONE top hairline — bottom/left/right are 0, not the UA 3px initial (MPO-124)", async () => {
329
385
  const { container } = renderWithHouseThemes(
330
- <FileUpload label="Attachment" name="attachment" />,
386
+ <FileUpload label="Attachment" name="attachment" multiple />,
331
387
  );
332
388
  await pickFile(container, new File(["hello"], "hello.txt", { type: "text/plain" }));
333
389
 
@@ -352,7 +408,7 @@ describe("FileUpload bento-derived dropzone (MPO-57)", () => {
352
408
  (URL as any).revokeObjectURL = () => {};
353
409
  }
354
410
  const { container } = renderWithHouseThemes(
355
- <FileUpload label="Attachment" name="attachment" accept="image/*" showPreview />,
411
+ <FileUpload label="Attachment" name="attachment" multiple accept="image/*" showPreview />,
356
412
  );
357
413
  await pickFile(container, new File(["fake-png-bytes"], "diagram.png", { type: "image/png" }));
358
414
 
@@ -532,3 +588,30 @@ describe("FileUpload transfer lifecycle (MPO-55)", () => {
532
588
  hold();
533
589
  });
534
590
  });
591
+
592
+ it("does not resurrect the old stored value after removing its replacement", async () => {
593
+ const onChange = vi.fn();
594
+ const result = renderWithProviders(
595
+ <FileUpload existing={{ src: "/files/old.png" }} onChange={onChange} />,
596
+ );
597
+ await pickFile(result.container, new File(["data"], "new.pdf", { type: "application/pdf" }));
598
+ await act(async () => {
599
+ fireEvent.click(result.getButton("Remove new.pdf")!);
600
+ });
601
+ expect(result.container.querySelector('[data-file-upload="preview"]')).toBeNull();
602
+ expect(result.container.textContent).toContain("Choose File");
603
+ expect(onChange).toHaveBeenLastCalledWith(null);
604
+ });
605
+
606
+ it("does not focus a stored attachment on mount", () => {
607
+ const before = document.activeElement;
608
+ renderWithProviders(<FileUpload existing={{ src: "/files/old.png" }} />);
609
+ expect(document.activeElement).toBe(before);
610
+ });
611
+
612
+ it("notifies standalone blur after a file selection", async () => {
613
+ const onBlur = vi.fn();
614
+ const result = renderWithProviders(<FileUpload onBlur={onBlur} />);
615
+ await pickFile(result.container, new File(["data"], "new.pdf", { type: "application/pdf" }));
616
+ expect(onBlur).toHaveBeenCalledTimes(1);
617
+ });
@@ -252,3 +252,18 @@ export const InTable: Story = {
252
252
  );
253
253
  },
254
254
  };
255
+
256
+ export const FilledImage: Story = {
257
+ render: () => {
258
+ const [src, setSrc] = useState(
259
+ "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/10.png",
260
+ );
261
+ return (
262
+ <FileUpload
263
+ label="Sprite"
264
+ existing={src ? { src } : undefined}
265
+ onExistingRemove={() => setSrc("")}
266
+ />
267
+ );
268
+ },
269
+ };
@@ -3,7 +3,7 @@ import { useTouchSurface } from "@multiplatform.one/theme";
3
3
  import { FileIcon, UploadIcon, XIcon } from "@phosphor-icons/react";
4
4
  import type { DeepKeys, DeepValue } from "@tanstack/form-core";
5
5
  import { type DragEvent, type ReactNode, useCallback, useEffect, useRef, useState } from "react";
6
- import { useProps, type SizeTokens } from "tamagui";
6
+ import { useMedia, useProps, type SizeTokens } from "tamagui";
7
7
  import { Image, isWeb, Text, XStack, YStack, styled } from "tamagui";
8
8
  import { Button } from "../../Button";
9
9
  import { Field, FieldLayout } from "../../fieldLayout";
@@ -112,7 +112,7 @@ export type FileUploadProps<
112
112
  * The file the value already names (a stored URL), shown as a preview
113
113
  * tile until a new pick replaces it — never as a raw path.
114
114
  */
115
- existing?: { src: string; name?: string } | null;
115
+ existing?: { src: string; name?: string; isImage?: boolean } | null;
116
116
  /** Removes the existing file; given, its tile carries a remove disc. */
117
117
  onExistingRemove?: () => void;
118
118
  };
@@ -203,6 +203,7 @@ export function FileUpload<
203
203
  TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
204
204
  >(props: FileUploadProps<TParentData, TName, TFieldValidator, TFormValidator, TData>) {
205
205
  const hydrationTouch = useTouchSurface();
206
+ const media = useMedia();
206
207
  const {
207
208
  defaultValue,
208
209
  form,
@@ -274,6 +275,29 @@ export function FileUpload<
274
275
  const tileRemoveInset = -Math.round(knobProps.nestedControl.px / 4);
275
276
 
276
277
  const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
278
+ const [replacing, setReplacing] = useState(false);
279
+ const [existingRemoved, setExistingRemoved] = useState(false);
280
+ const [pixelated, setPixelated] = useState(false);
281
+ const replaceRef = useRef<HTMLElement>(null);
282
+ const sourceRef = useRef<HTMLElement>(null);
283
+ const storedSrcRef = useRef(existing?.src);
284
+ const previousReplacing = useRef(replacing);
285
+ useEffect(() => {
286
+ if (storedSrcRef.current === existing?.src) return;
287
+ storedSrcRef.current = existing?.src;
288
+ const currentFiles: unknown[] = Array.isArray(defaultValue) ? defaultValue : [defaultValue];
289
+ if (existing?.src || !selectedFiles.every((file) => currentFiles.includes(file)))
290
+ setSelectedFiles([]);
291
+ setExistingRemoved(false);
292
+ setReplacing(false);
293
+ }, [existing?.src]);
294
+ useEffect(() => {
295
+ if (previousReplacing.current === replacing) return;
296
+ previousReplacing.current = replacing;
297
+ if (!isWeb) return;
298
+ const target = replacing ? sourceRef : replaceRef;
299
+ target.current?.querySelector<HTMLElement>('button, [role="button"]')?.focus();
300
+ }, [replacing]);
277
301
  const [transfers, setTransfers] = useState<TransferItem[]>([]);
278
302
  const [isDragOver, setIsDragOver] = useState(false);
279
303
  const [validationError, setValidationError] = useState<string | undefined>();
@@ -377,6 +401,7 @@ export function FileUpload<
377
401
  });
378
402
  if (controller.signal.aborted) return;
379
403
  setTransfersAndRef((prev) => prev.filter((item) => item.id !== id));
404
+ setReplacing(false);
380
405
  setSelectedFiles((prev) => {
381
406
  const nextFiles = multipleRef.current ? [...prev, file] : [file];
382
407
  syncFieldValue(nextFiles, emitFieldRef.current);
@@ -385,7 +410,10 @@ export function FileUpload<
385
410
  } catch (err) {
386
411
  if (
387
412
  controller.signal.aborted ||
388
- (err instanceof DOMException && err.name === "AbortError")
413
+ (err instanceof Error && err.name === "AbortError") ||
414
+ (typeof DOMException !== "undefined" &&
415
+ err instanceof DOMException &&
416
+ err.name === "AbortError")
389
417
  ) {
390
418
  setTransfersAndRef((prev) => prev.filter((item) => item.id !== id));
391
419
  return;
@@ -504,6 +532,7 @@ export function FileUpload<
504
532
  if (onUploadRef.current) {
505
533
  validFiles.forEach((file) => startTransfer(file));
506
534
  } else {
535
+ setReplacing(false);
507
536
  setSelectedFiles((prev) => {
508
537
  const nextFiles = multiple ? [...prev, ...validFiles] : validFiles.slice(0, 1);
509
538
  syncFieldValue(nextFiles, onValueChange);
@@ -532,9 +561,12 @@ export function FileUpload<
532
561
  return nextFiles;
533
562
  });
534
563
 
564
+ if (fileInputRef.current) fileInputRef.current.value = "";
565
+ setReplacing(false);
566
+ if (!multiple) setExistingRemoved(true);
535
567
  onFileRemove?.(fileToRemove);
536
568
  },
537
- [onFileRemove, syncFieldValue],
569
+ [multiple, onFileRemove, syncFieldValue],
538
570
  );
539
571
 
540
572
  // Depth counter so dragenter/dragleave pairs from nested children don't cancel the highlight
@@ -697,7 +729,7 @@ export function FileUpload<
697
729
  if (skeleton) {
698
730
  const minHeightPx = getFieldHeight(
699
731
  (fieldProps.size || knobProps.sizeToken) as SizeTokens,
700
- 5,
732
+ 2,
701
733
  hydrationTouch,
702
734
  );
703
735
  return (
@@ -708,8 +740,19 @@ export function FileUpload<
708
740
  }
709
741
 
710
742
  const canInteract = !disabled && !readOnly;
711
- const showExisting =
712
- Boolean(existing?.src) && selectedFiles.length === 0 && transfers.length === 0;
743
+ const showExisting = Boolean(existing?.src) && !existingRemoved && selectedFiles.length === 0;
744
+ const singleFile = !multiple ? selectedFiles[0] : undefined;
745
+ const filled = !multiple && (showExisting || Boolean(singleFile));
746
+ const storedImage =
747
+ existing?.isImage ??
748
+ /^(data:image\/)|\.(png|jpe?g|gif|webp|svg|avif|bmp)(?:[?#]|$)/i.test(existing?.src ?? "");
749
+ const singlePreview = showPreview
750
+ ? singleFile
751
+ ? getFilePreview(singleFile)
752
+ : storedImage
753
+ ? existing?.src
754
+ : undefined
755
+ : undefined;
713
756
  const existingName = existing?.name || fileNameFromSrc(existing?.src ?? "");
714
757
  const hasRows = selectedFiles.length > 0 || transfers.length > 0 || showExisting;
715
758
 
@@ -831,13 +874,13 @@ export function FileUpload<
831
874
  ? isWeb
832
875
  ? ({
833
876
  // DROPZONE-FULL-TARGET: the entire surface is the click target.
834
- role: "button",
835
- tabIndex: 0,
877
+ role: filled ? "group" : "button",
878
+ tabIndex: filled ? undefined : 0,
836
879
  onFocus: handleZoneFocus,
837
880
  onBlur: handleZoneBlur,
838
881
  cursor: "pointer",
839
- onClick: handleZoneClick,
840
- onKeyDown: handleZoneKeyDown,
882
+ onClick: filled ? undefined : handleZoneClick,
883
+ onKeyDown: filled ? undefined : handleZoneKeyDown,
841
884
  ...(dragDrop
842
885
  ? {
843
886
  onDragEnter: handleDragEnter,
@@ -850,7 +893,9 @@ export function FileUpload<
850
893
  }
851
894
  : null),
852
895
  } as any)
853
- : ({ role: "button", onPress: requestFiles } as any)
896
+ : filled
897
+ ? {}
898
+ : ({ role: "button", onPress: requestFiles } as any)
854
899
  : { cursor: disabled ? "not-allowed" : undefined };
855
900
 
856
901
  // Committed image picks become tiles; everything else stays a row.
@@ -887,14 +932,6 @@ export function FileUpload<
887
932
  {...(errorProp ? { borderColor: formCommonColors.error } : undefined)}
888
933
  elevation={knobProps.elevation}
889
934
  {...transitionProps(knobProps.motion.control)}
890
- // CONTRACT (boards media-01..03): the getFieldHeight floor sits on
891
- // the FRAME, so the frame border-box measures 220 — hanging it on
892
- // the inner stack painted 222, a number no token expresses.
893
- minHeight={getFieldHeight(
894
- (fieldProps.size || knobProps.sizeToken) as SizeTokens,
895
- 5,
896
- hydrationTouch,
897
- )}
898
935
  aria-required={fieldProps.required || undefined}
899
936
  aria-invalid={!!errorProp || undefined}
900
937
  aria-readonly={readOnly || undefined}
@@ -923,7 +960,7 @@ export function FileUpload<
923
960
  : undefined
924
961
  }
925
962
  {...zoneInteractionProps}
926
- {...(canInteract
963
+ {...(canInteract && !filled
927
964
  ? // Labeled fields get aria-labelledby auto-wired by the FieldLayout
928
965
  // Label (tamagui Label htmlFor → this id); the aria-label fallback
929
966
  // covers label-less usage, and is what a screen reader announces
@@ -966,36 +1003,119 @@ export function FileUpload<
966
1003
 
967
1004
  <YStack
968
1005
  {...knobProps.panelPadding}
969
- flexGrow={1}
970
1006
  width="100%"
971
1007
  alignItems="center"
972
1008
  justifyContent="center"
973
1009
  {...knobProps.gap}
974
1010
  >
975
- <XStack
976
- alignItems="center"
977
- justifyContent="center"
978
- flexWrap="wrap"
979
- maxWidth="100%"
980
- {...knobProps.gap}
981
- >
982
- <Button
983
- onPress={requestFiles}
984
- disabled={!canInteract}
985
- size={knobProps.sizeToken}
986
- tabIndex={-1}
987
- // BENTO-DERIVED (bento-pickers-measured.md §2/§4): NO standalone
988
- // glyph exists — the upload mark rides INSIDE the CTA. Held at
989
- // the house 44 control with the recipe's 16px icon (Bento draws
990
- // 14 on its own 36/$3 button — ruled exception).
991
- icon={UploadIcon}
1011
+ {filled ? (
1012
+ <YStack data-file-upload="preview" width="100%" alignItems="center" {...knobProps.gap}>
1013
+ <YStack
1014
+ data-file-upload={showExisting ? "existing" : "selected"}
1015
+ alignItems="center"
1016
+ width="100%"
1017
+ >
1018
+ {singlePreview ? (
1019
+ <Image
1020
+ src={singlePreview}
1021
+ alt={singleFile?.name ?? existingName}
1022
+ width="$14"
1023
+ height="$14"
1024
+ maxWidth="100%"
1025
+ objectFit="contain"
1026
+ onLoad={(event) => {
1027
+ if (!isWeb) return;
1028
+ const image = event.currentTarget as unknown as HTMLImageElement;
1029
+ setPixelated(image.naturalWidth > 0 && image.naturalWidth < image.width);
1030
+ }}
1031
+ {...(isWeb && pixelated
1032
+ ? { style: { imageRendering: "pixelated" } as any }
1033
+ : {})}
1034
+ />
1035
+ ) : (
1036
+ <YStack alignItems="center" {...knobProps.gap}>
1037
+ <FileIcon size={rowGlyphSize} />
1038
+ <Text {...knobProps.body} textAlign="center" numberOfLines={2}>
1039
+ {singleFile?.name ?? existingName}
1040
+ </Text>
1041
+ </YStack>
1042
+ )}
1043
+ </YStack>
1044
+ {canInteract ? (
1045
+ <XStack
1046
+ ref={replaceRef as any}
1047
+ {...knobProps.gap}
1048
+ justifyContent="center"
1049
+ flexWrap="wrap"
1050
+ >
1051
+ <Button
1052
+ size={knobProps.sizeToken}
1053
+ aria-label={replacing ? t("Cancel replacement") : t("Replace")}
1054
+ aria-expanded={replacing}
1055
+ onPress={(event) => {
1056
+ event.stopPropagation();
1057
+ if (replacing) {
1058
+ transfersRef.current.forEach((item) => item.controller.abort());
1059
+ setTransfersAndRef(() => []);
1060
+ if (fileInputRef.current) fileInputRef.current.value = "";
1061
+ if (isWeb)
1062
+ replaceRef.current
1063
+ ?.querySelector<HTMLElement>('button, [role="button"]')
1064
+ ?.focus();
1065
+ }
1066
+ setReplacing(!replacing);
1067
+ }}
1068
+ >
1069
+ {replacing ? t("Cancel") : t("Replace")}
1070
+ </Button>
1071
+ {singleFile || onExistingRemove ? (
1072
+ <Button
1073
+ size={knobProps.sizeToken}
1074
+ outlined
1075
+ aria-label={t("Remove {{name}}", { name: singleFile?.name ?? existingName })}
1076
+ onPress={(event) => {
1077
+ event.stopPropagation();
1078
+ transfersRef.current.forEach((item) => item.controller.abort());
1079
+ setTransfersAndRef(() => []);
1080
+ if (singleFile) handleFileRemove(singleFile, onValueChange);
1081
+ else onExistingRemove?.();
1082
+ setReplacing(false);
1083
+ }}
1084
+ >
1085
+ {t("Remove")}
1086
+ </Button>
1087
+ ) : null}
1088
+ </XStack>
1089
+ ) : null}
1090
+ </YStack>
1091
+ ) : null}
1092
+ {!filled || replacing ? (
1093
+ <XStack
1094
+ ref={sourceRef as any}
1095
+ data-file-upload="sources"
1096
+ width="100%"
1097
+ flexDirection={media.xs ? "column" : "row"}
1098
+ alignItems="stretch"
1099
+ {...knobProps.gap}
992
1100
  >
993
- <Button.Text {...knobProps.body}>{buttonText}</Button.Text>
994
- </Button>
995
- {actions}
996
- </XStack>
997
-
998
- {selectedFiles.length === 0 && transfers.length === 0 && !showExisting && (
1101
+ <Button
1102
+ alignSelf="stretch"
1103
+ flex={media.xs ? undefined : 1}
1104
+ onPress={(event) => {
1105
+ event.stopPropagation();
1106
+ requestFiles();
1107
+ }}
1108
+ disabled={!canInteract}
1109
+ size={knobProps.sizeToken}
1110
+ tabIndex={replacing ? 0 : -1}
1111
+ icon={UploadIcon}
1112
+ >
1113
+ <Button.Text {...knobProps.body}>{buttonText}</Button.Text>
1114
+ </Button>
1115
+ {actions}
1116
+ </XStack>
1117
+ ) : null}
1118
+ {!hasRows && (
999
1119
  <Text color={formCommonColors.muted} textAlign="center" {...knobProps.body}>
1000
1120
  {placeholder}
1001
1121
  </Text>
@@ -1018,13 +1138,13 @@ export function FileUpload<
1018
1138
  ) : null}
1019
1139
  </YStack>
1020
1140
 
1021
- {hasRows && (
1141
+ {((multiple && hasRows) || transfers.length > 0) && (
1022
1142
  <UploadFileListFrame
1023
1143
  data-file-upload="files"
1024
1144
  // The hairline tracks the frame edge's knob width — one dash voice.
1025
1145
  borderTopWidth={knobProps.borderRadius.borderWidth ?? 1}
1026
1146
  >
1027
- {showExisting && existing ? (
1147
+ {multiple && showExisting && existing ? (
1028
1148
  <UploadTileGridFrame
1029
1149
  data-file-upload="tiles"
1030
1150
  {...knobProps.gap}
@@ -1061,7 +1181,7 @@ export function FileUpload<
1061
1181
  </YStack>
1062
1182
  </UploadTileGridFrame>
1063
1183
  ) : null}
1064
- {imageTiles.length > 0 ? (
1184
+ {multiple && imageTiles.length > 0 ? (
1065
1185
  <UploadTileGridFrame
1066
1186
  data-file-upload="tiles"
1067
1187
  {...knobProps.gap}
@@ -1072,7 +1192,7 @@ export function FileUpload<
1072
1192
  )}
1073
1193
  </UploadTileGridFrame>
1074
1194
  ) : null}
1075
- {fileRows.map(({ file, preview, index }) => {
1195
+ {(multiple ? fileRows : []).map(({ file, preview, index }) => {
1076
1196
  return (
1077
1197
  <XStack
1078
1198
  key={`${file.name}-${index}`}
@@ -1187,7 +1307,7 @@ export function FileUpload<
1187
1307
  // the sibling label/helper readable) — it needs the disabled state.
1188
1308
  disabled={disabled}
1189
1309
  >
1190
- {renderUploadArea(standaloneError, emitChange)}
1310
+ {renderUploadArea(standaloneError, emitChange, fieldProps.onBlur)}
1191
1311
  </FieldLayout>
1192
1312
  );
1193
1313
  }
@@ -4,7 +4,7 @@ import type { Meta, StoryObj } from "@storybook/react-native-web-vite";
4
4
  import { ArrowsOutIcon, NavigationArrowIcon } from "@phosphor-icons/react";
5
5
  import { useForm } from "@tanstack/react-form";
6
6
  import { useCallback, useState } from "react";
7
- import { Text, YStack } from "tamagui";
7
+ import { YStack } from "tamagui";
8
8
  import { Button } from "../../Button";
9
9
  import { Form } from "../../Form";
10
10
  import { TableCellContext } from "../../shared/tableCellContext";
@@ -13,6 +13,7 @@ import type { GeocodeResult, Geocoder } from "./geocoder";
13
13
  import { GeocoderProvider } from "./geocoderContext";
14
14
  import { parseGeoValue } from "./geoValue";
15
15
  import { createPhotonGeocoder } from "./photonGeocoder";
16
+ import { Text } from "@multiplatform.one/theme";
16
17
 
17
18
  const meta: Meta<typeof Geolocation> = {
18
19
  title: "Forms/Geolocation",
@@ -1,6 +1,6 @@
1
1
  import { useEffect, useRef } from "react";
2
2
  import { Platform } from "react-native";
3
- import { Text, YStack } from "tamagui";
3
+ import { YStack } from "tamagui";
4
4
  // Type-only imports are erased at runtime — the value module loads through
5
5
  // `loadExpoMaps` so the peer stays optional (Video / expo-video precedent).
6
6
  import type { AppleMaps as AppleMapsNS, GoogleMaps as GoogleMapsNS } from "expo-maps";
@@ -8,6 +8,7 @@ import { t } from "../../shared/t";
8
8
  import { loadExpoMaps } from "./expoMapsLoader";
9
9
  import { zoomFromDelta } from "./mapMath";
10
10
  import type { GeolocationMapSurfaceProps } from "./mapTypes";
11
+ import { Text } from "@multiplatform.one/theme";
11
12
 
12
13
  interface MapClickEvent {
13
14
  coordinates?: { latitude?: number; longitude?: number };
@@ -1,11 +1,12 @@
1
1
  import { MapPinIcon } from "@phosphor-icons/react";
2
2
  import { useCallback, useMemo, useState } from "react";
3
3
  import type { LayoutChangeEvent } from "react-native";
4
- import { Text, View, YStack } from "tamagui";
4
+ import { View, YStack } from "tamagui";
5
5
  import { formCommonColors } from "../../shared/colorRamps";
6
6
  import { t } from "../../shared/t";
7
7
  import { OSM_TILE_SIZE, latLngFromMapClick, tilesForView, zoomFromDelta } from "./mapMath";
8
8
  import type { GeolocationMapSurfaceProps } from "./mapTypes";
9
+ import { Text } from "@multiplatform.one/theme";
9
10
 
10
11
  function tileSrc(zoom: number, x: number, y: number) {
11
12
  if (typeof process !== "undefined" && process.env.VITEST) {