@multiplatform.one/forms 7.58.0 → 7.60.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 (331) hide show
  1. package/dist/cjs/FloatingPanel/index.native.js +8 -2
  2. package/dist/cjs/FloatingPanel/index.native.js.map +1 -1
  3. package/dist/cjs/fields/DatePicker/DateRangePicker.cjs +5 -9
  4. package/dist/cjs/fields/DatePicker/DateRangePicker.native.js +5 -9
  5. package/dist/cjs/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  6. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.cjs +7 -11
  7. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js +7 -11
  8. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  9. package/dist/cjs/fields/DatePicker/DatetimePicker.native.js +5 -9
  10. package/dist/cjs/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  11. package/dist/cjs/fields/DatePicker/MonthPicker.cjs +5 -9
  12. package/dist/cjs/fields/DatePicker/MonthPicker.native.js +5 -9
  13. package/dist/cjs/fields/DatePicker/MonthPicker.native.js.map +1 -1
  14. package/dist/cjs/fields/DatePicker/MultiDatePicker.cjs +5 -9
  15. package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js +5 -9
  16. package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  17. package/dist/cjs/fields/DatePicker/catalog.cjs +5 -9
  18. package/dist/cjs/fields/DatePicker/catalog.native.js +5 -9
  19. package/dist/cjs/fields/DatePicker/catalog.native.js.map +1 -1
  20. package/dist/cjs/fields/DatePicker/index.native.js +5 -9
  21. package/dist/cjs/fields/DatePicker/index.native.js.map +1 -1
  22. package/dist/cjs/fields/DatePicker/parts.cjs +46 -4
  23. package/dist/cjs/fields/DatePicker/parts.native.js +50 -5
  24. package/dist/cjs/fields/DatePicker/parts.native.js.map +1 -1
  25. package/dist/cjs/fields/Select/InlineChoices.cjs +148 -0
  26. package/dist/cjs/fields/Select/InlineChoices.native.js +163 -0
  27. package/dist/cjs/fields/Select/InlineChoices.native.js.map +1 -0
  28. package/dist/cjs/fields/Select/index.cjs +66 -15
  29. package/dist/cjs/fields/Select/index.native.js +73 -17
  30. package/dist/cjs/fields/Select/index.native.js.map +1 -1
  31. package/dist/cjs/fields/Select/shouldInlineChoices.cjs +37 -0
  32. package/dist/cjs/fields/Select/shouldInlineChoices.native.js +43 -0
  33. package/dist/cjs/fields/Select/shouldInlineChoices.native.js.map +1 -0
  34. package/dist/cjs/fields/TimePicker/catalog.cjs +1 -1
  35. package/dist/cjs/fields/TimePicker/catalog.native.js +1 -1
  36. package/dist/cjs/fields/TimePicker/catalog.native.js.map +1 -1
  37. package/dist/cjs/fields/TimePicker/index.native.js +2 -2
  38. package/dist/cjs/fields/TimePicker/index.native.js.map +1 -1
  39. package/dist/cjs/fields/TimePicker/parts.cjs +13 -11
  40. package/dist/cjs/fields/TimePicker/parts.native.js +16 -13
  41. package/dist/cjs/fields/TimePicker/parts.native.js.map +1 -1
  42. package/dist/esm/AdaptivePopup/index.native.js.map +1 -1
  43. package/dist/esm/Button/index.native.js.map +1 -1
  44. package/dist/esm/Chip/index.native.js.map +1 -1
  45. package/dist/esm/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
  46. package/dist/esm/ContextualSaveBar/clientKnownIdentity.native.js.map +1 -1
  47. package/dist/esm/ContextualSaveBar/commitImmediateField.native.js.map +1 -1
  48. package/dist/esm/ContextualSaveBar/index.native.js.map +1 -1
  49. package/dist/esm/ContextualSaveBar/useUnsavedChangesGuard.native.js.map +1 -1
  50. package/dist/esm/ControlGroup/index.native.js.map +1 -1
  51. package/dist/esm/DescriptionList/index.native.js.map +1 -1
  52. package/dist/esm/ErrorSummary.native.js.map +1 -1
  53. package/dist/esm/FieldDisplay/editMode.native.js.map +1 -1
  54. package/dist/esm/FieldDisplay/formatters.native.js.map +1 -1
  55. package/dist/esm/FieldDisplay/index.native.js.map +1 -1
  56. package/dist/esm/FieldGroup.native.js.map +1 -1
  57. package/dist/esm/FloatingPanel/compactFace.native.js.map +1 -1
  58. package/dist/esm/FloatingPanel/index.native.js +8 -2
  59. package/dist/esm/FloatingPanel/index.native.js.map +1 -1
  60. package/dist/esm/FloatingPanel/nestedAction.native.js.map +1 -1
  61. package/dist/esm/FloatingPanel/pointAnchor.native.js.map +1 -1
  62. package/dist/esm/FloatingPanel/trailingAction.native.js.map +1 -1
  63. package/dist/esm/FloatingPanel/useFloatingPanel.native.js.map +1 -1
  64. package/dist/esm/Form/index.native.js.map +1 -1
  65. package/dist/esm/Form/submissionController.native.js.map +1 -1
  66. package/dist/esm/Form/validateOn.native.js.map +1 -1
  67. package/dist/esm/FormGrid.native.js.map +1 -1
  68. package/dist/esm/FormSection.native.js.map +1 -1
  69. package/dist/esm/InputParts/PasswordReveal.native.js.map +1 -1
  70. package/dist/esm/InputParts/index.native.js.map +1 -1
  71. package/dist/esm/Label/index.native.js.map +1 -1
  72. package/dist/esm/MediaPicker/base64.native.js.map +1 -1
  73. package/dist/esm/MediaPicker/payload.native.js.map +1 -1
  74. package/dist/esm/MediaPicker/types.native.js.map +1 -1
  75. package/dist/esm/MediaPicker/useMediaPicker.native.js.map +1 -1
  76. package/dist/esm/Skeleton/index.native.js.map +1 -1
  77. package/dist/esm/Spinner/SpinnerGlyph.native.js.map +1 -1
  78. package/dist/esm/Spinner/spinnerSize.native.js.map +1 -1
  79. package/dist/esm/Table/index.native.js.map +1 -1
  80. package/dist/esm/Wheel/haptic.native.js.map +1 -1
  81. package/dist/esm/Wheel/index.native.js.map +1 -1
  82. package/dist/esm/Wheel/wheelShared.native.js.map +1 -1
  83. package/dist/esm/actionLabel.native.js.map +1 -1
  84. package/dist/esm/fieldDefaults.native.js.map +1 -1
  85. package/dist/esm/fieldLayout.native.js.map +1 -1
  86. package/dist/esm/fields/Barcode/BarcodePreview.native.js.map +1 -1
  87. package/dist/esm/fields/Barcode/code128.native.js.map +1 -1
  88. package/dist/esm/fields/Barcode/index.native.js.map +1 -1
  89. package/dist/esm/fields/Barcode/qr.native.js.map +1 -1
  90. package/dist/esm/fields/Barcode/scannerTypes.native.js.map +1 -1
  91. package/dist/esm/fields/Checkbox/Checkbox.native.js.map +1 -1
  92. package/dist/esm/fields/Checkbox/CheckboxBox.native.js.map +1 -1
  93. package/dist/esm/fields/Checkbox/CheckboxCard.native.js.map +1 -1
  94. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  95. package/dist/esm/fields/Checkbox/CheckboxGroup.native.js.map +1 -1
  96. package/dist/esm/fields/Checkbox/checkboxGroupContext.native.js.map +1 -1
  97. package/dist/esm/fields/Checkbox/index.native.js.map +1 -1
  98. package/dist/esm/fields/ColorPicker/index.native.js.map +1 -1
  99. package/dist/esm/fields/ColorPicker/parts.native.js.map +1 -1
  100. package/dist/esm/fields/Combobox/authorOptions.native.js.map +1 -1
  101. package/dist/esm/fields/Combobox/index.native.js.map +1 -1
  102. package/dist/esm/fields/DatePicker/Calendar.native.js.map +1 -1
  103. package/dist/esm/fields/DatePicker/DateRangePicker.mjs +6 -10
  104. package/dist/esm/fields/DatePicker/DateRangePicker.mjs.map +1 -1
  105. package/dist/esm/fields/DatePicker/DateRangePicker.native.js +6 -10
  106. package/dist/esm/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  107. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.mjs +8 -12
  108. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.mjs.map +1 -1
  109. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.native.js +8 -12
  110. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  111. package/dist/esm/fields/DatePicker/DatetimePicker.native.js +6 -10
  112. package/dist/esm/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  113. package/dist/esm/fields/DatePicker/MonthPicker.mjs +6 -10
  114. package/dist/esm/fields/DatePicker/MonthPicker.mjs.map +1 -1
  115. package/dist/esm/fields/DatePicker/MonthPicker.native.js +6 -10
  116. package/dist/esm/fields/DatePicker/MonthPicker.native.js.map +1 -1
  117. package/dist/esm/fields/DatePicker/MultiDatePicker.mjs +6 -10
  118. package/dist/esm/fields/DatePicker/MultiDatePicker.mjs.map +1 -1
  119. package/dist/esm/fields/DatePicker/MultiDatePicker.native.js +6 -10
  120. package/dist/esm/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  121. package/dist/esm/fields/DatePicker/catalog.mjs +6 -10
  122. package/dist/esm/fields/DatePicker/catalog.mjs.map +1 -1
  123. package/dist/esm/fields/DatePicker/catalog.native.js +6 -10
  124. package/dist/esm/fields/DatePicker/catalog.native.js.map +1 -1
  125. package/dist/esm/fields/DatePicker/fieldValueSync.native.js.map +1 -1
  126. package/dist/esm/fields/DatePicker/index.native.js +6 -10
  127. package/dist/esm/fields/DatePicker/index.native.js.map +1 -1
  128. package/dist/esm/fields/DatePicker/parts.mjs +46 -5
  129. package/dist/esm/fields/DatePicker/parts.mjs.map +1 -1
  130. package/dist/esm/fields/DatePicker/parts.native.js +50 -6
  131. package/dist/esm/fields/DatePicker/parts.native.js.map +1 -1
  132. package/dist/esm/fields/DatePicker/utils.native.js.map +1 -1
  133. package/dist/esm/fields/Duration/durationMath.native.js.map +1 -1
  134. package/dist/esm/fields/Duration/index.native.js.map +1 -1
  135. package/dist/esm/fields/FileUpload/filePickerTypes.native.js.map +1 -1
  136. package/dist/esm/fields/FileUpload/index.native.js.map +1 -1
  137. package/dist/esm/fields/FileUpload/nativePickerLoader.native.js.map +1 -1
  138. package/dist/esm/fields/Geolocation/expoMapsLoader.native.js.map +1 -1
  139. package/dist/esm/fields/Geolocation/geoValue.native.js.map +1 -1
  140. package/dist/esm/fields/Geolocation/geocoder.native.js.map +1 -1
  141. package/dist/esm/fields/Geolocation/geocoderContext.native.js.map +1 -1
  142. package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
  143. package/dist/esm/fields/Geolocation/mapMath.native.js.map +1 -1
  144. package/dist/esm/fields/Geolocation/mapTypes.native.js.map +1 -1
  145. package/dist/esm/fields/Geolocation/nativeSearchFocus.native.js.map +1 -1
  146. package/dist/esm/fields/Geolocation/photonGeocoder.native.js.map +1 -1
  147. package/dist/esm/fields/Icon/drawnSet.native.js.map +1 -1
  148. package/dist/esm/fields/Icon/index.native.js.map +1 -1
  149. package/dist/esm/fields/ImageField/index.native.js.map +1 -1
  150. package/dist/esm/fields/Input/index.native.js.map +1 -1
  151. package/dist/esm/fields/MentionInput/index.native.js.map +1 -1
  152. package/dist/esm/fields/OTPInput/index.native.js.map +1 -1
  153. package/dist/esm/fields/OTPInput/otpCellCss.native.js.map +1 -1
  154. package/dist/esm/fields/PhoneInput/dialCodes.native.js.map +1 -1
  155. package/dist/esm/fields/PhoneInput/index.native.js.map +1 -1
  156. package/dist/esm/fields/PhoneInput/phone.native.js.map +1 -1
  157. package/dist/esm/fields/PhoneInput/regionNames.native.js.map +1 -1
  158. package/dist/esm/fields/Progress/index.native.js.map +1 -1
  159. package/dist/esm/fields/RadioGroup/index.native.js.map +1 -1
  160. package/dist/esm/fields/Rating/index.native.js.map +1 -1
  161. package/dist/esm/fields/Rating/ratingMath.native.js.map +1 -1
  162. package/dist/esm/fields/Rating/types.native.js.map +1 -1
  163. package/dist/esm/fields/SearchInput/index.native.js.map +1 -1
  164. package/dist/esm/fields/Select/InlineChoices.mjs +123 -0
  165. package/dist/esm/fields/Select/InlineChoices.mjs.map +1 -0
  166. package/dist/esm/fields/Select/InlineChoices.native.js +135 -0
  167. package/dist/esm/fields/Select/InlineChoices.native.js.map +1 -0
  168. package/dist/esm/fields/Select/index.mjs +67 -16
  169. package/dist/esm/fields/Select/index.mjs.map +1 -1
  170. package/dist/esm/fields/Select/index.native.js +74 -18
  171. package/dist/esm/fields/Select/index.native.js.map +1 -1
  172. package/dist/esm/fields/Select/shouldInlineChoices.mjs +11 -0
  173. package/dist/esm/fields/Select/shouldInlineChoices.mjs.map +1 -0
  174. package/dist/esm/fields/Select/shouldInlineChoices.native.js +14 -0
  175. package/dist/esm/fields/Select/shouldInlineChoices.native.js.map +1 -0
  176. package/dist/esm/fields/Signature/index.native.js.map +1 -1
  177. package/dist/esm/fields/Slider/index.native.js.map +1 -1
  178. package/dist/esm/fields/Slider/jumpMotion.native.js.map +1 -1
  179. package/dist/esm/fields/Stepper/index.native.js.map +1 -1
  180. package/dist/esm/fields/Stepper/resolveStepperPlacement.native.js.map +1 -1
  181. package/dist/esm/fields/Switch/footprint.native.js.map +1 -1
  182. package/dist/esm/fields/Switch/index.native.js.map +1 -1
  183. package/dist/esm/fields/TextArea/index.native.js.map +1 -1
  184. package/dist/esm/fields/TimePicker/catalog.mjs +1 -1
  185. package/dist/esm/fields/TimePicker/catalog.mjs.map +1 -1
  186. package/dist/esm/fields/TimePicker/catalog.native.js +1 -1
  187. package/dist/esm/fields/TimePicker/catalog.native.js.map +1 -1
  188. package/dist/esm/fields/TimePicker/index.native.js +2 -2
  189. package/dist/esm/fields/TimePicker/index.native.js.map +1 -1
  190. package/dist/esm/fields/TimePicker/parts.mjs +13 -11
  191. package/dist/esm/fields/TimePicker/parts.mjs.map +1 -1
  192. package/dist/esm/fields/TimePicker/parts.native.js +16 -13
  193. package/dist/esm/fields/TimePicker/parts.native.js.map +1 -1
  194. package/dist/esm/fields/TimeRangeScrubber/geometry.native.js.map +1 -1
  195. package/dist/esm/fields/TimeRangeScrubber/index.native.js.map +1 -1
  196. package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
  197. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  198. package/dist/esm/fields/nativeDateTime/dateTimePickerLoader.native.js.map +1 -1
  199. package/dist/esm/fields/nativeDateTime/osDateTimeIosDisplay.native.js.map +1 -1
  200. package/dist/esm/fields/nativeSelect.native.js.map +1 -1
  201. package/dist/esm/fields/selectedOrder.native.js.map +1 -1
  202. package/dist/esm/formSpacing.native.js.map +1 -1
  203. package/dist/esm/hooks/useFocusManagement.native.js.map +1 -1
  204. package/dist/esm/index.native.js.map +1 -1
  205. package/dist/esm/keyboard/chain.native.js.map +1 -1
  206. package/dist/esm/keyboard/index.native.js.map +1 -1
  207. package/dist/esm/keyboard/types.native.js.map +1 -1
  208. package/dist/esm/requiredMarking.native.js.map +1 -1
  209. package/dist/esm/shared/TimeColumn.native.js.map +1 -1
  210. package/dist/esm/shared/capabilityPreflight.native.js.map +1 -1
  211. package/dist/esm/shared/choiceRowPress.native.js.map +1 -1
  212. package/dist/esm/shared/colorRamps.native.js.map +1 -1
  213. package/dist/esm/shared/devWarn.native.js.map +1 -1
  214. package/dist/esm/shared/floatingList.native.js.map +1 -1
  215. package/dist/esm/shared/focusManagement.native.js.map +1 -1
  216. package/dist/esm/shared/groupContext.native.js.map +1 -1
  217. package/dist/esm/shared/i18n.native.js.map +1 -1
  218. package/dist/esm/shared/instantMotion.native.js.map +1 -1
  219. package/dist/esm/shared/nativeA11y.native.js.map +1 -1
  220. package/dist/esm/shared/nativeAutoFocus.native.js.map +1 -1
  221. package/dist/esm/shared/overlayStack.native.js.map +1 -1
  222. package/dist/esm/shared/panelPortal.native.js.map +1 -1
  223. package/dist/esm/shared/pickerTriggerContract.native.js.map +1 -1
  224. package/dist/esm/shared/pressSlopProps.native.js.map +1 -1
  225. package/dist/esm/shared/restoreRetries.native.js.map +1 -1
  226. package/dist/esm/shared/t.native.js.map +1 -1
  227. package/dist/esm/shared/tableCellContext.native.js.map +1 -1
  228. package/dist/esm/shared/useDragScroll.native.js.map +1 -1
  229. package/dist/esm/shared/useKeyboardInset.native.js.map +1 -1
  230. package/dist/esm/shared/useSheetEscapeDismiss.native.js.map +1 -1
  231. package/dist/esm/shared/useWheelIncrement.native.js.map +1 -1
  232. package/dist/esm/shared/utils.native.js.map +1 -1
  233. package/dist/esm/shared/zIndex.native.js.map +1 -1
  234. package/dist/esm/themedPrimitives.native.js.map +1 -1
  235. package/dist/esm/types.native.js.map +1 -1
  236. package/dist/esm/utils/LinkCell.native.js.map +1 -1
  237. package/dist/jsx/FloatingPanel/index.native.js +8 -2
  238. package/dist/jsx/FloatingPanel/index.native.js.map +1 -1
  239. package/dist/jsx/fields/DatePicker/DateRangePicker.mjs +6 -10
  240. package/dist/jsx/fields/DatePicker/DateRangePicker.mjs.map +1 -1
  241. package/dist/jsx/fields/DatePicker/DateRangePicker.native.js +5 -9
  242. package/dist/jsx/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  243. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.mjs +8 -12
  244. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.mjs.map +1 -1
  245. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.native.js +7 -11
  246. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  247. package/dist/jsx/fields/DatePicker/DatetimePicker.native.js +5 -9
  248. package/dist/jsx/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  249. package/dist/jsx/fields/DatePicker/MonthPicker.mjs +6 -10
  250. package/dist/jsx/fields/DatePicker/MonthPicker.mjs.map +1 -1
  251. package/dist/jsx/fields/DatePicker/MonthPicker.native.js +5 -9
  252. package/dist/jsx/fields/DatePicker/MonthPicker.native.js.map +1 -1
  253. package/dist/jsx/fields/DatePicker/MultiDatePicker.mjs +6 -10
  254. package/dist/jsx/fields/DatePicker/MultiDatePicker.mjs.map +1 -1
  255. package/dist/jsx/fields/DatePicker/MultiDatePicker.native.js +5 -9
  256. package/dist/jsx/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  257. package/dist/jsx/fields/DatePicker/catalog.mjs +6 -10
  258. package/dist/jsx/fields/DatePicker/catalog.mjs.map +1 -1
  259. package/dist/jsx/fields/DatePicker/catalog.native.js +5 -9
  260. package/dist/jsx/fields/DatePicker/catalog.native.js.map +1 -1
  261. package/dist/jsx/fields/DatePicker/index.native.js +5 -9
  262. package/dist/jsx/fields/DatePicker/index.native.js.map +1 -1
  263. package/dist/jsx/fields/DatePicker/parts.mjs +46 -5
  264. package/dist/jsx/fields/DatePicker/parts.mjs.map +1 -1
  265. package/dist/jsx/fields/DatePicker/parts.native.js +50 -5
  266. package/dist/jsx/fields/DatePicker/parts.native.js.map +1 -1
  267. package/dist/jsx/fields/Select/InlineChoices.mjs +123 -0
  268. package/dist/jsx/fields/Select/InlineChoices.mjs.map +1 -0
  269. package/dist/jsx/fields/Select/InlineChoices.native.js +163 -0
  270. package/dist/jsx/fields/Select/InlineChoices.native.js.map +1 -0
  271. package/dist/jsx/fields/Select/index.mjs +67 -16
  272. package/dist/jsx/fields/Select/index.mjs.map +1 -1
  273. package/dist/jsx/fields/Select/index.native.js +73 -17
  274. package/dist/jsx/fields/Select/index.native.js.map +1 -1
  275. package/dist/jsx/fields/Select/shouldInlineChoices.mjs +11 -0
  276. package/dist/jsx/fields/Select/shouldInlineChoices.mjs.map +1 -0
  277. package/dist/jsx/fields/Select/shouldInlineChoices.native.js +43 -0
  278. package/dist/jsx/fields/Select/shouldInlineChoices.native.js.map +1 -0
  279. package/dist/jsx/fields/TimePicker/catalog.mjs +1 -1
  280. package/dist/jsx/fields/TimePicker/catalog.mjs.map +1 -1
  281. package/dist/jsx/fields/TimePicker/catalog.native.js +1 -1
  282. package/dist/jsx/fields/TimePicker/catalog.native.js.map +1 -1
  283. package/dist/jsx/fields/TimePicker/index.native.js +2 -2
  284. package/dist/jsx/fields/TimePicker/index.native.js.map +1 -1
  285. package/dist/jsx/fields/TimePicker/parts.mjs +13 -11
  286. package/dist/jsx/fields/TimePicker/parts.mjs.map +1 -1
  287. package/dist/jsx/fields/TimePicker/parts.native.js +16 -13
  288. package/dist/jsx/fields/TimePicker/parts.native.js.map +1 -1
  289. package/dist/jsx/index.native.js.map +1 -1
  290. package/package.json +8 -8
  291. package/src/FloatingPanel/FloatingPanel.menuFace.native.spec.tsx +13 -1
  292. package/src/FloatingPanel/index.native.tsx +8 -1
  293. package/src/fields/DatePicker/DatePicker.stories.tsx +6 -2
  294. package/src/fields/DatePicker/DateRangePicker.tsx +7 -10
  295. package/src/fields/DatePicker/DatetimePicker.catalog.tsx +9 -12
  296. package/src/fields/DatePicker/DatetimePicker.native.tsx +7 -11
  297. package/src/fields/DatePicker/DatetimePicker.stories.tsx +11 -2
  298. package/src/fields/DatePicker/MonthPicker.tsx +7 -10
  299. package/src/fields/DatePicker/MultiDatePicker.tsx +7 -10
  300. package/src/fields/DatePicker/catalog.tsx +7 -10
  301. package/src/fields/DatePicker/fieldStates.spec.tsx +120 -0
  302. package/src/fields/DatePicker/index.native.tsx +7 -11
  303. package/src/fields/DatePicker/parts.tsx +61 -2
  304. package/src/fields/Select/InlineChoices.tsx +156 -0
  305. package/src/fields/Select/index.tsx +64 -39
  306. package/src/fields/Select/shouldInlineChoices.spec.ts +25 -0
  307. package/src/fields/Select/shouldInlineChoices.ts +22 -0
  308. package/src/fields/TimePicker/TimePicker.stories.tsx +3 -4
  309. package/src/fields/TimePicker/catalog.tsx +1 -1
  310. package/src/fields/TimePicker/index.native.tsx +2 -2
  311. package/src/fields/TimePicker/parts.tsx +15 -9
  312. package/types/FloatingPanel/index.native.d.ts +1 -1
  313. package/types/FloatingPanel/index.native.d.ts.map +1 -1
  314. package/types/fields/Checkbox/index.d.ts +3 -3
  315. package/types/fields/DatePicker/DateRangePicker.d.ts.map +1 -1
  316. package/types/fields/DatePicker/DatetimePicker.catalog.d.ts.map +1 -1
  317. package/types/fields/DatePicker/DatetimePicker.native.d.ts.map +1 -1
  318. package/types/fields/DatePicker/MonthPicker.d.ts.map +1 -1
  319. package/types/fields/DatePicker/MultiDatePicker.d.ts.map +1 -1
  320. package/types/fields/DatePicker/catalog.d.ts.map +1 -1
  321. package/types/fields/DatePicker/index.native.d.ts.map +1 -1
  322. package/types/fields/DatePicker/parts.d.ts +14 -0
  323. package/types/fields/DatePicker/parts.d.ts.map +1 -1
  324. package/types/fields/Select/InlineChoices.d.ts +29 -0
  325. package/types/fields/Select/InlineChoices.d.ts.map +1 -0
  326. package/types/fields/Select/index.d.ts +6 -0
  327. package/types/fields/Select/index.d.ts.map +1 -1
  328. package/types/fields/Select/shouldInlineChoices.d.ts +16 -0
  329. package/types/fields/Select/shouldInlineChoices.d.ts.map +1 -0
  330. package/types/fields/TimePicker/parts.d.ts +3 -1
  331. package/types/fields/TimePicker/parts.d.ts.map +1 -1
@@ -23,6 +23,7 @@ import {
23
23
  CalendarHeader,
24
24
  CalendarPanelFrame,
25
25
  DatePickerInputTrigger,
26
+ DatePickerReadOnlyField,
26
27
  DatePickerPopoverShell,
27
28
  CalendarViewSwitcher,
28
29
  isSameDay,
@@ -424,16 +425,12 @@ export function MultiDatePicker<
424
425
  ) => {
425
426
  if (readOnly) {
426
427
  return (
427
- <InputParts.Box>
428
- <InputParts.Area
429
- value={formatMultiDates(selectedDates)}
430
- readOnly
431
- aria-readonly="true"
432
- aria-required={required || undefined}
433
- aria-invalid={hasError || undefined}
434
- placeholder={placeholder}
435
- />
436
- </InputParts.Box>
428
+ <DatePickerReadOnlyField
429
+ value={formatMultiDates(selectedDates)}
430
+ aria-required={required || undefined}
431
+ aria-invalid={hasError || undefined}
432
+ placeholder={placeholder}
433
+ />
437
434
  );
438
435
  }
439
436
  const handleOpenChange = (isOpen: boolean) => {
@@ -22,6 +22,7 @@ import {
22
22
  CalendarHeader,
23
23
  CalendarPanelFrame,
24
24
  DatePickerInputTrigger,
25
+ DatePickerReadOnlyField,
25
26
  DatePickerPopoverShell,
26
27
  CalendarViewSwitcher,
27
28
  formatDateDisplay,
@@ -283,16 +284,12 @@ export function DatePicker<
283
284
  ) => {
284
285
  if (readOnly) {
285
286
  return (
286
- <InputParts.Box>
287
- <InputParts.Area
288
- value={formatDateDisplay(selectedDate)}
289
- readOnly
290
- aria-readonly="true"
291
- aria-required={required || undefined}
292
- aria-invalid={hasError || undefined}
293
- placeholder={placeholder}
294
- />
295
- </InputParts.Box>
287
+ <DatePickerReadOnlyField
288
+ value={formatDateDisplay(selectedDate)}
289
+ aria-required={required || undefined}
290
+ aria-invalid={hasError || undefined}
291
+ placeholder={placeholder}
292
+ />
296
293
  );
297
294
  }
298
295
 
@@ -0,0 +1,120 @@
1
+ import type { ReactElement } from "react";
2
+ import { describe, expect, it, vi } from "vitest";
3
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
4
+ import { YStack } from "tamagui";
5
+ import { TimePicker } from "../TimePicker";
6
+ import * as timeStories from "../TimePicker/TimePicker.stories";
7
+ import { DatePicker, DateRangePicker, DatetimePicker, MonthPicker, MultiDatePicker } from "./index";
8
+
9
+ vi.mock("@multiplatform.one/storybook", () => ({ action: () => () => {} }));
10
+ vi.mock("@multiplatform.one/table", () => ({ DataTable: () => null }));
11
+
12
+ // FZ-7853 round 2. happy-dom has no layout, so these pin the CSS and the
13
+ // anatomy; lc-verify LC-10 fieldEdge measures the shared right edge in the
14
+ // browser at 320 and 390.
15
+
16
+ function render(node: ReactElement) {
17
+ return renderWithProviders(<YStack width={360}>{node}</YStack>).container;
18
+ }
19
+
20
+ function box(root: HTMLElement) {
21
+ const found = root.querySelector<HTMLElement>("[data-mp-input-box]");
22
+ expect(found).toBeTruthy();
23
+ return found as HTMLElement;
24
+ }
25
+
26
+ const datePickers = [
27
+ ["DatePicker", (p: object) => <DatePicker label="Date" {...p} />, "2026-10-31"],
28
+ [
29
+ "DatetimePicker",
30
+ (p: object) => <DatetimePicker label="When" {...p} />,
31
+ new Date("2026-10-31T09:30:00"),
32
+ ],
33
+ [
34
+ "MonthPicker",
35
+ ({ value, ...p }: { value?: unknown; readOnly?: boolean }) => (
36
+ <MonthPicker label="Month" defaultValue={value} {...p} />
37
+ ),
38
+ { year: 2026, month: 9 },
39
+ ],
40
+ ] as const;
41
+
42
+ describe("FZ-7853 one right edge: every state fills its row", () => {
43
+ it.each([
44
+ ["DatePicker empty", <DatePicker key="a" label="Date" />],
45
+ ["DatePicker filled", <DatePicker key="b" label="Date" value="2026-10-31" />],
46
+ ["DatePicker read-only", <DatePicker key="c" label="Date" value="2026-10-31" readOnly />],
47
+ ["DatePicker disabled", <DatePicker key="d" label="Date" value="2026-10-31" disabled />],
48
+ ["DatetimePicker empty", <DatetimePicker key="e" label="When" />],
49
+ ["MonthPicker empty", <MonthPicker key="f" label="Month" />],
50
+ ["DateRangePicker empty", <DateRangePicker key="g" label="Range" />],
51
+ ["MultiDatePicker empty", <MultiDatePicker key="h" label="Days" />],
52
+ ["TimePicker empty", <TimePicker key="i" label="Time" />],
53
+ ["TimePicker filled", <TimePicker key="j" label="Time" value="09:30" />],
54
+ ["TimePicker read-only", <TimePicker key="k" label="Time" value="09:30" readOnly />],
55
+ ["TimePicker disabled", <TimePicker key="l" label="Time" value="09:30" disabled />],
56
+ ])("%s grows to the row, not to its content", (_name, node) => {
57
+ const cs = getComputedStyle(box(render(node)));
58
+ expect(cs.flexGrow).toBe("1");
59
+ expect(cs.minWidth).toBe("0px");
60
+ expect(cs.maxWidth).toBe("100%");
61
+ });
62
+ });
63
+
64
+ describe("FZ-7853 same shell in every state", () => {
65
+ it.each(datePickers)(
66
+ "%s read-only keeps the glyph and the insets, and drops only the clear action",
67
+ (_name, make, value) => {
68
+ const editable = box(render(make({ value })));
69
+ const readOnly = render(make({ value, readOnly: true }));
70
+ const readOnlyBox = box(readOnly);
71
+ expect(readOnlyBox.querySelector("[data-testid='date-picker-glyph']")).toBeTruthy();
72
+ expect(readOnly.querySelector("[data-testid='date-picker-clear']")).toBeNull();
73
+ expect(readOnly.querySelector("input")?.getAttribute("aria-readonly")).toBe("true");
74
+ for (const side of ["paddingLeft", "paddingRight", "height", "borderTopWidth"] as const) {
75
+ expect(getComputedStyle(readOnlyBox)[side]).toBe(getComputedStyle(editable)[side]);
76
+ }
77
+ },
78
+ );
79
+
80
+ it("TimePicker read-only keeps the clock glyph, drops the clear action and opens nothing", () => {
81
+ const editable = box(render(<TimePicker label="Time" value="09:30" />));
82
+ const root = render(<TimePicker label="Time" value="09:30" readOnly />);
83
+ const readOnlyBox = box(root);
84
+ expect(readOnlyBox.querySelector("[data-testid='time-picker-glyph']")).toBeTruthy();
85
+ expect(root.querySelector("[data-testid='time-picker-clear']")).toBeNull();
86
+ expect(root.querySelector("input")?.getAttribute("aria-readonly")).toBe("true");
87
+ for (const side of ["paddingLeft", "paddingRight", "height"] as const) {
88
+ expect(getComputedStyle(readOnlyBox)[side]).toBe(getComputedStyle(editable)[side]);
89
+ }
90
+ });
91
+
92
+ it.each([
93
+ ["DatePicker", <DatePicker key="a" label="Date" value="2026-10-31" disabled />, "date"],
94
+ ["TimePicker", <TimePicker key="b" label="Time" value="09:30" disabled />, "time"],
95
+ ])("%s disabled keeps the glyph and the geometry, dimmed", (_name, node, kind) => {
96
+ const disabled = box(render(node));
97
+ expect(disabled.querySelector(`[data-testid='${kind}-picker-glyph']`)).toBeTruthy();
98
+ expect(getComputedStyle(disabled).opacity).toBe("0.5");
99
+ });
100
+ });
101
+
102
+ describe("FZ-7853 TimePicker stories carry one label (LC-171)", () => {
103
+ it.each(["Basic", "Standalone", "WithError", "Disabled"] as const)(
104
+ "%s: the hint is the placeholder, not a second line under the label",
105
+ (name) => {
106
+ const args = (timeStories[name] as { args: Record<string, unknown> }).args;
107
+ expect(args.helperText).toBeUndefined();
108
+ const root = render(<TimePicker {...(args as object)} />);
109
+ expect(root.textContent ?? "").not.toContain("Select a time");
110
+ if (name !== "Disabled") {
111
+ expect(args.placeholder).toBe("Select a time");
112
+ }
113
+ },
114
+ );
115
+
116
+ it("an empty TimePicker shows the hint inside the field", () => {
117
+ const root = render(<TimePicker label="Time" placeholder="Select a time" />);
118
+ expect(root.querySelector("input")?.getAttribute("placeholder")).toBe("Select a time");
119
+ });
120
+ });
@@ -24,7 +24,7 @@ import { loadDateTimePicker } from "../nativeDateTime/dateTimePickerLoader";
24
24
  import { OsDateTimeSheet } from "../nativeDateTime/OsDateTimeSheet";
25
25
  import { DatePicker as CatalogDatePicker } from "./catalog";
26
26
  import { DatePickerFieldValueSync } from "./fieldValueSync";
27
- import { DatePickerInputTrigger, formatDateDisplay } from "./parts";
27
+ import { DatePickerInputTrigger, DatePickerReadOnlyField, formatDateDisplay } from "./parts";
28
28
  import { coerceToDate } from "./utils";
29
29
 
30
30
  export type DatePickerProps<
@@ -138,16 +138,12 @@ export function DatePicker<
138
138
  ) => {
139
139
  if (readOnly) {
140
140
  return (
141
- <InputParts.Box>
142
- <InputParts.Area
143
- value={formatDateDisplay(selectedDate)}
144
- readOnly
145
- aria-readonly="true"
146
- aria-required={required || undefined}
147
- aria-invalid={hasError || undefined}
148
- placeholder={placeholder}
149
- />
150
- </InputParts.Box>
141
+ <DatePickerReadOnlyField
142
+ value={formatDateDisplay(selectedDate)}
143
+ aria-required={required || undefined}
144
+ aria-invalid={hasError || undefined}
145
+ placeholder={placeholder}
146
+ />
151
147
  );
152
148
  }
153
149
  return (
@@ -933,8 +933,11 @@ export function DatePickerInputTrigger({
933
933
  pointerEvents={isWeb ? undefined : "none"}
934
934
  >
935
935
  <InputParts.Box
936
- // Yoga has no intrinsic TextInput width to size this row child.
937
- {...(isWeb ? undefined : { flex: 1, minWidth: 0 })}
936
+ // FZ-7853: the box fills its row on every platform, so an empty
937
+ // trigger ends on the same inset as a filled one (Yoga also has no
938
+ // intrinsic TextInput width to size it).
939
+ flex={1}
940
+ minWidth={0}
938
941
  // Elevation is an overlay recipe: it belongs on the open panel, never
939
942
  // on the closed text-field trigger.
940
943
  elevation={undefined}
@@ -984,6 +987,62 @@ export function DatePickerInputTrigger({
984
987
  );
985
988
  }
986
989
 
990
+ interface DatePickerReadOnlyFieldProps {
991
+ value: string;
992
+ placeholder?: string;
993
+ id?: string;
994
+ glyph?: "calendar" | "clock";
995
+ "aria-label"?: string;
996
+ "aria-required"?: boolean;
997
+ "aria-invalid"?: boolean;
998
+ }
999
+
1000
+ /**
1001
+ * FZ-7853: a read-only picker keeps the trigger's shell (glyph in the
1002
+ * secondary ink, same insets, full row) and leaves out only the clear action.
1003
+ */
1004
+ export function DatePickerReadOnlyField({
1005
+ value,
1006
+ placeholder,
1007
+ id,
1008
+ glyph = "calendar",
1009
+ "aria-label": ariaLabel,
1010
+ "aria-required": ariaRequired,
1011
+ "aria-invalid": ariaInvalid,
1012
+ }: DatePickerReadOnlyFieldProps) {
1013
+ const Glyph = glyph === "clock" ? ClockIcon : CalendarBlankIcon;
1014
+ return (
1015
+ <View flexDirection="row" alignItems="center" width="100%">
1016
+ <InputParts.Box
1017
+ flex={1}
1018
+ minWidth={0}
1019
+ elevation={undefined}
1020
+ data-testid="date-picker-readonly"
1021
+ >
1022
+ <InputParts.Section data-testid="date-picker-glyph">
1023
+ <InputParts.Icon adornment="leading" color={formCommonColors.muted}>
1024
+ <Glyph />
1025
+ </InputParts.Icon>
1026
+ </InputParts.Section>
1027
+ <InputParts.Section>
1028
+ <InputParts.Area
1029
+ readOnly
1030
+ id={id}
1031
+ value={value}
1032
+ placeholder={placeholder}
1033
+ color={formCommonColors.text}
1034
+ placeholderTextColor={formCommonColors.muted}
1035
+ aria-label={ariaLabel}
1036
+ aria-readonly="true"
1037
+ aria-required={ariaRequired}
1038
+ aria-invalid={ariaInvalid}
1039
+ />
1040
+ </InputParts.Section>
1041
+ </InputParts.Box>
1042
+ </View>
1043
+ );
1044
+ }
1045
+
987
1046
  // ---------------------------------------------------------------------------
988
1047
  // DatePickerPopoverShell — FloatingPanel (sheet below OVERLAY_BREAKPOINT)
989
1048
  // ---------------------------------------------------------------------------
@@ -0,0 +1,156 @@
1
+ import { hairline, IconSlot, keyboardFocusRingProps } from "@multiplatform.one/theme";
2
+ import { CheckIcon } from "@phosphor-icons/react";
3
+ import { useRef, type KeyboardEvent, type ReactNode } from "react";
4
+ import { Pressable } from "react-native";
5
+ import { isWeb, Text, View, XStack, YStack } from "tamagui";
6
+ import { useFieldDescribedBy } from "../../fieldLayout";
7
+ import { formCommonColors, formInputColors } from "../../shared/colorRamps";
8
+ import { choiceItemA11y } from "../../shared/nativeA11y";
9
+
10
+ export interface InlineChoice {
11
+ value: string;
12
+ label: string;
13
+ icon?: ReactNode;
14
+ }
15
+
16
+ export interface InlineChoicesProps {
17
+ options: InlineChoice[];
18
+ value?: string;
19
+ onValueChange: (value: string) => void;
20
+ onBlur?: (...args: any[]) => void;
21
+ disabled?: boolean;
22
+ /** The field id: FieldLayout's label points at it. */
23
+ id?: string;
24
+ labelledBy?: string;
25
+ "aria-label"?: string;
26
+ knobProps: any;
27
+ /** The LC-05 selected mark, already resolved to a paint. */
28
+ markColor: string;
29
+ }
30
+
31
+ const nextKeys = new Set(["ArrowDown", "ArrowRight"]);
32
+ const previousKeys = new Set(["ArrowUp", "ArrowLeft"]);
33
+
34
+ /**
35
+ * A short Select inside a sheet laid out in place (LC-262 DIRECT-ACTIONS): one
36
+ * grouped list of radio rows, each with its glyph and label, the chosen row
37
+ * marked by the accent check alone. No trigger and no popover. On the web it
38
+ * is one tab stop, arrows move and choose, Space and Enter choose (APG radio
39
+ * group).
40
+ */
41
+ export function InlineChoices({
42
+ options,
43
+ value,
44
+ onValueChange,
45
+ onBlur,
46
+ disabled,
47
+ id,
48
+ labelledBy,
49
+ "aria-label": ariaLabel,
50
+ knobProps,
51
+ markColor,
52
+ }: InlineChoicesProps) {
53
+ const describedBy = useFieldDescribedBy();
54
+ const rowsRef = useRef<Array<HTMLElement | null>>([]);
55
+ const textColor = knobProps.textAccentColor;
56
+ const selectedIndex = options.findIndex((option) => option.value === value);
57
+ const tabStop = selectedIndex >= 0 ? selectedIndex : 0;
58
+
59
+ const choose = (index: number) => {
60
+ const option = options[index];
61
+ if (disabled || !option || option.value === value) return;
62
+ onValueChange(option.value);
63
+ };
64
+
65
+ const onKeyDown = (index: number) => (event: KeyboardEvent) => {
66
+ const step = nextKeys.has(event.key) ? 1 : previousKeys.has(event.key) ? -1 : 0;
67
+ if (step) {
68
+ event.preventDefault();
69
+ const next = (index + step + options.length) % options.length;
70
+ rowsRef.current[next]?.focus();
71
+ choose(next);
72
+ } else if (event.key === " " || event.key === "Enter") {
73
+ event.preventDefault();
74
+ choose(index);
75
+ }
76
+ };
77
+
78
+ const rowContent = (option: InlineChoice, index: number, selected: boolean) => (
79
+ <XStack
80
+ alignItems="center"
81
+ height={knobProps.menuRow.minHeight}
82
+ paddingHorizontal={knobProps.panelPadding.padding}
83
+ {...knobProps.gap}
84
+ {...(index === 0 ? undefined : hairline.top)}
85
+ borderColor={formCommonColors.divider}
86
+ pointerEvents="none"
87
+ >
88
+ <View flexShrink={0} alignItems="center" justifyContent="center" minWidth={18}>
89
+ <IconSlot icon={option.icon} color={textColor} />
90
+ </View>
91
+ <Text
92
+ fontFamily={knobProps.body.fontFamily}
93
+ fontWeight={knobProps.body.fontWeight}
94
+ color={textColor}
95
+ numberOfLines={1}
96
+ flex={1}
97
+ >
98
+ {option.label}
99
+ </Text>
100
+ {selected ? <CheckIcon size={14} weight="bold" color={markColor} /> : null}
101
+ </XStack>
102
+ );
103
+
104
+ return (
105
+ <YStack
106
+ id={id}
107
+ role="radiogroup"
108
+ aria-labelledby={labelledBy}
109
+ aria-label={labelledBy ? undefined : ariaLabel}
110
+ aria-describedby={describedBy}
111
+ aria-disabled={disabled || undefined}
112
+ data-testid="select-inline-choices"
113
+ {...knobProps.borderRadius}
114
+ borderColor={formInputColors.border.base}
115
+ backgroundColor={formInputColors.background.base}
116
+ overflow="hidden"
117
+ width="100%"
118
+ >
119
+ {options.map((option, index) => {
120
+ const selected = option.value === value;
121
+ if (isWeb) {
122
+ return (
123
+ <View
124
+ key={option.value}
125
+ ref={(node: any) => {
126
+ rowsRef.current[index] = node;
127
+ }}
128
+ role="radio"
129
+ aria-checked={selected}
130
+ aria-disabled={disabled || undefined}
131
+ tabIndex={!disabled && index === tabStop ? 0 : -1}
132
+ cursor={disabled ? "default" : "pointer"}
133
+ onPress={() => choose(index)}
134
+ onKeyDown={onKeyDown(index)}
135
+ onBlur={onBlur}
136
+ outlineWidth={0}
137
+ focusVisibleStyle={keyboardFocusRingProps}
138
+ >
139
+ {rowContent(option, index, selected)}
140
+ </View>
141
+ );
142
+ }
143
+ return (
144
+ <Pressable
145
+ key={option.value}
146
+ {...choiceItemA11y({ name: option.label, selected, disabled: !!disabled })}
147
+ disabled={disabled}
148
+ onPress={() => choose(index)}
149
+ >
150
+ {rowContent(option, index, selected)}
151
+ </Pressable>
152
+ );
153
+ })}
154
+ </YStack>
155
+ );
156
+ }
@@ -1,4 +1,4 @@
1
- import { useTouchSurface } from "@multiplatform.one/theme";
1
+ import { IconSlot, useTouchSurface } from "@multiplatform.one/theme";
2
2
  import type { KeyboardEvent, MouseEvent, ReactNode, RefObject, UIEvent } from "react";
3
3
  import {
4
4
  useCallback,
@@ -71,6 +71,8 @@ import { useIsInTableCell } from "../../shared/tableCellContext";
71
71
  import { t } from "../../shared/t";
72
72
  import { orderOptionsBySelected, type SelectedOrder } from "../selectedOrder";
73
73
  import { shouldUseIosNativeSelect } from "../nativeSelect";
74
+ import { InlineChoices } from "./InlineChoices";
75
+ import { shouldInlineChoices } from "./shouldInlineChoices";
74
76
 
75
77
  /** Undefined on web (RNW ships no ActionSheetIOS); real on iOS. */
76
78
  const actionSheetIOS = (ReactNative as { ActionSheetIOS?: typeof ReactNative.ActionSheetIOS })
@@ -83,6 +85,12 @@ export interface SelectOption {
83
85
  label: string;
84
86
  /** Optional group label for grouping options */
85
87
  group?: string;
88
+ /**
89
+ * Leading glyph on the option's row (LC-112: every menu row carries one when
90
+ * the options have them). Inside a sheet, five or fewer options that all
91
+ * carry one render inline as an icon choice list (LC-262).
92
+ */
93
+ icon?: ReactNode;
86
94
  }
87
95
 
88
96
  export interface SelectProps {
@@ -160,8 +168,9 @@ const SelectRow = styled(View, {
160
168
  // Do not put outlineWidth here — Tamagui maps these onto mouse :focus and
161
169
  // they beat instance ring props. Rows paint the ring via selectItemRingProps.
162
170
  variants: {
171
+ // LC-262: the accent check alone marks the chosen row, never a grey fill.
163
172
  selected: {
164
- true: { backgroundColor: formInputColors.background.base, borderRadius: 0 },
173
+ true: { backgroundColor: "transparent", borderRadius: 0 },
165
174
  false: { backgroundColor: "transparent" },
166
175
  },
167
176
  active: {
@@ -174,6 +183,15 @@ const SelectRow = styled(View, {
174
183
  } as const,
175
184
  });
176
185
 
186
+ /** An option's leading glyph, in the row's ink. */
187
+ function OptionGlyph({ icon, color }: { icon: ReactNode; color?: string }) {
188
+ return (
189
+ <View flexShrink={0} alignItems="center" justifyContent="center" minWidth={18}>
190
+ <IconSlot icon={icon} color={color} />
191
+ </View>
192
+ );
193
+ }
194
+
177
195
  function GroupHeader(props: HouseTextProps) {
178
196
  return (
179
197
  <HouseText
@@ -442,7 +460,9 @@ const SelectItem = memo(function SelectItem({
442
460
  role="option"
443
461
  tabIndex={-1}
444
462
  selected={isSelected}
445
- active={isActive}
463
+ // The open-time cursor sits on the chosen row; it only paints while the
464
+ // keyboard drives it, so the chosen row never opens grey (LC-262).
465
+ active={Boolean(isActive) && ctx.kbNav}
446
466
  aria-selected={isSelected}
447
467
  data-state={isSelected ? "active" : "inactive"}
448
468
  height={ctx.knobProps.menuRow.minHeight}
@@ -456,22 +476,15 @@ const SelectItem = memo(function SelectItem({
456
476
  {...(suppressHover
457
477
  ? {
458
478
  hoverStyle: {
459
- backgroundColor: isActive
460
- ? formInputColors.background.focus
461
- : isSelected
462
- ? formInputColors.background.base
463
- : "transparent",
479
+ backgroundColor: isActive ? formInputColors.background.focus : "transparent",
464
480
  },
465
481
  }
466
482
  : {
467
- hoverStyle: {
468
- backgroundColor: isSelected
469
- ? formInputColors.background.base
470
- : formInputColors.background.focus,
471
- },
483
+ hoverStyle: { backgroundColor: formInputColors.background.focus },
472
484
  })}
473
485
  {...transitionProps(ctx.knobProps.motion.control)}
474
486
  >
487
+ {option.icon ? <OptionGlyph icon={option.icon} color={ctx.textColor} /> : null}
475
488
  <Text
476
489
  fontFamily={ctx.knobProps.body.fontFamily}
477
490
  fontWeight={ctx.knobProps.body.fontWeight}
@@ -1435,30 +1448,16 @@ function NativeSelectCore({
1435
1448
  {...(isWeb ? selectItemRingProps(active, kbNav) : undefined)}
1436
1449
  hoverStyle={
1437
1450
  activeIndex != null
1438
- ? {
1439
- backgroundColor: active
1440
- ? formInputColors.background.focus
1441
- : selected
1442
- ? formInputColors.background.base
1443
- : "transparent",
1444
- }
1445
- : {
1446
- backgroundColor: selected
1447
- ? formInputColors.background.base
1448
- : formInputColors.background.focus,
1449
- }
1450
- }
1451
- backgroundColor={
1452
- active
1453
- ? formInputColors.background.focus
1454
- : selected
1455
- ? formInputColors.background.base
1456
- : "transparent"
1451
+ ? { backgroundColor: active ? formInputColors.background.focus : "transparent" }
1452
+ : { backgroundColor: formInputColors.background.focus }
1457
1453
  }
1454
+ // LC-262: the accent check alone marks the chosen row.
1455
+ backgroundColor={active && kbNav ? formInputColors.background.focus : "transparent"}
1458
1456
  pressStyle={{ backgroundColor: formInputColors.background.focus }}
1459
1457
  // Native: parent RNPressable owns the hit; disable child stealing.
1460
1458
  pointerEvents={isWeb ? undefined : "none"}
1461
1459
  >
1460
+ {option.icon ? <OptionGlyph icon={option.icon} color={textColor} /> : null}
1462
1461
  <Text
1463
1462
  fontFamily={knobProps.body.fontFamily}
1464
1463
  fontWeight={knobProps.body.fontWeight}
@@ -1747,13 +1746,6 @@ export function Select({
1747
1746
  const isControlled = value !== undefined;
1748
1747
  const hasLabel = Boolean(label);
1749
1748
 
1750
- // DG-CTRL-01 / DG-CTRL-05 — short single-select lists prefer RadioGroup.
1751
- warnSelectTooFewOptions({
1752
- count: options?.length ?? 0,
1753
- multiple,
1754
- component: "Select",
1755
- id,
1756
- });
1757
1749
  const viewportGtSm = useViewportGtSm();
1758
1750
  const insideOverlay = useInsideOverlay();
1759
1751
  // Sheet core on native and below `$sm` (viewport < 640, OVERLAY_BREAKPOINT).
@@ -1767,6 +1759,19 @@ export function Select({
1767
1759
  hydrated &&
1768
1760
  resolveCompactFace(pickerCompactFace(options?.length ?? 0), insideOverlay) === "menu";
1769
1761
  const shouldUseSheet = !isWeb || (!effectiveGtSm && !compactMenu);
1762
+ const inTableCell = useIsInTableCell();
1763
+ const inline = !inTableCell && shouldInlineChoices({ insideOverlay, multiple, options });
1764
+ // DG-CTRL-01 / DG-CTRL-05 — short single-select lists prefer RadioGroup,
1765
+ // which the inline face already is.
1766
+ if (!inline) {
1767
+ warnSelectTooFewOptions({
1768
+ count: options?.length ?? 0,
1769
+ multiple,
1770
+ component: "Select",
1771
+ id,
1772
+ });
1773
+ }
1774
+ const markColor = useSelectedMarkColor();
1770
1775
 
1771
1776
  // Render skeleton placeholder
1772
1777
  if (skeleton) {
@@ -1831,6 +1836,26 @@ export function Select({
1831
1836
  handleBlur?: (...args: any[]) => void,
1832
1837
  ) => {
1833
1838
  if (readOnly) return renderReadOnly(selectValue);
1839
+ if (inline) {
1840
+ return (
1841
+ <InlineChoices
1842
+ options={options}
1843
+ value={typeof selectValue === "string" ? selectValue : undefined}
1844
+ onValueChange={(val) => {
1845
+ if (disabled) return;
1846
+ handleValueChange?.(val);
1847
+ emitValueChange(val);
1848
+ }}
1849
+ onBlur={handleBlur}
1850
+ disabled={disabled}
1851
+ id={id}
1852
+ labelledBy={hasLabel ? `${id}-label` : undefined}
1853
+ aria-label={ariaLabel}
1854
+ knobProps={knobProps}
1855
+ markColor={markColor}
1856
+ />
1857
+ );
1858
+ }
1834
1859
  const SelectCore = shouldUseSheet ? NativeSelectCore : FloatingSelectCore;
1835
1860
  return (
1836
1861
  <SelectCore
@@ -0,0 +1,25 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { INLINE_CHOICES_MAX, shouldInlineChoices } from "./shouldInlineChoices";
3
+
4
+ const glyph = "•";
5
+ const withIcons = (n: number) => Array.from({ length: n }, () => ({ icon: glyph }));
6
+
7
+ describe("shouldInlineChoices (LC-262, FZ-7830)", () => {
8
+ it("lays out five or fewer glyphed options inline inside an overlay", () => {
9
+ expect(INLINE_CHOICES_MAX).toBe(5);
10
+ expect(shouldInlineChoices({ insideOverlay: true, options: withIcons(2) })).toBe(true);
11
+ expect(shouldInlineChoices({ insideOverlay: true, options: withIcons(5) })).toBe(true);
12
+ });
13
+
14
+ it("keeps the trigger past five, without a glyph on every option, at page level, or for multiple", () => {
15
+ expect(shouldInlineChoices({ insideOverlay: true, options: withIcons(6) })).toBe(false);
16
+ expect(shouldInlineChoices({ insideOverlay: true, options: [...withIcons(3), {}] })).toBe(
17
+ false,
18
+ );
19
+ expect(shouldInlineChoices({ insideOverlay: false, options: withIcons(3) })).toBe(false);
20
+ expect(
21
+ shouldInlineChoices({ insideOverlay: true, multiple: true, options: withIcons(3) }),
22
+ ).toBe(false);
23
+ expect(shouldInlineChoices({ insideOverlay: true, options: [] })).toBe(false);
24
+ });
25
+ });