@multiplatform.one/forms 7.7.6 → 7.8.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 (533) hide show
  1. package/dist/cjs/Button/index.cjs +0 -3
  2. package/dist/cjs/Button/index.native.js +0 -3
  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 +8 -6
  14. package/dist/cjs/InputParts/index.native.js +9 -9
  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/Geolocation/GeolocationMap.native.js.map +1 -1
  51. package/dist/cjs/fields/Geolocation/geocoder.cjs +63 -0
  52. package/dist/cjs/fields/Geolocation/geocoder.native.js +68 -0
  53. package/dist/cjs/fields/Geolocation/geocoder.native.js.map +1 -0
  54. package/dist/cjs/fields/Geolocation/index.cjs +801 -152
  55. package/dist/cjs/fields/Geolocation/index.native.js +856 -167
  56. package/dist/cjs/fields/Geolocation/index.native.js.map +1 -1
  57. package/dist/cjs/fields/Geolocation/nativeSearchFocus.cjs +44 -0
  58. package/dist/cjs/fields/Geolocation/nativeSearchFocus.native.js +47 -0
  59. package/dist/cjs/fields/Geolocation/nativeSearchFocus.native.js.map +1 -0
  60. package/dist/cjs/fields/Icon/drawnSet.cjs +14 -3
  61. package/dist/cjs/fields/Icon/drawnSet.native.js +18 -3
  62. package/dist/cjs/fields/Icon/drawnSet.native.js.map +1 -1
  63. package/dist/cjs/fields/Icon/index.cjs +102 -27
  64. package/dist/cjs/fields/Icon/index.native.js +115 -31
  65. package/dist/cjs/fields/Icon/index.native.js.map +1 -1
  66. package/dist/cjs/fields/Input/index.cjs +5 -12
  67. package/dist/cjs/fields/Input/index.native.js +5 -13
  68. package/dist/cjs/fields/Input/index.native.js.map +1 -1
  69. package/dist/cjs/fields/PhoneInput/index.cjs +2 -2
  70. package/dist/cjs/fields/PhoneInput/index.native.js +2 -2
  71. package/dist/cjs/fields/PhoneInput/index.native.js.map +1 -1
  72. package/dist/cjs/fields/SearchInput/index.cjs +8 -9
  73. package/dist/cjs/fields/SearchInput/index.native.js +8 -9
  74. package/dist/cjs/fields/SearchInput/index.native.js.map +1 -1
  75. package/dist/cjs/fields/Select/index.cjs +42 -11
  76. package/dist/cjs/fields/Select/index.native.js +52 -20
  77. package/dist/cjs/fields/Select/index.native.js.map +1 -1
  78. package/dist/cjs/fields/Stepper/index.cjs +144 -31
  79. package/dist/cjs/fields/Stepper/index.native.js +151 -31
  80. package/dist/cjs/fields/Stepper/index.native.js.map +1 -1
  81. package/dist/cjs/index.cjs +2 -0
  82. package/dist/cjs/index.native.js +2 -0
  83. package/dist/cjs/index.native.js.map +1 -1
  84. package/dist/cjs/shared/focusManagement.cjs +24 -11
  85. package/dist/cjs/shared/focusManagement.native.js +24 -11
  86. package/dist/cjs/shared/focusManagement.native.js.map +1 -1
  87. package/dist/esm/AdaptivePopup/index.native.js.map +1 -1
  88. package/dist/esm/Button/index.mjs +0 -3
  89. package/dist/esm/Button/index.mjs.map +1 -1
  90. package/dist/esm/Button/index.native.js +0 -3
  91. package/dist/esm/Button/index.native.js.map +1 -1
  92. package/dist/esm/Chip/index.mjs +1 -1
  93. package/dist/esm/Chip/index.mjs.map +1 -1
  94. package/dist/esm/Chip/index.native.js +1 -1
  95. package/dist/esm/Chip/index.native.js.map +1 -1
  96. package/dist/esm/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
  97. package/dist/esm/ContextualSaveBar/clientKnownIdentity.native.js.map +1 -1
  98. package/dist/esm/ContextualSaveBar/commitImmediateField.native.js.map +1 -1
  99. package/dist/esm/ContextualSaveBar/index.native.js.map +1 -1
  100. package/dist/esm/ContextualSaveBar/useUnsavedChangesGuard.native.js.map +1 -1
  101. package/dist/esm/ControlGroup/index.native.js.map +1 -1
  102. package/dist/esm/DescriptionList/index.native.js.map +1 -1
  103. package/dist/esm/ErrorSummary.native.js.map +1 -1
  104. package/dist/esm/FieldDisplay/editMode.native.js.map +1 -1
  105. package/dist/esm/FieldDisplay/formatters.native.js.map +1 -1
  106. package/dist/esm/FieldDisplay/index.native.js.map +1 -1
  107. package/dist/esm/FieldGroup.native.js.map +1 -1
  108. package/dist/esm/FloatingPanel/index.mjs +58 -15
  109. package/dist/esm/FloatingPanel/index.mjs.map +1 -1
  110. package/dist/esm/FloatingPanel/index.native.js +15 -8
  111. package/dist/esm/FloatingPanel/index.native.js.map +1 -1
  112. package/dist/esm/FloatingPanel/nestedAction.mjs +11 -0
  113. package/dist/esm/FloatingPanel/nestedAction.mjs.map +1 -0
  114. package/dist/esm/FloatingPanel/nestedAction.native.js +13 -0
  115. package/dist/esm/FloatingPanel/nestedAction.native.js.map +1 -0
  116. package/dist/esm/FloatingPanel/useFloatingPanel.native.js.map +1 -1
  117. package/dist/esm/Form/index.native.js.map +1 -1
  118. package/dist/esm/Form/validateOn.native.js.map +1 -1
  119. package/dist/esm/FormGrid.native.js.map +1 -1
  120. package/dist/esm/FormSection.native.js.map +1 -1
  121. package/dist/esm/InputParts/index.mjs +9 -7
  122. package/dist/esm/InputParts/index.mjs.map +1 -1
  123. package/dist/esm/InputParts/index.native.js +10 -10
  124. package/dist/esm/InputParts/index.native.js.map +1 -1
  125. package/dist/esm/Label/index.native.js.map +1 -1
  126. package/dist/esm/Skeleton/index.native.js.map +1 -1
  127. package/dist/esm/Spinner/SpinnerGlyph.native.js.map +1 -1
  128. package/dist/esm/Spinner/spinnerSize.native.js.map +1 -1
  129. package/dist/esm/Table/index.native.js.map +1 -1
  130. package/dist/esm/Wheel/haptic.native.js.map +1 -1
  131. package/dist/esm/Wheel/index.mjs +3 -3
  132. package/dist/esm/Wheel/index.mjs.map +1 -1
  133. package/dist/esm/Wheel/index.native.js +3 -3
  134. package/dist/esm/Wheel/index.native.js.map +1 -1
  135. package/dist/esm/actionLabel.native.js.map +1 -1
  136. package/dist/esm/fieldDefaults.native.js.map +1 -1
  137. package/dist/esm/fieldLayout.mjs +3 -3
  138. package/dist/esm/fieldLayout.mjs.map +1 -1
  139. package/dist/esm/fieldLayout.native.js +3 -3
  140. package/dist/esm/fieldLayout.native.js.map +1 -1
  141. package/dist/esm/fields/Barcode/BarcodePreview.native.js.map +1 -1
  142. package/dist/esm/fields/Barcode/code128.native.js.map +1 -1
  143. package/dist/esm/fields/Barcode/index.native.js.map +1 -1
  144. package/dist/esm/fields/Barcode/qr.native.js.map +1 -1
  145. package/dist/esm/fields/Barcode/scannerTypes.native.js.map +1 -1
  146. package/dist/esm/fields/Checkbox/Checkbox.native.js.map +1 -1
  147. package/dist/esm/fields/Checkbox/CheckboxBox.native.js.map +1 -1
  148. package/dist/esm/fields/Checkbox/CheckboxCard.native.js.map +1 -1
  149. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.mjs +8 -1
  150. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.mjs.map +1 -1
  151. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.native.js +10 -1
  152. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  153. package/dist/esm/fields/Checkbox/CheckboxGroup.native.js.map +1 -1
  154. package/dist/esm/fields/Checkbox/checkboxGroupContext.native.js.map +1 -1
  155. package/dist/esm/fields/Checkbox/index.native.js.map +1 -1
  156. package/dist/esm/fields/ColorPicker/index.native.js.map +1 -1
  157. package/dist/esm/fields/ColorPicker/parts.native.js.map +1 -1
  158. package/dist/esm/fields/Combobox/authorOptions.native.js.map +1 -1
  159. package/dist/esm/fields/Combobox/index.mjs +36 -29
  160. package/dist/esm/fields/Combobox/index.mjs.map +1 -1
  161. package/dist/esm/fields/Combobox/index.native.js +38 -38
  162. package/dist/esm/fields/Combobox/index.native.js.map +1 -1
  163. package/dist/esm/fields/DatePicker/Calendar.mjs +6 -1
  164. package/dist/esm/fields/DatePicker/Calendar.mjs.map +1 -1
  165. package/dist/esm/fields/DatePicker/Calendar.native.js +6 -1
  166. package/dist/esm/fields/DatePicker/Calendar.native.js.map +1 -1
  167. package/dist/esm/fields/DatePicker/DateRangePicker.mjs +2 -2
  168. package/dist/esm/fields/DatePicker/DateRangePicker.mjs.map +1 -1
  169. package/dist/esm/fields/DatePicker/DateRangePicker.native.js +2 -2
  170. package/dist/esm/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  171. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.mjs +15 -12
  172. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.mjs.map +1 -1
  173. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.native.js +16 -12
  174. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  175. package/dist/esm/fields/DatePicker/DatetimePicker.native.js +39 -14
  176. package/dist/esm/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  177. package/dist/esm/fields/DatePicker/MonthPicker.mjs +10 -3
  178. package/dist/esm/fields/DatePicker/MonthPicker.mjs.map +1 -1
  179. package/dist/esm/fields/DatePicker/MonthPicker.native.js +10 -3
  180. package/dist/esm/fields/DatePicker/MonthPicker.native.js.map +1 -1
  181. package/dist/esm/fields/DatePicker/MultiDatePicker.mjs +2 -2
  182. package/dist/esm/fields/DatePicker/MultiDatePicker.mjs.map +1 -1
  183. package/dist/esm/fields/DatePicker/MultiDatePicker.native.js +2 -2
  184. package/dist/esm/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  185. package/dist/esm/fields/DatePicker/catalog.native.js.map +1 -1
  186. package/dist/esm/fields/DatePicker/fieldValueSync.native.js.map +1 -1
  187. package/dist/esm/fields/DatePicker/index.native.js +3 -0
  188. package/dist/esm/fields/DatePicker/index.native.js.map +1 -1
  189. package/dist/esm/fields/DatePicker/parts.mjs +28 -16
  190. package/dist/esm/fields/DatePicker/parts.mjs.map +1 -1
  191. package/dist/esm/fields/DatePicker/parts.native.js +30 -16
  192. package/dist/esm/fields/DatePicker/parts.native.js.map +1 -1
  193. package/dist/esm/fields/DatePicker/utils.native.js.map +1 -1
  194. package/dist/esm/fields/Duration/durationMath.native.js.map +1 -1
  195. package/dist/esm/fields/Duration/index.native.js.map +1 -1
  196. package/dist/esm/fields/FileUpload/filePickerTypes.native.js.map +1 -1
  197. package/dist/esm/fields/FileUpload/index.native.js.map +1 -1
  198. package/dist/esm/fields/FileUpload/nativePickerLoader.native.js.map +1 -1
  199. package/dist/esm/fields/Geolocation/GeolocationMap.mjs.map +1 -1
  200. package/dist/esm/fields/Geolocation/GeolocationMap.native.js.map +1 -1
  201. package/dist/esm/fields/Geolocation/expoMapsLoader.native.js.map +1 -1
  202. package/dist/esm/fields/Geolocation/geoValue.native.js.map +1 -1
  203. package/dist/esm/fields/Geolocation/geocoder.mjs +33 -0
  204. package/dist/esm/fields/Geolocation/geocoder.mjs.map +1 -0
  205. package/dist/esm/fields/Geolocation/geocoder.native.js +35 -0
  206. package/dist/esm/fields/Geolocation/geocoder.native.js.map +1 -0
  207. package/dist/esm/fields/Geolocation/index.mjs +792 -149
  208. package/dist/esm/fields/Geolocation/index.mjs.map +1 -1
  209. package/dist/esm/fields/Geolocation/index.native.js +847 -164
  210. package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
  211. package/dist/esm/fields/Geolocation/mapMath.native.js.map +1 -1
  212. package/dist/esm/fields/Geolocation/mapTypes.native.js.map +1 -1
  213. package/dist/esm/fields/Geolocation/nativeSearchFocus.mjs +19 -0
  214. package/dist/esm/fields/Geolocation/nativeSearchFocus.mjs.map +1 -0
  215. package/dist/esm/fields/Geolocation/nativeSearchFocus.native.js +19 -0
  216. package/dist/esm/fields/Geolocation/nativeSearchFocus.native.js.map +1 -0
  217. package/dist/esm/fields/Icon/drawnSet.mjs +14 -3
  218. package/dist/esm/fields/Icon/drawnSet.mjs.map +1 -1
  219. package/dist/esm/fields/Icon/drawnSet.native.js +18 -3
  220. package/dist/esm/fields/Icon/drawnSet.native.js.map +1 -1
  221. package/dist/esm/fields/Icon/index.mjs +93 -18
  222. package/dist/esm/fields/Icon/index.mjs.map +1 -1
  223. package/dist/esm/fields/Icon/index.native.js +106 -22
  224. package/dist/esm/fields/Icon/index.native.js.map +1 -1
  225. package/dist/esm/fields/ImageField/index.native.js.map +1 -1
  226. package/dist/esm/fields/Input/index.mjs +5 -12
  227. package/dist/esm/fields/Input/index.mjs.map +1 -1
  228. package/dist/esm/fields/Input/index.native.js +5 -13
  229. package/dist/esm/fields/Input/index.native.js.map +1 -1
  230. package/dist/esm/fields/MentionInput/index.native.js.map +1 -1
  231. package/dist/esm/fields/OTPInput/index.native.js.map +1 -1
  232. package/dist/esm/fields/OTPInput/otpCellCss.native.js.map +1 -1
  233. package/dist/esm/fields/PhoneInput/dialCodes.native.js.map +1 -1
  234. package/dist/esm/fields/PhoneInput/index.mjs +2 -2
  235. package/dist/esm/fields/PhoneInput/index.mjs.map +1 -1
  236. package/dist/esm/fields/PhoneInput/index.native.js +2 -2
  237. package/dist/esm/fields/PhoneInput/index.native.js.map +1 -1
  238. package/dist/esm/fields/PhoneInput/phone.native.js.map +1 -1
  239. package/dist/esm/fields/Progress/index.native.js.map +1 -1
  240. package/dist/esm/fields/RadioGroup/index.native.js.map +1 -1
  241. package/dist/esm/fields/Rating/index.native.js.map +1 -1
  242. package/dist/esm/fields/Rating/ratingMath.native.js.map +1 -1
  243. package/dist/esm/fields/Rating/types.native.js.map +1 -1
  244. package/dist/esm/fields/SearchInput/index.mjs +9 -10
  245. package/dist/esm/fields/SearchInput/index.mjs.map +1 -1
  246. package/dist/esm/fields/SearchInput/index.native.js +9 -10
  247. package/dist/esm/fields/SearchInput/index.native.js.map +1 -1
  248. package/dist/esm/fields/Select/index.mjs +42 -11
  249. package/dist/esm/fields/Select/index.mjs.map +1 -1
  250. package/dist/esm/fields/Select/index.native.js +52 -20
  251. package/dist/esm/fields/Select/index.native.js.map +1 -1
  252. package/dist/esm/fields/Signature/index.native.js.map +1 -1
  253. package/dist/esm/fields/Slider/index.native.js.map +1 -1
  254. package/dist/esm/fields/Slider/jumpMotion.native.js.map +1 -1
  255. package/dist/esm/fields/Stepper/index.mjs +145 -32
  256. package/dist/esm/fields/Stepper/index.mjs.map +1 -1
  257. package/dist/esm/fields/Stepper/index.native.js +152 -32
  258. package/dist/esm/fields/Stepper/index.native.js.map +1 -1
  259. package/dist/esm/fields/Stepper/resolveStepperPlacement.native.js.map +1 -1
  260. package/dist/esm/fields/Switch/index.native.js.map +1 -1
  261. package/dist/esm/fields/TextArea/index.native.js.map +1 -1
  262. package/dist/esm/fields/TimePicker/catalog.native.js.map +1 -1
  263. package/dist/esm/fields/TimePicker/parts.native.js.map +1 -1
  264. package/dist/esm/fields/TimeRangeScrubber/geometry.native.js.map +1 -1
  265. package/dist/esm/fields/TimeRangeScrubber/index.native.js.map +1 -1
  266. package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
  267. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  268. package/dist/esm/fields/nativeDateTime/osDateTimeIosDisplay.native.js.map +1 -1
  269. package/dist/esm/fields/nativeSelect.native.js.map +1 -1
  270. package/dist/esm/fields/selectedOrder.native.js.map +1 -1
  271. package/dist/esm/formSpacing.native.js.map +1 -1
  272. package/dist/esm/hooks/useFocusManagement.native.js.map +1 -1
  273. package/dist/esm/index.mjs +2 -1
  274. package/dist/esm/index.mjs.map +1 -1
  275. package/dist/esm/index.native.js +2 -1
  276. package/dist/esm/index.native.js.map +1 -1
  277. package/dist/esm/requiredMarking.native.js.map +1 -1
  278. package/dist/esm/shared/TimeColumn.native.js.map +1 -1
  279. package/dist/esm/shared/capabilityPreflight.native.js.map +1 -1
  280. package/dist/esm/shared/colorRamps.native.js.map +1 -1
  281. package/dist/esm/shared/devWarn.native.js.map +1 -1
  282. package/dist/esm/shared/floatingList.native.js.map +1 -1
  283. package/dist/esm/shared/focusManagement.mjs +24 -11
  284. package/dist/esm/shared/focusManagement.mjs.map +1 -1
  285. package/dist/esm/shared/focusManagement.native.js +24 -11
  286. package/dist/esm/shared/focusManagement.native.js.map +1 -1
  287. package/dist/esm/shared/groupContext.native.js.map +1 -1
  288. package/dist/esm/shared/i18n.native.js.map +1 -1
  289. package/dist/esm/shared/pickerTriggerContract.native.js.map +1 -1
  290. package/dist/esm/shared/pressSlopProps.native.js.map +1 -1
  291. package/dist/esm/shared/t.native.js.map +1 -1
  292. package/dist/esm/shared/tableCellContext.native.js.map +1 -1
  293. package/dist/esm/shared/useDragScroll.native.js.map +1 -1
  294. package/dist/esm/shared/useKeyboardInset.native.js.map +1 -1
  295. package/dist/esm/shared/useSheetEscapeDismiss.native.js.map +1 -1
  296. package/dist/esm/shared/useWheelIncrement.native.js.map +1 -1
  297. package/dist/esm/shared/utils.native.js.map +1 -1
  298. package/dist/esm/shared/zIndex.native.js.map +1 -1
  299. package/dist/esm/themedPrimitives.native.js.map +1 -1
  300. package/dist/esm/types.native.js.map +1 -1
  301. package/dist/esm/utils/LinkCell.native.js.map +1 -1
  302. package/dist/jsx/Button/index.mjs +0 -3
  303. package/dist/jsx/Button/index.mjs.map +1 -1
  304. package/dist/jsx/Button/index.native.js +0 -3
  305. package/dist/jsx/Button/index.native.js.map +1 -1
  306. package/dist/jsx/Chip/index.mjs +1 -1
  307. package/dist/jsx/Chip/index.mjs.map +1 -1
  308. package/dist/jsx/Chip/index.native.js +1 -1
  309. package/dist/jsx/Chip/index.native.js.map +1 -1
  310. package/dist/jsx/FloatingPanel/index.mjs +58 -15
  311. package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
  312. package/dist/jsx/FloatingPanel/index.native.js +16 -7
  313. package/dist/jsx/FloatingPanel/index.native.js.map +1 -1
  314. package/dist/jsx/FloatingPanel/nestedAction.mjs +11 -0
  315. package/dist/jsx/FloatingPanel/nestedAction.mjs.map +1 -0
  316. package/dist/jsx/FloatingPanel/nestedAction.native.js +42 -0
  317. package/dist/jsx/FloatingPanel/nestedAction.native.js.map +1 -0
  318. package/dist/jsx/InputParts/index.mjs +9 -7
  319. package/dist/jsx/InputParts/index.mjs.map +1 -1
  320. package/dist/jsx/InputParts/index.native.js +9 -9
  321. package/dist/jsx/InputParts/index.native.js.map +1 -1
  322. package/dist/jsx/Wheel/index.mjs +3 -3
  323. package/dist/jsx/Wheel/index.mjs.map +1 -1
  324. package/dist/jsx/Wheel/index.native.js +3 -3
  325. package/dist/jsx/Wheel/index.native.js.map +1 -1
  326. package/dist/jsx/fieldLayout.mjs +3 -3
  327. package/dist/jsx/fieldLayout.mjs.map +1 -1
  328. package/dist/jsx/fieldLayout.native.js +3 -3
  329. package/dist/jsx/fieldLayout.native.js.map +1 -1
  330. package/dist/jsx/fields/Checkbox/CheckboxFieldFrame.mjs +8 -1
  331. package/dist/jsx/fields/Checkbox/CheckboxFieldFrame.mjs.map +1 -1
  332. package/dist/jsx/fields/Checkbox/CheckboxFieldFrame.native.js +10 -1
  333. package/dist/jsx/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  334. package/dist/jsx/fields/Combobox/index.mjs +36 -29
  335. package/dist/jsx/fields/Combobox/index.mjs.map +1 -1
  336. package/dist/jsx/fields/Combobox/index.native.js +38 -38
  337. package/dist/jsx/fields/Combobox/index.native.js.map +1 -1
  338. package/dist/jsx/fields/DatePicker/Calendar.mjs +6 -1
  339. package/dist/jsx/fields/DatePicker/Calendar.mjs.map +1 -1
  340. package/dist/jsx/fields/DatePicker/Calendar.native.js +6 -1
  341. package/dist/jsx/fields/DatePicker/Calendar.native.js.map +1 -1
  342. package/dist/jsx/fields/DatePicker/DateRangePicker.mjs +2 -2
  343. package/dist/jsx/fields/DatePicker/DateRangePicker.mjs.map +1 -1
  344. package/dist/jsx/fields/DatePicker/DateRangePicker.native.js +2 -2
  345. package/dist/jsx/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  346. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.mjs +15 -12
  347. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.mjs.map +1 -1
  348. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.native.js +16 -12
  349. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  350. package/dist/jsx/fields/DatePicker/DatetimePicker.native.js +39 -14
  351. package/dist/jsx/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  352. package/dist/jsx/fields/DatePicker/MonthPicker.mjs +10 -3
  353. package/dist/jsx/fields/DatePicker/MonthPicker.mjs.map +1 -1
  354. package/dist/jsx/fields/DatePicker/MonthPicker.native.js +10 -3
  355. package/dist/jsx/fields/DatePicker/MonthPicker.native.js.map +1 -1
  356. package/dist/jsx/fields/DatePicker/MultiDatePicker.mjs +2 -2
  357. package/dist/jsx/fields/DatePicker/MultiDatePicker.mjs.map +1 -1
  358. package/dist/jsx/fields/DatePicker/MultiDatePicker.native.js +2 -2
  359. package/dist/jsx/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  360. package/dist/jsx/fields/DatePicker/index.native.js +3 -0
  361. package/dist/jsx/fields/DatePicker/index.native.js.map +1 -1
  362. package/dist/jsx/fields/DatePicker/parts.mjs +28 -16
  363. package/dist/jsx/fields/DatePicker/parts.mjs.map +1 -1
  364. package/dist/jsx/fields/DatePicker/parts.native.js +28 -14
  365. package/dist/jsx/fields/DatePicker/parts.native.js.map +1 -1
  366. package/dist/jsx/fields/Geolocation/GeolocationMap.mjs.map +1 -1
  367. package/dist/jsx/fields/Geolocation/GeolocationMap.native.js.map +1 -1
  368. package/dist/jsx/fields/Geolocation/geocoder.mjs +33 -0
  369. package/dist/jsx/fields/Geolocation/geocoder.mjs.map +1 -0
  370. package/dist/jsx/fields/Geolocation/geocoder.native.js +68 -0
  371. package/dist/jsx/fields/Geolocation/geocoder.native.js.map +1 -0
  372. package/dist/jsx/fields/Geolocation/index.mjs +792 -149
  373. package/dist/jsx/fields/Geolocation/index.mjs.map +1 -1
  374. package/dist/jsx/fields/Geolocation/index.native.js +856 -167
  375. package/dist/jsx/fields/Geolocation/index.native.js.map +1 -1
  376. package/dist/jsx/fields/Geolocation/nativeSearchFocus.mjs +19 -0
  377. package/dist/jsx/fields/Geolocation/nativeSearchFocus.mjs.map +1 -0
  378. package/dist/jsx/fields/Geolocation/nativeSearchFocus.native.js +47 -0
  379. package/dist/jsx/fields/Geolocation/nativeSearchFocus.native.js.map +1 -0
  380. package/dist/jsx/fields/Icon/drawnSet.mjs +14 -3
  381. package/dist/jsx/fields/Icon/drawnSet.mjs.map +1 -1
  382. package/dist/jsx/fields/Icon/drawnSet.native.js +18 -3
  383. package/dist/jsx/fields/Icon/drawnSet.native.js.map +1 -1
  384. package/dist/jsx/fields/Icon/index.mjs +93 -18
  385. package/dist/jsx/fields/Icon/index.mjs.map +1 -1
  386. package/dist/jsx/fields/Icon/index.native.js +115 -31
  387. package/dist/jsx/fields/Icon/index.native.js.map +1 -1
  388. package/dist/jsx/fields/Input/index.mjs +5 -12
  389. package/dist/jsx/fields/Input/index.mjs.map +1 -1
  390. package/dist/jsx/fields/Input/index.native.js +5 -13
  391. package/dist/jsx/fields/Input/index.native.js.map +1 -1
  392. package/dist/jsx/fields/PhoneInput/index.mjs +2 -2
  393. package/dist/jsx/fields/PhoneInput/index.mjs.map +1 -1
  394. package/dist/jsx/fields/PhoneInput/index.native.js +2 -2
  395. package/dist/jsx/fields/PhoneInput/index.native.js.map +1 -1
  396. package/dist/jsx/fields/SearchInput/index.mjs +9 -10
  397. package/dist/jsx/fields/SearchInput/index.mjs.map +1 -1
  398. package/dist/jsx/fields/SearchInput/index.native.js +8 -9
  399. package/dist/jsx/fields/SearchInput/index.native.js.map +1 -1
  400. package/dist/jsx/fields/Select/index.mjs +42 -11
  401. package/dist/jsx/fields/Select/index.mjs.map +1 -1
  402. package/dist/jsx/fields/Select/index.native.js +52 -20
  403. package/dist/jsx/fields/Select/index.native.js.map +1 -1
  404. package/dist/jsx/fields/Stepper/index.mjs +145 -32
  405. package/dist/jsx/fields/Stepper/index.mjs.map +1 -1
  406. package/dist/jsx/fields/Stepper/index.native.js +151 -31
  407. package/dist/jsx/fields/Stepper/index.native.js.map +1 -1
  408. package/dist/jsx/index.js +2 -1
  409. package/dist/jsx/index.js.map +1 -1
  410. package/dist/jsx/index.mjs +2 -1
  411. package/dist/jsx/index.mjs.map +1 -1
  412. package/dist/jsx/index.native.js +2 -0
  413. package/dist/jsx/index.native.js.map +1 -1
  414. package/dist/jsx/shared/focusManagement.mjs +24 -11
  415. package/dist/jsx/shared/focusManagement.mjs.map +1 -1
  416. package/dist/jsx/shared/focusManagement.native.js +24 -11
  417. package/dist/jsx/shared/focusManagement.native.js.map +1 -1
  418. package/package.json +8 -7
  419. package/src/Button/Button.labelInk.spec.tsx +21 -18
  420. package/src/Button/Button.outlinedChannel.spec.tsx +46 -0
  421. package/src/Button/Button.sizeLadder.spec.tsx +4 -3
  422. package/src/Button/Button.stories.tsx +20 -0
  423. package/src/Button/index.tsx +25 -4
  424. package/src/Chip/Chip.spec.tsx +3 -1
  425. package/src/Chip/index.tsx +1 -5
  426. package/src/FieldLayout.stories.tsx +41 -0
  427. package/src/FloatingPanel/FloatingPanel.native.spec.tsx +54 -0
  428. package/src/FloatingPanel/FloatingPanel.spec.tsx +109 -0
  429. package/src/FloatingPanel/index.native.tsx +24 -7
  430. package/src/FloatingPanel/index.tsx +80 -13
  431. package/src/FloatingPanel/nestedAction.spec.ts +36 -0
  432. package/src/FloatingPanel/nestedAction.ts +15 -0
  433. package/src/FloatingPanel/panelWidthContract.spec.ts +12 -15
  434. package/src/FormsIntegration.stories.tsx +2 -6
  435. package/src/InputParts/index.tsx +15 -5
  436. package/src/InputParts/layoutGap.spec.tsx +43 -0
  437. package/src/Wheel/Wheel.spec.tsx +16 -0
  438. package/src/Wheel/index.tsx +3 -3
  439. package/src/fieldLayout.spec.tsx +42 -1
  440. package/src/fieldLayout.tsx +9 -9
  441. package/src/fields/Checkbox/CheckboxFieldFrame.spec.tsx +18 -0
  442. package/src/fields/Checkbox/CheckboxFieldFrame.tsx +6 -1
  443. package/src/fields/Combobox/Combobox.spec.tsx +48 -1
  444. package/src/fields/Combobox/index.tsx +53 -39
  445. package/src/fields/DatePicker/Calendar.tsx +4 -1
  446. package/src/fields/DatePicker/DatePicker.stories.tsx +22 -1
  447. package/src/fields/DatePicker/DateRangePicker.tsx +4 -2
  448. package/src/fields/DatePicker/DatetimePicker.catalog.tsx +21 -19
  449. package/src/fields/DatePicker/DatetimePicker.native.spec.tsx +144 -0
  450. package/src/fields/DatePicker/DatetimePicker.native.tsx +57 -32
  451. package/src/fields/DatePicker/DatetimePicker.stories.tsx +22 -0
  452. package/src/fields/DatePicker/MonthPicker.tsx +8 -3
  453. package/src/fields/DatePicker/MultiDatePicker.tsx +4 -2
  454. package/src/fields/DatePicker/index.native.tsx +1 -0
  455. package/src/fields/DatePicker/parts.spec.tsx +56 -0
  456. package/src/fields/DatePicker/parts.tsx +33 -12
  457. package/src/fields/Geolocation/Geolocation.spec.tsx +287 -35
  458. package/src/fields/Geolocation/Geolocation.stories.tsx +141 -7
  459. package/src/fields/Geolocation/GeolocationMap.native.tsx +3 -0
  460. package/src/fields/Geolocation/GeolocationMap.tsx +4 -0
  461. package/src/fields/Geolocation/geocoder.spec.ts +59 -0
  462. package/src/fields/Geolocation/geocoder.ts +84 -0
  463. package/src/fields/Geolocation/geocoderSeam.spec.tsx +203 -0
  464. package/src/fields/Geolocation/index.tsx +912 -180
  465. package/src/fields/Geolocation/nativeSearchFocus.spec.ts +34 -0
  466. package/src/fields/Geolocation/nativeSearchFocus.ts +19 -0
  467. package/src/fields/Geolocation/salvage.spec.tsx +398 -0
  468. package/src/fields/Geolocation/storyProviders.spec.tsx +44 -0
  469. package/src/fields/Icon/Icon.spec.tsx +215 -1
  470. package/src/fields/Icon/Icon.stories.tsx +9 -1
  471. package/src/fields/Icon/drawnSet.tsx +39 -4
  472. package/src/fields/Icon/index.tsx +118 -18
  473. package/src/fields/Input/Input.copy.spec.tsx +1 -0
  474. package/src/fields/Input/Input.spec.tsx +50 -0
  475. package/src/fields/Input/Input.stories.tsx +1 -1
  476. package/src/fields/Input/index.tsx +7 -13
  477. package/src/fields/PhoneInput/index.tsx +2 -2
  478. package/src/fields/SearchInput/SearchInput.spec.tsx +14 -0
  479. package/src/fields/SearchInput/index.tsx +5 -6
  480. package/src/fields/Select/Select.spec.tsx +54 -0
  481. package/src/fields/Select/index.tsx +52 -17
  482. package/src/fields/Stepper/Stepper.spec.tsx +34 -1
  483. package/src/fields/Stepper/index.tsx +193 -33
  484. package/src/index.ts +9 -0
  485. package/src/shared/focusManagement.spec.tsx +68 -0
  486. package/src/shared/focusManagement.ts +20 -10
  487. package/types/Button/index.d.ts +22 -3
  488. package/types/Button/index.d.ts.map +1 -1
  489. package/types/Chip/index.d.ts.map +1 -1
  490. package/types/FloatingPanel/index.d.ts +11 -1
  491. package/types/FloatingPanel/index.d.ts.map +1 -1
  492. package/types/FloatingPanel/index.native.d.ts +2 -1
  493. package/types/FloatingPanel/index.native.d.ts.map +1 -1
  494. package/types/FloatingPanel/nestedAction.d.ts +13 -0
  495. package/types/FloatingPanel/nestedAction.d.ts.map +1 -0
  496. package/types/InputParts/index.d.ts.map +1 -1
  497. package/types/fields/Checkbox/CheckboxFieldFrame.d.ts +46 -2
  498. package/types/fields/Checkbox/CheckboxFieldFrame.d.ts.map +1 -1
  499. package/types/fields/Checkbox/index.d.ts +3 -3
  500. package/types/fields/Combobox/index.d.ts +3 -1
  501. package/types/fields/Combobox/index.d.ts.map +1 -1
  502. package/types/fields/DatePicker/Calendar.d.ts.map +1 -1
  503. package/types/fields/DatePicker/DateRangePicker.d.ts.map +1 -1
  504. package/types/fields/DatePicker/DatetimePicker.catalog.d.ts.map +1 -1
  505. package/types/fields/DatePicker/DatetimePicker.native.d.ts.map +1 -1
  506. package/types/fields/DatePicker/MonthPicker.d.ts.map +1 -1
  507. package/types/fields/DatePicker/MultiDatePicker.d.ts.map +1 -1
  508. package/types/fields/DatePicker/index.native.d.ts.map +1 -1
  509. package/types/fields/DatePicker/parts.d.ts.map +1 -1
  510. package/types/fields/Geolocation/GeolocationMap.d.ts +4 -0
  511. package/types/fields/Geolocation/GeolocationMap.d.ts.map +1 -1
  512. package/types/fields/Geolocation/GeolocationMap.native.d.ts +3 -0
  513. package/types/fields/Geolocation/GeolocationMap.native.d.ts.map +1 -1
  514. package/types/fields/Geolocation/geocoder.d.ts +53 -0
  515. package/types/fields/Geolocation/geocoder.d.ts.map +1 -0
  516. package/types/fields/Geolocation/index.d.ts +18 -2
  517. package/types/fields/Geolocation/index.d.ts.map +1 -1
  518. package/types/fields/Geolocation/nativeSearchFocus.d.ts +8 -0
  519. package/types/fields/Geolocation/nativeSearchFocus.d.ts.map +1 -0
  520. package/types/fields/Icon/drawnSet.d.ts.map +1 -1
  521. package/types/fields/Icon/index.d.ts.map +1 -1
  522. package/types/fields/Input/index.d.ts.map +1 -1
  523. package/types/fields/PhoneInput/index.d.ts.map +1 -1
  524. package/types/fields/RadioGroup/index.d.ts +2 -2
  525. package/types/fields/SearchInput/index.d.ts.map +1 -1
  526. package/types/fields/Select/index.d.ts.map +1 -1
  527. package/types/fields/Stepper/index.d.ts.map +1 -1
  528. package/types/fields/ToggleGroup/index.d.ts +1 -1
  529. package/types/index.d.ts +2 -0
  530. package/types/index.d.ts.map +1 -1
  531. package/types/shared/focusManagement.d.ts +2 -2
  532. package/types/shared/focusManagement.d.ts.map +1 -1
  533. package/src/router.d.ts +0 -16
@@ -1,7 +1,8 @@
1
1
  import { act, fireEvent, waitFor } from "@testing-library/react";
2
2
  import { describe, expect, it, vi } from "vitest";
3
3
  import { renderWithProviders } from "@multiplatform.one/test-utils";
4
- import { Icon } from "./index";
4
+ import { Theme } from "tamagui";
5
+ import { DrawnIcon, Icon } from "./index";
5
6
 
6
7
  describe("Icon", () => {
7
8
  it("renders an icon control, not an unsupported-type string", () => {
@@ -56,6 +57,29 @@ describe("Icon", () => {
56
57
  });
57
58
  });
58
59
 
60
+ it("uses fixed glyph cells and keeps search and selection working", async () => {
61
+ const onChange = vi.fn();
62
+ const result = renderWithProviders(
63
+ <Icon label="Workspace icon" value="mail" onChange={onChange} />,
64
+ );
65
+ const input = result.container.querySelector("input")!;
66
+ fireEvent.click(input);
67
+ await waitFor(() => expect(document.querySelector('[data-testid="icon-panel"]')).toBeTruthy());
68
+ for (const cell of document.querySelectorAll('[data-testid^="icon-option-"]')) {
69
+ // Tamagui extracts literal geometry into atomic classes in this test build.
70
+ expect(cell).toHaveClass("_w-64px");
71
+ expect(cell.firstElementChild).toHaveClass("_h-60px");
72
+ }
73
+ fireEvent.change(input, { target: { value: "chev" } });
74
+ await waitFor(() =>
75
+ expect(document.querySelectorAll('[data-testid^="icon-option-"]')).toHaveLength(4),
76
+ );
77
+ expect(input.value).toBe("chev");
78
+ fireEvent.click(document.querySelector('[data-testid="icon-option-chev-u"]')!);
79
+ await waitFor(() => expect(onChange).toHaveBeenCalledWith("chev-u"));
80
+ expect(input.value).toBe("mail");
81
+ });
82
+
59
83
  it("does not paint typed icon glyphs in the trigger", () => {
60
84
  const result = renderWithProviders(<Icon label="Workspace icon" value="mail" />);
61
85
  const text = result.container.textContent ?? "";
@@ -64,4 +88,194 @@ describe("Icon", () => {
64
88
  }
65
89
  expect(result.container.querySelector("svg")).toBeTruthy();
66
90
  });
91
+
92
+ it("keeps desktop option semantics without adding a second search field", async () => {
93
+ const result = renderWithProviders(<Icon label="Workspace icon" value="mail" />);
94
+ fireEvent.click(result.container.querySelector("input")!);
95
+ await waitFor(() => expect(document.querySelector('[data-testid="icon-panel"]')).toBeTruthy());
96
+ expect(document.querySelector('[data-testid="icon-sheet-search"]')).toBeNull();
97
+ expect(document.querySelector('[data-testid="icon-option-mail"]')).toHaveAttribute(
98
+ "role",
99
+ "option",
100
+ );
101
+ expect(document.querySelector('[data-testid="icon-option-mail"]')).toHaveAttribute(
102
+ "aria-selected",
103
+ "true",
104
+ );
105
+ });
106
+
107
+ it("lets a narrow sheet search, commit and reopen with a cleared query", async () => {
108
+ const width = window.innerWidth;
109
+ Object.defineProperty(window, "innerWidth", { configurable: true, value: 500 });
110
+ const onChange = vi.fn();
111
+ const result = renderWithProviders(
112
+ <Icon label="Workspace icon" value="mail" onChange={onChange} />,
113
+ );
114
+ try {
115
+ const input = result.container.querySelector("input")!;
116
+ fireEvent.click(input);
117
+ const search = await waitFor(() => {
118
+ const element = document.querySelector<HTMLInputElement>(
119
+ '[data-testid="icon-sheet-search"]',
120
+ );
121
+ expect(element).toBeTruthy();
122
+ return element!;
123
+ });
124
+ fireEvent.change(search, { target: { value: "chev" } });
125
+ await waitFor(() =>
126
+ expect(document.querySelectorAll('[data-testid^="icon-option-"]')).toHaveLength(4),
127
+ );
128
+ fireEvent.click(document.querySelector('[data-testid="icon-option-chev-u"]')!);
129
+ await waitFor(() => expect(onChange).toHaveBeenCalledWith("chev-u"));
130
+ fireEvent.click(input);
131
+ await waitFor(() =>
132
+ expect(document.querySelectorAll('[data-testid^="icon-option-"]')).toHaveLength(16),
133
+ );
134
+ expect(
135
+ document.querySelector<HTMLInputElement>('[data-testid="icon-sheet-search"]')?.value,
136
+ ).toBe("");
137
+ fireEvent.click(result.getByLabelText("Clear icon"));
138
+ expect(onChange).toHaveBeenCalledWith("");
139
+ } finally {
140
+ result.unmount();
141
+ Object.defineProperty(window, "innerWidth", { configurable: true, value: width });
142
+ }
143
+ });
144
+
145
+ it("returns focus after a sheet pick without reopening and supports keyboard reopening", async () => {
146
+ const width = window.innerWidth;
147
+ Object.defineProperty(window, "innerWidth", { configurable: true, value: 500 });
148
+ const onChange = vi.fn();
149
+ const result = renderWithProviders(<Icon label="Workspace icon" onChange={onChange} />);
150
+ try {
151
+ const input = result.container.querySelector("input")!;
152
+ await act(async () => input.focus());
153
+ const search = await waitFor(() => {
154
+ const element = document.querySelector<HTMLInputElement>(
155
+ '[data-testid="icon-sheet-search"]',
156
+ );
157
+ expect(element).toBeTruthy();
158
+ return element!;
159
+ });
160
+ await act(async () => search.focus());
161
+ fireEvent.change(search, { target: { value: "chev" } });
162
+ fireEvent.click(document.querySelector('[data-testid="icon-option-chev-u"]')!);
163
+ expect(onChange).toHaveBeenCalledWith("chev-u");
164
+ await act(async () => new Promise((resolve) => setTimeout(resolve, 400)));
165
+ expect(input).toHaveAttribute("aria-expanded", "false");
166
+ expect(document.activeElement).toBe(input);
167
+ fireEvent.keyDown(input, { key: "Enter" });
168
+ expect(input).toHaveAttribute("aria-expanded", "true");
169
+ } finally {
170
+ result.unmount();
171
+ Object.defineProperty(window, "innerWidth", { configurable: true, value: width });
172
+ }
173
+ });
174
+
175
+ it("returns desktop pick focus even when pointer capture opened before the input focused", async () => {
176
+ const result = renderWithProviders(<Icon label="Workspace icon" />);
177
+ const input = result.container.querySelector("input")!;
178
+ expect(document.activeElement).not.toBe(input);
179
+ fireEvent.click(input);
180
+ const option = await waitFor(() => {
181
+ const element = document.querySelector<HTMLElement>('[data-testid="icon-option-mail"]');
182
+ expect(element).toBeTruthy();
183
+ return element!;
184
+ });
185
+ fireEvent.click(option);
186
+ await act(async () => new Promise((resolve) => setTimeout(resolve, 400)));
187
+ expect(input).toHaveAttribute("aria-expanded", "false");
188
+ expect(document.activeElement).toBe(input);
189
+ });
190
+
191
+ it("does not reclaim focus after dismissal onto another field", async () => {
192
+ const result = renderWithProviders(
193
+ <>
194
+ <Icon label="Workspace icon" />
195
+ <input aria-label="Next field" />
196
+ </>,
197
+ );
198
+ const input = result.container.querySelector("input")!;
199
+ await act(async () => input.focus());
200
+ await waitFor(() => expect(document.querySelector('[data-testid="icon-panel"]')).toBeTruthy());
201
+ const next = result.getByLabelText("Next field");
202
+ await act(async () => next.focus());
203
+ fireEvent.pointerDown(next);
204
+ fireEvent.click(next);
205
+ await act(async () => new Promise((resolve) => setTimeout(resolve, 400)));
206
+ expect(input).toHaveAttribute("aria-expanded", "false");
207
+ expect(document.activeElement).toBe(next);
208
+ });
209
+
210
+ it("allows fresh focus entry after the restore window when the calendar clock is frozen", async () => {
211
+ const clock = vi.spyOn(Date, "now").mockReturnValue(1_768_478_400_000);
212
+ const result = renderWithProviders(<Icon label="Workspace icon" />);
213
+ try {
214
+ const input = result.container.querySelector("input")!;
215
+ fireEvent.click(input);
216
+ await waitFor(() =>
217
+ expect(document.querySelector('[data-testid="icon-option-mail"]')).toBeTruthy(),
218
+ );
219
+ fireEvent.click(document.querySelector('[data-testid="icon-option-mail"]')!);
220
+ await act(async () => new Promise((resolve) => setTimeout(resolve, 500)));
221
+ expect(input).toHaveAttribute("aria-expanded", "false");
222
+ await act(async () => input.blur());
223
+ await act(async () => input.focus());
224
+ expect(input).toHaveAttribute("aria-expanded", "true");
225
+ } finally {
226
+ result.unmount();
227
+ clock.mockRestore();
228
+ }
229
+ });
230
+
231
+ // MPO-72. A glyph outside InputParts.Icon has nothing injecting a colour, and
232
+ // `currentColor` does not cascade on react-native-svg: iOS resolved it to nil
233
+ // and Core Graphics then painted with whatever stroke was last in the
234
+ // context. Every paint has to leave here as a concrete value.
235
+ it("paints the readOnly glyph with a resolved colour, never currentColor", () => {
236
+ const result = renderWithProviders(<Icon label="Workspace icon" value="mail" readOnly />);
237
+ const svg = result.container.querySelector("svg");
238
+ expect(svg).toBeTruthy();
239
+ const color = svg?.getAttribute("color");
240
+ expect(color).toBeTruthy();
241
+ expect(color).not.toBe("currentColor");
242
+ // No token survives to the renderer either: "$color11" is not a paint.
243
+ expect(color?.startsWith("$")).toBe(false);
244
+ const strokes = Array.from(svg?.querySelectorAll("[stroke]") ?? []).map((el) =>
245
+ el.getAttribute("stroke"),
246
+ );
247
+ expect(strokes.length).toBeGreaterThan(0);
248
+ for (const stroke of strokes) {
249
+ expect(stroke).not.toBe("currentColor");
250
+ expect(stroke?.startsWith("$")).toBe(false);
251
+ }
252
+ });
253
+
254
+ for (const scheme of ["light", "dark"] as const) {
255
+ it(`${scheme} resolves default, token, and filled glyph paint`, () => {
256
+ const { container } = renderWithProviders(
257
+ <Theme name={scheme}>
258
+ <DrawnIcon name="mail" />
259
+ <DrawnIcon name="mail" color="$color11" />
260
+ <DrawnIcon name="mail" color="currentColor" />
261
+ <DrawnIcon name="grip" color="$unknownIconToken" />
262
+ <DrawnIcon name="mail" color="rebeccapurple" />
263
+ </Theme>,
264
+ );
265
+ const svgs = Array.from(container.querySelectorAll("svg"));
266
+ const ink = svgs[0].getAttribute("color");
267
+ expect(ink).toBeTruthy();
268
+ expect(ink).not.toMatch(/^(currentColor|\$)/);
269
+ for (const svg of svgs.slice(0, 4)) {
270
+ expect(svg.getAttribute("color")).toBe(ink);
271
+ for (const part of svg.querySelectorAll("[stroke], [fill]")) {
272
+ for (const attr of ["stroke", "fill"]) {
273
+ const paint = part.getAttribute(attr);
274
+ if (paint && paint !== "none") expect(paint).toBe(ink);
275
+ }
276
+ }
277
+ }
278
+ expect(svgs[4].getAttribute("color")).toBe("rebeccapurple");
279
+ });
280
+ }
67
281
  });
@@ -11,7 +11,7 @@ const meta: Meta<typeof Icon> = {
11
11
  docs: {
12
12
  description: {
13
13
  component:
14
- "Icon picker over FloatingPanel. Options come from the DG-IDN-06 drawn set. Field-shaped panel uses widthMode at-least-trigger.",
14
+ "Icon picker over FloatingPanel. Options come from the DG-IDN-06 drawn set. The panel matches its field and wraps fixed-size glyph cells.",
15
15
  },
16
16
  },
17
17
  },
@@ -50,6 +50,14 @@ export const Empty: Story = {
50
50
  ),
51
51
  };
52
52
 
53
+ export const Wide: Story = {
54
+ render: () => (
55
+ <YStack width={600} maxWidth="100%">
56
+ <Icon label="Workspace icon" value="mail" />
57
+ </YStack>
58
+ ),
59
+ };
60
+
53
61
  export const ReadOnly: Story = {
54
62
  render: () => (
55
63
  <YStack width={320}>
@@ -1,4 +1,5 @@
1
1
  import { Circle, Line, Path, Polyline, Rect, Svg } from "react-native-svg";
2
+ import { useTheme } from "tamagui";
2
3
 
3
4
  /**
4
5
  * The DG-IDN-06 drawn set — geometries lifted from design-mockups-v3/iconset.py
@@ -197,19 +198,53 @@ export function filterDrawnIcons(
197
198
  return catalog.filter((name) => name.toLowerCase().includes(needle));
198
199
  }
199
200
 
201
+ /**
202
+ * MPO-72 — the glyph paint is resolved here, never left as `currentColor`.
203
+ *
204
+ * react-native-svg has no CSS cascade. iOS resolves `currentColor` in
205
+ * RNSVGRenderable's getCurrentColor: self.color, else the parent Svg's color,
206
+ * else NIL. DrawnIcon passed no color to its own Svg, so the stroke arrived
207
+ * nil, CGContextSetStrokeColorWithColor kept whatever was last in the Core
208
+ * Graphics context, and the picker grid painted one glyph bright and the rest
209
+ * near-black by draw order.
210
+ *
211
+ * A Tamagui token fails one step earlier for the same reason: react-native-svg
212
+ * wants a color VALUE, so "$color11" would reach Core Graphics unparsed.
213
+ */
214
+ const drawnIconInkToken = "color11";
215
+
216
+ function useDrawnInk(color?: string): string | undefined {
217
+ const theme = useTheme() as unknown as Record<string, { val?: unknown } | undefined>;
218
+ const raw = !color || color === "currentColor" ? `$${drawnIconInkToken}` : color;
219
+ const val = raw.startsWith("$") ? theme[raw.slice(1)]?.val : raw;
220
+ // An unknown consumer token falls back to the active theme's readable ink.
221
+ const fallback = theme[drawnIconInkToken]?.val ?? theme.color?.val;
222
+ return typeof val === "string" ? val : typeof fallback === "string" ? fallback : undefined;
223
+ }
224
+
200
225
  export function DrawnIcon({
201
226
  name,
202
227
  size = 16,
203
- color = "currentColor",
228
+ color,
204
229
  }: {
205
230
  name: DrawnIconName;
206
231
  size?: number;
207
232
  color?: string;
208
233
  }) {
234
+ const ink = useDrawnInk(color);
209
235
  const geom = GEOM[name];
210
- const stroke = geom.fillStroke ? color : "none";
236
+ const stroke = geom.fillStroke ? ink : "none";
211
237
  return (
212
- <Svg width={size} height={size} viewBox="0 0 24 24" pointerEvents="none" aria-hidden>
238
+ <Svg
239
+ width={size}
240
+ height={size}
241
+ viewBox="0 0 24 24"
242
+ // Also the parent colour, so any nested `currentColor` resolves to ink
243
+ // instead of nil.
244
+ color={ink}
245
+ pointerEvents="none"
246
+ aria-hidden
247
+ >
213
248
  {geom.shapes.map((shape, index) => {
214
249
  const key = `${name}-${index}`;
215
250
  if (shape.kind === "polyline") {
@@ -277,7 +312,7 @@ export function DrawnIcon({
277
312
  cx={shape.cx}
278
313
  cy={shape.cy}
279
314
  r={shape.r}
280
- fill={shape.filled ? color : "none"}
315
+ fill={shape.filled ? ink : "none"}
281
316
  stroke={shape.filled ? "none" : stroke}
282
317
  strokeWidth={shape.filled ? 0 : geom.strokeWidth}
283
318
  />
@@ -1,13 +1,20 @@
1
1
  import type { DeepKeys, DeepValue } from "@tanstack/form-core";
2
- import { ensureFocusVisibleRing, useResolvedKnobs } from "@multiplatform.one/theme";
3
- import { useCallback, useEffect, useMemo, useState } from "react";
2
+ import { MagnifyingGlassIcon } from "@phosphor-icons/react";
3
+ import { Pressable as RNPressable } from "react-native";
4
+ import {
5
+ ensureFocusVisibleRing,
6
+ useAaSolidFill,
7
+ useReadableTextOn,
8
+ useResolvedKnobs,
9
+ } from "@multiplatform.one/theme";
10
+ import { useCallback, useEffect, useMemo, useRef, useState, type ComponentRef } from "react";
4
11
  import { Text, View, XStack, YStack, isWeb, useProps } from "tamagui";
5
12
  import { Field, FieldLayout } from "../../fieldLayout";
6
13
  import type { FormFieldProps } from "../../fieldLayout";
7
14
  import { Input as InputParts } from "../../InputParts";
8
- import { FloatingPanel } from "../../FloatingPanel";
15
+ import { FloatingPanel, useViewportGtSm } from "../../FloatingPanel";
9
16
  import { Skeleton } from "../../Skeleton";
10
- import { formCommonColors } from "../../shared/colorRamps";
17
+ import { formCommonColors, formSelectedColors } from "../../shared/colorRamps";
11
18
  import { useIsInTableCell } from "../../shared/tableCellContext";
12
19
  import {
13
20
  getFieldError,
@@ -116,10 +123,20 @@ function IconControl({
116
123
  const { knobProps } = useResolvedKnobs();
117
124
  const [open, setOpen] = useState(false);
118
125
  const [query, setQuery] = useState("");
126
+ const suppressFocusOpenUntilRef = useRef(0);
127
+ const triggerInputRef = useRef<ComponentRef<typeof InputParts.Area>>(null);
128
+ const viewportGtSm = useViewportGtSm();
129
+ const shouldUseSheet = !isWeb || !(typeof window !== "undefined" && viewportGtSm);
119
130
  const drawn = isDrawnIconName(value) ? value : undefined;
120
131
  const matches = useMemo(() => filterDrawnIcons(catalog, query), [catalog, query]);
132
+ // Ink that reads on the accent fill the selected cell carries (LC-05).
133
+ const markFill = useAaSolidFill(formSelectedColors.mark);
134
+ const onMark = useReadableTextOn(markFill);
121
135
 
122
136
  const closePanel = useCallback(() => {
137
+ // Focus restoration retries after 320ms in focusManagement.ts. Let that
138
+ // focus return without reopening; explicit pointer/key actions still open.
139
+ suppressFocusOpenUntilRef.current = performance.now() + 450;
123
140
  setOpen(false);
124
141
  setQuery("");
125
142
  onBlurControl?.();
@@ -129,6 +146,10 @@ function IconControl({
129
146
  (name: DrawnIconName) => {
130
147
  onValueChange(name);
131
148
  closePanel();
149
+ // Pointer capture can open before the trigger gets focus, leaving the
150
+ // shared restore target on body. A completed pick returns to its input.
151
+ // Other dismissals keep the user's chosen destination; native stays inert.
152
+ if (isWeb) triggerInputRef.current?.focus();
132
153
  },
133
154
  [closePanel, onValueChange],
134
155
  );
@@ -159,7 +180,12 @@ function IconControl({
159
180
  alignItems="center"
160
181
  justifyContent="center"
161
182
  >
162
- {drawn ? <DrawnIcon name={drawn} size={16} /> : <EmptyGlyphWell />}
183
+ {/* Outside InputParts.Icon, which is what injects a colour. */}
184
+ {drawn ? (
185
+ <DrawnIcon name={drawn} size={16} color={formCommonColors.text} />
186
+ ) : (
187
+ <EmptyGlyphWell />
188
+ )}
163
189
  </View>
164
190
  );
165
191
  }
@@ -185,6 +211,7 @@ function IconControl({
185
211
  </InputParts.Icon>
186
212
  {!inTableCell && (
187
213
  <InputParts.Area
214
+ ref={triggerInputRef}
188
215
  id={id}
189
216
  value={displayValue}
190
217
  placeholder={placeholder}
@@ -202,12 +229,21 @@ function IconControl({
202
229
  spellCheck={false}
203
230
  onChangeText={open ? setQuery : undefined}
204
231
  onFocus={() => {
205
- if (!disabled) setOpen(true);
232
+ if (!disabled && performance.now() > suppressFocusOpenUntilRef.current)
233
+ setOpen(true);
234
+ }}
235
+ onKeyDown={(e) => {
236
+ if (open || disabled) return;
237
+ if (["Enter", " ", "ArrowDown", "ArrowUp"].includes(e.key) || e.code === "Space") {
238
+ e.preventDefault();
239
+ setOpen(true);
240
+ }
206
241
  }}
207
242
  />
208
243
  )}
209
- {showClear ? (
244
+ {showClear && isWeb ? (
210
245
  <InputParts.Button
246
+ data-floating-panel-action="true"
211
247
  tabIndex={0}
212
248
  aria-label={t("Clear icon")}
213
249
  disabled={disabled}
@@ -231,15 +267,56 @@ function IconControl({
231
267
  </View>
232
268
  );
233
269
 
270
+ const sheetSearchHeader = shouldUseSheet ? (
271
+ <InputParts size={knobProps.sizeToken}>
272
+ <InputParts.Box>
273
+ <InputParts.Icon adornment="leading">
274
+ <MagnifyingGlassIcon size={16} />
275
+ </InputParts.Icon>
276
+ <InputParts.Area
277
+ testID="icon-sheet-search"
278
+ value={query}
279
+ placeholder={t("Search icons")}
280
+ accessibilityLabel={t("Search icons")}
281
+ aria-label={t("Search icons")}
282
+ fontFamily="$mono"
283
+ autoCapitalize="none"
284
+ autoCorrect={false}
285
+ returnKeyType="search"
286
+ onChangeText={setQuery}
287
+ />
288
+ </InputParts.Box>
289
+ </InputParts>
290
+ ) : undefined;
291
+ const nativeClear =
292
+ !isWeb && showClear ? (
293
+ <InputParts.Button
294
+ testID="icon-clear-native"
295
+ aria-label={t("Clear icon")}
296
+ accessibilityLabel={t("Clear icon")}
297
+ disabled={disabled}
298
+ onPress={(e) => {
299
+ e.stopPropagation();
300
+ handleClear();
301
+ }}
302
+ >
303
+ <InputParts.Icon>
304
+ <DrawnIcon name="x" size={16} />
305
+ </InputParts.Icon>
306
+ </InputParts.Button>
307
+ ) : undefined;
308
+
234
309
  return (
235
310
  <FloatingPanel
236
311
  open={open}
237
312
  onOpenChange={handleOpenChange}
238
313
  trigger={trigger}
314
+ triggerEnd={nativeClear}
315
+ header={sheetSearchHeader}
239
316
  disabled={disabled}
240
317
  scrollable
241
318
  sizing="fill"
242
- widthMode="at-least-trigger"
319
+ widthMode="match-trigger"
243
320
  triggerA11y={{
244
321
  label: a11yLabel || t("Icon"),
245
322
  value: value || placeholder,
@@ -251,7 +328,6 @@ function IconControl({
251
328
  id={`${id ?? "icon"}-listbox`}
252
329
  {...({ role: "listbox" } as Record<string, unknown>)}
253
330
  aria-label={t("Icons")}
254
- padding="$2"
255
331
  >
256
332
  {matches.length === 0 ? (
257
333
  <Text
@@ -267,16 +343,18 @@ function IconControl({
267
343
  <XStack flexWrap="wrap">
268
344
  {matches.map((name) => {
269
345
  const selected = name === value;
270
- return (
346
+ const cellInk = (selected && onMark) || formCommonColors.text;
347
+ const cell = (
271
348
  <View
272
349
  key={name}
273
- role="option"
274
- aria-selected={selected}
350
+ {...(isWeb
351
+ ? ({ role: "option", "aria-selected": selected } as Record<string, unknown>)
352
+ : { pointerEvents: "none" as const })}
275
353
  testID={`icon-option-${name}`}
276
- width="33.333%"
354
+ width={64}
277
355
  padding="$1"
278
356
  cursor="pointer"
279
- onPress={() => handlePick(name)}
357
+ onPress={isWeb ? () => handlePick(name) : undefined}
280
358
  >
281
359
  <YStack
282
360
  height={60}
@@ -284,16 +362,38 @@ function IconControl({
284
362
  justifyContent="center"
285
363
  gap="$1"
286
364
  borderRadius="$3"
287
- backgroundColor={selected ? "$color3" : "transparent"}
288
- hoverStyle={{ backgroundColor: "$color3" }}
365
+ // LC-05 ONE-EMPHASIS: the selected mark is the active
366
+ // accent, never a neutral ramp step.
367
+ backgroundColor={selected ? markFill : "transparent"}
368
+ hoverStyle={selected ? undefined : { backgroundColor: "$color3" }}
289
369
  >
290
- <DrawnIcon name={name} size={16} />
291
- <Text fontFamily="$mono" fontSize={11} color="$color10" numberOfLines={1}>
370
+ {/* Outside InputParts.Icon, so the colour is passed here. */}
371
+ <DrawnIcon name={name} size={16} color={cellInk} />
372
+ <Text
373
+ fontFamily="$mono"
374
+ fontSize={11}
375
+ // $color10 measures 3.95-4.36:1, under the 4.5:1 AA floor
376
+ // colorRamps.ts records; step 11 is the lowest that passes.
377
+ color={cellInk}
378
+ numberOfLines={1}
379
+ >
292
380
  {name}
293
381
  </Text>
294
382
  </YStack>
295
383
  </View>
296
384
  );
385
+ if (isWeb) return cell;
386
+ return (
387
+ <RNPressable
388
+ key={name}
389
+ onPress={() => handlePick(name)}
390
+ accessibilityRole="button"
391
+ accessibilityLabel={name}
392
+ accessibilityState={{ selected }}
393
+ >
394
+ {cell}
395
+ </RNPressable>
396
+ );
297
397
  })}
298
398
  </XStack>
299
399
  )}
@@ -19,6 +19,7 @@ describe("Input copy (CopyField slot)", () => {
19
19
 
20
20
  expect(input.getAttribute("aria-readonly")).toBe("true");
21
21
  expect(copy.getAttribute("tabindex")).toBe("0");
22
+ expect(copy.getAttribute("aria-label")).toBe("Copy to clipboard");
22
23
  expect(copy.className).toMatch(/mp-chip-dismiss/);
23
24
  expect(copy.className).not.toMatch(/mp-chip-dismiss-ring/);
24
25
  const ring = copy.querySelector(".mp-chip-dismiss-ring");
@@ -1,4 +1,5 @@
1
1
  import { act, fireEvent, waitFor } from "@testing-library/react";
2
+ import { useState } from "react";
2
3
  import { describe, expect, it, vi } from "vitest";
3
4
  import { renderWithProviders } from "@multiplatform.one/test-utils";
4
5
  import { Preset } from "@multiplatform.one/theme";
@@ -63,6 +64,55 @@ describe("Input", () => {
63
64
  });
64
65
  });
65
66
 
67
+ describe("standalone value ownership", () => {
68
+ it("reflects external controlled updates, including clearing, without remounting", () => {
69
+ const onChange = vi.fn();
70
+ const result = renderWithProviders(<Input label="Name" value="corp" onChange={onChange} />);
71
+ const input = result.container.querySelector("input") as HTMLInputElement;
72
+ act(() => input.focus());
73
+ fireEvent.change(input, { target: { value: "edited" } });
74
+ expect(onChange).toHaveBeenCalledOnce();
75
+ result.rerender(<Input label="Name" value="external" onChange={onChange} />);
76
+ expect(input.value).toBe("external");
77
+ result.rerender(<Input label="Name" value="" onChange={onChange} />);
78
+ expect(input.value).toBe("");
79
+ expect(result.container.querySelector("input")).toBe(input);
80
+ expect(document.activeElement).toBe(input);
81
+ });
82
+
83
+ it("keeps uncontrolled edits when a new default arrives", () => {
84
+ const result = renderWithProviders(<Input label="Name" defaultValue="corp" />);
85
+ const input = result.container.querySelector("input") as HTMLInputElement;
86
+ fireEvent.change(input, { target: { value: "draft" } });
87
+ result.rerender(<Input label="Name" defaultValue="external" />);
88
+ expect(input.value).toBe("draft");
89
+ });
90
+
91
+ it.each(["onChange", "onChangeText"] as const)(
92
+ "round-trips controlled edits through %s",
93
+ (callback) => {
94
+ function ControlledInput() {
95
+ const [value, setValue] = useState("corp");
96
+ return (
97
+ <Input
98
+ label="Name"
99
+ value={value}
100
+ {...(callback === "onChange"
101
+ ? { onChange: (event) => setValue(event.target.value) }
102
+ : { onChangeText: setValue })}
103
+ />
104
+ );
105
+ }
106
+ const result = renderWithProviders(<ControlledInput />);
107
+ const input = result.container.querySelector("input") as HTMLInputElement;
108
+ fireEvent.change(input, { target: { value: "draft" } });
109
+ expect(input.value).toBe("draft");
110
+ fireEvent.change(input, { target: { value: "" } });
111
+ expect(input.value).toBe("");
112
+ },
113
+ );
114
+ });
115
+
66
116
  describe("purpose → keyboard/autofill (DG §32)", () => {
67
117
  it("purpose=email sets autocomplete + inputmode on the DOM input", () => {
68
118
  const result = renderWithProviders(<Input label="Email" name="email" purpose="email" />);
@@ -151,8 +151,8 @@ export const Chromeless: Story = {
151
151
  label: "Toolbar search",
152
152
  chromeless: true,
153
153
  placeholder: "Filter…",
154
- leftIcon: <MagnifyingGlassIcon />,
155
154
  },
155
+ render: (args) => <Input leftIcon={<MagnifyingGlassIcon />} {...args} />,
156
156
  };
157
157
 
158
158
  /** Loading placeholder — the skeleton mirrors the field's anatomy (LC-20 / DG-ST-02). */