@multiplatform.one/forms 7.57.0 → 7.58.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 (507) hide show
  1. package/dist/cjs/AdaptivePopup/index.cjs +5 -1
  2. package/dist/cjs/AdaptivePopup/index.native.js +6 -2
  3. package/dist/cjs/AdaptivePopup/index.native.js.map +1 -1
  4. package/dist/cjs/Button/index.cjs +2 -1
  5. package/dist/cjs/Button/index.native.js +4 -3
  6. package/dist/cjs/Button/index.native.js.map +1 -1
  7. package/dist/cjs/Chip/index.native.js.map +1 -1
  8. package/dist/cjs/ContextualSaveBar/UnsavedChangesDialog.native.js +1 -1
  9. package/dist/cjs/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
  10. package/dist/cjs/ContextualSaveBar/clientKnownIdentity.native.js.map +1 -1
  11. package/dist/cjs/ContextualSaveBar/commitImmediateField.native.js.map +1 -1
  12. package/dist/cjs/ContextualSaveBar/index.native.js +3 -3
  13. package/dist/cjs/ContextualSaveBar/index.native.js.map +1 -1
  14. package/dist/cjs/ContextualSaveBar/useUnsavedChangesGuard.native.js.map +1 -1
  15. package/dist/cjs/ControlGroup/index.native.js +1 -1
  16. package/dist/cjs/ControlGroup/index.native.js.map +1 -1
  17. package/dist/cjs/DescriptionList/index.native.js +2 -2
  18. package/dist/cjs/DescriptionList/index.native.js.map +1 -1
  19. package/dist/cjs/ErrorSummary.native.js.map +1 -1
  20. package/dist/cjs/FieldDisplay/editMode.native.js.map +1 -1
  21. package/dist/cjs/FieldDisplay/formatters.native.js.map +1 -1
  22. package/dist/cjs/FieldDisplay/index.native.js +1 -1
  23. package/dist/cjs/FieldDisplay/index.native.js.map +1 -1
  24. package/dist/cjs/FieldGroup.native.js.map +1 -1
  25. package/dist/cjs/FloatingPanel/compactFace.cjs +38 -0
  26. package/dist/cjs/FloatingPanel/compactFace.native.js +42 -0
  27. package/dist/cjs/FloatingPanel/compactFace.native.js.map +1 -0
  28. package/dist/cjs/FloatingPanel/index.cjs +38 -9
  29. package/dist/cjs/FloatingPanel/index.native.js +154 -6
  30. package/dist/cjs/FloatingPanel/index.native.js.map +1 -1
  31. package/dist/cjs/FloatingPanel/nestedAction.native.js.map +1 -1
  32. package/dist/cjs/FloatingPanel/pointAnchor.cjs +22 -0
  33. package/dist/cjs/FloatingPanel/pointAnchor.native.js +23 -0
  34. package/dist/cjs/FloatingPanel/pointAnchor.native.js.map +1 -1
  35. package/dist/cjs/FloatingPanel/trailingAction.native.js +1 -1
  36. package/dist/cjs/FloatingPanel/trailingAction.native.js.map +1 -1
  37. package/dist/cjs/FloatingPanel/useFloatingPanel.native.js.map +1 -1
  38. package/dist/cjs/Form/index.native.js +1 -1
  39. package/dist/cjs/Form/index.native.js.map +1 -1
  40. package/dist/cjs/Form/submissionController.native.js.map +1 -1
  41. package/dist/cjs/Form/validateOn.native.js.map +1 -1
  42. package/dist/cjs/FormGrid.native.js.map +1 -1
  43. package/dist/cjs/FormSection.native.js.map +1 -1
  44. package/dist/cjs/InputParts/PasswordReveal.native.js.map +1 -1
  45. package/dist/cjs/InputParts/index.cjs +13 -7
  46. package/dist/cjs/InputParts/index.native.js +13 -7
  47. package/dist/cjs/InputParts/index.native.js.map +1 -1
  48. package/dist/cjs/Label/index.native.js.map +1 -1
  49. package/dist/cjs/MediaPicker/base64.native.js.map +1 -1
  50. package/dist/cjs/MediaPicker/payload.native.js.map +1 -1
  51. package/dist/cjs/MediaPicker/types.native.js.map +1 -1
  52. package/dist/cjs/MediaPicker/useMediaPicker.native.js.map +1 -1
  53. package/dist/cjs/Skeleton/index.native.js.map +1 -1
  54. package/dist/cjs/Spinner/SpinnerGlyph.native.js.map +1 -1
  55. package/dist/cjs/Spinner/spinnerSize.native.js.map +1 -1
  56. package/dist/cjs/Table/index.native.js.map +1 -1
  57. package/dist/cjs/Wheel/haptic.native.js.map +1 -1
  58. package/dist/cjs/Wheel/index.native.js.map +1 -1
  59. package/dist/cjs/Wheel/wheelShared.native.js.map +1 -1
  60. package/dist/cjs/actionLabel.native.js.map +1 -1
  61. package/dist/cjs/fieldDefaults.native.js.map +1 -1
  62. package/dist/cjs/fieldLayout.native.js +1 -1
  63. package/dist/cjs/fieldLayout.native.js.map +1 -1
  64. package/dist/cjs/fields/Barcode/BarcodePreview.native.js.map +1 -1
  65. package/dist/cjs/fields/Barcode/BarcodeScanner.native.js +1 -1
  66. package/dist/cjs/fields/Barcode/code128.native.js.map +1 -1
  67. package/dist/cjs/fields/Barcode/index.native.js +2 -2
  68. package/dist/cjs/fields/Barcode/index.native.js.map +1 -1
  69. package/dist/cjs/fields/Barcode/qr.native.js.map +1 -1
  70. package/dist/cjs/fields/Barcode/scannerTypes.native.js.map +1 -1
  71. package/dist/cjs/fields/Checkbox/Checkbox.cjs +24 -14
  72. package/dist/cjs/fields/Checkbox/Checkbox.native.js +39 -23
  73. package/dist/cjs/fields/Checkbox/Checkbox.native.js.map +1 -1
  74. package/dist/cjs/fields/Checkbox/CheckboxBox.native.js.map +1 -1
  75. package/dist/cjs/fields/Checkbox/CheckboxCard.native.js.map +1 -1
  76. package/dist/cjs/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  77. package/dist/cjs/fields/Checkbox/CheckboxGroup.native.js +1 -1
  78. package/dist/cjs/fields/Checkbox/CheckboxGroup.native.js.map +1 -1
  79. package/dist/cjs/fields/Checkbox/checkboxGroupContext.native.js.map +1 -1
  80. package/dist/cjs/fields/Checkbox/index.native.js.map +1 -1
  81. package/dist/cjs/fields/ColorPicker/index.native.js +2 -2
  82. package/dist/cjs/fields/ColorPicker/index.native.js.map +1 -1
  83. package/dist/cjs/fields/ColorPicker/parts.native.js +2 -2
  84. package/dist/cjs/fields/ColorPicker/parts.native.js.map +1 -1
  85. package/dist/cjs/fields/Combobox/authorOptions.native.js.map +1 -1
  86. package/dist/cjs/fields/Combobox/index.native.js +5 -5
  87. package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
  88. package/dist/cjs/fields/DatePicker/Calendar.native.js.map +1 -1
  89. package/dist/cjs/fields/DatePicker/DateRangePicker.native.js +2 -2
  90. package/dist/cjs/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  91. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js +3 -3
  92. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  93. package/dist/cjs/fields/DatePicker/DatetimePicker.native.js +2 -2
  94. package/dist/cjs/fields/DatePicker/MonthPicker.native.js +2 -2
  95. package/dist/cjs/fields/DatePicker/MonthPicker.native.js.map +1 -1
  96. package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js +2 -2
  97. package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  98. package/dist/cjs/fields/DatePicker/catalog.native.js +2 -2
  99. package/dist/cjs/fields/DatePicker/catalog.native.js.map +1 -1
  100. package/dist/cjs/fields/DatePicker/fieldValueSync.native.js.map +1 -1
  101. package/dist/cjs/fields/DatePicker/index.native.js +2 -2
  102. package/dist/cjs/fields/DatePicker/parts.native.js +2 -2
  103. package/dist/cjs/fields/DatePicker/parts.native.js.map +1 -1
  104. package/dist/cjs/fields/DatePicker/utils.native.js.map +1 -1
  105. package/dist/cjs/fields/Duration/durationMath.native.js.map +1 -1
  106. package/dist/cjs/fields/Duration/index.native.js +3 -3
  107. package/dist/cjs/fields/Duration/index.native.js.map +1 -1
  108. package/dist/cjs/fields/FileUpload/filePickerTypes.native.js.map +1 -1
  109. package/dist/cjs/fields/FileUpload/index.native.js +2 -2
  110. package/dist/cjs/fields/FileUpload/index.native.js.map +1 -1
  111. package/dist/cjs/fields/FileUpload/nativePickerLoader.native.js.map +1 -1
  112. package/dist/cjs/fields/Geolocation/expoMapsLoader.native.js.map +1 -1
  113. package/dist/cjs/fields/Geolocation/geoValue.native.js.map +1 -1
  114. package/dist/cjs/fields/Geolocation/geocoder.native.js.map +1 -1
  115. package/dist/cjs/fields/Geolocation/geocoderContext.native.js.map +1 -1
  116. package/dist/cjs/fields/Geolocation/index.native.js +5 -5
  117. package/dist/cjs/fields/Geolocation/index.native.js.map +1 -1
  118. package/dist/cjs/fields/Geolocation/mapMath.native.js.map +1 -1
  119. package/dist/cjs/fields/Geolocation/mapTypes.native.js.map +1 -1
  120. package/dist/cjs/fields/Geolocation/nativeSearchFocus.native.js.map +1 -1
  121. package/dist/cjs/fields/Geolocation/photonGeocoder.native.js.map +1 -1
  122. package/dist/cjs/fields/Icon/drawnSet.native.js.map +1 -1
  123. package/dist/cjs/fields/Icon/index.native.js +3 -3
  124. package/dist/cjs/fields/Icon/index.native.js.map +1 -1
  125. package/dist/cjs/fields/ImageField/index.native.js +2 -2
  126. package/dist/cjs/fields/ImageField/index.native.js.map +1 -1
  127. package/dist/cjs/fields/Input/index.native.js +3 -3
  128. package/dist/cjs/fields/Input/index.native.js.map +1 -1
  129. package/dist/cjs/fields/MentionInput/index.native.js +3 -3
  130. package/dist/cjs/fields/MentionInput/index.native.js.map +1 -1
  131. package/dist/cjs/fields/OTPInput/index.native.js +3 -3
  132. package/dist/cjs/fields/OTPInput/index.native.js.map +1 -1
  133. package/dist/cjs/fields/OTPInput/otpCellCss.native.js.map +1 -1
  134. package/dist/cjs/fields/PhoneInput/dialCodes.native.js.map +1 -1
  135. package/dist/cjs/fields/PhoneInput/index.native.js +3 -3
  136. package/dist/cjs/fields/PhoneInput/index.native.js.map +1 -1
  137. package/dist/cjs/fields/PhoneInput/phone.native.js.map +1 -1
  138. package/dist/cjs/fields/PhoneInput/regionNames.native.js.map +1 -1
  139. package/dist/cjs/fields/Progress/index.native.js +1 -1
  140. package/dist/cjs/fields/Progress/index.native.js.map +1 -1
  141. package/dist/cjs/fields/RadioGroup/index.cjs +6 -1
  142. package/dist/cjs/fields/RadioGroup/index.native.js +7 -2
  143. package/dist/cjs/fields/RadioGroup/index.native.js.map +1 -1
  144. package/dist/cjs/fields/Rating/index.native.js +1 -1
  145. package/dist/cjs/fields/Rating/index.native.js.map +1 -1
  146. package/dist/cjs/fields/Rating/ratingMath.native.js.map +1 -1
  147. package/dist/cjs/fields/Rating/types.native.js.map +1 -1
  148. package/dist/cjs/fields/SearchInput/index.native.js +2 -2
  149. package/dist/cjs/fields/SearchInput/index.native.js.map +1 -1
  150. package/dist/cjs/fields/Select/index.cjs +13 -2
  151. package/dist/cjs/fields/Select/index.native.js +26 -7
  152. package/dist/cjs/fields/Select/index.native.js.map +1 -1
  153. package/dist/cjs/fields/Signature/index.native.js +2 -2
  154. package/dist/cjs/fields/Signature/index.native.js.map +1 -1
  155. package/dist/cjs/fields/Slider/index.native.js +1 -1
  156. package/dist/cjs/fields/Slider/index.native.js.map +1 -1
  157. package/dist/cjs/fields/Slider/jumpMotion.native.js.map +1 -1
  158. package/dist/cjs/fields/Stepper/index.native.js +2 -2
  159. package/dist/cjs/fields/Stepper/index.native.js.map +1 -1
  160. package/dist/cjs/fields/Stepper/resolveStepperPlacement.native.js.map +1 -1
  161. package/dist/cjs/fields/Switch/footprint.native.js.map +1 -1
  162. package/dist/cjs/fields/Switch/index.cjs +22 -10
  163. package/dist/cjs/fields/Switch/index.native.js +30 -16
  164. package/dist/cjs/fields/Switch/index.native.js.map +1 -1
  165. package/dist/cjs/fields/TextArea/index.native.js +2 -2
  166. package/dist/cjs/fields/TextArea/index.native.js.map +1 -1
  167. package/dist/cjs/fields/TimePicker/catalog.native.js +3 -3
  168. package/dist/cjs/fields/TimePicker/catalog.native.js.map +1 -1
  169. package/dist/cjs/fields/TimePicker/index.native.js +2 -2
  170. package/dist/cjs/fields/TimePicker/parts.native.js +1 -1
  171. package/dist/cjs/fields/TimePicker/parts.native.js.map +1 -1
  172. package/dist/cjs/fields/TimeRangeScrubber/geometry.native.js.map +1 -1
  173. package/dist/cjs/fields/TimeRangeScrubber/index.native.js +2 -2
  174. package/dist/cjs/fields/TimeRangeScrubber/index.native.js.map +1 -1
  175. package/dist/cjs/fields/ToggleGroup/index.native.js +1 -1
  176. package/dist/cjs/fields/ToggleGroup/index.native.js.map +1 -1
  177. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  178. package/dist/cjs/fields/nativeDateTime/dateTimePickerLoader.native.js.map +1 -1
  179. package/dist/cjs/fields/nativeDateTime/osDateTimeIosDisplay.native.js.map +1 -1
  180. package/dist/cjs/fields/nativeSelect.native.js.map +1 -1
  181. package/dist/cjs/fields/selectedOrder.native.js.map +1 -1
  182. package/dist/cjs/formSpacing.native.js.map +1 -1
  183. package/dist/cjs/hooks/useFocusManagement.native.js.map +1 -1
  184. package/dist/cjs/index.native.js +45 -45
  185. package/dist/cjs/index.native.js.map +1 -1
  186. package/dist/cjs/keyboard/KeyboardDoneBar.native.js +1 -1
  187. package/dist/cjs/keyboard/chain.native.js.map +1 -1
  188. package/dist/cjs/keyboard/index.native.js.map +1 -1
  189. package/dist/cjs/keyboard/types.native.js.map +1 -1
  190. package/dist/cjs/requiredMarking.native.js.map +1 -1
  191. package/dist/cjs/shared/TimeColumn.native.js +1 -1
  192. package/dist/cjs/shared/TimeColumn.native.js.map +1 -1
  193. package/dist/cjs/shared/capabilityPreflight.native.js.map +1 -1
  194. package/dist/cjs/shared/choiceRowPress.cjs +46 -0
  195. package/dist/cjs/shared/choiceRowPress.native.js +50 -0
  196. package/dist/cjs/shared/choiceRowPress.native.js.map +1 -0
  197. package/dist/cjs/shared/colorRamps.native.js.map +1 -1
  198. package/dist/cjs/shared/devWarn.native.js.map +1 -1
  199. package/dist/cjs/shared/floatingList.native.js +1 -1
  200. package/dist/cjs/shared/floatingList.native.js.map +1 -1
  201. package/dist/cjs/shared/focusManagement.native.js.map +1 -1
  202. package/dist/cjs/shared/groupContext.native.js.map +1 -1
  203. package/dist/cjs/shared/i18n.native.js.map +1 -1
  204. package/dist/cjs/shared/instantMotion.native.js.map +1 -1
  205. package/dist/cjs/shared/nativeA11y.native.js.map +1 -1
  206. package/dist/cjs/shared/nativeAutoFocus.native.js.map +1 -1
  207. package/dist/cjs/shared/overlayStack.cjs +4 -0
  208. package/dist/cjs/shared/overlayStack.native.js +4 -0
  209. package/dist/cjs/shared/overlayStack.native.js.map +1 -1
  210. package/dist/cjs/shared/panelPortal.native.js.map +1 -1
  211. package/dist/cjs/shared/pickerTriggerContract.native.js.map +1 -1
  212. package/dist/cjs/shared/pressSlopProps.native.js.map +1 -1
  213. package/dist/cjs/shared/restoreRetries.native.js.map +1 -1
  214. package/dist/cjs/shared/t.native.js.map +1 -1
  215. package/dist/cjs/shared/tableCellContext.native.js.map +1 -1
  216. package/dist/cjs/shared/useDragScroll.native.js.map +1 -1
  217. package/dist/cjs/shared/useKeyboardInset.native.js.map +1 -1
  218. package/dist/cjs/shared/useSheetEscapeDismiss.native.js.map +1 -1
  219. package/dist/cjs/shared/useWheelIncrement.native.js.map +1 -1
  220. package/dist/cjs/shared/utils.native.js +1 -1
  221. package/dist/cjs/shared/utils.native.js.map +1 -1
  222. package/dist/cjs/shared/zIndex.native.js.map +1 -1
  223. package/dist/cjs/themedPrimitives.native.js.map +1 -1
  224. package/dist/cjs/types.native.js.map +1 -1
  225. package/dist/cjs/utils/LinkCell.native.js.map +1 -1
  226. package/dist/esm/AdaptivePopup/index.mjs +6 -2
  227. package/dist/esm/AdaptivePopup/index.mjs.map +1 -1
  228. package/dist/esm/AdaptivePopup/index.native.js +6 -2
  229. package/dist/esm/AdaptivePopup/index.native.js.map +1 -1
  230. package/dist/esm/Button/index.mjs +3 -2
  231. package/dist/esm/Button/index.mjs.map +1 -1
  232. package/dist/esm/Button/index.native.js +3 -2
  233. package/dist/esm/Button/index.native.js.map +1 -1
  234. package/dist/esm/Chip/index.native.js.map +1 -1
  235. package/dist/esm/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
  236. package/dist/esm/ContextualSaveBar/clientKnownIdentity.native.js.map +1 -1
  237. package/dist/esm/ContextualSaveBar/commitImmediateField.native.js.map +1 -1
  238. package/dist/esm/ContextualSaveBar/index.native.js.map +1 -1
  239. package/dist/esm/ContextualSaveBar/useUnsavedChangesGuard.native.js.map +1 -1
  240. package/dist/esm/ControlGroup/index.native.js.map +1 -1
  241. package/dist/esm/DescriptionList/index.native.js.map +1 -1
  242. package/dist/esm/ErrorSummary.native.js.map +1 -1
  243. package/dist/esm/FieldDisplay/editMode.native.js.map +1 -1
  244. package/dist/esm/FieldDisplay/formatters.native.js.map +1 -1
  245. package/dist/esm/FieldDisplay/index.native.js.map +1 -1
  246. package/dist/esm/FieldGroup.native.js.map +1 -1
  247. package/dist/esm/FloatingPanel/compactFace.mjs +11 -0
  248. package/dist/esm/FloatingPanel/compactFace.mjs.map +1 -0
  249. package/dist/esm/FloatingPanel/compactFace.native.js +12 -0
  250. package/dist/esm/FloatingPanel/compactFace.native.js.map +1 -0
  251. package/dist/esm/FloatingPanel/index.mjs +40 -11
  252. package/dist/esm/FloatingPanel/index.mjs.map +1 -1
  253. package/dist/esm/FloatingPanel/index.native.js +156 -8
  254. package/dist/esm/FloatingPanel/index.native.js.map +1 -1
  255. package/dist/esm/FloatingPanel/nestedAction.native.js.map +1 -1
  256. package/dist/esm/FloatingPanel/pointAnchor.mjs +22 -1
  257. package/dist/esm/FloatingPanel/pointAnchor.mjs.map +1 -1
  258. package/dist/esm/FloatingPanel/pointAnchor.native.js +23 -1
  259. package/dist/esm/FloatingPanel/pointAnchor.native.js.map +1 -1
  260. package/dist/esm/FloatingPanel/trailingAction.native.js.map +1 -1
  261. package/dist/esm/FloatingPanel/useFloatingPanel.native.js.map +1 -1
  262. package/dist/esm/Form/index.native.js.map +1 -1
  263. package/dist/esm/Form/submissionController.native.js.map +1 -1
  264. package/dist/esm/Form/validateOn.native.js.map +1 -1
  265. package/dist/esm/FormGrid.native.js.map +1 -1
  266. package/dist/esm/FormSection.native.js.map +1 -1
  267. package/dist/esm/InputParts/PasswordReveal.native.js.map +1 -1
  268. package/dist/esm/InputParts/index.mjs +13 -7
  269. package/dist/esm/InputParts/index.mjs.map +1 -1
  270. package/dist/esm/InputParts/index.native.js +13 -7
  271. package/dist/esm/InputParts/index.native.js.map +1 -1
  272. package/dist/esm/Label/index.native.js.map +1 -1
  273. package/dist/esm/MediaPicker/base64.native.js.map +1 -1
  274. package/dist/esm/MediaPicker/payload.native.js.map +1 -1
  275. package/dist/esm/MediaPicker/types.native.js.map +1 -1
  276. package/dist/esm/MediaPicker/useMediaPicker.native.js.map +1 -1
  277. package/dist/esm/Skeleton/index.native.js.map +1 -1
  278. package/dist/esm/Spinner/SpinnerGlyph.native.js.map +1 -1
  279. package/dist/esm/Spinner/spinnerSize.native.js.map +1 -1
  280. package/dist/esm/Table/index.native.js.map +1 -1
  281. package/dist/esm/Wheel/haptic.native.js.map +1 -1
  282. package/dist/esm/Wheel/index.native.js.map +1 -1
  283. package/dist/esm/Wheel/wheelShared.native.js.map +1 -1
  284. package/dist/esm/actionLabel.native.js.map +1 -1
  285. package/dist/esm/fieldDefaults.native.js.map +1 -1
  286. package/dist/esm/fieldLayout.native.js.map +1 -1
  287. package/dist/esm/fields/Barcode/BarcodePreview.native.js.map +1 -1
  288. package/dist/esm/fields/Barcode/code128.native.js.map +1 -1
  289. package/dist/esm/fields/Barcode/index.native.js.map +1 -1
  290. package/dist/esm/fields/Barcode/qr.native.js.map +1 -1
  291. package/dist/esm/fields/Barcode/scannerTypes.native.js.map +1 -1
  292. package/dist/esm/fields/Checkbox/Checkbox.mjs +24 -14
  293. package/dist/esm/fields/Checkbox/Checkbox.mjs.map +1 -1
  294. package/dist/esm/fields/Checkbox/Checkbox.native.js +38 -22
  295. package/dist/esm/fields/Checkbox/Checkbox.native.js.map +1 -1
  296. package/dist/esm/fields/Checkbox/CheckboxBox.native.js.map +1 -1
  297. package/dist/esm/fields/Checkbox/CheckboxCard.native.js.map +1 -1
  298. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  299. package/dist/esm/fields/Checkbox/CheckboxGroup.native.js.map +1 -1
  300. package/dist/esm/fields/Checkbox/checkboxGroupContext.native.js.map +1 -1
  301. package/dist/esm/fields/Checkbox/index.native.js.map +1 -1
  302. package/dist/esm/fields/ColorPicker/index.native.js.map +1 -1
  303. package/dist/esm/fields/ColorPicker/parts.native.js.map +1 -1
  304. package/dist/esm/fields/Combobox/authorOptions.native.js.map +1 -1
  305. package/dist/esm/fields/Combobox/index.native.js.map +1 -1
  306. package/dist/esm/fields/DatePicker/Calendar.native.js.map +1 -1
  307. package/dist/esm/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  308. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  309. package/dist/esm/fields/DatePicker/MonthPicker.native.js.map +1 -1
  310. package/dist/esm/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  311. package/dist/esm/fields/DatePicker/catalog.native.js.map +1 -1
  312. package/dist/esm/fields/DatePicker/fieldValueSync.native.js.map +1 -1
  313. package/dist/esm/fields/DatePicker/parts.native.js.map +1 -1
  314. package/dist/esm/fields/DatePicker/utils.native.js.map +1 -1
  315. package/dist/esm/fields/Duration/durationMath.native.js.map +1 -1
  316. package/dist/esm/fields/Duration/index.native.js.map +1 -1
  317. package/dist/esm/fields/FileUpload/filePickerTypes.native.js.map +1 -1
  318. package/dist/esm/fields/FileUpload/index.native.js.map +1 -1
  319. package/dist/esm/fields/FileUpload/nativePickerLoader.native.js.map +1 -1
  320. package/dist/esm/fields/Geolocation/expoMapsLoader.native.js.map +1 -1
  321. package/dist/esm/fields/Geolocation/geoValue.native.js.map +1 -1
  322. package/dist/esm/fields/Geolocation/geocoder.native.js.map +1 -1
  323. package/dist/esm/fields/Geolocation/geocoderContext.native.js.map +1 -1
  324. package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
  325. package/dist/esm/fields/Geolocation/mapMath.native.js.map +1 -1
  326. package/dist/esm/fields/Geolocation/mapTypes.native.js.map +1 -1
  327. package/dist/esm/fields/Geolocation/nativeSearchFocus.native.js.map +1 -1
  328. package/dist/esm/fields/Geolocation/photonGeocoder.native.js.map +1 -1
  329. package/dist/esm/fields/Icon/drawnSet.native.js.map +1 -1
  330. package/dist/esm/fields/Icon/index.native.js.map +1 -1
  331. package/dist/esm/fields/ImageField/index.native.js.map +1 -1
  332. package/dist/esm/fields/Input/index.native.js.map +1 -1
  333. package/dist/esm/fields/MentionInput/index.native.js.map +1 -1
  334. package/dist/esm/fields/OTPInput/index.native.js.map +1 -1
  335. package/dist/esm/fields/OTPInput/otpCellCss.native.js.map +1 -1
  336. package/dist/esm/fields/PhoneInput/dialCodes.native.js.map +1 -1
  337. package/dist/esm/fields/PhoneInput/index.native.js.map +1 -1
  338. package/dist/esm/fields/PhoneInput/phone.native.js.map +1 -1
  339. package/dist/esm/fields/PhoneInput/regionNames.native.js.map +1 -1
  340. package/dist/esm/fields/Progress/index.native.js.map +1 -1
  341. package/dist/esm/fields/RadioGroup/index.mjs +6 -1
  342. package/dist/esm/fields/RadioGroup/index.mjs.map +1 -1
  343. package/dist/esm/fields/RadioGroup/index.native.js +6 -1
  344. package/dist/esm/fields/RadioGroup/index.native.js.map +1 -1
  345. package/dist/esm/fields/Rating/index.native.js.map +1 -1
  346. package/dist/esm/fields/Rating/ratingMath.native.js.map +1 -1
  347. package/dist/esm/fields/Rating/types.native.js.map +1 -1
  348. package/dist/esm/fields/SearchInput/index.native.js.map +1 -1
  349. package/dist/esm/fields/Select/index.mjs +15 -4
  350. package/dist/esm/fields/Select/index.mjs.map +1 -1
  351. package/dist/esm/fields/Select/index.native.js +24 -5
  352. package/dist/esm/fields/Select/index.native.js.map +1 -1
  353. package/dist/esm/fields/Signature/index.native.js.map +1 -1
  354. package/dist/esm/fields/Slider/index.native.js.map +1 -1
  355. package/dist/esm/fields/Slider/jumpMotion.native.js.map +1 -1
  356. package/dist/esm/fields/Stepper/index.native.js.map +1 -1
  357. package/dist/esm/fields/Stepper/resolveStepperPlacement.native.js.map +1 -1
  358. package/dist/esm/fields/Switch/footprint.native.js.map +1 -1
  359. package/dist/esm/fields/Switch/index.mjs +22 -10
  360. package/dist/esm/fields/Switch/index.mjs.map +1 -1
  361. package/dist/esm/fields/Switch/index.native.js +28 -14
  362. package/dist/esm/fields/Switch/index.native.js.map +1 -1
  363. package/dist/esm/fields/TextArea/index.native.js.map +1 -1
  364. package/dist/esm/fields/TimePicker/catalog.native.js.map +1 -1
  365. package/dist/esm/fields/TimePicker/parts.native.js.map +1 -1
  366. package/dist/esm/fields/TimeRangeScrubber/geometry.native.js.map +1 -1
  367. package/dist/esm/fields/TimeRangeScrubber/index.native.js.map +1 -1
  368. package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
  369. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  370. package/dist/esm/fields/nativeDateTime/dateTimePickerLoader.native.js.map +1 -1
  371. package/dist/esm/fields/nativeDateTime/osDateTimeIosDisplay.native.js.map +1 -1
  372. package/dist/esm/fields/nativeSelect.native.js.map +1 -1
  373. package/dist/esm/fields/selectedOrder.native.js.map +1 -1
  374. package/dist/esm/formSpacing.native.js.map +1 -1
  375. package/dist/esm/hooks/useFocusManagement.native.js.map +1 -1
  376. package/dist/esm/index.native.js.map +1 -1
  377. package/dist/esm/keyboard/chain.native.js.map +1 -1
  378. package/dist/esm/keyboard/index.native.js.map +1 -1
  379. package/dist/esm/keyboard/types.native.js.map +1 -1
  380. package/dist/esm/requiredMarking.native.js.map +1 -1
  381. package/dist/esm/shared/TimeColumn.native.js.map +1 -1
  382. package/dist/esm/shared/capabilityPreflight.native.js.map +1 -1
  383. package/dist/esm/shared/choiceRowPress.mjs +20 -0
  384. package/dist/esm/shared/choiceRowPress.mjs.map +1 -0
  385. package/dist/esm/shared/choiceRowPress.native.js +21 -0
  386. package/dist/esm/shared/choiceRowPress.native.js.map +1 -0
  387. package/dist/esm/shared/colorRamps.native.js.map +1 -1
  388. package/dist/esm/shared/devWarn.native.js.map +1 -1
  389. package/dist/esm/shared/floatingList.native.js.map +1 -1
  390. package/dist/esm/shared/focusManagement.native.js.map +1 -1
  391. package/dist/esm/shared/groupContext.native.js.map +1 -1
  392. package/dist/esm/shared/i18n.native.js.map +1 -1
  393. package/dist/esm/shared/instantMotion.native.js.map +1 -1
  394. package/dist/esm/shared/nativeA11y.native.js.map +1 -1
  395. package/dist/esm/shared/nativeAutoFocus.native.js.map +1 -1
  396. package/dist/esm/shared/overlayStack.mjs +4 -1
  397. package/dist/esm/shared/overlayStack.mjs.map +1 -1
  398. package/dist/esm/shared/overlayStack.native.js +4 -1
  399. package/dist/esm/shared/overlayStack.native.js.map +1 -1
  400. package/dist/esm/shared/panelPortal.native.js.map +1 -1
  401. package/dist/esm/shared/pickerTriggerContract.native.js.map +1 -1
  402. package/dist/esm/shared/pressSlopProps.native.js.map +1 -1
  403. package/dist/esm/shared/restoreRetries.native.js.map +1 -1
  404. package/dist/esm/shared/t.native.js.map +1 -1
  405. package/dist/esm/shared/tableCellContext.native.js.map +1 -1
  406. package/dist/esm/shared/useDragScroll.native.js.map +1 -1
  407. package/dist/esm/shared/useKeyboardInset.native.js.map +1 -1
  408. package/dist/esm/shared/useSheetEscapeDismiss.native.js.map +1 -1
  409. package/dist/esm/shared/useWheelIncrement.native.js.map +1 -1
  410. package/dist/esm/shared/utils.native.js.map +1 -1
  411. package/dist/esm/shared/zIndex.native.js.map +1 -1
  412. package/dist/esm/themedPrimitives.native.js.map +1 -1
  413. package/dist/esm/types.native.js.map +1 -1
  414. package/dist/esm/utils/LinkCell.native.js.map +1 -1
  415. package/dist/jsx/AdaptivePopup/index.mjs +6 -2
  416. package/dist/jsx/AdaptivePopup/index.mjs.map +1 -1
  417. package/dist/jsx/AdaptivePopup/index.native.js +5 -1
  418. package/dist/jsx/AdaptivePopup/index.native.js.map +1 -1
  419. package/dist/jsx/Button/index.mjs +3 -2
  420. package/dist/jsx/Button/index.mjs.map +1 -1
  421. package/dist/jsx/Button/index.native.js +2 -1
  422. package/dist/jsx/Button/index.native.js.map +1 -1
  423. package/dist/jsx/FloatingPanel/compactFace.mjs +11 -0
  424. package/dist/jsx/FloatingPanel/compactFace.mjs.map +1 -0
  425. package/dist/jsx/FloatingPanel/compactFace.native.js +42 -0
  426. package/dist/jsx/FloatingPanel/compactFace.native.js.map +1 -0
  427. package/dist/jsx/FloatingPanel/index.mjs +40 -11
  428. package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
  429. package/dist/jsx/FloatingPanel/index.native.js +154 -6
  430. package/dist/jsx/FloatingPanel/index.native.js.map +1 -1
  431. package/dist/jsx/FloatingPanel/pointAnchor.mjs +22 -1
  432. package/dist/jsx/FloatingPanel/pointAnchor.mjs.map +1 -1
  433. package/dist/jsx/FloatingPanel/pointAnchor.native.js +23 -0
  434. package/dist/jsx/FloatingPanel/pointAnchor.native.js.map +1 -1
  435. package/dist/jsx/InputParts/index.mjs +13 -7
  436. package/dist/jsx/InputParts/index.mjs.map +1 -1
  437. package/dist/jsx/InputParts/index.native.js +13 -7
  438. package/dist/jsx/InputParts/index.native.js.map +1 -1
  439. package/dist/jsx/fields/Checkbox/Checkbox.mjs +24 -14
  440. package/dist/jsx/fields/Checkbox/Checkbox.mjs.map +1 -1
  441. package/dist/jsx/fields/Checkbox/Checkbox.native.js +38 -22
  442. package/dist/jsx/fields/Checkbox/Checkbox.native.js.map +1 -1
  443. package/dist/jsx/fields/RadioGroup/index.mjs +6 -1
  444. package/dist/jsx/fields/RadioGroup/index.mjs.map +1 -1
  445. package/dist/jsx/fields/RadioGroup/index.native.js +6 -1
  446. package/dist/jsx/fields/RadioGroup/index.native.js.map +1 -1
  447. package/dist/jsx/fields/Select/index.mjs +15 -4
  448. package/dist/jsx/fields/Select/index.mjs.map +1 -1
  449. package/dist/jsx/fields/Select/index.native.js +22 -3
  450. package/dist/jsx/fields/Select/index.native.js.map +1 -1
  451. package/dist/jsx/fields/Switch/index.mjs +22 -10
  452. package/dist/jsx/fields/Switch/index.mjs.map +1 -1
  453. package/dist/jsx/fields/Switch/index.native.js +28 -14
  454. package/dist/jsx/fields/Switch/index.native.js.map +1 -1
  455. package/dist/jsx/shared/choiceRowPress.mjs +20 -0
  456. package/dist/jsx/shared/choiceRowPress.mjs.map +1 -0
  457. package/dist/jsx/shared/choiceRowPress.native.js +50 -0
  458. package/dist/jsx/shared/choiceRowPress.native.js.map +1 -0
  459. package/dist/jsx/shared/overlayStack.mjs +4 -1
  460. package/dist/jsx/shared/overlayStack.mjs.map +1 -1
  461. package/dist/jsx/shared/overlayStack.native.js +4 -0
  462. package/dist/jsx/shared/overlayStack.native.js.map +1 -1
  463. package/package.json +8 -8
  464. package/src/AdaptivePopup/index.tsx +6 -1
  465. package/src/Button/Button.controlTiers.spec.tsx +29 -0
  466. package/src/Button/index.tsx +3 -1
  467. package/src/FloatingPanel/FloatingPanel.compactFace.spec.tsx +187 -0
  468. package/src/FloatingPanel/FloatingPanel.menuFace.native.spec.tsx +183 -0
  469. package/src/FloatingPanel/compactFace.spec.ts +40 -0
  470. package/src/FloatingPanel/compactFace.ts +32 -0
  471. package/src/FloatingPanel/index.native.tsx +171 -4
  472. package/src/FloatingPanel/index.tsx +55 -11
  473. package/src/FloatingPanel/pointAnchor.spec.ts +80 -0
  474. package/src/FloatingPanel/pointAnchor.ts +52 -0
  475. package/src/InputParts/index.tsx +18 -7
  476. package/src/fields/Checkbox/Checkbox.native.spec.tsx +44 -0
  477. package/src/fields/Checkbox/Checkbox.tsx +31 -18
  478. package/src/fields/DatePicker/columnFit.spec.tsx +85 -0
  479. package/src/fields/RadioGroup/RadioGroup.native.spec.tsx +65 -0
  480. package/src/fields/RadioGroup/RadioGroup.stories.tsx +49 -0
  481. package/src/fields/RadioGroup/index.tsx +14 -2
  482. package/src/fields/Select/index.tsx +36 -6
  483. package/src/fields/Switch/Switch.rowPress.native.spec.tsx +69 -0
  484. package/src/fields/Switch/index.tsx +29 -11
  485. package/src/fields/pickerRows.spec.tsx +2 -0
  486. package/src/overlayGround.spec.ts +181 -0
  487. package/src/shared/choiceRowPress.ts +40 -0
  488. package/src/shared/overlayStack.tsx +5 -0
  489. package/types/AdaptivePopup/index.d.ts.map +1 -1
  490. package/types/Button/index.d.ts.map +1 -1
  491. package/types/FloatingPanel/compactFace.d.ts +21 -0
  492. package/types/FloatingPanel/compactFace.d.ts.map +1 -0
  493. package/types/FloatingPanel/index.d.ts +10 -0
  494. package/types/FloatingPanel/index.d.ts.map +1 -1
  495. package/types/FloatingPanel/index.native.d.ts +8 -1
  496. package/types/FloatingPanel/index.native.d.ts.map +1 -1
  497. package/types/FloatingPanel/pointAnchor.d.ts +29 -0
  498. package/types/FloatingPanel/pointAnchor.d.ts.map +1 -1
  499. package/types/InputParts/index.d.ts.map +1 -1
  500. package/types/fields/Checkbox/Checkbox.d.ts.map +1 -1
  501. package/types/fields/RadioGroup/index.d.ts.map +1 -1
  502. package/types/fields/Select/index.d.ts.map +1 -1
  503. package/types/fields/Switch/index.d.ts.map +1 -1
  504. package/types/shared/choiceRowPress.d.ts +40 -0
  505. package/types/shared/choiceRowPress.d.ts.map +1 -0
  506. package/types/shared/overlayStack.d.ts +2 -0
  507. package/types/shared/overlayStack.d.ts.map +1 -1
@@ -0,0 +1,183 @@
1
+ /**
2
+ * FZ-7830: on native a menu-faced FloatingPanel opens over its trigger (LC-112,
3
+ * the UIMenu pull-down) instead of as a bottom sheet, and an `auto` panel does
4
+ * so only inside another overlay, so a sheet never stacks on a sheet.
5
+ */
6
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
7
+ import { act } from "@testing-library/react";
8
+ import { useState, type ReactNode } from "react";
9
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
10
+ import { Text } from "tamagui";
11
+ import { OverlayStackProvider } from "../shared/overlayStack";
12
+ import type { CompactFace } from "./compactFace";
13
+ import { FloatingPanel } from "./index.native";
14
+ import { panelViewportPadding } from "./useFloatingPanel";
15
+
16
+ vi.mock("react-native-web", async (importOriginal) => {
17
+ const actual = await importOriginal<typeof import("react-native")>();
18
+ return {
19
+ ...actual,
20
+ ActionSheetIOS: undefined,
21
+ Modal: ({ children, visible }: { children: ReactNode; visible: boolean }) =>
22
+ visible ? children : null,
23
+ useWindowDimensions: () => ({ width: 390, height: 844, scale: 3, fontScale: 1 }),
24
+ };
25
+ });
26
+
27
+ let trigger = { x: 20, y: 240, width: 120, height: 44 };
28
+ beforeEach(() => {
29
+ vi.useFakeTimers();
30
+ trigger = { x: 20, y: 240, width: 120, height: 44 };
31
+ // RN-web's measureInWindow reads the node's client rect on a timer.
32
+ vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockImplementation(() => ({
33
+ x: trigger.x,
34
+ y: trigger.y,
35
+ left: trigger.x,
36
+ top: trigger.y,
37
+ width: trigger.width,
38
+ height: trigger.height,
39
+ right: trigger.x + trigger.width,
40
+ bottom: trigger.y + trigger.height,
41
+ toJSON: () => ({}),
42
+ }));
43
+ });
44
+ afterEach(() => {
45
+ vi.restoreAllMocks();
46
+ vi.useRealTimers();
47
+ });
48
+
49
+ function Menu({ face }: { face?: CompactFace }) {
50
+ const [open, setOpen] = useState(false);
51
+ return (
52
+ <FloatingPanel
53
+ open={open}
54
+ onOpenChange={setOpen}
55
+ compactFace={face}
56
+ triggerSizing="content"
57
+ contentPadding="none"
58
+ trigger={<Text>Stack actions</Text>}
59
+ triggerA11y={{ label: "Stack actions" }}
60
+ >
61
+ <Text>Stop</Text>
62
+ <Text>Restart</Text>
63
+ </FloatingPanel>
64
+ );
65
+ }
66
+
67
+ /** What a native SheetModal's OverlayWindow puts around its content. */
68
+ function InSheet({ children }: { children: ReactNode }) {
69
+ return <OverlayStackProvider zIndex={100_000}>{children}</OverlayStackProvider>;
70
+ }
71
+
72
+ function tap(target: Element) {
73
+ act(() => {
74
+ target.dispatchEvent(new MouseEvent("mousedown", { bubbles: true, button: 0 }));
75
+ target.dispatchEvent(new MouseEvent("mouseup", { bubbles: true, button: 0 }));
76
+ target.dispatchEvent(new MouseEvent("click", { bubbles: true, button: 0 }));
77
+ });
78
+ // measureInWindow answers on the next tick.
79
+ act(() => {
80
+ vi.advanceTimersByTime(1);
81
+ });
82
+ }
83
+
84
+ /** RN-web parks onLayout on the node for a ResizeObserver happy-dom never fires. */
85
+ function layout(node: Element, width: number, height: number) {
86
+ const onLayout = (node as unknown as { __reactLayoutHandler?: (event: unknown) => void })
87
+ .__reactLayoutHandler;
88
+ expect(onLayout).toBeTypeOf("function");
89
+ act(() => {
90
+ onLayout?.({ nativeEvent: { layout: { x: 0, y: 0, width, height } } });
91
+ });
92
+ }
93
+
94
+ const menu = () => document.querySelector<HTMLElement>('[data-testid="floating-panel-menu"]');
95
+ const sheet = () => document.querySelector('[data-testid="floating-panel-sheet"]');
96
+ const echo = () => document.querySelector('[data-testid="floating-panel-menu-echo"]');
97
+
98
+ describe("FloatingPanel native menu face (FZ-7830)", () => {
99
+ it("opens the menu face over the trigger at page level, never a sheet", () => {
100
+ const result = renderWithProviders(<Menu face="menu" />);
101
+ tap(result.getByRole("button", { name: "Stack actions" }));
102
+ const panel = menu();
103
+ expect(panel).not.toBeNull();
104
+ expect(sheet()).toBeNull();
105
+ expect(panel?.style.opacity).toBe("0");
106
+ layout(panel as HTMLElement, 200, 180);
107
+ expect(panel?.style.left).toBe("20px");
108
+ expect(panel?.style.top).toBe("240px");
109
+ expect(panel?.style.opacity).toBe("1");
110
+ });
111
+
112
+ it("repeats the trigger as the first row, in the trigger's own box", () => {
113
+ const result = renderWithProviders(<Menu face="menu" />);
114
+ tap(result.getByRole("button", { name: "Stack actions" }));
115
+ const row = echo() as HTMLElement;
116
+ expect(row).not.toBeNull();
117
+ expect(row.textContent).toBe("Stack actions");
118
+ expect(row.style.height).toBe("44px");
119
+ expect(row.getAttribute("aria-expanded")).toBe("true");
120
+ });
121
+
122
+ it("closes when the repeated trigger row is pressed", () => {
123
+ const result = renderWithProviders(<Menu face="menu" />);
124
+ tap(result.getByRole("button", { name: "Stack actions" }));
125
+ act(() => {
126
+ vi.advanceTimersByTime(1000);
127
+ });
128
+ tap(echo() as HTMLElement);
129
+ expect(menu()).toBeNull();
130
+ });
131
+
132
+ it("slides a trailing ⋯ menu back inside the padded window", () => {
133
+ trigger = { x: 330, y: 240, width: 44, height: 44 };
134
+ const result = renderWithProviders(<Menu face="menu" />);
135
+ tap(result.getByRole("button", { name: "Stack actions" }));
136
+ const panel = menu() as HTMLElement;
137
+ layout(panel, 200, 180);
138
+ expect(panel.style.left).toBe(`${390 - panelViewportPadding - 200}px`);
139
+ expect(panel.style.top).toBe("240px");
140
+ });
141
+
142
+ it("slides up from the bottom edge instead of running under it", () => {
143
+ trigger = { x: 20, y: 800, width: 120, height: 44 };
144
+ const result = renderWithProviders(<Menu face="menu" />);
145
+ tap(result.getByRole("button", { name: "Stack actions" }));
146
+ const panel = menu() as HTMLElement;
147
+ layout(panel, 200, 180);
148
+ const top = parseFloat(panel.style.top);
149
+ expect(top + 180).toBeLessThanOrEqual(844 - panelViewportPadding);
150
+ expect(top).toBeLessThan(800);
151
+ });
152
+
153
+ it("keeps the sheet at page level for the auto face", () => {
154
+ const result = renderWithProviders(<Menu face="auto" />);
155
+ tap(result.getByRole("button", { name: "Stack actions" }));
156
+ expect(sheet()).not.toBeNull();
157
+ expect(menu()).toBeNull();
158
+ });
159
+
160
+ it("opens the auto face over the trigger inside another overlay, never a second sheet", () => {
161
+ const result = renderWithProviders(
162
+ <InSheet>
163
+ <Menu face="auto" />
164
+ </InSheet>,
165
+ );
166
+ tap(result.getByRole("button", { name: "Stack actions" }));
167
+ expect(sheet()).toBeNull();
168
+ const panel = menu() as HTMLElement;
169
+ layout(panel, 200, 180);
170
+ expect(panel.style.top).toBe("240px");
171
+ });
172
+
173
+ it("leaves a panel without a face as a sheet, even inside an overlay", () => {
174
+ const result = renderWithProviders(
175
+ <InSheet>
176
+ <Menu />
177
+ </InSheet>,
178
+ );
179
+ tap(result.getByRole("button", { name: "Stack actions" }));
180
+ expect(sheet()).not.toBeNull();
181
+ expect(menu()).toBeNull();
182
+ });
183
+ });
@@ -0,0 +1,40 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { pickerCompactFace, resolveCompactFace, SHORT_LIST_MAX } from "./compactFace";
3
+
4
+ describe("resolveCompactFace (FZ-7830)", () => {
5
+ it("keeps the sheet by default, at page level and inside an overlay", () => {
6
+ expect(resolveCompactFace(undefined, false)).toBe("sheet");
7
+ expect(resolveCompactFace(undefined, true)).toBe("sheet");
8
+ expect(resolveCompactFace("sheet", true)).toBe("sheet");
9
+ });
10
+
11
+ it("opens a menu everywhere for the menu face", () => {
12
+ expect(resolveCompactFace("menu", false)).toBe("menu");
13
+ expect(resolveCompactFace("menu", true)).toBe("menu");
14
+ });
15
+
16
+ it("opens a menu only inside another overlay for the auto face", () => {
17
+ expect(resolveCompactFace("auto", false)).toBe("sheet");
18
+ expect(resolveCompactFace("auto", true)).toBe("menu");
19
+ });
20
+ });
21
+
22
+ describe("pickerCompactFace (FZ-7830)", () => {
23
+ it("opens a short list as a menu at every level", () => {
24
+ expect(SHORT_LIST_MAX).toBe(7);
25
+ expect(pickerCompactFace(1)).toBe("menu");
26
+ expect(pickerCompactFace(7)).toBe("menu");
27
+ expect(resolveCompactFace(pickerCompactFace(7), false)).toBe("menu");
28
+ });
29
+
30
+ it("keeps a long list's sheet at page level and opens it as a menu inside an overlay", () => {
31
+ expect(pickerCompactFace(8)).toBe("auto");
32
+ expect(resolveCompactFace(pickerCompactFace(8), false)).toBe("sheet");
33
+ expect(resolveCompactFace(pickerCompactFace(8), true)).toBe("menu");
34
+ });
35
+
36
+ it("keeps a searchable list's sheet at page level, however short", () => {
37
+ expect(pickerCompactFace(3, true)).toBe("auto");
38
+ expect(resolveCompactFace(pickerCompactFace(3, true), false)).toBe("sheet");
39
+ });
40
+ });
@@ -0,0 +1,32 @@
1
+ /**
2
+ * What a FloatingPanel becomes where it would otherwise be a bottom sheet:
3
+ * on native, and on the web at or below OVERLAY_BREAKPOINT.
4
+ *
5
+ * - `"sheet"`: the bottom sheet, wherever it opens.
6
+ * - `"menu"`: a menu over its trigger (LC-112) wherever it opens.
7
+ * - `"auto"`: the sheet at page level, the menu inside another overlay. A
8
+ * sheet over a sheet is the one thing a phone must never show (FZ-7830).
9
+ */
10
+ export type CompactFace = "sheet" | "menu" | "auto";
11
+
12
+ export function resolveCompactFace(
13
+ face: CompactFace | undefined,
14
+ insideOverlay: boolean,
15
+ ): "sheet" | "menu" {
16
+ if (face === "menu") return "menu";
17
+ if (face === "auto") return insideOverlay ? "menu" : "sheet";
18
+ return "sheet";
19
+ }
20
+
21
+ /** The longest list a picker opens as a menu over its trigger (FZ-7830). */
22
+ export const SHORT_LIST_MAX = 7;
23
+
24
+ /**
25
+ * A picker's face (FZ-7830, LC-112): a short list with no search opens as a
26
+ * menu over its trigger at every level, the iOS 14+ pull-down picker. A long or
27
+ * searchable list keeps the sheet at page level and opens as a scrolling menu
28
+ * inside another overlay.
29
+ */
30
+ export function pickerCompactFace(optionCount: number, searchable = false): CompactFace {
31
+ return !searchable && optionCount <= SHORT_LIST_MAX ? "menu" : "auto";
32
+ }
@@ -44,6 +44,13 @@
44
44
  * - Opening a Modal under the same finger can synthesize a backdrop press;
45
45
  * backdrop dismiss is armed a short delay after the present begins.
46
46
  *
47
+ * Menu face (`compactFace`, FZ-7830): instead of the sheet, a menu opens
48
+ * over the trigger (LC-112), its top start corner on the trigger's, the
49
+ * trigger echoed as its first row, sliding back inside the safe area where it
50
+ * would run off screen. DropdownMenu always opens this way (a UIMenu
51
+ * pull-down); Select opens this way for a short list, and for any list inside
52
+ * another overlay, so a sheet never stacks on a sheet.
53
+ *
47
54
  * ContextMenu (`openOn="contextmenu"`): long-press opens it. On a window wider
48
55
  * than OVERLAY_BREAKPOINT (a tablet) it opens at the long-press point, the
49
56
  * same free overlay the web draws at the pointer; a phone keeps the sheet,
@@ -83,12 +90,19 @@ import {
83
90
  motionDurationMs,
84
91
  } from "@multiplatform.one/theme";
85
92
  import { View, YStack } from "tamagui";
86
- import { useOverlayZIndex } from "../shared/overlayStack";
93
+ import { useInsideOverlay, useOverlayZIndex } from "../shared/overlayStack";
87
94
  import { OverlayWindow } from "../shared/OverlayWindow";
88
95
  import { t } from "../shared/t";
89
96
  import { useKeyboardInset } from "../shared/useKeyboardInset";
90
97
  import type { FloatingPanelProps } from "./index";
91
- import { placeAtPoint, type PanelBounds, type PanelPoint } from "./pointAnchor";
98
+ import { resolveCompactFace } from "./compactFace";
99
+ import {
100
+ placeAtPoint,
101
+ placeOverTrigger,
102
+ type PanelBounds,
103
+ type PanelPoint,
104
+ type TriggerRect,
105
+ } from "./pointAnchor";
92
106
  import { panelViewportPadding } from "./useFloatingPanel";
93
107
  import { TrailingActionOverlay, TriggerWithTrailingAction } from "./trailingAction";
94
108
 
@@ -142,11 +156,18 @@ export function FloatingPanel({
142
156
  triggerA11y,
143
157
  sheetFill,
144
158
  openOn = "press",
159
+ compactFace,
160
+ triggerRow,
161
+ triggerEcho = true,
145
162
  }: FloatingPanelProps) {
146
163
  // The panel floats over the page: it never inherits a painted ancestor.
147
164
  const { knobProps } = useResolvedKnobs({ painted: false });
148
165
  const windowZIndex = useOverlayZIndex("sheet");
149
- const children = <Surface painted={false}>{panelChildren}</Surface>;
166
+ const children = (
167
+ <Surface painted={false} elevated>
168
+ {panelChildren}
169
+ </Surface>
170
+ );
150
171
  const slideTransition = knobProps.motion.slide.transition;
151
172
  const enterDuration = motionDurationMs(slideTransition);
152
173
  const scrimDuration = motionDurationMs(knobProps.motion.scrim.transition);
@@ -181,6 +202,34 @@ export function FloatingPanel({
181
202
  );
182
203
  const isContextMenu = openOn === "contextmenu";
183
204
  const atPoint = isContextMenu && pressPoint !== null && windowWidth > OVERLAY_BREAKPOINT;
205
+ const insideOverlay = useInsideOverlay();
206
+ const asMenu = !isContextMenu && resolveCompactFace(compactFace, insideOverlay) === "menu";
207
+ const triggerRef = useRef<RNView | null>(null);
208
+ const [anchor, setAnchor] = useState<TriggerRect | null>(null);
209
+ // The trigger's window rect, read each time the menu opens: it may have
210
+ // moved (a scrolled sheet) since the last open.
211
+ useLayoutEffect(() => {
212
+ if (!asMenu || !open) {
213
+ setAnchor(null);
214
+ return;
215
+ }
216
+ const node = triggerRef.current as
217
+ | (RNView & {
218
+ measureInWindow?: (cb: (x: number, y: number, w: number, h: number) => void) => void;
219
+ })
220
+ | null;
221
+ let live = true;
222
+ if (typeof node?.measureInWindow === "function") {
223
+ node.measureInWindow((x, y, width, height) => {
224
+ if (live) setAnchor({ x, y, width, height });
225
+ });
226
+ } else {
227
+ setAnchor({ x: 0, y: 0, width: 0, height: 0 });
228
+ }
229
+ return () => {
230
+ live = false;
231
+ };
232
+ }, [asMenu, open]);
184
233
 
185
234
  const handleBackdropPress = useCallback(() => {
186
235
  if (backdropArmed) close();
@@ -473,6 +522,8 @@ export function FloatingPanel({
473
522
  return (
474
523
  <>
475
524
  <RNView
525
+ ref={triggerRef}
526
+ collapsable={false}
476
527
  style={{
477
528
  flexDirection: "row",
478
529
  alignItems: "center",
@@ -526,7 +577,29 @@ export function FloatingPanel({
526
577
  }}
527
578
  >
528
579
  <OverlayWindow zIndex={windowZIndex}>
529
- {atPoint && pressPoint ? (
580
+ {asMenu ? (
581
+ <TriggerMenuPanel
582
+ anchor={anchor}
583
+ bounds={{
584
+ top: topInset + panelViewportPadding,
585
+ left: (safeArea?.left ?? 0) + panelViewportPadding,
586
+ right: windowWidth - (safeArea?.right ?? 0) - panelViewportPadding,
587
+ bottom:
588
+ windowHeight -
589
+ Math.max(safeArea?.bottom ?? 0, keyboardInset) -
590
+ panelViewportPadding,
591
+ }}
592
+ echo={triggerEcho ? (triggerRow ?? trigger) : null}
593
+ echoLabel={triggerA11y?.label}
594
+ framePadding={framePadding}
595
+ frameGap={frameGap}
596
+ onBackdropPress={handleBackdropPress}
597
+ onClose={close}
598
+ >
599
+ {header}
600
+ {children}
601
+ </TriggerMenuPanel>
602
+ ) : atPoint && pressPoint ? (
530
603
  <PointPanel
531
604
  key={`${pressPoint.x},${pressPoint.y}`}
532
605
  point={pressPoint}
@@ -644,6 +717,100 @@ export function FloatingPanel({
644
717
  );
645
718
  }
646
719
 
720
+ /**
721
+ * The menu over its trigger (LC-112): measured once per open at its natural
722
+ * size, then placed on the trigger's window rect. The first row repeats the
723
+ * trigger in the trigger's own box, and pressing it closes the menu, as the
724
+ * web echo row does.
725
+ */
726
+ function TriggerMenuPanel({
727
+ anchor,
728
+ bounds,
729
+ echo,
730
+ echoLabel,
731
+ framePadding,
732
+ frameGap,
733
+ onBackdropPress,
734
+ onClose,
735
+ children,
736
+ }: {
737
+ anchor: TriggerRect | null;
738
+ bounds: PanelBounds;
739
+ echo: ReactNode;
740
+ echoLabel?: string;
741
+ framePadding: string;
742
+ frameGap: string | undefined;
743
+ onBackdropPress: () => void;
744
+ onClose: () => void;
745
+ children: ReactNode;
746
+ }) {
747
+ const { knobProps } = useResolvedKnobs({ painted: false });
748
+ const [size, setSize] = useState<{ width: number; height: number } | null>(null);
749
+ const placement =
750
+ anchor && size
751
+ ? placeOverTrigger({
752
+ trigger: anchor,
753
+ width: size.width,
754
+ height: size.height,
755
+ bounds,
756
+ rtl: I18nManager.isRTL,
757
+ })
758
+ : null;
759
+ return (
760
+ <RNView style={StyleSheet.absoluteFill}>
761
+ <Pressable
762
+ style={StyleSheet.absoluteFill}
763
+ onPress={onBackdropPress}
764
+ accessibilityRole="button"
765
+ accessibilityLabel={t("Close")}
766
+ />
767
+ <RNView
768
+ testID="floating-panel-menu"
769
+ onLayout={(e) => {
770
+ if (size) return;
771
+ const { width, height } = e.nativeEvent.layout;
772
+ if (width > 0 && height > 0) setSize({ width, height });
773
+ }}
774
+ style={{
775
+ position: "absolute",
776
+ left: placement?.left ?? bounds.left,
777
+ top: placement?.top ?? bounds.top,
778
+ minWidth: anchor?.width ?? 0,
779
+ maxWidth: bounds.right - bounds.left,
780
+ maxHeight: placement?.maxHeight ?? bounds.bottom - bounds.top,
781
+ opacity: placement ? 1 : 0,
782
+ }}
783
+ >
784
+ <YStack
785
+ {...knobProps.elevatedSurface}
786
+ flexShrink={1}
787
+ minHeight={0}
788
+ overflow="hidden"
789
+ onAccessibilityEscape={onClose}
790
+ >
791
+ {echo != null && anchor && anchor.height > 0 ? (
792
+ <Pressable
793
+ testID="floating-panel-menu-echo"
794
+ onPress={onClose}
795
+ accessibilityRole="button"
796
+ {...(echoLabel ? { accessibilityLabel: echoLabel } : undefined)}
797
+ aria-expanded
798
+ style={{ height: anchor.height, minWidth: anchor.width, justifyContent: "center" }}
799
+ >
800
+ <RNView pointerEvents="none">{echo}</RNView>
801
+ </Pressable>
802
+ ) : null}
803
+ <RNScrollView style={{ flexGrow: 0, flexShrink: 1 }} keyboardShouldPersistTaps="handled">
804
+ <YStack padding={framePadding} gap={frameGap}>
805
+ {children}
806
+ </YStack>
807
+ </RNScrollView>
808
+ </YStack>
809
+ </RNView>
810
+ </RNView>
811
+ );
812
+ }
813
+
647
814
  /**
648
815
  * The menu at the long-press point: measured once per open at its natural
649
816
  * size, then placed by the same rule as the web pointer menu. Later layouts
@@ -28,11 +28,13 @@ import { useReturnFocusOnClose, useSheetModalFocus } from "../shared/focusManage
28
28
  import { useSheetEscapeDismiss } from "../shared/useSheetEscapeDismiss";
29
29
  import { useFloatingPanel, panelViewportPadding } from "./useFloatingPanel";
30
30
  import type { PanelWidthMode } from "./useFloatingPanel";
31
- import { OverlayStackProvider, useOverlayZIndex } from "../shared/overlayStack";
31
+ import { OverlayStackProvider, useInsideOverlay, useOverlayZIndex } from "../shared/overlayStack";
32
+ import { resolveCompactFace, type CompactFace } from "./compactFace";
32
33
  import { isNestedPanelAction, type PanelActionEvent } from "./nestedAction";
33
34
  import { PanelPortal } from "./PanelPortal";
34
35
  import {
35
36
  contextMenuPoint,
37
+ placeOverTrigger,
36
38
  pointOpensUp,
37
39
  pointPanelLeft,
38
40
  referenceCornerPoint,
@@ -99,6 +101,15 @@ export interface FloatingPanelProps {
99
101
  * OVERLAY_BREAKPOINT), floating panel from `$sm` up.
100
102
  */
101
103
  sheet?: boolean;
104
+ /**
105
+ * What the panel becomes where it would be a bottom sheet (native, and web
106
+ * at or below 640). `"sheet"` (default) keeps the sheet; `"menu"` opens a
107
+ * menu over the trigger; `"auto"` keeps the sheet at page level and opens
108
+ * the menu inside another overlay, so a sheet never stacks on a sheet
109
+ * (FZ-7830). A menu inside an overlay slides back on screen instead of
110
+ * taking LC-139's collision sheet. An explicit `sheet` wins on the web.
111
+ */
112
+ compactFace?: CompactFace;
102
113
  /**
103
114
  * Sizing mode for the web floating panel.
104
115
  * - `"grow"` (default): opens from the trigger to the nearest viewport
@@ -435,19 +446,25 @@ export function FloatingPanel(props: FloatingPanelProps) {
435
446
  // the panel is already classified as keyboard-origin when focus moves in.
436
447
  if (isWeb) ensureKeyboardModalityTracking();
437
448
  const viewportGtSm = useViewportGtSm();
449
+ const insideOverlay = useInsideOverlay();
450
+ const compactMenu = resolveCompactFace(props.compactFace, insideOverlay) === "menu";
438
451
  // SSR and the hydration render use the same sheet structure. The viewport
439
452
  // snapshot switches to floating after hydration when the browser is wide.
440
- const shouldUseSheet = props.sheet ?? (!isWeb || !viewportGtSm);
453
+ const shouldUseSheet = props.sheet ?? (!isWeb || (!viewportGtSm && !compactMenu));
441
454
  // The panel floats over the page: its content never sits on a painted
442
455
  // ancestor, so a Card inside it paints as top-level.
443
456
  const panelProps = {
444
457
  ...props,
445
458
  cover: props.anchorMode ? props.anchorMode === "cover-trigger" : props.cover,
446
- children: <Surface painted={false}>{props.children}</Surface>,
459
+ children: (
460
+ <Surface painted={false} elevated>
461
+ {props.children}
462
+ </Surface>
463
+ ),
447
464
  };
448
465
 
449
466
  if (shouldUseSheet) return <FloatingPanelSheet {...panelProps} />;
450
- return <FloatingPanelWeb {...panelProps} />;
467
+ return <FloatingPanelWeb {...panelProps} clampCollisions={compactMenu && insideOverlay} />;
451
468
  }
452
469
 
453
470
  // ── Sheet (mobile / native / forced) ──────────────────────────
@@ -644,8 +661,9 @@ function FloatingPanelWeb({
644
661
  triggerEcho = true,
645
662
  triggerRow,
646
663
  anchorRect,
664
+ clampCollisions = false,
647
665
  ...sheetProps
648
- }: FloatingPanelProps) {
666
+ }: FloatingPanelProps & { clampCollisions?: boolean }) {
649
667
  const panelZIndex = useOverlayZIndex("dropdown");
650
668
  const [collisionSheet, setCollisionSheet] = useState(false);
651
669
  const isFill = sizing === "fill";
@@ -783,6 +801,8 @@ function FloatingPanelWeb({
783
801
  measured.height + firstActionHeight + bodyPadding + totalBorderWidth,
784
802
  )
785
803
  : totalContentHeight;
804
+ let placedTop = measured.top;
805
+ let placedLeft = left;
786
806
  if (
787
807
  measured.width > 0 &&
788
808
  measured.height > 0 &&
@@ -793,13 +813,36 @@ function FloatingPanelWeb({
793
813
  measured.top + Math.max(neededHeight, measured.height) >
794
814
  viewportBottom - panelViewportPadding)
795
815
  ) {
796
- dropdownElement.style.visibility = "hidden";
797
- setCollisionSheet(true);
798
- return;
816
+ if (!clampCollisions) {
817
+ dropdownElement.style.visibility = "hidden";
818
+ setCollisionSheet(true);
819
+ return;
820
+ }
821
+ // FZ-7830: inside another overlay the collision sheet would stack a
822
+ // sheet on a sheet, so the menu slides back on screen instead.
823
+ const placed = placeOverTrigger({
824
+ trigger: {
825
+ x: measured.left,
826
+ y: measured.top,
827
+ width: measured.width,
828
+ height: measured.height,
829
+ },
830
+ width,
831
+ height: neededHeight,
832
+ bounds: {
833
+ top: viewportTop + panelViewportPadding,
834
+ left: viewportLeft + panelViewportPadding,
835
+ right: viewportRight - panelViewportPadding,
836
+ bottom: viewportBottom - panelViewportPadding,
837
+ },
838
+ rtl,
839
+ });
840
+ placedTop = placed.top;
841
+ placedLeft = placed.left;
799
842
  }
800
- const top = measured.top - containingBlock.top;
801
- const cssLeft = left - containingBlock.left;
802
- const maxHeight = Math.max(0, viewportBottom - panelViewportPadding - measured.top);
843
+ const top = placedTop - containingBlock.top;
844
+ const cssLeft = placedLeft - containingBlock.left;
845
+ const maxHeight = Math.max(0, viewportBottom - panelViewportPadding - placedTop);
803
846
  dropdownElement.style.top = `${top}px`;
804
847
  dropdownElement.style.left = `${cssLeft}px`;
805
848
  dropdownElement.style.maxHeight = `${maxHeight}px`;
@@ -966,6 +1009,7 @@ function FloatingPanelWeb({
966
1009
  isContextMenu,
967
1010
  cover,
968
1011
  anchorRect,
1012
+ clampCollisions,
969
1013
  sheetProps.scrollable,
970
1014
  panel.placement,
971
1015
  panel.refs,