@multiplatform.one/forms 7.77.0 → 7.77.2

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 (429) hide show
  1. package/dist/cjs/Button/IconButtonGroup.cjs +45 -18
  2. package/dist/cjs/Button/IconButtonGroup.native.js +51 -20
  3. package/dist/cjs/Button/IconButtonGroup.native.js.map +1 -1
  4. package/dist/cjs/Button/circleGlyph.cjs +12 -2
  5. package/dist/cjs/Button/circleGlyph.native.js +12 -1
  6. package/dist/cjs/Button/circleGlyph.native.js.map +1 -1
  7. package/dist/cjs/Button/iconButtonGroupContext.cjs +7 -1
  8. package/dist/cjs/Button/iconButtonGroupContext.native.js +7 -1
  9. package/dist/cjs/Button/iconButtonGroupContext.native.js.map +1 -1
  10. package/dist/cjs/Button/index.cjs +3 -11
  11. package/dist/cjs/Button/index.native.js +3 -12
  12. package/dist/cjs/Button/index.native.js.map +1 -1
  13. package/dist/cjs/FloatingPanel/coverRect.cjs +50 -0
  14. package/dist/cjs/FloatingPanel/coverRect.native.js +54 -0
  15. package/dist/cjs/FloatingPanel/coverRect.native.js.map +1 -0
  16. package/dist/cjs/FloatingPanel/iconEcho.cjs +3 -1
  17. package/dist/cjs/FloatingPanel/iconEcho.native.js +3 -1
  18. package/dist/cjs/FloatingPanel/iconEcho.native.js.map +1 -1
  19. package/dist/cjs/FloatingPanel/index.cjs +27 -29
  20. package/dist/cjs/FloatingPanel/index.native.js +41 -15
  21. package/dist/cjs/FloatingPanel/index.native.js.map +1 -1
  22. package/dist/cjs/InputParts/index.cjs +5 -0
  23. package/dist/cjs/InputParts/index.native.js +7 -0
  24. package/dist/cjs/InputParts/index.native.js.map +1 -1
  25. package/dist/cjs/InputParts/keyboardAppearance.cjs +30 -0
  26. package/dist/cjs/InputParts/keyboardAppearance.native.js +33 -0
  27. package/dist/cjs/InputParts/keyboardAppearance.native.js.map +1 -0
  28. package/dist/cjs/fields/Duration/DurationWheel.cjs +34 -0
  29. package/dist/cjs/fields/Duration/DurationWheel.native.js +132 -0
  30. package/dist/cjs/fields/Duration/DurationWheel.native.js.map +1 -0
  31. package/dist/cjs/fields/Duration/durationMath.cjs +19 -1
  32. package/dist/cjs/fields/Duration/durationMath.native.js +19 -1
  33. package/dist/cjs/fields/Duration/durationMath.native.js.map +1 -1
  34. package/dist/cjs/fields/Duration/durationWheelTypes.cjs +18 -0
  35. package/dist/cjs/fields/Duration/durationWheelTypes.native.js +21 -0
  36. package/dist/cjs/fields/Duration/durationWheelTypes.native.js.map +1 -0
  37. package/dist/cjs/fields/Duration/index.cjs +30 -10
  38. package/dist/cjs/fields/Duration/index.native.js +32 -12
  39. package/dist/cjs/fields/Duration/index.native.js.map +1 -1
  40. package/dist/cjs/fields/Select/index.cjs +98 -30
  41. package/dist/cjs/fields/Select/index.native.js +122 -54
  42. package/dist/cjs/fields/Select/index.native.js.map +1 -1
  43. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.cjs +8 -7
  44. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js +8 -7
  45. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  46. package/dist/cjs/fields/nativeDateTime/osDateTimeIosDisplay.cjs +1 -1
  47. package/dist/cjs/fields/nativeDateTime/osDateTimeIosDisplay.native.js +1 -1
  48. package/dist/cjs/fields/nativeDateTime/osDateTimeIosDisplay.native.js.map +1 -1
  49. package/dist/cjs/fields/nativeDateTime/sheetKeyboard.cjs +1 -1
  50. package/dist/cjs/fields/nativeDateTime/sheetKeyboard.native.js +1 -1
  51. package/dist/cjs/fields/nativeDateTime/sheetKeyboard.native.js.map +1 -1
  52. package/dist/cjs/shared/floatingList.cjs +2 -3
  53. package/dist/cjs/shared/floatingList.native.js +2 -3
  54. package/dist/cjs/shared/floatingList.native.js.map +1 -1
  55. package/dist/esm/AdaptivePopup/index.native.js.map +1 -1
  56. package/dist/esm/Button/IconButtonGroup.mjs +47 -20
  57. package/dist/esm/Button/IconButtonGroup.mjs.map +1 -1
  58. package/dist/esm/Button/IconButtonGroup.native.js +53 -22
  59. package/dist/esm/Button/IconButtonGroup.native.js.map +1 -1
  60. package/dist/esm/Button/circleGlyph.mjs +9 -1
  61. package/dist/esm/Button/circleGlyph.mjs.map +1 -1
  62. package/dist/esm/Button/circleGlyph.native.js +10 -1
  63. package/dist/esm/Button/circleGlyph.native.js.map +1 -1
  64. package/dist/esm/Button/iconButtonGroupContext.mjs +5 -1
  65. package/dist/esm/Button/iconButtonGroupContext.mjs.map +1 -1
  66. package/dist/esm/Button/iconButtonGroupContext.native.js +5 -1
  67. package/dist/esm/Button/iconButtonGroupContext.native.js.map +1 -1
  68. package/dist/esm/Button/index.mjs +1 -9
  69. package/dist/esm/Button/index.mjs.map +1 -1
  70. package/dist/esm/Button/index.native.js +1 -10
  71. package/dist/esm/Button/index.native.js.map +1 -1
  72. package/dist/esm/Button/mediaPlate.native.js.map +1 -1
  73. package/dist/esm/Button/webGlass.native.js.map +1 -1
  74. package/dist/esm/Chip/index.native.js.map +1 -1
  75. package/dist/esm/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
  76. package/dist/esm/ContextualSaveBar/clientKnownIdentity.native.js.map +1 -1
  77. package/dist/esm/ContextualSaveBar/commitImmediateField.native.js.map +1 -1
  78. package/dist/esm/ContextualSaveBar/index.native.js.map +1 -1
  79. package/dist/esm/ContextualSaveBar/useUnsavedChangesGuard.native.js.map +1 -1
  80. package/dist/esm/ControlGroup/index.native.js.map +1 -1
  81. package/dist/esm/DescriptionList/index.native.js.map +1 -1
  82. package/dist/esm/ErrorSummary.native.js.map +1 -1
  83. package/dist/esm/FieldDisplay/editMode.native.js.map +1 -1
  84. package/dist/esm/FieldDisplay/formatters.native.js.map +1 -1
  85. package/dist/esm/FieldDisplay/index.native.js.map +1 -1
  86. package/dist/esm/FieldGroup.native.js.map +1 -1
  87. package/dist/esm/FloatingPanel/PanelHeader.native.js.map +1 -1
  88. package/dist/esm/FloatingPanel/RegularPanel.native.js.map +1 -1
  89. package/dist/esm/FloatingPanel/compactFace.native.js.map +1 -1
  90. package/dist/esm/FloatingPanel/containingBlock.native.js.map +1 -1
  91. package/dist/esm/FloatingPanel/coverRect.mjs +23 -0
  92. package/dist/esm/FloatingPanel/coverRect.mjs.map +1 -0
  93. package/dist/esm/FloatingPanel/coverRect.native.js +24 -0
  94. package/dist/esm/FloatingPanel/coverRect.native.js.map +1 -0
  95. package/dist/esm/FloatingPanel/echoContext.native.js.map +1 -1
  96. package/dist/esm/FloatingPanel/iconEcho.mjs +4 -2
  97. package/dist/esm/FloatingPanel/iconEcho.mjs.map +1 -1
  98. package/dist/esm/FloatingPanel/iconEcho.native.js +4 -2
  99. package/dist/esm/FloatingPanel/iconEcho.native.js.map +1 -1
  100. package/dist/esm/FloatingPanel/index.mjs +27 -29
  101. package/dist/esm/FloatingPanel/index.mjs.map +1 -1
  102. package/dist/esm/FloatingPanel/index.native.js +41 -15
  103. package/dist/esm/FloatingPanel/index.native.js.map +1 -1
  104. package/dist/esm/FloatingPanel/nestedAction.native.js.map +1 -1
  105. package/dist/esm/FloatingPanel/paintedBox.native.js.map +1 -1
  106. package/dist/esm/FloatingPanel/panelWidth.native.js.map +1 -1
  107. package/dist/esm/FloatingPanel/pointAnchor.native.js.map +1 -1
  108. package/dist/esm/FloatingPanel/regularPlacement.native.js.map +1 -1
  109. package/dist/esm/FloatingPanel/trailingAction.native.js.map +1 -1
  110. package/dist/esm/FloatingPanel/useFloatingPanel.native.js.map +1 -1
  111. package/dist/esm/Form/index.native.js.map +1 -1
  112. package/dist/esm/Form/submissionController.native.js.map +1 -1
  113. package/dist/esm/Form/validateOn.native.js.map +1 -1
  114. package/dist/esm/FormGrid.native.js.map +1 -1
  115. package/dist/esm/FormSection.native.js.map +1 -1
  116. package/dist/esm/InputParts/PasswordReveal.native.js.map +1 -1
  117. package/dist/esm/InputParts/index.mjs +6 -1
  118. package/dist/esm/InputParts/index.mjs.map +1 -1
  119. package/dist/esm/InputParts/index.native.js +8 -1
  120. package/dist/esm/InputParts/index.native.js.map +1 -1
  121. package/dist/esm/InputParts/keyboardAppearance.mjs +5 -0
  122. package/dist/esm/InputParts/keyboardAppearance.mjs.map +1 -0
  123. package/dist/esm/InputParts/keyboardAppearance.native.js +5 -0
  124. package/dist/esm/InputParts/keyboardAppearance.native.js.map +1 -0
  125. package/dist/esm/Label/index.native.js.map +1 -1
  126. package/dist/esm/MediaPicker/base64.native.js.map +1 -1
  127. package/dist/esm/MediaPicker/payload.native.js.map +1 -1
  128. package/dist/esm/MediaPicker/types.native.js.map +1 -1
  129. package/dist/esm/MediaPicker/useMediaPicker.native.js.map +1 -1
  130. package/dist/esm/Skeleton/index.native.js.map +1 -1
  131. package/dist/esm/Spinner/SpinnerGlyph.native.js.map +1 -1
  132. package/dist/esm/Spinner/spinnerSize.native.js.map +1 -1
  133. package/dist/esm/Table/index.native.js.map +1 -1
  134. package/dist/esm/Wheel/haptic.native.js.map +1 -1
  135. package/dist/esm/Wheel/index.native.js.map +1 -1
  136. package/dist/esm/Wheel/wheelShared.native.js.map +1 -1
  137. package/dist/esm/actionLabel.native.js.map +1 -1
  138. package/dist/esm/fieldDefaults.native.js.map +1 -1
  139. package/dist/esm/fieldLayout.native.js.map +1 -1
  140. package/dist/esm/fields/Barcode/BarcodePreview.native.js.map +1 -1
  141. package/dist/esm/fields/Barcode/code128.native.js.map +1 -1
  142. package/dist/esm/fields/Barcode/index.native.js.map +1 -1
  143. package/dist/esm/fields/Barcode/qr.native.js.map +1 -1
  144. package/dist/esm/fields/Barcode/scannerTypes.native.js.map +1 -1
  145. package/dist/esm/fields/Checkbox/Checkbox.native.js.map +1 -1
  146. package/dist/esm/fields/Checkbox/CheckboxBox.native.js.map +1 -1
  147. package/dist/esm/fields/Checkbox/CheckboxCard.native.js.map +1 -1
  148. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  149. package/dist/esm/fields/Checkbox/CheckboxGroup.native.js.map +1 -1
  150. package/dist/esm/fields/Checkbox/checkboxGroupContext.native.js.map +1 -1
  151. package/dist/esm/fields/Checkbox/index.native.js.map +1 -1
  152. package/dist/esm/fields/ColorPicker/SystemColorField.native.js.map +1 -1
  153. package/dist/esm/fields/ColorPicker/index.native.js.map +1 -1
  154. package/dist/esm/fields/ColorPicker/parts.native.js.map +1 -1
  155. package/dist/esm/fields/ColorPicker/systemColorWell.gnome.native.js.map +1 -1
  156. package/dist/esm/fields/Combobox/authorOptions.native.js.map +1 -1
  157. package/dist/esm/fields/Combobox/index.native.js.map +1 -1
  158. package/dist/esm/fields/DatePicker/Calendar.native.js.map +1 -1
  159. package/dist/esm/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  160. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  161. package/dist/esm/fields/DatePicker/MonthPicker.native.js.map +1 -1
  162. package/dist/esm/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  163. package/dist/esm/fields/DatePicker/catalog.native.js.map +1 -1
  164. package/dist/esm/fields/DatePicker/fieldValueSync.native.js.map +1 -1
  165. package/dist/esm/fields/DatePicker/parts.native.js.map +1 -1
  166. package/dist/esm/fields/DatePicker/utils.native.js.map +1 -1
  167. package/dist/esm/fields/Duration/DurationWheel.mjs +8 -0
  168. package/dist/esm/fields/Duration/DurationWheel.mjs.map +1 -0
  169. package/dist/esm/fields/Duration/DurationWheel.native.js +103 -0
  170. package/dist/esm/fields/Duration/DurationWheel.native.js.map +1 -0
  171. package/dist/esm/fields/Duration/durationMath.mjs +16 -1
  172. package/dist/esm/fields/Duration/durationMath.mjs.map +1 -1
  173. package/dist/esm/fields/Duration/durationMath.native.js +16 -1
  174. package/dist/esm/fields/Duration/durationMath.native.js.map +1 -1
  175. package/dist/esm/fields/Duration/durationWheelTypes.mjs +2 -0
  176. package/dist/esm/fields/Duration/durationWheelTypes.mjs.map +1 -0
  177. package/dist/esm/fields/Duration/durationWheelTypes.native.js +2 -0
  178. package/dist/esm/fields/Duration/durationWheelTypes.native.js.map +1 -0
  179. package/dist/esm/fields/Duration/index.mjs +28 -11
  180. package/dist/esm/fields/Duration/index.mjs.map +1 -1
  181. package/dist/esm/fields/Duration/index.native.js +30 -13
  182. package/dist/esm/fields/Duration/index.native.js.map +1 -1
  183. package/dist/esm/fields/FileUpload/filePickerTypes.native.js.map +1 -1
  184. package/dist/esm/fields/FileUpload/index.native.js.map +1 -1
  185. package/dist/esm/fields/FileUpload/nativePickerLoader.native.js.map +1 -1
  186. package/dist/esm/fields/Geolocation/expoMapsLoader.native.js.map +1 -1
  187. package/dist/esm/fields/Geolocation/geoValue.native.js.map +1 -1
  188. package/dist/esm/fields/Geolocation/geocoder.native.js.map +1 -1
  189. package/dist/esm/fields/Geolocation/geocoderContext.native.js.map +1 -1
  190. package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
  191. package/dist/esm/fields/Geolocation/mapMath.native.js.map +1 -1
  192. package/dist/esm/fields/Geolocation/mapTypes.native.js.map +1 -1
  193. package/dist/esm/fields/Geolocation/nativeSearchFocus.native.js.map +1 -1
  194. package/dist/esm/fields/Geolocation/photonGeocoder.native.js.map +1 -1
  195. package/dist/esm/fields/Icon/drawnSet.native.js.map +1 -1
  196. package/dist/esm/fields/Icon/index.native.js.map +1 -1
  197. package/dist/esm/fields/ImageField/index.native.js.map +1 -1
  198. package/dist/esm/fields/Input/index.native.js.map +1 -1
  199. package/dist/esm/fields/MentionInput/index.native.js.map +1 -1
  200. package/dist/esm/fields/OTPInput/index.native.js.map +1 -1
  201. package/dist/esm/fields/OTPInput/otpCellCss.native.js.map +1 -1
  202. package/dist/esm/fields/PhoneInput/dialCodes.native.js.map +1 -1
  203. package/dist/esm/fields/PhoneInput/index.native.js.map +1 -1
  204. package/dist/esm/fields/PhoneInput/phone.native.js.map +1 -1
  205. package/dist/esm/fields/PhoneInput/regionNames.native.js.map +1 -1
  206. package/dist/esm/fields/Progress/index.native.js.map +1 -1
  207. package/dist/esm/fields/RadioGroup/index.native.js.map +1 -1
  208. package/dist/esm/fields/Rating/index.native.js.map +1 -1
  209. package/dist/esm/fields/Rating/ratingMath.native.js.map +1 -1
  210. package/dist/esm/fields/Rating/types.native.js.map +1 -1
  211. package/dist/esm/fields/SearchInput/index.native.js.map +1 -1
  212. package/dist/esm/fields/Select/InlineChoices.native.js.map +1 -1
  213. package/dist/esm/fields/Select/SheetPickerRow.native.js.map +1 -1
  214. package/dist/esm/fields/Select/index.mjs +98 -30
  215. package/dist/esm/fields/Select/index.mjs.map +1 -1
  216. package/dist/esm/fields/Select/index.native.js +122 -54
  217. package/dist/esm/fields/Select/index.native.js.map +1 -1
  218. package/dist/esm/fields/Select/shouldInlineChoices.native.js.map +1 -1
  219. package/dist/esm/fields/Signature/index.native.js.map +1 -1
  220. package/dist/esm/fields/Slider/index.native.js.map +1 -1
  221. package/dist/esm/fields/Slider/jumpMotion.native.js.map +1 -1
  222. package/dist/esm/fields/Stepper/index.native.js.map +1 -1
  223. package/dist/esm/fields/Stepper/resolveStepperPlacement.native.js.map +1 -1
  224. package/dist/esm/fields/Switch/footprint.native.js.map +1 -1
  225. package/dist/esm/fields/Switch/index.native.js.map +1 -1
  226. package/dist/esm/fields/TextArea/index.native.js.map +1 -1
  227. package/dist/esm/fields/TimePicker/catalog.native.js.map +1 -1
  228. package/dist/esm/fields/TimePicker/parts.native.js.map +1 -1
  229. package/dist/esm/fields/TimeRangeScrubber/geometry.native.js.map +1 -1
  230. package/dist/esm/fields/TimeRangeScrubber/index.native.js.map +1 -1
  231. package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
  232. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs +8 -7
  233. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
  234. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js +8 -7
  235. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  236. package/dist/esm/fields/nativeDateTime/dateTimePickerLoader.native.js.map +1 -1
  237. package/dist/esm/fields/nativeDateTime/osDateTimeIosDisplay.mjs +1 -1
  238. package/dist/esm/fields/nativeDateTime/osDateTimeIosDisplay.mjs.map +1 -1
  239. package/dist/esm/fields/nativeDateTime/osDateTimeIosDisplay.native.js +1 -1
  240. package/dist/esm/fields/nativeDateTime/osDateTimeIosDisplay.native.js.map +1 -1
  241. package/dist/esm/fields/nativeDateTime/sheetKeyboard.mjs +1 -1
  242. package/dist/esm/fields/nativeDateTime/sheetKeyboard.mjs.map +1 -1
  243. package/dist/esm/fields/nativeDateTime/sheetKeyboard.native.js +1 -1
  244. package/dist/esm/fields/nativeDateTime/sheetKeyboard.native.js.map +1 -1
  245. package/dist/esm/fields/nativeSelect.native.js.map +1 -1
  246. package/dist/esm/fields/selectedOrder.native.js.map +1 -1
  247. package/dist/esm/formSpacing.native.js.map +1 -1
  248. package/dist/esm/hooks/useFocusManagement.native.js.map +1 -1
  249. package/dist/esm/index.native.js.map +1 -1
  250. package/dist/esm/keyboard/chain.native.js.map +1 -1
  251. package/dist/esm/keyboard/index.native.js.map +1 -1
  252. package/dist/esm/keyboard/types.native.js.map +1 -1
  253. package/dist/esm/requiredMarking.native.js.map +1 -1
  254. package/dist/esm/shared/TimeColumn.native.js.map +1 -1
  255. package/dist/esm/shared/capabilityPreflight.native.js.map +1 -1
  256. package/dist/esm/shared/choiceRowPress.native.js.map +1 -1
  257. package/dist/esm/shared/colorRamps.native.js.map +1 -1
  258. package/dist/esm/shared/devWarn.native.js.map +1 -1
  259. package/dist/esm/shared/fieldRowContext.native.js.map +1 -1
  260. package/dist/esm/shared/floatingList.mjs +2 -3
  261. package/dist/esm/shared/floatingList.mjs.map +1 -1
  262. package/dist/esm/shared/floatingList.native.js +2 -3
  263. package/dist/esm/shared/floatingList.native.js.map +1 -1
  264. package/dist/esm/shared/focusManagement.native.js.map +1 -1
  265. package/dist/esm/shared/groupContext.native.js.map +1 -1
  266. package/dist/esm/shared/i18n.native.js.map +1 -1
  267. package/dist/esm/shared/instantMotion.native.js.map +1 -1
  268. package/dist/esm/shared/nativeA11y.native.js.map +1 -1
  269. package/dist/esm/shared/nativeAutoFocus.native.js.map +1 -1
  270. package/dist/esm/shared/overlaySizeClass.native.js.map +1 -1
  271. package/dist/esm/shared/overlayStack.native.js.map +1 -1
  272. package/dist/esm/shared/panelPortal.native.js.map +1 -1
  273. package/dist/esm/shared/pickerTriggerContract.native.js.map +1 -1
  274. package/dist/esm/shared/pressSlopProps.native.js.map +1 -1
  275. package/dist/esm/shared/restoreRetries.native.js.map +1 -1
  276. package/dist/esm/shared/sheetNavigation.native.js.map +1 -1
  277. package/dist/esm/shared/systemControlModules.gnome.native.js.map +1 -1
  278. package/dist/esm/shared/systemControls.native.js.map +1 -1
  279. package/dist/esm/shared/t.native.js.map +1 -1
  280. package/dist/esm/shared/tableCellContext.native.js.map +1 -1
  281. package/dist/esm/shared/useDragScroll.native.js.map +1 -1
  282. package/dist/esm/shared/useKeyboardInset.native.js.map +1 -1
  283. package/dist/esm/shared/useSheetEscapeDismiss.native.js.map +1 -1
  284. package/dist/esm/shared/useWheelIncrement.native.js.map +1 -1
  285. package/dist/esm/shared/utils.native.js.map +1 -1
  286. package/dist/esm/shared/zIndex.native.js.map +1 -1
  287. package/dist/esm/standardActions.native.js.map +1 -1
  288. package/dist/esm/themedPrimitives.native.js.map +1 -1
  289. package/dist/esm/types.native.js.map +1 -1
  290. package/dist/esm/utils/LinkCell.native.js.map +1 -1
  291. package/dist/jsx/Button/IconButtonGroup.mjs +47 -20
  292. package/dist/jsx/Button/IconButtonGroup.mjs.map +1 -1
  293. package/dist/jsx/Button/IconButtonGroup.native.js +51 -20
  294. package/dist/jsx/Button/IconButtonGroup.native.js.map +1 -1
  295. package/dist/jsx/Button/circleGlyph.mjs +9 -1
  296. package/dist/jsx/Button/circleGlyph.mjs.map +1 -1
  297. package/dist/jsx/Button/circleGlyph.native.js +12 -1
  298. package/dist/jsx/Button/circleGlyph.native.js.map +1 -1
  299. package/dist/jsx/Button/iconButtonGroupContext.mjs +5 -1
  300. package/dist/jsx/Button/iconButtonGroupContext.mjs.map +1 -1
  301. package/dist/jsx/Button/iconButtonGroupContext.native.js +7 -1
  302. package/dist/jsx/Button/iconButtonGroupContext.native.js.map +1 -1
  303. package/dist/jsx/Button/index.mjs +1 -9
  304. package/dist/jsx/Button/index.mjs.map +1 -1
  305. package/dist/jsx/Button/index.native.js +3 -12
  306. package/dist/jsx/Button/index.native.js.map +1 -1
  307. package/dist/jsx/FloatingPanel/coverRect.mjs +23 -0
  308. package/dist/jsx/FloatingPanel/coverRect.mjs.map +1 -0
  309. package/dist/jsx/FloatingPanel/coverRect.native.js +54 -0
  310. package/dist/jsx/FloatingPanel/coverRect.native.js.map +1 -0
  311. package/dist/jsx/FloatingPanel/iconEcho.mjs +4 -2
  312. package/dist/jsx/FloatingPanel/iconEcho.mjs.map +1 -1
  313. package/dist/jsx/FloatingPanel/iconEcho.native.js +3 -1
  314. package/dist/jsx/FloatingPanel/iconEcho.native.js.map +1 -1
  315. package/dist/jsx/FloatingPanel/index.mjs +27 -29
  316. package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
  317. package/dist/jsx/FloatingPanel/index.native.js +41 -15
  318. package/dist/jsx/FloatingPanel/index.native.js.map +1 -1
  319. package/dist/jsx/InputParts/index.mjs +6 -1
  320. package/dist/jsx/InputParts/index.mjs.map +1 -1
  321. package/dist/jsx/InputParts/index.native.js +7 -0
  322. package/dist/jsx/InputParts/index.native.js.map +1 -1
  323. package/dist/jsx/InputParts/keyboardAppearance.mjs +5 -0
  324. package/dist/jsx/InputParts/keyboardAppearance.mjs.map +1 -0
  325. package/dist/jsx/InputParts/keyboardAppearance.native.js +33 -0
  326. package/dist/jsx/InputParts/keyboardAppearance.native.js.map +1 -0
  327. package/dist/jsx/fields/Duration/DurationWheel.mjs +8 -0
  328. package/dist/jsx/fields/Duration/DurationWheel.mjs.map +1 -0
  329. package/dist/jsx/fields/Duration/DurationWheel.native.js +132 -0
  330. package/dist/jsx/fields/Duration/DurationWheel.native.js.map +1 -0
  331. package/dist/jsx/fields/Duration/durationMath.mjs +16 -1
  332. package/dist/jsx/fields/Duration/durationMath.mjs.map +1 -1
  333. package/dist/jsx/fields/Duration/durationMath.native.js +19 -1
  334. package/dist/jsx/fields/Duration/durationMath.native.js.map +1 -1
  335. package/dist/jsx/fields/Duration/durationWheelTypes.mjs +2 -0
  336. package/dist/jsx/fields/Duration/durationWheelTypes.mjs.map +1 -0
  337. package/dist/jsx/fields/Duration/durationWheelTypes.native.js +21 -0
  338. package/dist/jsx/fields/Duration/durationWheelTypes.native.js.map +1 -0
  339. package/dist/jsx/fields/Duration/index.mjs +28 -11
  340. package/dist/jsx/fields/Duration/index.mjs.map +1 -1
  341. package/dist/jsx/fields/Duration/index.native.js +32 -12
  342. package/dist/jsx/fields/Duration/index.native.js.map +1 -1
  343. package/dist/jsx/fields/Select/index.mjs +98 -30
  344. package/dist/jsx/fields/Select/index.mjs.map +1 -1
  345. package/dist/jsx/fields/Select/index.native.js +122 -54
  346. package/dist/jsx/fields/Select/index.native.js.map +1 -1
  347. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs +8 -7
  348. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
  349. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js +8 -7
  350. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  351. package/dist/jsx/fields/nativeDateTime/osDateTimeIosDisplay.mjs +1 -1
  352. package/dist/jsx/fields/nativeDateTime/osDateTimeIosDisplay.mjs.map +1 -1
  353. package/dist/jsx/fields/nativeDateTime/osDateTimeIosDisplay.native.js +1 -1
  354. package/dist/jsx/fields/nativeDateTime/sheetKeyboard.mjs +1 -1
  355. package/dist/jsx/fields/nativeDateTime/sheetKeyboard.mjs.map +1 -1
  356. package/dist/jsx/fields/nativeDateTime/sheetKeyboard.native.js +1 -1
  357. package/dist/jsx/fields/nativeDateTime/sheetKeyboard.native.js.map +1 -1
  358. package/dist/jsx/index.native.js.map +1 -1
  359. package/dist/jsx/shared/floatingList.mjs +2 -3
  360. package/dist/jsx/shared/floatingList.mjs.map +1 -1
  361. package/dist/jsx/shared/floatingList.native.js +2 -3
  362. package/dist/jsx/shared/floatingList.native.js.map +1 -1
  363. package/package.json +8 -8
  364. package/src/Button/IconButtonGroup.spec.tsx +20 -0
  365. package/src/Button/IconButtonGroup.tsx +60 -25
  366. package/src/Button/circleGlyph.ts +18 -0
  367. package/src/Button/iconButtonGroupContext.ts +25 -0
  368. package/src/Button/index.tsx +2 -20
  369. package/src/FloatingPanel/FloatingPanel.iconEcho.spec.tsx +61 -1
  370. package/src/FloatingPanel/FloatingPanel.menuFace.native.spec.tsx +104 -0
  371. package/src/FloatingPanel/coverRect.ts +42 -0
  372. package/src/FloatingPanel/iconEcho.tsx +9 -3
  373. package/src/FloatingPanel/index.native.tsx +63 -18
  374. package/src/FloatingPanel/index.tsx +38 -35
  375. package/src/InputParts/index.tsx +6 -0
  376. package/src/InputParts/keyboardAppearance.spec.ts +12 -0
  377. package/src/InputParts/keyboardAppearance.ts +4 -0
  378. package/src/fields/Duration/Duration.spec.tsx +19 -10
  379. package/src/fields/Duration/Duration.wheel.native.spec.tsx +98 -0
  380. package/src/fields/Duration/DurationWheel.native.tsx +101 -0
  381. package/src/fields/Duration/DurationWheel.tsx +11 -0
  382. package/src/fields/Duration/durationMath.spec.ts +43 -0
  383. package/src/fields/Duration/durationMath.ts +31 -0
  384. package/src/fields/Duration/durationWheelTypes.ts +18 -0
  385. package/src/fields/Duration/index.tsx +58 -27
  386. package/src/fields/Select/Select.containingBlock.spec.tsx +88 -12
  387. package/src/fields/Select/Select.stories.tsx +74 -0
  388. package/src/fields/Select/index.tsx +113 -44
  389. package/src/fields/nativeDateTime/OsDateTimeSheet.countdown.native.spec.tsx +121 -0
  390. package/src/fields/nativeDateTime/OsDateTimeSheet.spec.ts +4 -0
  391. package/src/fields/nativeDateTime/OsDateTimeSheet.tsx +14 -9
  392. package/src/fields/nativeDateTime/osDateTimeIosDisplay.ts +3 -3
  393. package/src/fields/nativeDateTime/sheetKeyboard.spec.ts +6 -0
  394. package/src/fields/nativeDateTime/sheetKeyboard.ts +2 -2
  395. package/src/shared/floatingList.tsx +1 -4
  396. package/types/Button/IconButtonGroup.d.ts.map +1 -1
  397. package/types/Button/circleGlyph.d.ts +12 -0
  398. package/types/Button/circleGlyph.d.ts.map +1 -1
  399. package/types/Button/iconButtonGroupContext.d.ts +19 -0
  400. package/types/Button/iconButtonGroupContext.d.ts.map +1 -1
  401. package/types/Button/index.d.ts +2 -9
  402. package/types/Button/index.d.ts.map +1 -1
  403. package/types/FloatingPanel/coverRect.d.ts +25 -0
  404. package/types/FloatingPanel/coverRect.d.ts.map +1 -0
  405. package/types/FloatingPanel/index.d.ts +1 -6
  406. package/types/FloatingPanel/index.d.ts.map +1 -1
  407. package/types/FloatingPanel/index.native.d.ts.map +1 -1
  408. package/types/InputParts/index.d.ts.map +1 -1
  409. package/types/InputParts/keyboardAppearance.d.ts +3 -0
  410. package/types/InputParts/keyboardAppearance.d.ts.map +1 -0
  411. package/types/fields/Duration/DurationWheel.d.ts +5 -0
  412. package/types/fields/Duration/DurationWheel.d.ts.map +1 -0
  413. package/types/fields/Duration/DurationWheel.native.d.ts +5 -0
  414. package/types/fields/Duration/DurationWheel.native.d.ts.map +1 -0
  415. package/types/fields/Duration/durationMath.d.ts +13 -0
  416. package/types/fields/Duration/durationMath.d.ts.map +1 -1
  417. package/types/fields/Duration/durationWheelTypes.d.ts +18 -0
  418. package/types/fields/Duration/durationWheelTypes.d.ts.map +1 -0
  419. package/types/fields/Duration/index.d.ts +8 -3
  420. package/types/fields/Duration/index.d.ts.map +1 -1
  421. package/types/fields/Select/index.d.ts.map +1 -1
  422. package/types/fields/nativeDateTime/OsDateTimeSheet.d.ts +1 -1
  423. package/types/fields/nativeDateTime/OsDateTimeSheet.d.ts.map +1 -1
  424. package/types/fields/nativeDateTime/osDateTimeIosDisplay.d.ts +2 -2
  425. package/types/fields/nativeDateTime/osDateTimeIosDisplay.d.ts.map +1 -1
  426. package/types/fields/nativeDateTime/sheetKeyboard.d.ts +1 -1
  427. package/types/fields/nativeDateTime/sheetKeyboard.d.ts.map +1 -1
  428. package/types/shared/floatingList.d.ts +1 -3
  429. package/types/shared/floatingList.d.ts.map +1 -1
@@ -539,3 +539,77 @@ export const PhoneLists: Story = {
539
539
  </YStack>
540
540
  ),
541
541
  };
542
+
543
+ const cityOptions: SelectOption[] = [
544
+ "Honolulu",
545
+ "Anchorage",
546
+ "Los Angeles",
547
+ "Denver",
548
+ "Chicago",
549
+ "New York",
550
+ "Halifax",
551
+ "St. John's",
552
+ "São Paulo",
553
+ "Buenos Aires",
554
+ "Nuuk",
555
+ "Azores",
556
+ "Reykjavik",
557
+ "London",
558
+ "Lisbon",
559
+ "Paris",
560
+ "Berlin",
561
+ "Rome",
562
+ "Helsinki",
563
+ "Athens",
564
+ "Cairo",
565
+ "Istanbul",
566
+ "Moscow",
567
+ "Dubai",
568
+ "Karachi",
569
+ "Kolkata",
570
+ "Kathmandu",
571
+ "Dhaka",
572
+ "Bangkok",
573
+ "Jakarta",
574
+ "Singapore",
575
+ "Shanghai",
576
+ "Seoul",
577
+ "Tokyo",
578
+ "Adelaide",
579
+ "Sydney",
580
+ "Nouméa",
581
+ "Auckland",
582
+ "Chatham",
583
+ "Kiritimati",
584
+ ].map((label) => ({ value: label.toLowerCase(), label }));
585
+
586
+ /**
587
+ * LC-112 cover and scroll (FZ-8463, Clay's pick on rv_485ae88062c1a2eb): a
588
+ * list that doesn't fit below its field covers the field and grows toward
589
+ * the side with more room, to the safe screen edge, then scrolls with the
590
+ * checked row on the field. `spaceAbove` moves the field: 880 sits it low on
591
+ * an iPad, 0 high, 440 mid. `count` trims the list (seven or fewer opens a
592
+ * menu at phone width, where a longer one opens its sheet).
593
+ */
594
+ export const LowOnPage: StoryObj<{ spaceAbove: number; count: number }> = {
595
+ args: { spaceAbove: 880, count: cityOptions.length },
596
+ argTypes: {
597
+ spaceAbove: { control: { type: "number", min: 0, step: 40 } },
598
+ count: { control: { type: "number", min: 1, max: cityOptions.length } },
599
+ },
600
+ render: ({ spaceAbove, count }) => {
601
+ const options = cityOptions.slice(0, count);
602
+ return (
603
+ <YStack padding="$4" gap="$4">
604
+ <Paragraph>Account settings</Paragraph>
605
+ <Select label="Role" options={roleOptions} defaultValue={roleOptions[0].value} />
606
+ <YStack height={spaceAbove} />
607
+ <Select
608
+ label="Time zone"
609
+ options={options}
610
+ defaultValue={options[Math.floor(options.length / 2)]?.value}
611
+ />
612
+ </YStack>
613
+ );
614
+ },
615
+ };
@@ -630,10 +630,14 @@ function FloatingSelectCore({
630
630
  const growUpOnlyRef = useRef(false);
631
631
  const growDownOnlyRef = useRef(false);
632
632
  const lastScrollTopRef = useRef(0);
633
- // LC-112 drop-up (FZ-8438 r3): a field too low for its list opens upward,
634
- // the panel's bottom edge on the field's, the echo its last row.
635
- const dropUpRef = useRef(false);
636
- const [dropUp, setDropUp] = useState(false);
633
+ // LC-112 cover and scroll (FZ-8463): a list that doesn't fit below its
634
+ // field covers the field with no echo row and grows toward the side with
635
+ // more room, then scrolls.
636
+ const coverScrollRef = useRef(false);
637
+ const [coverScroll, setCoverScroll] = useState(false);
638
+ const growsUpRef = useRef(false);
639
+ const coverTrimRef = useRef(0);
640
+ const echoed = !beside && !coverScroll;
637
641
 
638
642
  const repositionRef = useRef<(() => void) | null>(null);
639
643
 
@@ -653,7 +657,10 @@ function FloatingSelectCore({
653
657
  growDownOnlyRef.current = false;
654
658
  lastScrollTopRef.current = 0;
655
659
  programmaticScrollRef.current = 0;
656
- dropUpRef.current = false;
660
+ coverScrollRef.current = false;
661
+ growsUpRef.current = false;
662
+ coverTrimRef.current = 0;
663
+ setCoverScroll(false);
657
664
  },
658
665
  panelWidth,
659
666
  });
@@ -740,21 +747,97 @@ function FloatingSelectCore({
740
747
  const totalContentHeight = scrollContentHeight + totalBorderWidth;
741
748
 
742
749
  // LC-112 seamless cover (FZ-8438): the panel's top edge is the trigger's,
743
- // the trigger echoed as its first row, the list below it. A field too low
744
- // for its list, with more room above it, opens upward instead: the
745
- // panel's bottom edge on the field's bottom edge and the echo its last
746
- // row, so the echo still sits on the field (FZ-8438 r3).
750
+ // the trigger echoed as its first row, the list below it. A list that
751
+ // doesn't fit below its field covers the field with no echo row and
752
+ // grows toward the side with more room: down from the field's top edge,
753
+ // or up from its bottom edge. Past the safe screen edge it scrolls, and
754
+ // scrolling grows it to fill the screen (FZ-8463).
747
755
  const firstPlacement = pinnedTopRef.current === 0 && pinnedHeightRef.current === 0;
748
- const roomBelow = viewportHeight - panelViewportPadding - triggerBounds.top;
749
- const roomAbove = triggerBounds.bottom - panelViewportPadding;
750
- if (firstPlacement) {
751
- dropUpRef.current = totalContentHeight > roomBelow && roomAbove > roomBelow;
752
- setDropUp(dropUpRef.current);
756
+ const boundsTop = panelViewportPadding;
757
+ const boundsBottom = viewportHeight - panelViewportPadding;
758
+ const echoRow = dropdownElement.querySelector<HTMLElement>("[data-fp-trigger-row]");
759
+ const echoHeight = echoRow ? triggerBounds.height : 0;
760
+ const listHeight = totalContentHeight - echoHeight;
761
+ const roomBelow = boundsBottom - triggerBounds.top;
762
+ const roomAbove = triggerBounds.bottom - boundsTop;
763
+ if (firstPlacement && totalContentHeight > roomBelow) {
764
+ coverScrollRef.current = true;
765
+ growsUpRef.current = roomAbove > roomBelow;
766
+ setCoverScroll(true);
753
767
  }
754
- const idealTop = dropUpRef.current
755
- ? triggerBounds.bottom - totalContentHeight
756
- : triggerBounds.top;
757
- const idealBottom = dropUpRef.current ? triggerBounds.bottom : idealTop + totalContentHeight;
768
+
769
+ if (coverScrollRef.current) {
770
+ const grown = grownRef.current || growUpOnlyRef.current || growDownOnlyRef.current;
771
+ const room = grown ? boundsBottom - boundsTop : growsUpRef.current ? roomAbove : roomBelow;
772
+ const trim = grown ? 0 : coverTrimRef.current;
773
+ const height = Math.max(0, Math.min(listHeight, room - trim));
774
+ const anchor = growsUpRef.current ? triggerBounds.bottom - height : triggerBounds.top;
775
+ const top = Math.min(Math.max(anchor, boundsTop), boundsBottom - height);
776
+ const previousTop = pinnedTopRef.current;
777
+ if (
778
+ !overlayStyle.current ||
779
+ overlayStyle.current.top !== top - originTop ||
780
+ overlayStyle.current.maxHeight !== height
781
+ ) {
782
+ dropdownElement.style.top = `${top - originTop}px`;
783
+ dropdownElement.style.maxHeight = `${height}px`;
784
+ dropdownElement.style.height = "";
785
+ overlayStyle.current = { top: top - originTop, maxHeight: height };
786
+ void dropdownElement.offsetHeight;
787
+ }
788
+ pinnedTopRef.current = top;
789
+ pinnedHeightRef.current = height;
790
+ // Rows stay under the pointer while the panel grows upward.
791
+ if (grown && previousTop > top && dropdownElement.scrollTop > 0) {
792
+ programmaticScrollRef.current++;
793
+ dropdownElement.scrollTop = Math.max(0, dropdownElement.scrollTop - (previousTop - top));
794
+ }
795
+ if (echoRow) return;
796
+ const rowHeight = selectedItem.offsetHeight || 1;
797
+ if (isInitial && selectedIndex >= 0) {
798
+ // The checked row lands on the field when the list can scroll that
799
+ // far. Opening down, short of that it stops a whole row short, so the
800
+ // top row isn't cut in half. Two pixels of rounding are not a row.
801
+ const maxScrollTop = dropdownElement.scrollHeight - dropdownElement.clientHeight;
802
+ let scrollTop: number;
803
+ if (growsUpRef.current) {
804
+ scrollTop = selectedItem.offsetTop + rowHeight - (triggerBounds.bottom - top);
805
+ } else {
806
+ const short = Math.max(0, selectedItem.offsetTop - maxScrollTop - 2);
807
+ scrollTop = selectedItem.offsetTop - Math.ceil(short / rowHeight) * rowHeight;
808
+ }
809
+ programmaticScrollRef.current++;
810
+ dropdownElement.scrollTop = Math.min(maxScrollTop, Math.max(0, scrollTop));
811
+ }
812
+ if (isInitial && !grown) {
813
+ // The far edge ends on a whole row: growing up, the row on the field
814
+ // isn't cut in half; growing down, no sliver sits at the screen edge.
815
+ const firstRow = listItemsRef.current[0];
816
+ const visibleBottom = dropdownElement.scrollTop + dropdownElement.clientHeight;
817
+ if (firstRow && visibleBottom < dropdownElement.scrollHeight - 2) {
818
+ const cut = (visibleBottom - firstRow.offsetTop) % rowHeight;
819
+ if (cut > 3 && cut < rowHeight - 3) {
820
+ coverTrimRef.current = cut;
821
+ const trimmedHeight = height - cut;
822
+ const trimmedTop = growsUpRef.current ? top + cut : top;
823
+ dropdownElement.style.top = `${trimmedTop - originTop}px`;
824
+ dropdownElement.style.maxHeight = `${trimmedHeight}px`;
825
+ overlayStyle.current = { top: trimmedTop - originTop, maxHeight: trimmedHeight };
826
+ pinnedTopRef.current = trimmedTop;
827
+ pinnedHeightRef.current = trimmedHeight;
828
+ }
829
+ }
830
+ }
831
+ panel.initializingRef.current = false;
832
+ void dropdownElement.offsetHeight;
833
+ if (isInitial) dropdownElement.style.transition = panel.panelTransition;
834
+ requestAnimationFrame(() => {
835
+ if (dropdownElement) panel.updateArrows(dropdownElement);
836
+ });
837
+ return;
838
+ }
839
+ const idealTop = triggerBounds.top;
840
+ const idealBottom = idealTop + totalContentHeight;
758
841
  const pinnedTop = Math.max(panelViewportPadding, idealTop);
759
842
  const pinnedBottom = Math.min(viewportHeight - panelViewportPadding, idealBottom);
760
843
  const pinnedHeight = Math.max(120, pinnedBottom - pinnedTop);
@@ -768,10 +851,7 @@ function FloatingSelectCore({
768
851
  let height = pinnedHeightRef.current;
769
852
 
770
853
  if (grownRef.current) {
771
- // A drop-up keeps its echo on the field: it grows upward only.
772
- const canGrowDown = dropUpRef.current
773
- ? 0
774
- : Math.max(0, viewportHeight - panelViewportPadding - (top + height));
854
+ const canGrowDown = Math.max(0, viewportHeight - panelViewportPadding - (top + height));
775
855
  height += canGrowDown;
776
856
  const canGrowUp = Math.max(0, top - panelViewportPadding);
777
857
  top -= canGrowUp;
@@ -783,7 +863,7 @@ function FloatingSelectCore({
783
863
  top -= canGrowUp;
784
864
  height += canGrowUp;
785
865
  }
786
- if (growDownOnlyRef.current && !dropUpRef.current) {
866
+ if (growDownOnlyRef.current) {
787
867
  const canGrowDown = Math.max(0, viewportHeight - panelViewportPadding - (top + height));
788
868
  height += canGrowDown;
789
869
  }
@@ -826,18 +906,9 @@ function FloatingSelectCore({
826
906
  !growUpOnlyRef.current &&
827
907
  !growDownOnlyRef.current
828
908
  ) {
829
- // The selected row starts in view, just under the sticky echo row (or
830
- // just above it in a drop-up, where the echo is the last row).
831
- const echoHeight = triggerBounds.height;
909
+ // The selected row starts in view, just under the sticky echo row.
832
910
  const rowBottom = selectedItem.offsetTop + selectedItem.offsetHeight;
833
- if (dropUpRef.current) {
834
- const maxScrollTop = dropdownElement.scrollHeight - dropdownElement.clientHeight;
835
- const wanted = rowBottom - (dropdownElement.clientHeight - echoHeight);
836
- if (wanted > 0) {
837
- programmaticScrollRef.current++;
838
- dropdownElement.scrollTop = Math.min(wanted, maxScrollTop);
839
- }
840
- } else if (rowBottom > dropdownElement.clientHeight) {
911
+ if (rowBottom > dropdownElement.clientHeight) {
841
912
  const maxScrollTop = dropdownElement.scrollHeight - dropdownElement.clientHeight;
842
913
  programmaticScrollRef.current++;
843
914
  dropdownElement.scrollTop = Math.max(
@@ -882,6 +953,8 @@ function FloatingSelectCore({
882
953
  panel.panelTransition,
883
954
  options.length,
884
955
  beside,
956
+ coverScroll,
957
+ panelWidth,
885
958
  ]);
886
959
 
887
960
  repositionRef.current = repositionOverlay;
@@ -1218,7 +1291,9 @@ function FloatingSelectCore({
1218
1291
  transform: panel.visible ? "scale(1)" : "scale(0.96)",
1219
1292
  transition: panel.panelTransition,
1220
1293
  transformOrigin:
1221
- dropUp || panel.placement.startsWith("top") ? "bottom left" : "top left",
1294
+ (coverScroll && growsUpRef.current) || panel.placement.startsWith("top")
1295
+ ? "bottom left"
1296
+ : "top left",
1222
1297
  ...dragProps.style,
1223
1298
  },
1224
1299
  onPointerDown: dragProps.onPointerDown,
@@ -1261,24 +1336,21 @@ function FloatingSelectCore({
1261
1336
  paddingVertical={0}
1262
1337
  paddingBottom={panel.coverCornerInset || 0}
1263
1338
  >
1264
- {!beside && (
1339
+ {echoed ? (
1265
1340
  <TriggerEchoRow
1266
1341
  sourceRef={panel.triggerRef}
1267
1342
  source={selectedOption?.label ?? placeholder}
1268
1343
  onPress={() => setOpen(false)}
1269
1344
  presentational
1270
- edge={dropUp ? "bottom" : "top"}
1271
1345
  />
1272
- )}
1346
+ ) : null}
1273
1347
  <ScrollArrow
1274
1348
  direction="up"
1275
1349
  scrollRef={panel.refs.floating}
1276
1350
  visible={panel.arrowUp}
1277
1351
  arrowScrollDirRef={panel.arrowScrollDirRef}
1278
1352
  topOffset={
1279
- dropUp || beside
1280
- ? 0
1281
- : (panel.triggerRef.current?.getBoundingClientRect().height ?? 0)
1353
+ echoed ? (panel.triggerRef.current?.getBoundingClientRect().height ?? 0) : 0
1282
1354
  }
1283
1355
  />
1284
1356
  {groupLabel && (
@@ -1330,9 +1402,6 @@ function FloatingSelectCore({
1330
1402
  scrollRef={panel.refs.floating}
1331
1403
  visible={panel.arrowDown}
1332
1404
  arrowScrollDirRef={panel.arrowScrollDirRef}
1333
- bottomOffset={
1334
- dropUp ? (panel.triggerRef.current?.getBoundingClientRect().height ?? 0) : 0
1335
- }
1336
1405
  />
1337
1406
  </YStack>
1338
1407
  </FloatingFocusManager>
@@ -0,0 +1,121 @@
1
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
2
+ import { fireEvent } from "@testing-library/react";
3
+ import { describe, expect, it, vi } from "vitest";
4
+ import { OsDateTimeSheet } from "./OsDateTimeSheet";
5
+ import { DATE_PICKER_WHEEL_HEIGHT } from "./sheetKeyboard";
6
+
7
+ const os = vi.hoisted(() => ({ name: "ios" as "ios" | "android" }));
8
+ const seen = vi.hoisted(() => ({ props: [] as Record<string, unknown>[] }));
9
+
10
+ vi.mock("react-native-web", async (importOriginal) => ({
11
+ ...(await importOriginal<typeof import("react-native")>()),
12
+ useWindowDimensions: () => ({ width: 390, height: 844, scale: 3, fontScale: 1 }),
13
+ }));
14
+
15
+ vi.mock("@multiplatform.one/platform", async (importOriginal) => {
16
+ const actual = (await importOriginal()) as Record<string, unknown>;
17
+ const real = actual.platform as Record<string, unknown>;
18
+ return {
19
+ ...actual,
20
+ platform: new Proxy(
21
+ {},
22
+ {
23
+ get(_target, prop) {
24
+ if (prop === "isIos") return os.name === "ios";
25
+ if (prop === "isAndroid") return os.name === "android";
26
+ return real[prop as string];
27
+ },
28
+ },
29
+ ),
30
+ };
31
+ });
32
+
33
+ vi.mock("./dateTimePickerLoader", () => ({
34
+ loadDateTimePicker: () => (props: Record<string, unknown>) => {
35
+ seen.props.push(props);
36
+ return <div data-testid="os-picker" />;
37
+ },
38
+ }));
39
+
40
+ const at = (h: number, m: number) => {
41
+ const d = new Date(2026, 9, 29);
42
+ d.setHours(h, m, 0, 0);
43
+ return d;
44
+ };
45
+
46
+ describe("OsDateTimeSheet countdown (FZ-8111)", () => {
47
+ it("opens the iOS countdown-timer wheel in the app's scheme", () => {
48
+ os.name = "ios";
49
+ seen.props = [];
50
+ renderWithProviders(
51
+ <OsDateTimeSheet
52
+ open
53
+ mode="countdown"
54
+ value={at(1, 2)}
55
+ onCancel={vi.fn()}
56
+ onConfirm={vi.fn()}
57
+ />,
58
+ );
59
+ const props = seen.props.at(-1)!;
60
+ expect(props.mode).toBe("countdown");
61
+ expect(props.display).toBe("spinner");
62
+ expect(props.themeVariant).toBe("light");
63
+ expect((props.value as Date).getHours()).toBe(1);
64
+ expect((props.value as Date).getMinutes()).toBe(2);
65
+ expect((props.style as { height: number }).height).toBe(DATE_PICKER_WHEEL_HEIGHT);
66
+ });
67
+
68
+ it("confirms the wheel's hours and minutes", () => {
69
+ os.name = "ios";
70
+ seen.props = [];
71
+ const onConfirm = vi.fn();
72
+ const onCancel = vi.fn();
73
+ const result = renderWithProviders(
74
+ <OsDateTimeSheet
75
+ open
76
+ mode="countdown"
77
+ value={at(1, 2)}
78
+ onCancel={onCancel}
79
+ onConfirm={onConfirm}
80
+ />,
81
+ );
82
+ fireEvent.click(result.getByRole("button", { name: "Done" }));
83
+ expect(onConfirm).toHaveBeenCalledOnce();
84
+ const picked = onConfirm.mock.calls[0]![0] as Date;
85
+ expect([picked.getHours(), picked.getMinutes()]).toEqual([1, 2]);
86
+ fireEvent.click(result.getByRole("button", { name: "Cancel" }));
87
+ expect(onCancel).toHaveBeenCalledOnce();
88
+ });
89
+
90
+ it("opens Android's 24-hour spinner, never the AM/PM clock dial", () => {
91
+ os.name = "android";
92
+ seen.props = [];
93
+ renderWithProviders(
94
+ <OsDateTimeSheet
95
+ open
96
+ mode="countdown"
97
+ value={at(2, 30)}
98
+ onCancel={vi.fn()}
99
+ onConfirm={vi.fn()}
100
+ />,
101
+ );
102
+ const props = seen.props.at(-1)!;
103
+ expect(props.mode).toBe("time");
104
+ expect(props.display).toBe("spinner");
105
+ expect(props.is24Hour).toBe(true);
106
+ os.name = "ios";
107
+ });
108
+
109
+ it("leaves the Android date dialog as it was", () => {
110
+ os.name = "android";
111
+ seen.props = [];
112
+ renderWithProviders(
113
+ <OsDateTimeSheet open mode="date" value={at(0, 0)} onCancel={vi.fn()} onConfirm={vi.fn()} />,
114
+ );
115
+ const props = seen.props.at(-1)!;
116
+ expect(props.mode).toBe("date");
117
+ expect(props.display).toBe("default");
118
+ expect(props.is24Hour).toBeUndefined();
119
+ os.name = "ios";
120
+ });
121
+ });
@@ -9,4 +9,8 @@ describe("osDateTimeIosDisplay", () => {
9
9
  it("keeps the time wheel", () => {
10
10
  expect(osDateTimeIosDisplay("time")).toBe("spinner");
11
11
  });
12
+
13
+ it("keeps the wheel for a countdown (FZ-8111)", () => {
14
+ expect(osDateTimeIosDisplay("countdown")).toBe("spinner");
15
+ });
12
16
  });
@@ -33,7 +33,7 @@ import { osDateTimeIosDisplay } from "./osDateTimeIosDisplay";
33
33
  import { datePickerHeight, dateSheetBottomPadding, dateSheetMaxHeight } from "./sheetKeyboard";
34
34
  import { useKeyboardInset } from "../../shared/useKeyboardInset";
35
35
 
36
- export type OsDateTimeMode = "date" | "time" | "datetime";
36
+ export type OsDateTimeMode = "date" | "time" | "datetime" | "countdown";
37
37
 
38
38
  export type OsDateTimeSheetProps = {
39
39
  open: boolean;
@@ -74,8 +74,12 @@ export function OsDateTimeSheet({
74
74
  const maxHeight = dateSheetMaxHeight(windowHeight, keyboardInset, topInset);
75
75
  const [showTimePicker, setShowTimePicker] = useState(false);
76
76
  const [temp, setTemp] = useState(value);
77
- const pickerMode: "date" | "time" =
78
- mode === "time" || (mode === "datetime" && showTimePicker) ? "time" : "date";
77
+ const pickerMode: "date" | "time" | "countdown" =
78
+ mode === "countdown"
79
+ ? "countdown"
80
+ : mode === "time" || (mode === "datetime" && showTimePicker)
81
+ ? "time"
82
+ : "date";
79
83
  const iosDisplay = osDateTimeIosDisplay(pickerMode);
80
84
 
81
85
  const reset = useCallback(() => {
@@ -182,11 +186,12 @@ export function OsDateTimeSheet({
182
186
  return (
183
187
  <DateTimePicker
184
188
  value={temp}
185
- mode={pickerMode}
186
- display="default"
189
+ mode={pickerMode === "countdown" ? "time" : pickerMode}
190
+ display={pickerMode === "countdown" ? "spinner" : "default"}
191
+ is24Hour={pickerMode === "countdown" ? true : undefined}
187
192
  onChange={handleAndroidChange}
188
- minimumDate={mode !== "time" ? minDate : undefined}
189
- maximumDate={mode !== "time" ? maxDate : undefined}
193
+ minimumDate={mode === "date" || mode === "datetime" ? minDate : undefined}
194
+ maximumDate={mode === "date" || mode === "datetime" ? maxDate : undefined}
190
195
  />
191
196
  );
192
197
  }
@@ -242,8 +247,8 @@ export function OsDateTimeSheet({
242
247
  themeVariant={themeVariant}
243
248
  accentColor={accentColor}
244
249
  onChange={handleIOSChange}
245
- minimumDate={mode !== "time" ? minDate : undefined}
246
- maximumDate={mode !== "time" ? maxDate : undefined}
250
+ minimumDate={mode === "date" || mode === "datetime" ? minDate : undefined}
251
+ maximumDate={mode === "date" || mode === "datetime" ? maxDate : undefined}
247
252
  style={{ width: "100%", height: datePickerHeight(pickerMode, maxHeight) }}
248
253
  />
249
254
  </YStack>
@@ -1,4 +1,4 @@
1
- /** iOS date is the inline calendar; time keeps the wheel users expect. */
2
- export function osDateTimeIosDisplay(mode: "date" | "time"): "inline" | "spinner" {
3
- return mode === "time" ? "spinner" : "inline";
1
+ /** iOS date is the inline calendar; time and countdown keep the wheel users expect. */
2
+ export function osDateTimeIosDisplay(mode: "date" | "time" | "countdown"): "inline" | "spinner" {
3
+ return mode === "date" ? "inline" : "spinner";
4
4
  }
@@ -10,6 +10,7 @@ import {
10
10
  dateSheetBottomPadding,
11
11
  dateSheetMaxHeight,
12
12
  DATE_PICKER_CALENDAR_HEIGHT,
13
+ DATE_PICKER_WHEEL_HEIGHT,
13
14
  DATE_SHEET_BACKDROP_STRIP,
14
15
  DATE_SHEET_MIN_HEIGHT,
15
16
  } from "./sheetKeyboard";
@@ -49,6 +50,11 @@ describe("datePickerHeight", () => {
49
50
  expect(height).toBeLessThan(DATE_PICKER_CALENDAR_HEIGHT);
50
51
  expect(height).toBeLessThanOrEqual(maxHeight);
51
52
  });
53
+
54
+ it("gives the countdown the wheel height, not the calendar's (FZ-8111)", () => {
55
+ expect(datePickerHeight("countdown", 700)).toBe(DATE_PICKER_WHEEL_HEIGHT);
56
+ expect(datePickerHeight("countdown", 700)).toBe(datePickerHeight("time", 700));
57
+ });
52
58
  });
53
59
 
54
60
  describe("dateSheetBottomPadding", () => {
@@ -39,7 +39,7 @@ export function dateSheetBottomPadding(keyboardInset: number, isIos: boolean): n
39
39
  return isIos ? 24 : 16;
40
40
  }
41
41
 
42
- export function datePickerHeight(mode: "date" | "time", maxHeight: number): number {
43
- const preferred = mode === "time" ? DATE_PICKER_WHEEL_HEIGHT : DATE_PICKER_CALENDAR_HEIGHT;
42
+ export function datePickerHeight(mode: "date" | "time" | "countdown", maxHeight: number): number {
43
+ const preferred = mode === "date" ? DATE_PICKER_CALENDAR_HEIGHT : DATE_PICKER_WHEEL_HEIGHT;
44
44
  return Math.min(preferred, Math.max(minPickerHeight, maxHeight - DATE_SHEET_CHROME));
45
45
  }
@@ -34,7 +34,6 @@ export function ScrollArrow({
34
34
  visible,
35
35
  arrowScrollDirRef,
36
36
  topOffset = 0,
37
- bottomOffset = 0,
38
37
  }: {
39
38
  direction: "up" | "down";
40
39
  scrollRef: RefObject<HTMLElement | null>;
@@ -42,8 +41,6 @@ export function ScrollArrow({
42
41
  arrowScrollDirRef: RefObject<"up" | "down" | null>;
43
42
  /** Below a sticky echo row (LC-112 seamless cover), the up arrow sits under it. */
44
43
  topOffset?: number;
45
- /** Above a sticky echo row at the bottom (a drop-up), the down arrow sits over it. */
46
- bottomOffset?: number;
47
44
  }) {
48
45
  const isUp = direction === "up";
49
46
  const animationFrameRef = useRef(0);
@@ -159,7 +156,7 @@ export function ScrollArrow({
159
156
  <View
160
157
  position="sticky"
161
158
  top={isUp ? topOffset : undefined}
162
- bottom={isUp ? undefined : bottomOffset}
159
+ bottom={isUp ? undefined : 0}
163
160
  height={0}
164
161
  zIndex={2}
165
162
  >
@@ -1 +1 @@
1
- {"version":3,"file":"IconButtonGroup.d.ts","sourceRoot":"","sources":["../../src/Button/IconButtonGroup.tsx"],"names":[],"mappings":"AACA,OAAO,EAAyB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAC9D,OAAO,EAA8B,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAMvE;;;GAGG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C,MAAM,WAAW,oBAAqB,SAAQ,WAAW;IACvD,oEAAoE;IACpE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,oBAAoB,2CA0GjF"}
1
+ {"version":3,"file":"IconButtonGroup.d.ts","sourceRoot":"","sources":["../../src/Button/IconButtonGroup.tsx"],"names":[],"mappings":"AACA,OAAO,EAA0C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAC/E,OAAO,EAA8B,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAWvE;;;GAGG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAQ7C,MAAM,WAAW,oBAAqB,SAAQ,WAAW;IACvD,oEAAoE;IACpE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,oBAAoB,2CAkIjF"}
@@ -4,4 +4,16 @@
4
4
  * ratio, never a small glyph lost in a big plate.
5
5
  */
6
6
  export declare const ICON_BUTTON_CIRCLE_GLYPH_RATIO = 0.58;
7
+ /**
8
+ * LC-176: Phosphor bold's stem is 0.12 of its ink, an SF Symbols bold plus's
9
+ * 0.18 (measured at 17 and 24pt). An outline stroke this wide, in the 256-unit
10
+ * grid, brings a bold glyph to SF semibold-bold (0.154); a wider one closes
11
+ * Phosphor bold's 16-unit counters (the trash lid, copy's overlap).
12
+ */
13
+ export declare const GLYPH_BOLD_STROKE_UNITS = 8;
14
+ export declare function boldStroke(weight: "regular" | "bold", color?: string): {
15
+ stroke: string;
16
+ strokeWidth: number;
17
+ strokeLinejoin: "round";
18
+ } | undefined;
7
19
  //# sourceMappingURL=circleGlyph.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"circleGlyph.d.ts","sourceRoot":"","sources":["../../src/Button/circleGlyph.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,OAAO,CAAC"}
1
+ {"version":3,"file":"circleGlyph.d.ts","sourceRoot":"","sources":["../../src/Button/circleGlyph.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,OAAO,CAAC;AAEnD;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,EAAE,KAAK,SAAiB;;;;cAQ5E"}
@@ -14,4 +14,23 @@ export declare function useIconButtonGroupGround(): IconButtonGroupGround;
14
14
  */
15
15
  export declare const IconButtonGroupRegistry: import("react").Context<(() => () => void) | null>;
16
16
  export declare function useIconButtonGroupMember(iconOnly: boolean): void;
17
+ /**
18
+ * The window frame and corner radius of the plate an `IconButtonGroup` paints
19
+ * (a native Liquid Glass capsule). Native has no DOM to walk, so a panel
20
+ * opening from a grouped button reads the plate it covers here (LC-112,
21
+ * FZ-8550).
22
+ */
23
+ export interface IconButtonGroupPlate {
24
+ x: number;
25
+ y: number;
26
+ width: number;
27
+ height: number;
28
+ radius: number;
29
+ }
30
+ export interface IconButtonGroupSurface {
31
+ /** Answers once: the plate, or null when it cannot be measured. */
32
+ measure(callback: (plate: IconButtonGroupPlate | null) => void): void;
33
+ }
34
+ export declare const IconButtonGroupSurfaceContext: import("react").Context<IconButtonGroupSurface | null>;
35
+ export declare function useIconButtonGroupSurface(): IconButtonGroupSurface | null;
17
36
  //# sourceMappingURL=iconButtonGroupContext.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"iconButtonGroupContext.d.ts","sourceRoot":"","sources":["../../src/Button/iconButtonGroupContext.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;AAE7D,eAAO,MAAM,sBAAsB,gDAA6C,CAAC;AAEjF,wBAAgB,wBAAwB,IAAI,qBAAqB,CAEhE;AAED;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,iCAAwB,MAAM,IAAI,SAAe,CAAC;AAEtF,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAMhE"}
1
+ {"version":3,"file":"iconButtonGroupContext.d.ts","sourceRoot":"","sources":["../../src/Button/iconButtonGroupContext.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;AAE7D,eAAO,MAAM,sBAAsB,gDAA6C,CAAC;AAEjF,wBAAgB,wBAAwB,IAAI,qBAAqB,CAEhE;AAED;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,iCAAwB,MAAM,IAAI,SAAe,CAAC;AAEtF,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAMhE;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,mEAAmE;IACnE,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAAC;CACvE;AAED,eAAO,MAAM,6BAA6B,wDAAqD,CAAC;AAEhG,wBAAgB,yBAAyB,IAAI,sBAAsB,GAAG,IAAI,CAEzE"}
@@ -3,8 +3,8 @@ import { type RecipeFamilyName, type SizeRecipe } from "@multiplatform.one/theme
3
3
  import { type ButtonProps as TamaguiButtonProps } from "tamagui";
4
4
  import type { AnyFormApi } from "../types";
5
5
  import type { SizeTokens } from "@tamagui/web";
6
- import { ICON_BUTTON_CIRCLE_GLYPH_RATIO } from "./circleGlyph";
7
- export { ICON_BUTTON_CIRCLE_GLYPH_RATIO };
6
+ import { GLYPH_BOLD_STROKE_UNITS, ICON_BUTTON_CIRCLE_GLYPH_RATIO } from "./circleGlyph";
7
+ export { GLYPH_BOLD_STROKE_UNITS, ICON_BUTTON_CIRCLE_GLYPH_RATIO };
8
8
  /**
9
9
  * Coordinated size recipe (Polaris slim/medium/large, Primer s/m/l, Linear
10
10
  * 28/32/40, Spectrum S/M, M3 XS/S). Height, pad, type, icon, gap and radius
@@ -173,13 +173,6 @@ export declare const ICON_BUTTON_NEUTRAL_GLYPH_PX = 24;
173
173
  * target.
174
174
  */
175
175
  export declare function iconButtonGlyphPx(rowLinePx: number | undefined): number;
176
- /**
177
- * LC-176: Phosphor bold's stem is 0.12 of its ink, an SF Symbols bold plus's
178
- * 0.18 (measured at 17 and 24pt). An outline stroke this wide, in the 256-unit
179
- * grid, brings a bold glyph to SF semibold-bold (0.154); a wider one closes
180
- * Phosphor bold's 16-unit counters (the trash lid, copy's overlap).
181
- */
182
- export declare const GLYPH_BOLD_STROKE_UNITS = 8;
183
176
  export declare function Button({ children, action, form: formProp, loading, accent, error, warning, success, skeleton, outlined, disabled, theme, onPress, onKeyDown, tabIndex, icon, iconAfter, selected, nested, circular: circularProp, chromeless, edge, accentInk, plate, inline, glyphWeight, verb, noun, actionRole, disabledReason, disabledReasonPlacement, sizeRecipeEscape, recipeFamily, height: heightProp, paddingHorizontal: paddingHorizontalProp, ...props }: ButtonProps): import("react/jsx-runtime").JSX.Element;
184
177
  export declare namespace Button {
185
178
  var Icon: (props: {