@multiplatform.one/forms 7.7.4 → 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 (579) hide show
  1. package/dist/cjs/Button/index.cjs +3 -36
  2. package/dist/cjs/Button/index.native.js +3 -36
  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/ContextualSaveBar/index.cjs +17 -10
  8. package/dist/cjs/ContextualSaveBar/index.native.js +18 -10
  9. package/dist/cjs/ContextualSaveBar/index.native.js.map +1 -1
  10. package/dist/cjs/FloatingPanel/index.cjs +59 -14
  11. package/dist/cjs/FloatingPanel/index.native.js +16 -7
  12. package/dist/cjs/FloatingPanel/index.native.js.map +1 -1
  13. package/dist/cjs/FloatingPanel/nestedAction.cjs +37 -0
  14. package/dist/cjs/FloatingPanel/nestedAction.native.js +42 -0
  15. package/dist/cjs/FloatingPanel/nestedAction.native.js.map +1 -0
  16. package/dist/cjs/InputParts/index.cjs +11 -7
  17. package/dist/cjs/InputParts/index.native.js +12 -10
  18. package/dist/cjs/InputParts/index.native.js.map +1 -1
  19. package/dist/cjs/Wheel/index.cjs +3 -3
  20. package/dist/cjs/Wheel/index.native.js +3 -3
  21. package/dist/cjs/Wheel/index.native.js.map +1 -1
  22. package/dist/cjs/fieldLayout.cjs +3 -3
  23. package/dist/cjs/fieldLayout.native.js +3 -3
  24. package/dist/cjs/fieldLayout.native.js.map +1 -1
  25. package/dist/cjs/fields/Checkbox/CheckboxFieldFrame.cjs +9 -2
  26. package/dist/cjs/fields/Checkbox/CheckboxFieldFrame.native.js +10 -1
  27. package/dist/cjs/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  28. package/dist/cjs/fields/Combobox/index.cjs +74 -76
  29. package/dist/cjs/fields/Combobox/index.native.js +78 -86
  30. package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
  31. package/dist/cjs/fields/DatePicker/Calendar.cjs +6 -1
  32. package/dist/cjs/fields/DatePicker/Calendar.native.js +6 -1
  33. package/dist/cjs/fields/DatePicker/Calendar.native.js.map +1 -1
  34. package/dist/cjs/fields/DatePicker/DateRangePicker.cjs +2 -2
  35. package/dist/cjs/fields/DatePicker/DateRangePicker.native.js +2 -2
  36. package/dist/cjs/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  37. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.cjs +15 -12
  38. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js +16 -12
  39. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  40. package/dist/cjs/fields/DatePicker/DatetimePicker.native.js +39 -14
  41. package/dist/cjs/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  42. package/dist/cjs/fields/DatePicker/MonthPicker.cjs +10 -3
  43. package/dist/cjs/fields/DatePicker/MonthPicker.native.js +10 -3
  44. package/dist/cjs/fields/DatePicker/MonthPicker.native.js.map +1 -1
  45. package/dist/cjs/fields/DatePicker/MultiDatePicker.cjs +2 -2
  46. package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js +2 -2
  47. package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  48. package/dist/cjs/fields/DatePicker/index.native.js +3 -0
  49. package/dist/cjs/fields/DatePicker/index.native.js.map +1 -1
  50. package/dist/cjs/fields/DatePicker/parts.cjs +26 -14
  51. package/dist/cjs/fields/DatePicker/parts.native.js +28 -14
  52. package/dist/cjs/fields/DatePicker/parts.native.js.map +1 -1
  53. package/dist/cjs/fields/Geolocation/GeolocationMap.native.js.map +1 -1
  54. package/dist/cjs/fields/Geolocation/geocoder.cjs +63 -0
  55. package/dist/cjs/fields/Geolocation/geocoder.native.js +68 -0
  56. package/dist/cjs/fields/Geolocation/geocoder.native.js.map +1 -0
  57. package/dist/cjs/fields/Geolocation/index.cjs +801 -152
  58. package/dist/cjs/fields/Geolocation/index.native.js +856 -167
  59. package/dist/cjs/fields/Geolocation/index.native.js.map +1 -1
  60. package/dist/cjs/fields/Geolocation/nativeSearchFocus.cjs +44 -0
  61. package/dist/cjs/fields/Geolocation/nativeSearchFocus.native.js +47 -0
  62. package/dist/cjs/fields/Geolocation/nativeSearchFocus.native.js.map +1 -0
  63. package/dist/cjs/fields/Icon/drawnSet.cjs +14 -3
  64. package/dist/cjs/fields/Icon/drawnSet.native.js +18 -3
  65. package/dist/cjs/fields/Icon/drawnSet.native.js.map +1 -1
  66. package/dist/cjs/fields/Icon/index.cjs +102 -27
  67. package/dist/cjs/fields/Icon/index.native.js +115 -31
  68. package/dist/cjs/fields/Icon/index.native.js.map +1 -1
  69. package/dist/cjs/fields/Input/index.cjs +5 -12
  70. package/dist/cjs/fields/Input/index.native.js +5 -13
  71. package/dist/cjs/fields/Input/index.native.js.map +1 -1
  72. package/dist/cjs/fields/PhoneInput/index.cjs +2 -2
  73. package/dist/cjs/fields/PhoneInput/index.native.js +2 -2
  74. package/dist/cjs/fields/PhoneInput/index.native.js.map +1 -1
  75. package/dist/cjs/fields/SearchInput/index.cjs +8 -9
  76. package/dist/cjs/fields/SearchInput/index.native.js +8 -9
  77. package/dist/cjs/fields/SearchInput/index.native.js.map +1 -1
  78. package/dist/cjs/fields/Select/index.cjs +53 -18
  79. package/dist/cjs/fields/Select/index.native.js +63 -37
  80. package/dist/cjs/fields/Select/index.native.js.map +1 -1
  81. package/dist/cjs/fields/Stepper/index.cjs +144 -31
  82. package/dist/cjs/fields/Stepper/index.native.js +151 -31
  83. package/dist/cjs/fields/Stepper/index.native.js.map +1 -1
  84. package/dist/cjs/index.cjs +2 -0
  85. package/dist/cjs/index.native.js +2 -0
  86. package/dist/cjs/index.native.js.map +1 -1
  87. package/dist/cjs/shared/focusManagement.cjs +24 -11
  88. package/dist/cjs/shared/focusManagement.native.js +24 -11
  89. package/dist/cjs/shared/focusManagement.native.js.map +1 -1
  90. package/dist/cjs/shared/pickerTriggerContract.cjs +38 -0
  91. package/dist/cjs/shared/pickerTriggerContract.native.js +41 -0
  92. package/dist/cjs/shared/pickerTriggerContract.native.js.map +1 -0
  93. package/dist/cjs/shared/pressSlopProps.cjs +68 -0
  94. package/dist/cjs/shared/pressSlopProps.native.js +72 -0
  95. package/dist/cjs/shared/pressSlopProps.native.js.map +1 -0
  96. package/dist/esm/AdaptivePopup/index.native.js.map +1 -1
  97. package/dist/esm/Button/index.mjs +1 -34
  98. package/dist/esm/Button/index.mjs.map +1 -1
  99. package/dist/esm/Button/index.native.js +1 -34
  100. package/dist/esm/Button/index.native.js.map +1 -1
  101. package/dist/esm/Chip/index.mjs +1 -1
  102. package/dist/esm/Chip/index.mjs.map +1 -1
  103. package/dist/esm/Chip/index.native.js +1 -1
  104. package/dist/esm/Chip/index.native.js.map +1 -1
  105. package/dist/esm/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
  106. package/dist/esm/ContextualSaveBar/clientKnownIdentity.native.js.map +1 -1
  107. package/dist/esm/ContextualSaveBar/commitImmediateField.native.js.map +1 -1
  108. package/dist/esm/ContextualSaveBar/index.mjs +17 -10
  109. package/dist/esm/ContextualSaveBar/index.mjs.map +1 -1
  110. package/dist/esm/ContextualSaveBar/index.native.js +18 -10
  111. package/dist/esm/ContextualSaveBar/index.native.js.map +1 -1
  112. package/dist/esm/ContextualSaveBar/useUnsavedChangesGuard.native.js.map +1 -1
  113. package/dist/esm/ControlGroup/index.native.js.map +1 -1
  114. package/dist/esm/DescriptionList/index.native.js.map +1 -1
  115. package/dist/esm/ErrorSummary.native.js.map +1 -1
  116. package/dist/esm/FieldDisplay/editMode.native.js.map +1 -1
  117. package/dist/esm/FieldDisplay/formatters.native.js.map +1 -1
  118. package/dist/esm/FieldDisplay/index.native.js.map +1 -1
  119. package/dist/esm/FieldGroup.native.js.map +1 -1
  120. package/dist/esm/FloatingPanel/index.mjs +58 -15
  121. package/dist/esm/FloatingPanel/index.mjs.map +1 -1
  122. package/dist/esm/FloatingPanel/index.native.js +15 -8
  123. package/dist/esm/FloatingPanel/index.native.js.map +1 -1
  124. package/dist/esm/FloatingPanel/nestedAction.mjs +11 -0
  125. package/dist/esm/FloatingPanel/nestedAction.mjs.map +1 -0
  126. package/dist/esm/FloatingPanel/nestedAction.native.js +13 -0
  127. package/dist/esm/FloatingPanel/nestedAction.native.js.map +1 -0
  128. package/dist/esm/FloatingPanel/useFloatingPanel.native.js.map +1 -1
  129. package/dist/esm/Form/index.native.js.map +1 -1
  130. package/dist/esm/Form/validateOn.native.js.map +1 -1
  131. package/dist/esm/FormGrid.native.js.map +1 -1
  132. package/dist/esm/FormSection.native.js.map +1 -1
  133. package/dist/esm/InputParts/index.mjs +12 -8
  134. package/dist/esm/InputParts/index.mjs.map +1 -1
  135. package/dist/esm/InputParts/index.native.js +13 -11
  136. package/dist/esm/InputParts/index.native.js.map +1 -1
  137. package/dist/esm/Label/index.native.js.map +1 -1
  138. package/dist/esm/Skeleton/index.native.js.map +1 -1
  139. package/dist/esm/Spinner/SpinnerGlyph.native.js.map +1 -1
  140. package/dist/esm/Spinner/spinnerSize.native.js.map +1 -1
  141. package/dist/esm/Table/index.native.js.map +1 -1
  142. package/dist/esm/Wheel/haptic.native.js.map +1 -1
  143. package/dist/esm/Wheel/index.mjs +3 -3
  144. package/dist/esm/Wheel/index.mjs.map +1 -1
  145. package/dist/esm/Wheel/index.native.js +3 -3
  146. package/dist/esm/Wheel/index.native.js.map +1 -1
  147. package/dist/esm/actionLabel.native.js.map +1 -1
  148. package/dist/esm/fieldDefaults.native.js.map +1 -1
  149. package/dist/esm/fieldLayout.mjs +3 -3
  150. package/dist/esm/fieldLayout.mjs.map +1 -1
  151. package/dist/esm/fieldLayout.native.js +3 -3
  152. package/dist/esm/fieldLayout.native.js.map +1 -1
  153. package/dist/esm/fields/Barcode/BarcodePreview.native.js.map +1 -1
  154. package/dist/esm/fields/Barcode/code128.native.js.map +1 -1
  155. package/dist/esm/fields/Barcode/index.native.js.map +1 -1
  156. package/dist/esm/fields/Barcode/qr.native.js.map +1 -1
  157. package/dist/esm/fields/Barcode/scannerTypes.native.js.map +1 -1
  158. package/dist/esm/fields/Checkbox/Checkbox.native.js.map +1 -1
  159. package/dist/esm/fields/Checkbox/CheckboxBox.native.js.map +1 -1
  160. package/dist/esm/fields/Checkbox/CheckboxCard.native.js.map +1 -1
  161. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.mjs +8 -1
  162. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.mjs.map +1 -1
  163. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.native.js +10 -1
  164. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  165. package/dist/esm/fields/Checkbox/CheckboxGroup.native.js.map +1 -1
  166. package/dist/esm/fields/Checkbox/checkboxGroupContext.native.js.map +1 -1
  167. package/dist/esm/fields/Checkbox/index.native.js.map +1 -1
  168. package/dist/esm/fields/ColorPicker/index.native.js.map +1 -1
  169. package/dist/esm/fields/ColorPicker/parts.native.js.map +1 -1
  170. package/dist/esm/fields/Combobox/authorOptions.native.js.map +1 -1
  171. package/dist/esm/fields/Combobox/index.mjs +74 -76
  172. package/dist/esm/fields/Combobox/index.mjs.map +1 -1
  173. package/dist/esm/fields/Combobox/index.native.js +78 -86
  174. package/dist/esm/fields/Combobox/index.native.js.map +1 -1
  175. package/dist/esm/fields/DatePicker/Calendar.mjs +6 -1
  176. package/dist/esm/fields/DatePicker/Calendar.mjs.map +1 -1
  177. package/dist/esm/fields/DatePicker/Calendar.native.js +6 -1
  178. package/dist/esm/fields/DatePicker/Calendar.native.js.map +1 -1
  179. package/dist/esm/fields/DatePicker/DateRangePicker.mjs +2 -2
  180. package/dist/esm/fields/DatePicker/DateRangePicker.mjs.map +1 -1
  181. package/dist/esm/fields/DatePicker/DateRangePicker.native.js +2 -2
  182. package/dist/esm/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  183. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.mjs +15 -12
  184. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.mjs.map +1 -1
  185. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.native.js +16 -12
  186. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  187. package/dist/esm/fields/DatePicker/DatetimePicker.native.js +39 -14
  188. package/dist/esm/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  189. package/dist/esm/fields/DatePicker/MonthPicker.mjs +10 -3
  190. package/dist/esm/fields/DatePicker/MonthPicker.mjs.map +1 -1
  191. package/dist/esm/fields/DatePicker/MonthPicker.native.js +10 -3
  192. package/dist/esm/fields/DatePicker/MonthPicker.native.js.map +1 -1
  193. package/dist/esm/fields/DatePicker/MultiDatePicker.mjs +2 -2
  194. package/dist/esm/fields/DatePicker/MultiDatePicker.mjs.map +1 -1
  195. package/dist/esm/fields/DatePicker/MultiDatePicker.native.js +2 -2
  196. package/dist/esm/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  197. package/dist/esm/fields/DatePicker/catalog.native.js.map +1 -1
  198. package/dist/esm/fields/DatePicker/fieldValueSync.native.js.map +1 -1
  199. package/dist/esm/fields/DatePicker/index.native.js +3 -0
  200. package/dist/esm/fields/DatePicker/index.native.js.map +1 -1
  201. package/dist/esm/fields/DatePicker/parts.mjs +28 -16
  202. package/dist/esm/fields/DatePicker/parts.mjs.map +1 -1
  203. package/dist/esm/fields/DatePicker/parts.native.js +30 -16
  204. package/dist/esm/fields/DatePicker/parts.native.js.map +1 -1
  205. package/dist/esm/fields/DatePicker/utils.native.js.map +1 -1
  206. package/dist/esm/fields/Duration/durationMath.native.js.map +1 -1
  207. package/dist/esm/fields/Duration/index.native.js.map +1 -1
  208. package/dist/esm/fields/FileUpload/filePickerTypes.native.js.map +1 -1
  209. package/dist/esm/fields/FileUpload/index.native.js.map +1 -1
  210. package/dist/esm/fields/FileUpload/nativePickerLoader.native.js.map +1 -1
  211. package/dist/esm/fields/Geolocation/GeolocationMap.mjs.map +1 -1
  212. package/dist/esm/fields/Geolocation/GeolocationMap.native.js.map +1 -1
  213. package/dist/esm/fields/Geolocation/expoMapsLoader.native.js.map +1 -1
  214. package/dist/esm/fields/Geolocation/geoValue.native.js.map +1 -1
  215. package/dist/esm/fields/Geolocation/geocoder.mjs +33 -0
  216. package/dist/esm/fields/Geolocation/geocoder.mjs.map +1 -0
  217. package/dist/esm/fields/Geolocation/geocoder.native.js +35 -0
  218. package/dist/esm/fields/Geolocation/geocoder.native.js.map +1 -0
  219. package/dist/esm/fields/Geolocation/index.mjs +792 -149
  220. package/dist/esm/fields/Geolocation/index.mjs.map +1 -1
  221. package/dist/esm/fields/Geolocation/index.native.js +847 -164
  222. package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
  223. package/dist/esm/fields/Geolocation/mapMath.native.js.map +1 -1
  224. package/dist/esm/fields/Geolocation/mapTypes.native.js.map +1 -1
  225. package/dist/esm/fields/Geolocation/nativeSearchFocus.mjs +19 -0
  226. package/dist/esm/fields/Geolocation/nativeSearchFocus.mjs.map +1 -0
  227. package/dist/esm/fields/Geolocation/nativeSearchFocus.native.js +19 -0
  228. package/dist/esm/fields/Geolocation/nativeSearchFocus.native.js.map +1 -0
  229. package/dist/esm/fields/Icon/drawnSet.mjs +14 -3
  230. package/dist/esm/fields/Icon/drawnSet.mjs.map +1 -1
  231. package/dist/esm/fields/Icon/drawnSet.native.js +18 -3
  232. package/dist/esm/fields/Icon/drawnSet.native.js.map +1 -1
  233. package/dist/esm/fields/Icon/index.mjs +93 -18
  234. package/dist/esm/fields/Icon/index.mjs.map +1 -1
  235. package/dist/esm/fields/Icon/index.native.js +106 -22
  236. package/dist/esm/fields/Icon/index.native.js.map +1 -1
  237. package/dist/esm/fields/ImageField/index.native.js.map +1 -1
  238. package/dist/esm/fields/Input/index.mjs +5 -12
  239. package/dist/esm/fields/Input/index.mjs.map +1 -1
  240. package/dist/esm/fields/Input/index.native.js +5 -13
  241. package/dist/esm/fields/Input/index.native.js.map +1 -1
  242. package/dist/esm/fields/MentionInput/index.native.js.map +1 -1
  243. package/dist/esm/fields/OTPInput/index.native.js.map +1 -1
  244. package/dist/esm/fields/OTPInput/otpCellCss.native.js.map +1 -1
  245. package/dist/esm/fields/PhoneInput/dialCodes.native.js.map +1 -1
  246. package/dist/esm/fields/PhoneInput/index.mjs +2 -2
  247. package/dist/esm/fields/PhoneInput/index.mjs.map +1 -1
  248. package/dist/esm/fields/PhoneInput/index.native.js +2 -2
  249. package/dist/esm/fields/PhoneInput/index.native.js.map +1 -1
  250. package/dist/esm/fields/PhoneInput/phone.native.js.map +1 -1
  251. package/dist/esm/fields/Progress/index.native.js.map +1 -1
  252. package/dist/esm/fields/RadioGroup/index.native.js.map +1 -1
  253. package/dist/esm/fields/Rating/index.native.js.map +1 -1
  254. package/dist/esm/fields/Rating/ratingMath.native.js.map +1 -1
  255. package/dist/esm/fields/Rating/types.native.js.map +1 -1
  256. package/dist/esm/fields/SearchInput/index.mjs +9 -10
  257. package/dist/esm/fields/SearchInput/index.mjs.map +1 -1
  258. package/dist/esm/fields/SearchInput/index.native.js +9 -10
  259. package/dist/esm/fields/SearchInput/index.native.js.map +1 -1
  260. package/dist/esm/fields/Select/index.mjs +54 -19
  261. package/dist/esm/fields/Select/index.mjs.map +1 -1
  262. package/dist/esm/fields/Select/index.native.js +64 -38
  263. package/dist/esm/fields/Select/index.native.js.map +1 -1
  264. package/dist/esm/fields/Signature/index.native.js.map +1 -1
  265. package/dist/esm/fields/Slider/index.native.js.map +1 -1
  266. package/dist/esm/fields/Slider/jumpMotion.native.js.map +1 -1
  267. package/dist/esm/fields/Stepper/index.mjs +145 -32
  268. package/dist/esm/fields/Stepper/index.mjs.map +1 -1
  269. package/dist/esm/fields/Stepper/index.native.js +152 -32
  270. package/dist/esm/fields/Stepper/index.native.js.map +1 -1
  271. package/dist/esm/fields/Stepper/resolveStepperPlacement.native.js.map +1 -1
  272. package/dist/esm/fields/Switch/index.native.js.map +1 -1
  273. package/dist/esm/fields/TextArea/index.native.js.map +1 -1
  274. package/dist/esm/fields/TimePicker/catalog.native.js.map +1 -1
  275. package/dist/esm/fields/TimePicker/parts.native.js.map +1 -1
  276. package/dist/esm/fields/TimeRangeScrubber/geometry.native.js.map +1 -1
  277. package/dist/esm/fields/TimeRangeScrubber/index.native.js.map +1 -1
  278. package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
  279. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  280. package/dist/esm/fields/nativeDateTime/osDateTimeIosDisplay.native.js.map +1 -1
  281. package/dist/esm/fields/nativeSelect.native.js.map +1 -1
  282. package/dist/esm/fields/selectedOrder.native.js.map +1 -1
  283. package/dist/esm/formSpacing.native.js.map +1 -1
  284. package/dist/esm/hooks/useFocusManagement.native.js.map +1 -1
  285. package/dist/esm/index.mjs +2 -1
  286. package/dist/esm/index.mjs.map +1 -1
  287. package/dist/esm/index.native.js +2 -1
  288. package/dist/esm/index.native.js.map +1 -1
  289. package/dist/esm/requiredMarking.native.js.map +1 -1
  290. package/dist/esm/shared/TimeColumn.native.js.map +1 -1
  291. package/dist/esm/shared/capabilityPreflight.native.js.map +1 -1
  292. package/dist/esm/shared/colorRamps.native.js.map +1 -1
  293. package/dist/esm/shared/devWarn.native.js.map +1 -1
  294. package/dist/esm/shared/floatingList.native.js.map +1 -1
  295. package/dist/esm/shared/focusManagement.mjs +24 -11
  296. package/dist/esm/shared/focusManagement.mjs.map +1 -1
  297. package/dist/esm/shared/focusManagement.native.js +24 -11
  298. package/dist/esm/shared/focusManagement.native.js.map +1 -1
  299. package/dist/esm/shared/groupContext.native.js.map +1 -1
  300. package/dist/esm/shared/i18n.native.js.map +1 -1
  301. package/dist/esm/shared/pickerTriggerContract.mjs +13 -0
  302. package/dist/esm/shared/pickerTriggerContract.mjs.map +1 -0
  303. package/dist/esm/shared/pickerTriggerContract.native.js +13 -0
  304. package/dist/esm/shared/pickerTriggerContract.native.js.map +1 -0
  305. package/dist/esm/shared/pressSlopProps.mjs +43 -0
  306. package/dist/esm/shared/pressSlopProps.mjs.map +1 -0
  307. package/dist/esm/shared/pressSlopProps.native.js +44 -0
  308. package/dist/esm/shared/pressSlopProps.native.js.map +1 -0
  309. package/dist/esm/shared/t.native.js.map +1 -1
  310. package/dist/esm/shared/tableCellContext.native.js.map +1 -1
  311. package/dist/esm/shared/useDragScroll.native.js.map +1 -1
  312. package/dist/esm/shared/useKeyboardInset.native.js.map +1 -1
  313. package/dist/esm/shared/useSheetEscapeDismiss.native.js.map +1 -1
  314. package/dist/esm/shared/useWheelIncrement.native.js.map +1 -1
  315. package/dist/esm/shared/utils.native.js.map +1 -1
  316. package/dist/esm/shared/zIndex.native.js.map +1 -1
  317. package/dist/esm/themedPrimitives.native.js.map +1 -1
  318. package/dist/esm/types.native.js.map +1 -1
  319. package/dist/esm/utils/LinkCell.native.js.map +1 -1
  320. package/dist/jsx/Button/index.mjs +1 -34
  321. package/dist/jsx/Button/index.mjs.map +1 -1
  322. package/dist/jsx/Button/index.native.js +3 -36
  323. package/dist/jsx/Button/index.native.js.map +1 -1
  324. package/dist/jsx/Chip/index.mjs +1 -1
  325. package/dist/jsx/Chip/index.mjs.map +1 -1
  326. package/dist/jsx/Chip/index.native.js +1 -1
  327. package/dist/jsx/Chip/index.native.js.map +1 -1
  328. package/dist/jsx/ContextualSaveBar/index.mjs +17 -10
  329. package/dist/jsx/ContextualSaveBar/index.mjs.map +1 -1
  330. package/dist/jsx/ContextualSaveBar/index.native.js +18 -10
  331. package/dist/jsx/ContextualSaveBar/index.native.js.map +1 -1
  332. package/dist/jsx/FloatingPanel/index.mjs +58 -15
  333. package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
  334. package/dist/jsx/FloatingPanel/index.native.js +16 -7
  335. package/dist/jsx/FloatingPanel/index.native.js.map +1 -1
  336. package/dist/jsx/FloatingPanel/nestedAction.mjs +11 -0
  337. package/dist/jsx/FloatingPanel/nestedAction.mjs.map +1 -0
  338. package/dist/jsx/FloatingPanel/nestedAction.native.js +42 -0
  339. package/dist/jsx/FloatingPanel/nestedAction.native.js.map +1 -0
  340. package/dist/jsx/InputParts/index.mjs +12 -8
  341. package/dist/jsx/InputParts/index.mjs.map +1 -1
  342. package/dist/jsx/InputParts/index.native.js +12 -10
  343. package/dist/jsx/InputParts/index.native.js.map +1 -1
  344. package/dist/jsx/Wheel/index.mjs +3 -3
  345. package/dist/jsx/Wheel/index.mjs.map +1 -1
  346. package/dist/jsx/Wheel/index.native.js +3 -3
  347. package/dist/jsx/Wheel/index.native.js.map +1 -1
  348. package/dist/jsx/fieldLayout.mjs +3 -3
  349. package/dist/jsx/fieldLayout.mjs.map +1 -1
  350. package/dist/jsx/fieldLayout.native.js +3 -3
  351. package/dist/jsx/fieldLayout.native.js.map +1 -1
  352. package/dist/jsx/fields/Checkbox/CheckboxFieldFrame.mjs +8 -1
  353. package/dist/jsx/fields/Checkbox/CheckboxFieldFrame.mjs.map +1 -1
  354. package/dist/jsx/fields/Checkbox/CheckboxFieldFrame.native.js +10 -1
  355. package/dist/jsx/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  356. package/dist/jsx/fields/Combobox/index.mjs +74 -76
  357. package/dist/jsx/fields/Combobox/index.mjs.map +1 -1
  358. package/dist/jsx/fields/Combobox/index.native.js +78 -86
  359. package/dist/jsx/fields/Combobox/index.native.js.map +1 -1
  360. package/dist/jsx/fields/DatePicker/Calendar.mjs +6 -1
  361. package/dist/jsx/fields/DatePicker/Calendar.mjs.map +1 -1
  362. package/dist/jsx/fields/DatePicker/Calendar.native.js +6 -1
  363. package/dist/jsx/fields/DatePicker/Calendar.native.js.map +1 -1
  364. package/dist/jsx/fields/DatePicker/DateRangePicker.mjs +2 -2
  365. package/dist/jsx/fields/DatePicker/DateRangePicker.mjs.map +1 -1
  366. package/dist/jsx/fields/DatePicker/DateRangePicker.native.js +2 -2
  367. package/dist/jsx/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  368. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.mjs +15 -12
  369. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.mjs.map +1 -1
  370. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.native.js +16 -12
  371. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  372. package/dist/jsx/fields/DatePicker/DatetimePicker.native.js +39 -14
  373. package/dist/jsx/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  374. package/dist/jsx/fields/DatePicker/MonthPicker.mjs +10 -3
  375. package/dist/jsx/fields/DatePicker/MonthPicker.mjs.map +1 -1
  376. package/dist/jsx/fields/DatePicker/MonthPicker.native.js +10 -3
  377. package/dist/jsx/fields/DatePicker/MonthPicker.native.js.map +1 -1
  378. package/dist/jsx/fields/DatePicker/MultiDatePicker.mjs +2 -2
  379. package/dist/jsx/fields/DatePicker/MultiDatePicker.mjs.map +1 -1
  380. package/dist/jsx/fields/DatePicker/MultiDatePicker.native.js +2 -2
  381. package/dist/jsx/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  382. package/dist/jsx/fields/DatePicker/index.native.js +3 -0
  383. package/dist/jsx/fields/DatePicker/index.native.js.map +1 -1
  384. package/dist/jsx/fields/DatePicker/parts.mjs +28 -16
  385. package/dist/jsx/fields/DatePicker/parts.mjs.map +1 -1
  386. package/dist/jsx/fields/DatePicker/parts.native.js +28 -14
  387. package/dist/jsx/fields/DatePicker/parts.native.js.map +1 -1
  388. package/dist/jsx/fields/Geolocation/GeolocationMap.mjs.map +1 -1
  389. package/dist/jsx/fields/Geolocation/GeolocationMap.native.js.map +1 -1
  390. package/dist/jsx/fields/Geolocation/geocoder.mjs +33 -0
  391. package/dist/jsx/fields/Geolocation/geocoder.mjs.map +1 -0
  392. package/dist/jsx/fields/Geolocation/geocoder.native.js +68 -0
  393. package/dist/jsx/fields/Geolocation/geocoder.native.js.map +1 -0
  394. package/dist/jsx/fields/Geolocation/index.mjs +792 -149
  395. package/dist/jsx/fields/Geolocation/index.mjs.map +1 -1
  396. package/dist/jsx/fields/Geolocation/index.native.js +856 -167
  397. package/dist/jsx/fields/Geolocation/index.native.js.map +1 -1
  398. package/dist/jsx/fields/Geolocation/nativeSearchFocus.mjs +19 -0
  399. package/dist/jsx/fields/Geolocation/nativeSearchFocus.mjs.map +1 -0
  400. package/dist/jsx/fields/Geolocation/nativeSearchFocus.native.js +47 -0
  401. package/dist/jsx/fields/Geolocation/nativeSearchFocus.native.js.map +1 -0
  402. package/dist/jsx/fields/Icon/drawnSet.mjs +14 -3
  403. package/dist/jsx/fields/Icon/drawnSet.mjs.map +1 -1
  404. package/dist/jsx/fields/Icon/drawnSet.native.js +18 -3
  405. package/dist/jsx/fields/Icon/drawnSet.native.js.map +1 -1
  406. package/dist/jsx/fields/Icon/index.mjs +93 -18
  407. package/dist/jsx/fields/Icon/index.mjs.map +1 -1
  408. package/dist/jsx/fields/Icon/index.native.js +115 -31
  409. package/dist/jsx/fields/Icon/index.native.js.map +1 -1
  410. package/dist/jsx/fields/Input/index.mjs +5 -12
  411. package/dist/jsx/fields/Input/index.mjs.map +1 -1
  412. package/dist/jsx/fields/Input/index.native.js +5 -13
  413. package/dist/jsx/fields/Input/index.native.js.map +1 -1
  414. package/dist/jsx/fields/PhoneInput/index.mjs +2 -2
  415. package/dist/jsx/fields/PhoneInput/index.mjs.map +1 -1
  416. package/dist/jsx/fields/PhoneInput/index.native.js +2 -2
  417. package/dist/jsx/fields/PhoneInput/index.native.js.map +1 -1
  418. package/dist/jsx/fields/SearchInput/index.mjs +9 -10
  419. package/dist/jsx/fields/SearchInput/index.mjs.map +1 -1
  420. package/dist/jsx/fields/SearchInput/index.native.js +8 -9
  421. package/dist/jsx/fields/SearchInput/index.native.js.map +1 -1
  422. package/dist/jsx/fields/Select/index.mjs +54 -19
  423. package/dist/jsx/fields/Select/index.mjs.map +1 -1
  424. package/dist/jsx/fields/Select/index.native.js +63 -37
  425. package/dist/jsx/fields/Select/index.native.js.map +1 -1
  426. package/dist/jsx/fields/Stepper/index.mjs +145 -32
  427. package/dist/jsx/fields/Stepper/index.mjs.map +1 -1
  428. package/dist/jsx/fields/Stepper/index.native.js +151 -31
  429. package/dist/jsx/fields/Stepper/index.native.js.map +1 -1
  430. package/dist/jsx/index.js +2 -1
  431. package/dist/jsx/index.js.map +1 -1
  432. package/dist/jsx/index.mjs +2 -1
  433. package/dist/jsx/index.mjs.map +1 -1
  434. package/dist/jsx/index.native.js +2 -0
  435. package/dist/jsx/index.native.js.map +1 -1
  436. package/dist/jsx/shared/focusManagement.mjs +24 -11
  437. package/dist/jsx/shared/focusManagement.mjs.map +1 -1
  438. package/dist/jsx/shared/focusManagement.native.js +24 -11
  439. package/dist/jsx/shared/focusManagement.native.js.map +1 -1
  440. package/dist/jsx/shared/pickerTriggerContract.mjs +13 -0
  441. package/dist/jsx/shared/pickerTriggerContract.mjs.map +1 -0
  442. package/dist/jsx/shared/pickerTriggerContract.native.js +41 -0
  443. package/dist/jsx/shared/pickerTriggerContract.native.js.map +1 -0
  444. package/dist/jsx/shared/pressSlopProps.mjs +43 -0
  445. package/dist/jsx/shared/pressSlopProps.mjs.map +1 -0
  446. package/dist/jsx/shared/pressSlopProps.native.js +72 -0
  447. package/dist/jsx/shared/pressSlopProps.native.js.map +1 -0
  448. package/package.json +8 -7
  449. package/src/Button/Button.labelInk.spec.tsx +21 -18
  450. package/src/Button/Button.outlinedChannel.spec.tsx +46 -0
  451. package/src/Button/Button.sizeLadder.spec.tsx +4 -3
  452. package/src/Button/Button.stories.tsx +20 -0
  453. package/src/Button/index.tsx +26 -39
  454. package/src/Chip/Chip.spec.tsx +3 -1
  455. package/src/Chip/index.tsx +1 -5
  456. package/src/ContextualSaveBar/ContextualSaveBar.spec.tsx +33 -0
  457. package/src/ContextualSaveBar/ContextualSaveBar.stories.tsx +19 -0
  458. package/src/ContextualSaveBar/index.tsx +12 -8
  459. package/src/ContextualSaveBar/nativeFlow.spec.tsx +20 -0
  460. package/src/FieldLayout.stories.tsx +41 -0
  461. package/src/FloatingPanel/FloatingPanel.native.spec.tsx +54 -0
  462. package/src/FloatingPanel/FloatingPanel.spec.tsx +109 -0
  463. package/src/FloatingPanel/index.native.tsx +24 -7
  464. package/src/FloatingPanel/index.tsx +80 -13
  465. package/src/FloatingPanel/nestedAction.spec.ts +36 -0
  466. package/src/FloatingPanel/nestedAction.ts +15 -0
  467. package/src/FloatingPanel/panelWidthContract.spec.ts +12 -15
  468. package/src/FormsIntegration.stories.tsx +2 -6
  469. package/src/InputParts/index.tsx +20 -6
  470. package/src/InputParts/layoutGap.spec.tsx +43 -0
  471. package/src/Wheel/Wheel.spec.tsx +16 -0
  472. package/src/Wheel/index.tsx +3 -3
  473. package/src/fieldLayout.spec.tsx +42 -1
  474. package/src/fieldLayout.tsx +9 -9
  475. package/src/fields/Checkbox/CheckboxFieldFrame.spec.tsx +18 -0
  476. package/src/fields/Checkbox/CheckboxFieldFrame.tsx +6 -1
  477. package/src/fields/Combobox/Combobox.spec.tsx +48 -1
  478. package/src/fields/Combobox/index.tsx +90 -80
  479. package/src/fields/DatePicker/Calendar.tsx +4 -1
  480. package/src/fields/DatePicker/DatePicker.stories.tsx +22 -1
  481. package/src/fields/DatePicker/DateRangePicker.tsx +4 -2
  482. package/src/fields/DatePicker/DatetimePicker.catalog.tsx +21 -19
  483. package/src/fields/DatePicker/DatetimePicker.native.spec.tsx +144 -0
  484. package/src/fields/DatePicker/DatetimePicker.native.tsx +57 -32
  485. package/src/fields/DatePicker/DatetimePicker.stories.tsx +22 -0
  486. package/src/fields/DatePicker/MonthPicker.tsx +8 -3
  487. package/src/fields/DatePicker/MultiDatePicker.tsx +4 -2
  488. package/src/fields/DatePicker/index.native.tsx +1 -0
  489. package/src/fields/DatePicker/parts.spec.tsx +56 -0
  490. package/src/fields/DatePicker/parts.tsx +33 -12
  491. package/src/fields/Geolocation/Geolocation.spec.tsx +287 -35
  492. package/src/fields/Geolocation/Geolocation.stories.tsx +141 -7
  493. package/src/fields/Geolocation/GeolocationMap.native.tsx +3 -0
  494. package/src/fields/Geolocation/GeolocationMap.tsx +4 -0
  495. package/src/fields/Geolocation/geocoder.spec.ts +59 -0
  496. package/src/fields/Geolocation/geocoder.ts +84 -0
  497. package/src/fields/Geolocation/geocoderSeam.spec.tsx +203 -0
  498. package/src/fields/Geolocation/index.tsx +912 -180
  499. package/src/fields/Geolocation/nativeSearchFocus.spec.ts +34 -0
  500. package/src/fields/Geolocation/nativeSearchFocus.ts +19 -0
  501. package/src/fields/Geolocation/salvage.spec.tsx +398 -0
  502. package/src/fields/Geolocation/storyProviders.spec.tsx +44 -0
  503. package/src/fields/Icon/Icon.spec.tsx +215 -1
  504. package/src/fields/Icon/Icon.stories.tsx +9 -1
  505. package/src/fields/Icon/drawnSet.tsx +39 -4
  506. package/src/fields/Icon/index.tsx +118 -18
  507. package/src/fields/Input/Input.copy.spec.tsx +1 -0
  508. package/src/fields/Input/Input.spec.tsx +50 -0
  509. package/src/fields/Input/Input.stories.tsx +1 -1
  510. package/src/fields/Input/index.tsx +7 -13
  511. package/src/fields/PhoneInput/index.tsx +2 -2
  512. package/src/fields/SearchInput/SearchInput.spec.tsx +14 -0
  513. package/src/fields/SearchInput/index.tsx +5 -6
  514. package/src/fields/Select/Select.spec.tsx +54 -0
  515. package/src/fields/Select/index.tsx +63 -33
  516. package/src/fields/Stepper/Stepper.spec.tsx +34 -1
  517. package/src/fields/Stepper/index.tsx +193 -33
  518. package/src/fields/pickerActivation.spec.tsx +105 -0
  519. package/src/fields/pickerDensity.spec.tsx +86 -0
  520. package/src/fields/pickerRows.spec.tsx +66 -0
  521. package/src/index.ts +9 -0
  522. package/src/shared/focusManagement.spec.tsx +68 -0
  523. package/src/shared/focusManagement.ts +20 -10
  524. package/src/shared/pickerTriggerContract.ts +13 -0
  525. package/src/shared/pressSlopProps.spec.ts +39 -0
  526. package/src/shared/pressSlopProps.ts +52 -0
  527. package/types/Button/index.d.ts +22 -3
  528. package/types/Button/index.d.ts.map +1 -1
  529. package/types/Chip/index.d.ts.map +1 -1
  530. package/types/ContextualSaveBar/index.d.ts +1 -1
  531. package/types/ContextualSaveBar/index.d.ts.map +1 -1
  532. package/types/FloatingPanel/index.d.ts +11 -1
  533. package/types/FloatingPanel/index.d.ts.map +1 -1
  534. package/types/FloatingPanel/index.native.d.ts +2 -1
  535. package/types/FloatingPanel/index.native.d.ts.map +1 -1
  536. package/types/FloatingPanel/nestedAction.d.ts +13 -0
  537. package/types/FloatingPanel/nestedAction.d.ts.map +1 -0
  538. package/types/InputParts/index.d.ts.map +1 -1
  539. package/types/fields/Checkbox/CheckboxFieldFrame.d.ts +46 -2
  540. package/types/fields/Checkbox/CheckboxFieldFrame.d.ts.map +1 -1
  541. package/types/fields/Checkbox/index.d.ts +3 -3
  542. package/types/fields/Combobox/index.d.ts +3 -1
  543. package/types/fields/Combobox/index.d.ts.map +1 -1
  544. package/types/fields/DatePicker/Calendar.d.ts.map +1 -1
  545. package/types/fields/DatePicker/DateRangePicker.d.ts.map +1 -1
  546. package/types/fields/DatePicker/DatetimePicker.catalog.d.ts.map +1 -1
  547. package/types/fields/DatePicker/DatetimePicker.native.d.ts.map +1 -1
  548. package/types/fields/DatePicker/MonthPicker.d.ts.map +1 -1
  549. package/types/fields/DatePicker/MultiDatePicker.d.ts.map +1 -1
  550. package/types/fields/DatePicker/index.native.d.ts.map +1 -1
  551. package/types/fields/DatePicker/parts.d.ts.map +1 -1
  552. package/types/fields/Geolocation/GeolocationMap.d.ts +4 -0
  553. package/types/fields/Geolocation/GeolocationMap.d.ts.map +1 -1
  554. package/types/fields/Geolocation/GeolocationMap.native.d.ts +3 -0
  555. package/types/fields/Geolocation/GeolocationMap.native.d.ts.map +1 -1
  556. package/types/fields/Geolocation/geocoder.d.ts +53 -0
  557. package/types/fields/Geolocation/geocoder.d.ts.map +1 -0
  558. package/types/fields/Geolocation/index.d.ts +18 -2
  559. package/types/fields/Geolocation/index.d.ts.map +1 -1
  560. package/types/fields/Geolocation/nativeSearchFocus.d.ts +8 -0
  561. package/types/fields/Geolocation/nativeSearchFocus.d.ts.map +1 -0
  562. package/types/fields/Icon/drawnSet.d.ts.map +1 -1
  563. package/types/fields/Icon/index.d.ts.map +1 -1
  564. package/types/fields/Input/index.d.ts.map +1 -1
  565. package/types/fields/PhoneInput/index.d.ts.map +1 -1
  566. package/types/fields/RadioGroup/index.d.ts +2 -2
  567. package/types/fields/SearchInput/index.d.ts.map +1 -1
  568. package/types/fields/Select/index.d.ts.map +1 -1
  569. package/types/fields/Stepper/index.d.ts.map +1 -1
  570. package/types/fields/ToggleGroup/index.d.ts +1 -1
  571. package/types/index.d.ts +2 -0
  572. package/types/index.d.ts.map +1 -1
  573. package/types/shared/focusManagement.d.ts +2 -2
  574. package/types/shared/focusManagement.d.ts.map +1 -1
  575. package/types/shared/pickerTriggerContract.d.ts +18 -0
  576. package/types/shared/pickerTriggerContract.d.ts.map +1 -0
  577. package/types/shared/pressSlopProps.d.ts +8 -0
  578. package/types/shared/pressSlopProps.d.ts.map +1 -0
  579. package/src/router.d.ts +0 -16
@@ -2,9 +2,40 @@ import { describe, expect, it, vi, afterEach } from "vitest";
2
2
  import { fireEvent, waitFor } from "@testing-library/react";
3
3
  import { renderWithProviders } from "@multiplatform.one/test-utils";
4
4
  import { Form } from "../../Form";
5
+ import { TableCellContext } from "../../shared/tableCellContext";
5
6
  import { Geolocation, preflightGeolocation } from "./index";
7
+ import type { GeocodeResult } from "./geocoder";
8
+ import { Theme } from "tamagui";
9
+ import { NavigationArrowIcon } from "@phosphor-icons/react";
6
10
 
7
11
  const locationIcon = <span data-testid="location-icon" />;
12
+ const HELSINKI = JSON.stringify({ lat: 60.16952, lng: 24.93545 });
13
+
14
+ const mannerheim: GeocodeResult = {
15
+ lat: 60.16952,
16
+ lng: 24.93545,
17
+ label: "Mannerheimintie 3",
18
+ description: "Kamppi, Helsinki, Finland",
19
+ };
20
+
21
+ function mockGeocode(results: GeocodeResult[] = [mannerheim]) {
22
+ return vi.fn().mockResolvedValue(results);
23
+ }
24
+
25
+ function mockReverse(result: GeocodeResult | null = mannerheim) {
26
+ return vi.fn().mockResolvedValue(result);
27
+ }
28
+
29
+ function searchInput(container: HTMLElement | Document = document) {
30
+ return (container.querySelector("[data-testid='geolocation-search']") ??
31
+ container.querySelector("[aria-label='Search for a location']")) as HTMLInputElement | null;
32
+ }
33
+
34
+ function typeSearch(container: HTMLElement, text: string) {
35
+ const input = searchInput(container);
36
+ expect(input).not.toBeNull();
37
+ fireEvent.change(input as HTMLInputElement, { target: { value: text } });
38
+ }
8
39
 
9
40
  /**
10
41
  * Recorded stock-Frappe Geolocation value: what
@@ -69,50 +100,268 @@ describe("Geolocation", () => {
69
100
  expect(label?.textContent).toContain("*");
70
101
  });
71
102
 
72
- // UX-010 / Axiom 13 ONE BODY: bare use renders the full locate affordance.
73
103
  it("renders bare without locationIcon — package default glyph on Locate", () => {
74
- const result = renderWithProviders(
75
- <Geolocation label="Bare" value={JSON.stringify({ lat: 1, lng: 2 })} />,
76
- );
104
+ const result = renderWithProviders(<Geolocation label="Bare" value={HELSINKI} />);
77
105
  const locate = result.container.querySelector("[aria-label='Locate']");
78
106
  expect(locate).not.toBeNull();
79
107
  expect(locate?.querySelector("svg")).not.toBeNull();
80
108
  });
81
109
 
82
- it("renders map-primary surface without inline Lat/Lng inputs", () => {
110
+ it.each(["light", "dark"] as const)(
111
+ "paints the default Locate glyph with concrete %s ink",
112
+ (scheme) => {
113
+ const result = renderWithProviders(
114
+ <Theme name={scheme}>
115
+ <Geolocation label="Location" value={HELSINKI} />
116
+ </Theme>,
117
+ );
118
+ const glyph = result.container.querySelector("[aria-label='Locate'] svg")!;
119
+ const color = glyph.getAttribute("fill");
120
+ expect(color).toMatch(/^(#|rgb|hsl)/);
121
+ expect(color).not.toBe("currentColor");
122
+ },
123
+ );
124
+
125
+ it("preserves explicit Locate glyph paint and an explicit null glyph", () => {
83
126
  const result = renderWithProviders(
84
127
  <Geolocation
85
128
  label="Location"
86
- name="loc"
87
- locationIcon={locationIcon}
88
- value={JSON.stringify({ lat: 51.5, lng: -0.12 })}
129
+ value={HELSINKI}
130
+ locationIcon={<NavigationArrowIcon color="#123456" />}
89
131
  />,
90
132
  );
133
+ expect(
134
+ result.container.querySelector("[aria-label='Locate'] svg")?.getAttribute("fill"),
135
+ ).toBe("#123456");
136
+ result.rerender(<Geolocation label="Location" value={HELSINKI} locationIcon={null} />);
137
+ expect(result.container.querySelector("[aria-label='Locate']")).not.toBeNull();
138
+ expect(result.container.querySelector("[aria-label='Locate'] svg")).toBeNull();
139
+ });
140
+
141
+ it("empty state teaches three paths and labels Use my current location", () => {
142
+ const result = renderWithProviders(<Geolocation label="Location" />);
143
+ expect(result.container.textContent).not.toContain("0.00000, 0.00000");
144
+ expect(result.container.textContent).toContain("No location set");
145
+ expect(result.container.textContent).toContain("Use my current location");
146
+ expect(result.container.textContent).toContain("Search, tap the map, or use your location.");
147
+ expect(searchInput(result.container)).not.toBeNull();
148
+ });
149
+
150
+ it("no input control is absolutely positioned over the map surface", () => {
151
+ const result = renderWithProviders(
152
+ <Geolocation label="Location" value={HELSINKI} locationIcon={locationIcon} />,
153
+ );
154
+ const map = result.container.querySelector("[data-testid='geolocation-map']");
155
+ expect(map).not.toBeNull();
156
+ const inputs = [...result.container.querySelectorAll("input")];
157
+ expect(inputs.length).toBeGreaterThan(0);
158
+ for (const input of inputs) {
159
+ expect(map?.contains(input)).toBe(false);
160
+ }
161
+ expect(result.container.querySelector("[data-testid='geolocation-coords-chip']")).toBeNull();
162
+ });
163
+
164
+ it("without an injected geocoder, search is disabled and map/manual paths stay", () => {
165
+ const result = renderWithProviders(
166
+ <Geolocation label="Location" value={HELSINKI} locationIcon={locationIcon} />,
167
+ );
168
+ const input = searchInput(result.container);
169
+ expect(input).not.toBeNull();
170
+ expect(input?.disabled || input?.getAttribute("aria-disabled") === "true").toBeTruthy();
91
171
  expect(result.container.querySelector("[data-testid='geolocation-map']")).not.toBeNull();
92
172
  expect(
93
- result.container.querySelector("[data-testid='geolocation-coords-chip']"),
173
+ result.container.querySelector("[data-testid='geolocation-coordline']"),
94
174
  ).not.toBeNull();
95
- expect(result.container.textContent).toContain("51.5000, -0.1200");
96
- // Lat/Lng inputs are NOT always-visible under the map
97
- expect(result.container.querySelector("input")).toBeNull();
98
- expect(result.container.querySelector("[aria-label='Edit coordinates']")).not.toBeNull();
99
175
  expect(result.container.querySelector("[aria-label='Locate']")).not.toBeNull();
100
176
  });
101
177
 
102
- it("empty value does not paint Null Island coordinates", () => {
103
- const result = renderWithProviders(<Geolocation label="Location" />);
104
- expect(result.container.textContent).not.toContain("0.0000, 0.0000");
105
- expect(result.container.textContent).toContain("Set location");
178
+ it("a set value renders a reverse-geocoded address, pair subordinate", async () => {
179
+ const reverseGeocode = mockReverse();
180
+ const result = renderWithProviders(
181
+ <Geolocation
182
+ label="Location"
183
+ value={HELSINKI}
184
+ reverseGeocode={reverseGeocode}
185
+ locationIcon={locationIcon}
186
+ />,
187
+ );
188
+ await waitFor(() => {
189
+ expect(reverseGeocode).toHaveBeenCalledWith({ lat: 60.16952, lng: 24.93545 });
190
+ expect(searchInput(result.container)?.value).toBe(
191
+ "Mannerheimintie 3, Kamppi, Helsinki, Finland",
192
+ );
193
+ });
194
+ expect(result.container.textContent).toContain("60.16952, 24.93545");
106
195
  });
107
196
 
108
- it("LC-71: map frame is the keyboard stop; pick layer is not a tab stop", () => {
197
+ it("typing a place name produces a results panel; picking sets the value", async () => {
198
+ const geocode = mockGeocode();
199
+ const onChange = vi.fn();
200
+ const result = renderWithProviders(
201
+ <Geolocation
202
+ label="Location"
203
+ geocode={geocode}
204
+ onChange={onChange}
205
+ locationIcon={locationIcon}
206
+ />,
207
+ );
208
+ typeSearch(result.container, "manner");
209
+ await waitFor(() => {
210
+ expect(geocode).toHaveBeenCalledWith({ query: "manner" });
211
+ expect(document.querySelector("[data-testid='geolocation-results']")).not.toBeNull();
212
+ expect(document.body.textContent).toContain("Use my current location");
213
+ expect(document.body.textContent).toContain("Mannerheimintie 3");
214
+ expect(document.body.textContent).toContain("Kamppi, Helsinki, Finland");
215
+ });
216
+ fireEvent.click(document.querySelector("[data-testid='geolocation-result-0']") as Element);
217
+ await waitFor(() => {
218
+ expect(onChange).toHaveBeenCalledWith(HELSINKI);
219
+ });
220
+ expect(searchInput(result.container)?.value).toBe(
221
+ "Mannerheimintie 3, Kamppi, Helsinki, Finland",
222
+ );
223
+ });
224
+
225
+ it("Use my current location is the first results row", async () => {
226
+ const geocode = mockGeocode();
227
+ const result = renderWithProviders(
228
+ <Geolocation label="Location" geocode={geocode} locationIcon={locationIcon} />,
229
+ );
230
+ typeSearch(result.container, "manner");
231
+ await waitFor(() => {
232
+ expect(document.querySelector("[data-testid='geolocation-results']")).not.toBeNull();
233
+ });
234
+ const list = document.querySelector("[data-testid='geolocation-results']") as HTMLElement;
235
+ const first = list.firstElementChild as HTMLElement;
236
+ expect(first.getAttribute("data-testid")).toBe("geolocation-use-location");
237
+ expect(first.textContent).toContain("Use my current location");
238
+ });
239
+
240
+ it("zero-results and geocoder failure leave the map and coordinates working", async () => {
241
+ const geocode = vi.fn().mockResolvedValueOnce([]).mockRejectedValueOnce(new Error("down"));
242
+ const onChange = vi.fn();
109
243
  const result = renderWithProviders(
110
244
  <Geolocation
111
245
  label="Location"
112
- value={JSON.stringify({ lat: 1, lng: 2 })}
246
+ geocode={geocode}
247
+ onChange={onChange}
113
248
  locationIcon={locationIcon}
114
249
  />,
115
250
  );
251
+ typeSearch(result.container, "mannerheimintei");
252
+ await waitFor(() => {
253
+ expect(document.body.textContent).toContain('No places match "mannerheimintei"');
254
+ });
255
+ expect(result.container.querySelector("[data-testid='geolocation-map']")).not.toBeNull();
256
+
257
+ typeSearch(result.container, "manner");
258
+ await waitFor(() => {
259
+ expect(document.body.textContent).toContain(
260
+ "Search is unavailable — check your connection",
261
+ );
262
+ });
263
+
264
+ const pick = result.container.querySelector(
265
+ "[data-testid='geolocation-map-pick']",
266
+ ) as HTMLElement;
267
+ pick.getBoundingClientRect = () =>
268
+ ({
269
+ width: 200,
270
+ height: 200,
271
+ left: 0,
272
+ top: 0,
273
+ right: 200,
274
+ bottom: 200,
275
+ x: 0,
276
+ y: 0,
277
+ toJSON() {},
278
+ }) as DOMRect;
279
+ fireEvent.click(pick, { clientX: 100, clientY: 100 });
280
+ expect(onChange).toHaveBeenCalled();
281
+ });
282
+
283
+ it("a typed lat, lng pair offers the exact point", async () => {
284
+ const geocode = mockGeocode();
285
+ const onChange = vi.fn();
286
+ const result = renderWithProviders(
287
+ <Geolocation
288
+ label="Location"
289
+ geocode={geocode}
290
+ onChange={onChange}
291
+ locationIcon={locationIcon}
292
+ />,
293
+ );
294
+ typeSearch(result.container, "60.169, 24.935");
295
+ await waitFor(() => {
296
+ expect(document.body.textContent).toContain("Go to 60.16900, 24.93500");
297
+ expect(document.body.textContent).toContain("Exact coordinates — no address");
298
+ });
299
+ expect(geocode).not.toHaveBeenCalled();
300
+ fireEvent.click(
301
+ document.querySelector("[data-testid='geolocation-coord-result']") as Element,
302
+ );
303
+ await waitFor(() => {
304
+ expect(onChange).toHaveBeenCalledWith(JSON.stringify({ lat: 60.169, lng: 24.935 }));
305
+ });
306
+ });
307
+
308
+ it("inTableCell renders a TEXT face inside the row rhythm, never the map", async () => {
309
+ const reverseGeocode = mockReverse();
310
+ const result = renderWithProviders(
311
+ <TableCellContext.Provider value={{ inTableCell: true, isHeader: false, editable: true }}>
312
+ <Geolocation
313
+ label="Location"
314
+ value={HELSINKI}
315
+ reverseGeocode={reverseGeocode}
316
+ locationIcon={locationIcon}
317
+ />
318
+ </TableCellContext.Provider>,
319
+ );
320
+ expect(result.container.querySelector("[data-testid='geolocation-map']")).toBeNull();
321
+ expect(
322
+ result.container.querySelector("[data-testid='geolocation-cell-face']"),
323
+ ).not.toBeNull();
324
+ await waitFor(() => {
325
+ expect(result.container.textContent).toContain(
326
+ "Mannerheimintie 3, Kamppi, Helsinki, Finland",
327
+ );
328
+ });
329
+ });
330
+
331
+ it("at <=640 the results panel is a sheet with a pinned search row", async () => {
332
+ const width = vi.spyOn(window, "innerWidth", "get").mockReturnValue(390);
333
+ window.dispatchEvent(new Event("resize"));
334
+ const geocode = mockGeocode();
335
+ const result = renderWithProviders(
336
+ <Geolocation label="Location" geocode={geocode} locationIcon={locationIcon} />,
337
+ );
338
+ expect(
339
+ result.container
340
+ .querySelector("[data-testid='geolocation-search-anchor']")
341
+ ?.getAttribute("data-sheet"),
342
+ ).toBe("true");
343
+ typeSearch(result.container, "manner");
344
+ await waitFor(() => {
345
+ expect(geocode).toHaveBeenCalled();
346
+ });
347
+ await waitFor(() => {
348
+ const sheet =
349
+ document.querySelector("[data-testid='geolocation-results-sheet']") ??
350
+ document.querySelector("[role='dialog']");
351
+ expect(sheet).not.toBeNull();
352
+ expect(
353
+ sheet?.querySelector("[aria-label='Search for a location']") ??
354
+ document.querySelector("[data-testid='geolocation-search']"),
355
+ ).not.toBeNull();
356
+ expect(document.querySelector("[data-testid='geolocation-results']")).not.toBeNull();
357
+ });
358
+ width.mockRestore();
359
+ });
360
+
361
+ it("LC-71: map frame is the keyboard stop; pick layer is not a tab stop", () => {
362
+ const result = renderWithProviders(
363
+ <Geolocation label="Location" value={HELSINKI} locationIcon={locationIcon} />,
364
+ );
116
365
  const map = result.container.querySelector("[data-testid='geolocation-map']");
117
366
  const pick = result.container.querySelector("[data-testid='geolocation-map-pick']");
118
367
  expect(map?.getAttribute("tabindex")).toBe("0");
@@ -189,11 +438,9 @@ describe("Geolocation", () => {
189
438
  />,
190
439
  );
191
440
  fireEvent.click(result.container.querySelector("[aria-label='Edit coordinates']") as Element);
192
- // Sheet mode portals outside the field container — query document.
193
441
  await waitFor(() => {
194
442
  expect(document.querySelector("[data-testid='geolocation-coords-panel']")).not.toBeNull();
195
443
  });
196
- // LC-21 EDITOR: no Apply / Cancel / Done affordance — dismiss is outside/Escape
197
444
  expect(document.querySelector("[aria-label='Apply coordinates']")).toBeNull();
198
445
  expect(document.querySelector("[aria-label='Cancel coordinates']")).toBeNull();
199
446
  expect(document.body.textContent).not.toMatch(/\bApply\b/);
@@ -205,7 +452,6 @@ describe("Geolocation", () => {
205
452
  expect(latInput).not.toBeNull();
206
453
  expect(lngInput).not.toBeNull();
207
454
 
208
- // Valid parse commits live (as soon as the number is set)
209
455
  fireEvent.change(latInput, { target: { value: "12.34" } });
210
456
  await waitFor(() => {
211
457
  expect(onChange).toHaveBeenCalledWith(JSON.stringify({ lat: 12.34, lng: 20 }));
@@ -228,7 +474,7 @@ describe("Geolocation", () => {
228
474
  expect(result.findTextElement("Pick a point")).toBeDefined();
229
475
  });
230
476
 
231
- it("renders skeleton placeholder as map-only", () => {
477
+ it("renders skeleton placeholder as search + map", () => {
232
478
  const result = renderWithProviders(
233
479
  <Geolocation label="Loading" name="l" locationIcon={locationIcon} skeleton />,
234
480
  );
@@ -237,11 +483,6 @@ describe("Geolocation", () => {
237
483
  expect(result.container.querySelector("input")).toBeNull();
238
484
  });
239
485
 
240
- // A disabled control opens nothing. Expand was the one overlay in this
241
- // field that still did: unlike Locate and Coordinates it carried no
242
- // `disabled`, and it opens its AdaptivePopup programmatically, so the
243
- // Button's own pointerEvents:none was never the whole guard. Both halves
244
- // of a real press are fired — `click` alone would pass against the bug.
245
486
  describe("disabled opens no overlay", () => {
246
487
  const expandIcon = <span data-testid="expand-icon" />;
247
488
  const value = JSON.stringify({ lat: 51.5, lng: -0.12 });
@@ -264,7 +505,7 @@ describe("Geolocation", () => {
264
505
  );
265
506
  press(result.container.querySelector("[aria-label='Expand map']") as Element);
266
507
  await waitFor(() => {
267
- expect(document.querySelector("[role='dialog']")).not.toBeNull();
508
+ expect(document.querySelector("[role='dialog'][data-state='open']")).not.toBeNull();
268
509
  });
269
510
  });
270
511
 
@@ -283,7 +524,7 @@ describe("Geolocation", () => {
283
524
  expect(expand).not.toBeNull();
284
525
  press(expand as Element);
285
526
  await new Promise((resolve) => setTimeout(resolve, 50));
286
- expect(document.querySelector("[role='dialog']")).toBeNull();
527
+ expect(document.querySelector("[role='dialog'][data-state='open']")).toBeNull();
287
528
  });
288
529
 
289
530
  it("disabled: Coordinates opens no panel", async () => {
@@ -296,28 +537,39 @@ describe("Geolocation", () => {
296
537
  disabled
297
538
  />,
298
539
  );
299
- press(result.container.querySelector("[aria-label='Edit coordinates']") as Element);
540
+ const line = result.container.querySelector("[data-testid='geolocation-coordline']");
541
+ expect(line).not.toBeNull();
542
+ press(line as Element);
300
543
  await new Promise((resolve) => setTimeout(resolve, 50));
301
544
  expect(document.querySelector("[data-testid='geolocation-coords-panel']")).toBeNull();
302
545
  expect(document.querySelector("[data-testid='floating-panel-viewport']")).toBeNull();
303
546
  });
304
547
  });
305
548
 
306
- it("renders readOnly — hides locate and coordinates overlay controls", () => {
549
+ it("renders readOnly — address as fact, no search, no locate", async () => {
550
+ const reverseGeocode = mockReverse();
307
551
  const result = renderWithProviders(
308
552
  <Geolocation
309
553
  label="ReadOnly"
310
554
  name="r"
311
555
  locationIcon={locationIcon}
312
556
  readOnly
313
- value={JSON.stringify({ lat: 1.23, lng: 4.56 })}
557
+ value={HELSINKI}
558
+ reverseGeocode={reverseGeocode}
314
559
  />,
315
560
  );
561
+ expect(searchInput(result.container)).toBeNull();
316
562
  expect(result.container.querySelector("[aria-label='Locate']")).toBeNull();
317
563
  expect(result.container.querySelector("[aria-label='Edit coordinates']")).toBeNull();
318
564
  expect(
319
- result.container.querySelector("[data-testid='geolocation-coords-chip']"),
565
+ result.container.querySelector("[data-testid='geolocation-readonly-address']"),
320
566
  ).not.toBeNull();
567
+ expect(result.container.querySelector("[data-testid='geolocation-map']")).not.toBeNull();
568
+ await waitFor(() => {
569
+ expect(result.container.textContent).toContain(
570
+ "Mannerheimintie 3, Kamppi, Helsinki, Finland",
571
+ );
572
+ });
321
573
  });
322
574
  });
323
575
 
@@ -470,7 +722,7 @@ describe("Geolocation", () => {
470
722
  const result = renderWithProviders(
471
723
  <Geolocation label="Location" value={stockFrappePoint} locationIcon={locationIcon} />,
472
724
  );
473
- expect(result.container.textContent).toContain("37.7749, -122.4194");
725
+ expect(result.container.textContent).toContain("37.77490, -122.41940");
474
726
  expect(result.container.textContent).not.toContain("Set location");
475
727
  expect(result.container.querySelector("[data-testid='geolocation-map']")).not.toBeNull();
476
728
  });
@@ -3,11 +3,14 @@ import { DataTable, type DataTableColumn } from "@multiplatform.one/table";
3
3
  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
- import { useState } from "react";
6
+ import { useCallback, useState } from "react";
7
7
  import { Text, YStack } from "tamagui";
8
8
  import { Button } from "../../Button";
9
9
  import { Form } from "../../Form";
10
- import { Geolocation } from "./index";
10
+ import { TableCellContext } from "../../shared/tableCellContext";
11
+ import { Geolocation, type GeolocationProps } from "./index";
12
+ import type { GeocodeResult, Geocoder } from "./geocoder";
13
+ import { parseGeoValue } from "./geoValue";
11
14
 
12
15
  const meta: Meta<typeof Geolocation> = {
13
16
  title: "Forms/Geolocation",
@@ -16,7 +19,7 @@ const meta: Meta<typeof Geolocation> = {
16
19
  docs: {
17
20
  description: {
18
21
  component:
19
- "Map-primary geolocation field: click the map to drop a pin. Locate is an icon overlay; the coordinate chip opens a FloatingPanel (no Apply — LC-21 dismiss-by-intent). LC-19 preflight gates Locate. LC-71: the map frame is the keyboard stop (inset ring, overflow hidden); overlay actions ring themselves. Accepts a custom `renderMap` prop for interactive maps.",
22
+ "Search-first geolocation field. Inject `geocode` / `reverseGeocode` (or a `geocoder` object); No default provider is supplied. The map is the output; coordinates live below it as a mono disclosure. Locate is a labeled action. LC-19 preflight gates Locate. LC-21: no Apply on the coordinate editor.",
20
23
  },
21
24
  },
22
25
  },
@@ -157,12 +160,12 @@ export const Interactive: Story = {
157
160
  render: () => {
158
161
  const InteractiveExample = () => {
159
162
  const [value, setValue] = useState(JSON.stringify({ lat: 40.7128, lng: -74.006 }));
160
- const parsed = JSON.parse(value) as { lat: number; lng: number };
163
+ const parsed = parseGeoValue(value);
161
164
  return (
162
165
  <YStack gap="$4" maxWidth={500}>
163
166
  <Geolocation
164
167
  label="Pick Location"
165
- helperText={`Lat: ${parsed.lat.toFixed(4)}, Lng: ${parsed.lng.toFixed(4)}`}
168
+ helperText={`Lat: ${parsed?.lat.toFixed(4) ?? ""}, Lng: ${parsed?.lng.toFixed(4) ?? ""}`}
166
169
  value={value}
167
170
  onChange={(v) => {
168
171
  setValue(v);
@@ -182,12 +185,12 @@ export const WithCoordinates: Story = {
182
185
  render: () => {
183
186
  const Example = () => {
184
187
  const [value, setValue] = useState(JSON.stringify({ lat: 37.7749, lng: -122.4194 }));
185
- const parsed = JSON.parse(value) as { lat: number; lng: number };
188
+ const parsed = parseGeoValue(value);
186
189
  return (
187
190
  <YStack gap="$4" maxWidth={500}>
188
191
  <Geolocation
189
192
  label="Office Location"
190
- helperText={`Lat: ${parsed.lat.toFixed(4)}, Lng: ${parsed.lng.toFixed(4)}`}
193
+ helperText={`Lat: ${parsed?.lat.toFixed(4) ?? ""}, Lng: ${parsed?.lng.toFixed(4) ?? ""}`}
191
194
  value={value}
192
195
  onChange={(v) => {
193
196
  setValue(v);
@@ -295,3 +298,134 @@ export const InTable: Story = {
295
298
  );
296
299
  },
297
300
  };
301
+
302
+ const places: GeocodeResult[] = [
303
+ { lat: 60.16952, lng: 24.93545, label: "Mannerheimintie 3", description: "Kamppi, Helsinki" },
304
+ { lat: -33.8688, lng: 151.2093, label: "Sydney", description: "New South Wales, Australia" },
305
+ ];
306
+
307
+ const fakeGeocoder: Geocoder = {
308
+ geocode: async ({ query }) =>
309
+ places.filter((place) =>
310
+ `${place.label} ${place.description}`.toLowerCase().includes(query.trim().toLowerCase()),
311
+ ),
312
+ reverseGeocode: async ({ lat, lng }) =>
313
+ places.find((place) => Math.abs(place.lat - lat) < 0.01 && Math.abs(place.lng - lng) < 0.01) ??
314
+ null,
315
+ };
316
+
317
+ function FakeProviderExample(props: GeolocationProps) {
318
+ const [value, setValue] = useState(props.value ?? "");
319
+ return <Geolocation {...props} value={value} onChange={setValue} />;
320
+ }
321
+
322
+ export const SearchWithFakeProvider: Story = {
323
+ args: {
324
+ label: "Location",
325
+ helperText: "Search Sydney or Helsinki. This example uses an offline provider.",
326
+ geocoder: fakeGeocoder,
327
+ },
328
+ render: (args) => <FakeProviderExample {...args} />,
329
+ };
330
+
331
+ export const AddressWithFakeProvider: Story = {
332
+ args: {
333
+ label: "Office",
334
+ value: JSON.stringify({ lat: 60.16952, lng: 24.93545 }),
335
+ geocoder: fakeGeocoder,
336
+ readOnly: true,
337
+ },
338
+ };
339
+
340
+ export const FailedFakeProvider: Story = {
341
+ args: {
342
+ label: "Location",
343
+ geocode: async () => {
344
+ throw new Error("Offline example failure");
345
+ },
346
+ },
347
+ render: (args) => <FakeProviderExample {...args} />,
348
+ };
349
+
350
+ /** Direct cell contract, independent of the table adapter's display formatter. */
351
+ export const CellWithFakeProvider: Story = {
352
+ args: {
353
+ label: "Location",
354
+ value: JSON.stringify({ lat: 60.16952, lng: 24.93545 }),
355
+ geocoder: fakeGeocoder,
356
+ },
357
+ render: (args) => (
358
+ <TableCellContext.Provider value={{ inTableCell: true, isHeader: false, editable: true }}>
359
+ <FakeProviderExample {...args} />
360
+ </TableCellContext.Provider>
361
+ ),
362
+ };
363
+
364
+ function DeferredControlledExample() {
365
+ const [value, setValue] = useState(JSON.stringify({ lat: places[0].lat, lng: places[0].lng }));
366
+ const [proposal, setProposal] = useState<string | null>(null);
367
+ const [readOnly, setReadOnly] = useState(false);
368
+ return (
369
+ <YStack gap="$3">
370
+ <Geolocation
371
+ label="Location"
372
+ value={value}
373
+ onChange={setProposal}
374
+ readOnly={readOnly}
375
+ geocoder={fakeGeocoder}
376
+ />
377
+ <Text>The parent holds the current location until it accepts the proposal.</Text>
378
+ <Button onPress={() => setReadOnly(!readOnly)}>
379
+ {readOnly ? "Edit search" : "Show selected fact"}
380
+ </Button>
381
+ {proposal !== null ? (
382
+ <Button onPress={() => setValue(proposal)}>Accept proposed location</Button>
383
+ ) : null}
384
+ </YStack>
385
+ );
386
+ }
387
+
388
+ export const DeferredControlledSelection: Story = {
389
+ render: () => <DeferredControlledExample />,
390
+ };
391
+
392
+ function PendingReverseExample() {
393
+ const [value, setValue] = useState(JSON.stringify({ lat: places[0].lat, lng: places[0].lng }));
394
+ const [readOnly, setReadOnly] = useState(true);
395
+ const [resolvePending, setResolvePending] = useState<(() => void) | null>(null);
396
+ const reverseGeocode = useCallback<NonNullable<GeolocationProps["reverseGeocode"]>>(({ lat }) => {
397
+ if (lat === places[0].lat) return Promise.resolve(places[0]);
398
+ return new Promise((resolve) => setResolvePending(() => () => resolve(places[1])));
399
+ }, []);
400
+ return (
401
+ <YStack gap="$3">
402
+ <Geolocation
403
+ label="Location"
404
+ value={value}
405
+ readOnly={readOnly}
406
+ geocode={fakeGeocoder.geocode}
407
+ reverseGeocode={reverseGeocode}
408
+ />
409
+ <Button onPress={() => setReadOnly(!readOnly)}>
410
+ {readOnly ? "Edit search" : "Show selected fact"}
411
+ </Button>
412
+ <Button onPress={() => setValue(JSON.stringify({ lat: places[1].lat, lng: places[1].lng }))}>
413
+ Move bound location to Sydney
414
+ </Button>
415
+ {resolvePending ? (
416
+ <Button
417
+ onPress={() => {
418
+ resolvePending();
419
+ setResolvePending(null);
420
+ }}
421
+ >
422
+ Resolve Sydney address
423
+ </Button>
424
+ ) : null}
425
+ </YStack>
426
+ );
427
+ }
428
+
429
+ export const PendingControlledReverse: Story = {
430
+ render: () => <PendingReverseExample />,
431
+ };
@@ -56,6 +56,9 @@ function MapFallback({
56
56
  * field's existing onChange path. When the module is missing the surface
57
57
  * degrades to the placeholder instead of crashing — `loadExpoMaps` requires
58
58
  * it as a Metro optional dependency.
59
+ *
60
+ * Output surface of the search-first field (MPO-54). Search and the
61
+ * coordinate disclosure live in the parent.
59
62
  */
60
63
  export function GeolocationMap({
61
64
  lat,
@@ -19,6 +19,10 @@ function tileSrc(zoom: number, x: number, y: number) {
19
19
  * (Frappe Desk / Leaflet, Google/Apple compact pickers) can commit through
20
20
  * the field's onChange path. The iframe embed could not report clicks.
21
21
  * Native interactive maps live in `GeolocationMap.native.tsx`.
22
+ *
23
+ * This surface is the OUTPUT of the search-first field (MPO-54). Search,
24
+ * geocoding, and the coordinate disclosure live in the parent — nothing
25
+ * here is an input pasted over the tiles.
22
26
  */
23
27
  export function GeolocationMap({
24
28
  lat,