@multiplatform.one/forms 7.5.0 → 7.6.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 (586) hide show
  1. package/dist/cjs/AdaptivePopup/index.native.js +1 -1
  2. package/dist/cjs/AdaptivePopup/index.native.js.map +1 -1
  3. package/dist/cjs/Button/index.cjs +6 -10
  4. package/dist/cjs/Button/index.native.js +7 -11
  5. package/dist/cjs/Button/index.native.js.map +1 -1
  6. package/dist/cjs/Chip/index.native.js.map +1 -1
  7. package/dist/cjs/ContextualSaveBar/UnsavedChangesDialog.cjs +0 -1
  8. package/dist/cjs/ContextualSaveBar/UnsavedChangesDialog.native.js +1 -2
  9. package/dist/cjs/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
  10. package/dist/cjs/ContextualSaveBar/clientKnownIdentity.native.js.map +1 -1
  11. package/dist/cjs/ContextualSaveBar/commitImmediateField.native.js.map +1 -1
  12. package/dist/cjs/ContextualSaveBar/index.native.js +3 -3
  13. package/dist/cjs/ContextualSaveBar/index.native.js.map +1 -1
  14. package/dist/cjs/ContextualSaveBar/useUnsavedChangesGuard.native.js.map +1 -1
  15. package/dist/cjs/ControlGroup/index.native.js +1 -1
  16. package/dist/cjs/ControlGroup/index.native.js.map +1 -1
  17. package/dist/cjs/DescriptionList/index.native.js +2 -2
  18. package/dist/cjs/DescriptionList/index.native.js.map +1 -1
  19. package/dist/cjs/ErrorSummary.native.js.map +1 -1
  20. package/dist/cjs/FieldDisplay/editMode.native.js.map +1 -1
  21. package/dist/cjs/FieldDisplay/formatters.native.js.map +1 -1
  22. package/dist/cjs/FieldDisplay/index.cjs +2 -1
  23. package/dist/cjs/FieldDisplay/index.native.js +10 -3
  24. package/dist/cjs/FieldDisplay/index.native.js.map +1 -1
  25. package/dist/cjs/FieldGroup.native.js.map +1 -1
  26. package/dist/cjs/FloatingPanel/index.cjs +8 -1
  27. package/dist/cjs/FloatingPanel/useFloatingPanel.native.js.map +1 -1
  28. package/dist/cjs/Form/index.native.js +1 -1
  29. package/dist/cjs/Form/index.native.js.map +1 -1
  30. package/dist/cjs/Form/validateOn.native.js.map +1 -1
  31. package/dist/cjs/FormGrid.native.js.map +1 -1
  32. package/dist/cjs/FormSection.native.js.map +1 -1
  33. package/dist/cjs/InputParts/index.cjs +64 -2
  34. package/dist/cjs/InputParts/index.native.js +70 -4
  35. package/dist/cjs/InputParts/index.native.js.map +1 -1
  36. package/dist/cjs/Label/index.native.js.map +1 -1
  37. package/dist/cjs/Skeleton/index.native.js.map +1 -1
  38. package/dist/cjs/Spinner/SpinnerGlyph.native.js.map +1 -1
  39. package/dist/cjs/Spinner/spinnerSize.native.js.map +1 -1
  40. package/dist/cjs/Table/index.native.js.map +1 -1
  41. package/dist/cjs/Wheel/haptic.native.js.map +1 -1
  42. package/dist/cjs/Wheel/index.native.js.map +1 -1
  43. package/dist/cjs/actionLabel.native.js.map +1 -1
  44. package/dist/cjs/fieldDefaults.native.js.map +1 -1
  45. package/dist/cjs/fieldLayout.native.js +1 -1
  46. package/dist/cjs/fieldLayout.native.js.map +1 -1
  47. package/dist/cjs/fields/Barcode/BarcodePreview.cjs +15 -9
  48. package/dist/cjs/fields/Barcode/BarcodePreview.native.js +15 -9
  49. package/dist/cjs/fields/Barcode/BarcodePreview.native.js.map +1 -1
  50. package/dist/cjs/fields/Barcode/BarcodeScanner.native.js +1 -1
  51. package/dist/cjs/fields/Barcode/code128.native.js.map +1 -1
  52. package/dist/cjs/fields/Barcode/index.native.js +2 -2
  53. package/dist/cjs/fields/Barcode/index.native.js.map +1 -1
  54. package/dist/cjs/fields/Barcode/qr.native.js.map +1 -1
  55. package/dist/cjs/fields/Barcode/scannerTypes.native.js.map +1 -1
  56. package/dist/cjs/fields/Checkbox/Checkbox.native.js +1 -1
  57. package/dist/cjs/fields/Checkbox/Checkbox.native.js.map +1 -1
  58. package/dist/cjs/fields/Checkbox/CheckboxBox.native.js.map +1 -1
  59. package/dist/cjs/fields/Checkbox/CheckboxCard.native.js.map +1 -1
  60. package/dist/cjs/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  61. package/dist/cjs/fields/Checkbox/CheckboxGroup.native.js +1 -1
  62. package/dist/cjs/fields/Checkbox/CheckboxGroup.native.js.map +1 -1
  63. package/dist/cjs/fields/Checkbox/index.native.js.map +1 -1
  64. package/dist/cjs/fields/ColorPicker/index.native.js +3 -3
  65. package/dist/cjs/fields/ColorPicker/index.native.js.map +1 -1
  66. package/dist/cjs/fields/ColorPicker/parts.native.js +2 -2
  67. package/dist/cjs/fields/ColorPicker/parts.native.js.map +1 -1
  68. package/dist/cjs/fields/Combobox/authorOptions.native.js.map +1 -1
  69. package/dist/cjs/fields/Combobox/index.cjs +14 -11
  70. package/dist/cjs/fields/Combobox/index.native.js +21 -16
  71. package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
  72. package/dist/cjs/fields/DatePicker/Calendar.native.js.map +1 -1
  73. package/dist/cjs/fields/DatePicker/DateRangePicker.native.js +2 -2
  74. package/dist/cjs/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  75. package/dist/cjs/fields/DatePicker/DatetimePicker.native.js +3 -3
  76. package/dist/cjs/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  77. package/dist/cjs/fields/DatePicker/MonthPicker.native.js +2 -2
  78. package/dist/cjs/fields/DatePicker/MonthPicker.native.js.map +1 -1
  79. package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js +2 -2
  80. package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  81. package/dist/cjs/fields/DatePicker/fieldValueSync.native.js.map +1 -1
  82. package/dist/cjs/fields/DatePicker/index.native.js +2 -2
  83. package/dist/cjs/fields/DatePicker/index.native.js.map +1 -1
  84. package/dist/cjs/fields/DatePicker/parts.native.js +2 -2
  85. package/dist/cjs/fields/DatePicker/parts.native.js.map +1 -1
  86. package/dist/cjs/fields/DatePicker/utils.native.js.map +1 -1
  87. package/dist/cjs/fields/Duration/durationMath.native.js.map +1 -1
  88. package/dist/cjs/fields/Duration/index.native.js +3 -3
  89. package/dist/cjs/fields/Duration/index.native.js.map +1 -1
  90. package/dist/cjs/fields/FileUpload/filePickerTypes.native.js.map +1 -1
  91. package/dist/cjs/fields/FileUpload/index.cjs +11 -3
  92. package/dist/cjs/fields/FileUpload/index.native.js +22 -5
  93. package/dist/cjs/fields/FileUpload/index.native.js.map +1 -1
  94. package/dist/cjs/fields/FileUpload/nativePickerLoader.native.js.map +1 -1
  95. package/dist/cjs/fields/Geolocation/expoMapsLoader.native.js.map +1 -1
  96. package/dist/cjs/fields/Geolocation/index.native.js +5 -5
  97. package/dist/cjs/fields/Geolocation/index.native.js.map +1 -1
  98. package/dist/cjs/fields/Geolocation/mapMath.native.js.map +1 -1
  99. package/dist/cjs/fields/Geolocation/mapTypes.native.js.map +1 -1
  100. package/dist/cjs/fields/Icon/drawnSet.native.js.map +1 -1
  101. package/dist/cjs/fields/Icon/index.cjs +1 -0
  102. package/dist/cjs/fields/Icon/index.native.js +4 -3
  103. package/dist/cjs/fields/Icon/index.native.js.map +1 -1
  104. package/dist/cjs/fields/ImageField/index.native.js +2 -2
  105. package/dist/cjs/fields/ImageField/index.native.js.map +1 -1
  106. package/dist/cjs/fields/Input/index.cjs +175 -95
  107. package/dist/cjs/fields/Input/index.native.js +85 -6
  108. package/dist/cjs/fields/Input/index.native.js.map +1 -1
  109. package/dist/cjs/fields/MentionInput/index.cjs +6 -1
  110. package/dist/cjs/fields/MentionInput/index.native.js +9 -4
  111. package/dist/cjs/fields/MentionInput/index.native.js.map +1 -1
  112. package/dist/cjs/fields/OTPInput/index.cjs +7 -2
  113. package/dist/cjs/fields/OTPInput/index.native.js +10 -5
  114. package/dist/cjs/fields/OTPInput/index.native.js.map +1 -1
  115. package/dist/cjs/fields/OTPInput/otpCellCss.native.js.map +1 -1
  116. package/dist/cjs/fields/PhoneInput/dialCodes.native.js.map +1 -1
  117. package/dist/cjs/fields/PhoneInput/index.native.js +4 -3
  118. package/dist/cjs/fields/PhoneInput/index.native.js.map +1 -1
  119. package/dist/cjs/fields/PhoneInput/phone.native.js.map +1 -1
  120. package/dist/cjs/fields/Progress/index.native.js +1 -1
  121. package/dist/cjs/fields/Progress/index.native.js.map +1 -1
  122. package/dist/cjs/fields/RadioGroup/index.native.js +1 -1
  123. package/dist/cjs/fields/RadioGroup/index.native.js.map +1 -1
  124. package/dist/cjs/fields/Rating/index.native.js +1 -1
  125. package/dist/cjs/fields/Rating/index.native.js.map +1 -1
  126. package/dist/cjs/fields/Rating/ratingMath.native.js.map +1 -1
  127. package/dist/cjs/fields/Rating/types.native.js.map +1 -1
  128. package/dist/cjs/fields/SearchInput/index.native.js +2 -2
  129. package/dist/cjs/fields/SearchInput/index.native.js.map +1 -1
  130. package/dist/cjs/fields/Select/index.native.js +4 -4
  131. package/dist/cjs/fields/Select/index.native.js.map +1 -1
  132. package/dist/cjs/fields/Signature/index.native.js +2 -2
  133. package/dist/cjs/fields/Signature/index.native.js.map +1 -1
  134. package/dist/cjs/fields/Slider/index.native.js +1 -1
  135. package/dist/cjs/fields/Slider/index.native.js.map +1 -1
  136. package/dist/cjs/fields/Slider/jumpMotion.native.js.map +1 -1
  137. package/dist/cjs/fields/Stepper/index.native.js +2 -2
  138. package/dist/cjs/fields/Stepper/index.native.js.map +1 -1
  139. package/dist/cjs/fields/Stepper/resolveStepperPlacement.native.js.map +1 -1
  140. package/dist/cjs/fields/Switch/index.native.js +2 -2
  141. package/dist/cjs/fields/Switch/index.native.js.map +1 -1
  142. package/dist/cjs/fields/TextArea/index.native.js +2 -2
  143. package/dist/cjs/fields/TextArea/index.native.js.map +1 -1
  144. package/dist/cjs/fields/TimePicker/index.native.js +3 -3
  145. package/dist/cjs/fields/TimePicker/index.native.js.map +1 -1
  146. package/dist/cjs/fields/TimePicker/parts.native.js +1 -1
  147. package/dist/cjs/fields/TimePicker/parts.native.js.map +1 -1
  148. package/dist/cjs/fields/TimeRangeScrubber/geometry.native.js.map +1 -1
  149. package/dist/cjs/fields/TimeRangeScrubber/index.native.js +2 -2
  150. package/dist/cjs/fields/TimeRangeScrubber/index.native.js.map +1 -1
  151. package/dist/cjs/fields/ToggleGroup/index.native.js +1 -1
  152. package/dist/cjs/fields/ToggleGroup/index.native.js.map +1 -1
  153. package/dist/cjs/fields/selectedOrder.native.js.map +1 -1
  154. package/dist/cjs/formSpacing.native.js.map +1 -1
  155. package/dist/cjs/hooks/useFocusManagement.native.js.map +1 -1
  156. package/dist/cjs/index.native.js +43 -43
  157. package/dist/cjs/index.native.js.map +1 -1
  158. package/dist/cjs/requiredMarking.native.js.map +1 -1
  159. package/dist/cjs/shared/TimeColumn.native.js +1 -1
  160. package/dist/cjs/shared/TimeColumn.native.js.map +1 -1
  161. package/dist/cjs/shared/capabilityPreflight.native.js.map +1 -1
  162. package/dist/cjs/shared/colorRamps.native.js.map +1 -1
  163. package/dist/cjs/shared/devWarn.native.js.map +1 -1
  164. package/dist/cjs/shared/floatingList.native.js +1 -1
  165. package/dist/cjs/shared/floatingList.native.js.map +1 -1
  166. package/dist/cjs/shared/focusManagement.native.js.map +1 -1
  167. package/dist/cjs/shared/groupContext.native.js.map +1 -1
  168. package/dist/cjs/shared/i18n.native.js.map +1 -1
  169. package/dist/cjs/shared/t.native.js.map +1 -1
  170. package/dist/cjs/shared/tableCellContext.native.js.map +1 -1
  171. package/dist/cjs/shared/useDragScroll.native.js.map +1 -1
  172. package/dist/cjs/shared/useKeyboardInset.native.js.map +1 -1
  173. package/dist/cjs/shared/useSheetEscapeDismiss.native.js.map +1 -1
  174. package/dist/cjs/shared/useWheelIncrement.native.js.map +1 -1
  175. package/dist/cjs/shared/utils.cjs +4 -14
  176. package/dist/cjs/shared/utils.native.js +7 -15
  177. package/dist/cjs/shared/utils.native.js.map +1 -1
  178. package/dist/cjs/shared/zIndex.native.js.map +1 -1
  179. package/dist/cjs/themedPrimitives.native.js.map +1 -1
  180. package/dist/cjs/types.native.js.map +1 -1
  181. package/dist/cjs/utils/LinkCell.native.js.map +1 -1
  182. package/dist/esm/AdaptivePopup/index.native.js.map +1 -1
  183. package/dist/esm/Button/index.mjs +6 -9
  184. package/dist/esm/Button/index.mjs.map +1 -1
  185. package/dist/esm/Button/index.native.js +6 -9
  186. package/dist/esm/Button/index.native.js.map +1 -1
  187. package/dist/esm/Chip/index.native.js.map +1 -1
  188. package/dist/esm/ContextualSaveBar/UnsavedChangesDialog.mjs +0 -1
  189. package/dist/esm/ContextualSaveBar/UnsavedChangesDialog.mjs.map +1 -1
  190. package/dist/esm/ContextualSaveBar/UnsavedChangesDialog.native.js +0 -1
  191. package/dist/esm/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
  192. package/dist/esm/ContextualSaveBar/clientKnownIdentity.native.js.map +1 -1
  193. package/dist/esm/ContextualSaveBar/commitImmediateField.native.js.map +1 -1
  194. package/dist/esm/ContextualSaveBar/index.native.js.map +1 -1
  195. package/dist/esm/ContextualSaveBar/useUnsavedChangesGuard.native.js.map +1 -1
  196. package/dist/esm/ControlGroup/index.native.js.map +1 -1
  197. package/dist/esm/DescriptionList/index.native.js.map +1 -1
  198. package/dist/esm/ErrorSummary.native.js.map +1 -1
  199. package/dist/esm/FieldDisplay/editMode.native.js.map +1 -1
  200. package/dist/esm/FieldDisplay/formatters.native.js.map +1 -1
  201. package/dist/esm/FieldDisplay/index.mjs +2 -1
  202. package/dist/esm/FieldDisplay/index.mjs.map +1 -1
  203. package/dist/esm/FieldDisplay/index.native.js +9 -2
  204. package/dist/esm/FieldDisplay/index.native.js.map +1 -1
  205. package/dist/esm/FieldGroup.native.js.map +1 -1
  206. package/dist/esm/FloatingPanel/index.mjs +8 -1
  207. package/dist/esm/FloatingPanel/index.mjs.map +1 -1
  208. package/dist/esm/FloatingPanel/useFloatingPanel.native.js.map +1 -1
  209. package/dist/esm/Form/index.native.js.map +1 -1
  210. package/dist/esm/Form/validateOn.native.js.map +1 -1
  211. package/dist/esm/FormGrid.native.js.map +1 -1
  212. package/dist/esm/FormSection.native.js.map +1 -1
  213. package/dist/esm/InputParts/index.mjs +64 -2
  214. package/dist/esm/InputParts/index.mjs.map +1 -1
  215. package/dist/esm/InputParts/index.native.js +70 -4
  216. package/dist/esm/InputParts/index.native.js.map +1 -1
  217. package/dist/esm/Label/index.native.js.map +1 -1
  218. package/dist/esm/Skeleton/index.native.js.map +1 -1
  219. package/dist/esm/Spinner/SpinnerGlyph.native.js.map +1 -1
  220. package/dist/esm/Spinner/spinnerSize.native.js.map +1 -1
  221. package/dist/esm/Table/index.native.js.map +1 -1
  222. package/dist/esm/Wheel/haptic.native.js.map +1 -1
  223. package/dist/esm/Wheel/index.native.js.map +1 -1
  224. package/dist/esm/actionLabel.native.js.map +1 -1
  225. package/dist/esm/fieldDefaults.native.js.map +1 -1
  226. package/dist/esm/fieldLayout.native.js.map +1 -1
  227. package/dist/esm/fields/Barcode/BarcodePreview.mjs +15 -9
  228. package/dist/esm/fields/Barcode/BarcodePreview.mjs.map +1 -1
  229. package/dist/esm/fields/Barcode/BarcodePreview.native.js +15 -9
  230. package/dist/esm/fields/Barcode/BarcodePreview.native.js.map +1 -1
  231. package/dist/esm/fields/Barcode/code128.native.js.map +1 -1
  232. package/dist/esm/fields/Barcode/index.native.js.map +1 -1
  233. package/dist/esm/fields/Barcode/qr.native.js.map +1 -1
  234. package/dist/esm/fields/Barcode/scannerTypes.native.js.map +1 -1
  235. package/dist/esm/fields/Checkbox/Checkbox.native.js.map +1 -1
  236. package/dist/esm/fields/Checkbox/CheckboxBox.native.js.map +1 -1
  237. package/dist/esm/fields/Checkbox/CheckboxCard.native.js.map +1 -1
  238. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  239. package/dist/esm/fields/Checkbox/CheckboxGroup.native.js.map +1 -1
  240. package/dist/esm/fields/Checkbox/index.native.js.map +1 -1
  241. package/dist/esm/fields/ColorPicker/index.native.js.map +1 -1
  242. package/dist/esm/fields/ColorPicker/parts.native.js.map +1 -1
  243. package/dist/esm/fields/Combobox/authorOptions.native.js.map +1 -1
  244. package/dist/esm/fields/Combobox/index.mjs +14 -11
  245. package/dist/esm/fields/Combobox/index.mjs.map +1 -1
  246. package/dist/esm/fields/Combobox/index.native.js +16 -11
  247. package/dist/esm/fields/Combobox/index.native.js.map +1 -1
  248. package/dist/esm/fields/DatePicker/Calendar.native.js.map +1 -1
  249. package/dist/esm/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  250. package/dist/esm/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  251. package/dist/esm/fields/DatePicker/MonthPicker.native.js.map +1 -1
  252. package/dist/esm/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  253. package/dist/esm/fields/DatePicker/fieldValueSync.native.js.map +1 -1
  254. package/dist/esm/fields/DatePicker/index.native.js.map +1 -1
  255. package/dist/esm/fields/DatePicker/parts.native.js.map +1 -1
  256. package/dist/esm/fields/DatePicker/utils.native.js.map +1 -1
  257. package/dist/esm/fields/Duration/durationMath.native.js.map +1 -1
  258. package/dist/esm/fields/Duration/index.native.js.map +1 -1
  259. package/dist/esm/fields/FileUpload/filePickerTypes.native.js.map +1 -1
  260. package/dist/esm/fields/FileUpload/index.mjs +11 -3
  261. package/dist/esm/fields/FileUpload/index.mjs.map +1 -1
  262. package/dist/esm/fields/FileUpload/index.native.js +20 -3
  263. package/dist/esm/fields/FileUpload/index.native.js.map +1 -1
  264. package/dist/esm/fields/FileUpload/nativePickerLoader.native.js.map +1 -1
  265. package/dist/esm/fields/Geolocation/expoMapsLoader.native.js.map +1 -1
  266. package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
  267. package/dist/esm/fields/Geolocation/mapMath.native.js.map +1 -1
  268. package/dist/esm/fields/Geolocation/mapTypes.native.js.map +1 -1
  269. package/dist/esm/fields/Icon/drawnSet.native.js.map +1 -1
  270. package/dist/esm/fields/Icon/index.mjs +1 -0
  271. package/dist/esm/fields/Icon/index.mjs.map +1 -1
  272. package/dist/esm/fields/Icon/index.native.js +1 -0
  273. package/dist/esm/fields/Icon/index.native.js.map +1 -1
  274. package/dist/esm/fields/ImageField/index.native.js.map +1 -1
  275. package/dist/esm/fields/Input/index.mjs +177 -98
  276. package/dist/esm/fields/Input/index.mjs.map +1 -1
  277. package/dist/esm/fields/Input/index.native.js +85 -7
  278. package/dist/esm/fields/Input/index.native.js.map +1 -1
  279. package/dist/esm/fields/MentionInput/index.mjs +6 -1
  280. package/dist/esm/fields/MentionInput/index.mjs.map +1 -1
  281. package/dist/esm/fields/MentionInput/index.native.js +6 -1
  282. package/dist/esm/fields/MentionInput/index.native.js.map +1 -1
  283. package/dist/esm/fields/OTPInput/index.mjs +7 -3
  284. package/dist/esm/fields/OTPInput/index.mjs.map +1 -1
  285. package/dist/esm/fields/OTPInput/index.native.js +7 -3
  286. package/dist/esm/fields/OTPInput/index.native.js.map +1 -1
  287. package/dist/esm/fields/OTPInput/otpCellCss.native.js.map +1 -1
  288. package/dist/esm/fields/PhoneInput/dialCodes.native.js.map +1 -1
  289. package/dist/esm/fields/PhoneInput/index.mjs.map +1 -1
  290. package/dist/esm/fields/PhoneInput/index.native.js +1 -0
  291. package/dist/esm/fields/PhoneInput/index.native.js.map +1 -1
  292. package/dist/esm/fields/PhoneInput/phone.native.js.map +1 -1
  293. package/dist/esm/fields/Progress/index.native.js.map +1 -1
  294. package/dist/esm/fields/RadioGroup/index.native.js.map +1 -1
  295. package/dist/esm/fields/Rating/index.native.js.map +1 -1
  296. package/dist/esm/fields/Rating/ratingMath.native.js.map +1 -1
  297. package/dist/esm/fields/Rating/types.native.js.map +1 -1
  298. package/dist/esm/fields/SearchInput/index.mjs.map +1 -1
  299. package/dist/esm/fields/SearchInput/index.native.js.map +1 -1
  300. package/dist/esm/fields/Select/index.native.js.map +1 -1
  301. package/dist/esm/fields/Signature/index.native.js.map +1 -1
  302. package/dist/esm/fields/Slider/index.native.js.map +1 -1
  303. package/dist/esm/fields/Slider/jumpMotion.native.js.map +1 -1
  304. package/dist/esm/fields/Stepper/index.native.js.map +1 -1
  305. package/dist/esm/fields/Stepper/resolveStepperPlacement.native.js.map +1 -1
  306. package/dist/esm/fields/Switch/index.native.js.map +1 -1
  307. package/dist/esm/fields/TextArea/index.native.js.map +1 -1
  308. package/dist/esm/fields/TimePicker/index.native.js.map +1 -1
  309. package/dist/esm/fields/TimePicker/parts.native.js.map +1 -1
  310. package/dist/esm/fields/TimeRangeScrubber/geometry.native.js.map +1 -1
  311. package/dist/esm/fields/TimeRangeScrubber/index.native.js.map +1 -1
  312. package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
  313. package/dist/esm/fields/selectedOrder.native.js.map +1 -1
  314. package/dist/esm/formSpacing.native.js.map +1 -1
  315. package/dist/esm/hooks/useFocusManagement.native.js.map +1 -1
  316. package/dist/esm/index.native.js.map +1 -1
  317. package/dist/esm/requiredMarking.native.js.map +1 -1
  318. package/dist/esm/shared/TimeColumn.native.js.map +1 -1
  319. package/dist/esm/shared/capabilityPreflight.native.js.map +1 -1
  320. package/dist/esm/shared/colorRamps.native.js.map +1 -1
  321. package/dist/esm/shared/devWarn.native.js.map +1 -1
  322. package/dist/esm/shared/floatingList.native.js.map +1 -1
  323. package/dist/esm/shared/focusManagement.native.js.map +1 -1
  324. package/dist/esm/shared/groupContext.native.js.map +1 -1
  325. package/dist/esm/shared/i18n.native.js.map +1 -1
  326. package/dist/esm/shared/t.native.js.map +1 -1
  327. package/dist/esm/shared/tableCellContext.native.js.map +1 -1
  328. package/dist/esm/shared/useDragScroll.native.js.map +1 -1
  329. package/dist/esm/shared/useKeyboardInset.native.js.map +1 -1
  330. package/dist/esm/shared/useSheetEscapeDismiss.native.js.map +1 -1
  331. package/dist/esm/shared/useWheelIncrement.native.js.map +1 -1
  332. package/dist/esm/shared/utils.mjs +4 -14
  333. package/dist/esm/shared/utils.mjs.map +1 -1
  334. package/dist/esm/shared/utils.native.js +6 -14
  335. package/dist/esm/shared/utils.native.js.map +1 -1
  336. package/dist/esm/shared/zIndex.native.js.map +1 -1
  337. package/dist/esm/themedPrimitives.native.js.map +1 -1
  338. package/dist/esm/types.native.js.map +1 -1
  339. package/dist/esm/utils/LinkCell.native.js.map +1 -1
  340. package/dist/jsx/AdaptivePopup/index.native.js +1 -1
  341. package/dist/jsx/AdaptivePopup/index.native.js.map +1 -1
  342. package/dist/jsx/Button/index.mjs +6 -9
  343. package/dist/jsx/Button/index.mjs.map +1 -1
  344. package/dist/jsx/Button/index.native.js +7 -11
  345. package/dist/jsx/Button/index.native.js.map +1 -1
  346. package/dist/jsx/Chip/index.native.js.map +1 -1
  347. package/dist/jsx/ContextualSaveBar/UnsavedChangesDialog.mjs +0 -1
  348. package/dist/jsx/ContextualSaveBar/UnsavedChangesDialog.mjs.map +1 -1
  349. package/dist/jsx/ContextualSaveBar/UnsavedChangesDialog.native.js +1 -2
  350. package/dist/jsx/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
  351. package/dist/jsx/ContextualSaveBar/clientKnownIdentity.native.js.map +1 -1
  352. package/dist/jsx/ContextualSaveBar/commitImmediateField.native.js.map +1 -1
  353. package/dist/jsx/ContextualSaveBar/index.native.js +3 -3
  354. package/dist/jsx/ContextualSaveBar/index.native.js.map +1 -1
  355. package/dist/jsx/ContextualSaveBar/useUnsavedChangesGuard.native.js.map +1 -1
  356. package/dist/jsx/ControlGroup/index.native.js +1 -1
  357. package/dist/jsx/ControlGroup/index.native.js.map +1 -1
  358. package/dist/jsx/DescriptionList/index.native.js +2 -2
  359. package/dist/jsx/DescriptionList/index.native.js.map +1 -1
  360. package/dist/jsx/ErrorSummary.native.js.map +1 -1
  361. package/dist/jsx/FieldDisplay/editMode.native.js.map +1 -1
  362. package/dist/jsx/FieldDisplay/formatters.native.js.map +1 -1
  363. package/dist/jsx/FieldDisplay/index.mjs +2 -1
  364. package/dist/jsx/FieldDisplay/index.mjs.map +1 -1
  365. package/dist/jsx/FieldDisplay/index.native.js +10 -3
  366. package/dist/jsx/FieldDisplay/index.native.js.map +1 -1
  367. package/dist/jsx/FieldGroup.native.js.map +1 -1
  368. package/dist/jsx/FloatingPanel/index.mjs +8 -1
  369. package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
  370. package/dist/jsx/FloatingPanel/useFloatingPanel.native.js.map +1 -1
  371. package/dist/jsx/Form/index.native.js +1 -1
  372. package/dist/jsx/Form/index.native.js.map +1 -1
  373. package/dist/jsx/Form/validateOn.native.js.map +1 -1
  374. package/dist/jsx/FormGrid.native.js.map +1 -1
  375. package/dist/jsx/FormSection.native.js.map +1 -1
  376. package/dist/jsx/InputParts/index.mjs +64 -2
  377. package/dist/jsx/InputParts/index.mjs.map +1 -1
  378. package/dist/jsx/InputParts/index.native.js +70 -4
  379. package/dist/jsx/InputParts/index.native.js.map +1 -1
  380. package/dist/jsx/Label/index.native.js.map +1 -1
  381. package/dist/jsx/Skeleton/index.native.js.map +1 -1
  382. package/dist/jsx/Spinner/SpinnerGlyph.native.js.map +1 -1
  383. package/dist/jsx/Spinner/spinnerSize.native.js.map +1 -1
  384. package/dist/jsx/Table/index.native.js.map +1 -1
  385. package/dist/jsx/Wheel/haptic.native.js.map +1 -1
  386. package/dist/jsx/Wheel/index.native.js.map +1 -1
  387. package/dist/jsx/actionLabel.native.js.map +1 -1
  388. package/dist/jsx/fieldDefaults.native.js.map +1 -1
  389. package/dist/jsx/fieldLayout.native.js +1 -1
  390. package/dist/jsx/fieldLayout.native.js.map +1 -1
  391. package/dist/jsx/fields/Barcode/BarcodePreview.mjs +15 -9
  392. package/dist/jsx/fields/Barcode/BarcodePreview.mjs.map +1 -1
  393. package/dist/jsx/fields/Barcode/BarcodePreview.native.js +15 -9
  394. package/dist/jsx/fields/Barcode/BarcodePreview.native.js.map +1 -1
  395. package/dist/jsx/fields/Barcode/BarcodeScanner.native.js +1 -1
  396. package/dist/jsx/fields/Barcode/code128.native.js.map +1 -1
  397. package/dist/jsx/fields/Barcode/index.native.js +2 -2
  398. package/dist/jsx/fields/Barcode/index.native.js.map +1 -1
  399. package/dist/jsx/fields/Barcode/qr.native.js.map +1 -1
  400. package/dist/jsx/fields/Barcode/scannerTypes.native.js.map +1 -1
  401. package/dist/jsx/fields/Checkbox/Checkbox.native.js +1 -1
  402. package/dist/jsx/fields/Checkbox/Checkbox.native.js.map +1 -1
  403. package/dist/jsx/fields/Checkbox/CheckboxBox.native.js.map +1 -1
  404. package/dist/jsx/fields/Checkbox/CheckboxCard.native.js.map +1 -1
  405. package/dist/jsx/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  406. package/dist/jsx/fields/Checkbox/CheckboxGroup.native.js +1 -1
  407. package/dist/jsx/fields/Checkbox/CheckboxGroup.native.js.map +1 -1
  408. package/dist/jsx/fields/Checkbox/index.native.js.map +1 -1
  409. package/dist/jsx/fields/ColorPicker/index.native.js +3 -3
  410. package/dist/jsx/fields/ColorPicker/index.native.js.map +1 -1
  411. package/dist/jsx/fields/ColorPicker/parts.native.js +2 -2
  412. package/dist/jsx/fields/ColorPicker/parts.native.js.map +1 -1
  413. package/dist/jsx/fields/Combobox/authorOptions.native.js.map +1 -1
  414. package/dist/jsx/fields/Combobox/index.mjs +14 -11
  415. package/dist/jsx/fields/Combobox/index.mjs.map +1 -1
  416. package/dist/jsx/fields/Combobox/index.native.js +21 -16
  417. package/dist/jsx/fields/Combobox/index.native.js.map +1 -1
  418. package/dist/jsx/fields/DatePicker/Calendar.native.js.map +1 -1
  419. package/dist/jsx/fields/DatePicker/DateRangePicker.native.js +2 -2
  420. package/dist/jsx/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  421. package/dist/jsx/fields/DatePicker/DatetimePicker.native.js +3 -3
  422. package/dist/jsx/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  423. package/dist/jsx/fields/DatePicker/MonthPicker.native.js +2 -2
  424. package/dist/jsx/fields/DatePicker/MonthPicker.native.js.map +1 -1
  425. package/dist/jsx/fields/DatePicker/MultiDatePicker.native.js +2 -2
  426. package/dist/jsx/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  427. package/dist/jsx/fields/DatePicker/fieldValueSync.native.js.map +1 -1
  428. package/dist/jsx/fields/DatePicker/index.native.js +2 -2
  429. package/dist/jsx/fields/DatePicker/index.native.js.map +1 -1
  430. package/dist/jsx/fields/DatePicker/parts.native.js +2 -2
  431. package/dist/jsx/fields/DatePicker/parts.native.js.map +1 -1
  432. package/dist/jsx/fields/DatePicker/utils.native.js.map +1 -1
  433. package/dist/jsx/fields/Duration/durationMath.native.js.map +1 -1
  434. package/dist/jsx/fields/Duration/index.native.js +3 -3
  435. package/dist/jsx/fields/Duration/index.native.js.map +1 -1
  436. package/dist/jsx/fields/FileUpload/filePickerTypes.native.js.map +1 -1
  437. package/dist/jsx/fields/FileUpload/index.mjs +11 -3
  438. package/dist/jsx/fields/FileUpload/index.mjs.map +1 -1
  439. package/dist/jsx/fields/FileUpload/index.native.js +22 -5
  440. package/dist/jsx/fields/FileUpload/index.native.js.map +1 -1
  441. package/dist/jsx/fields/FileUpload/nativePickerLoader.native.js.map +1 -1
  442. package/dist/jsx/fields/Geolocation/expoMapsLoader.native.js.map +1 -1
  443. package/dist/jsx/fields/Geolocation/index.native.js +5 -5
  444. package/dist/jsx/fields/Geolocation/index.native.js.map +1 -1
  445. package/dist/jsx/fields/Geolocation/mapMath.native.js.map +1 -1
  446. package/dist/jsx/fields/Geolocation/mapTypes.native.js.map +1 -1
  447. package/dist/jsx/fields/Icon/drawnSet.native.js.map +1 -1
  448. package/dist/jsx/fields/Icon/index.mjs +1 -0
  449. package/dist/jsx/fields/Icon/index.mjs.map +1 -1
  450. package/dist/jsx/fields/Icon/index.native.js +4 -3
  451. package/dist/jsx/fields/Icon/index.native.js.map +1 -1
  452. package/dist/jsx/fields/ImageField/index.native.js +2 -2
  453. package/dist/jsx/fields/ImageField/index.native.js.map +1 -1
  454. package/dist/jsx/fields/Input/index.mjs +177 -98
  455. package/dist/jsx/fields/Input/index.mjs.map +1 -1
  456. package/dist/jsx/fields/Input/index.native.js +85 -6
  457. package/dist/jsx/fields/Input/index.native.js.map +1 -1
  458. package/dist/jsx/fields/MentionInput/index.mjs +6 -1
  459. package/dist/jsx/fields/MentionInput/index.mjs.map +1 -1
  460. package/dist/jsx/fields/MentionInput/index.native.js +9 -4
  461. package/dist/jsx/fields/MentionInput/index.native.js.map +1 -1
  462. package/dist/jsx/fields/OTPInput/index.mjs +7 -3
  463. package/dist/jsx/fields/OTPInput/index.mjs.map +1 -1
  464. package/dist/jsx/fields/OTPInput/index.native.js +10 -5
  465. package/dist/jsx/fields/OTPInput/index.native.js.map +1 -1
  466. package/dist/jsx/fields/OTPInput/otpCellCss.native.js.map +1 -1
  467. package/dist/jsx/fields/PhoneInput/dialCodes.native.js.map +1 -1
  468. package/dist/jsx/fields/PhoneInput/index.mjs.map +1 -1
  469. package/dist/jsx/fields/PhoneInput/index.native.js +4 -3
  470. package/dist/jsx/fields/PhoneInput/index.native.js.map +1 -1
  471. package/dist/jsx/fields/PhoneInput/phone.native.js.map +1 -1
  472. package/dist/jsx/fields/Progress/index.native.js +1 -1
  473. package/dist/jsx/fields/Progress/index.native.js.map +1 -1
  474. package/dist/jsx/fields/RadioGroup/index.native.js +1 -1
  475. package/dist/jsx/fields/RadioGroup/index.native.js.map +1 -1
  476. package/dist/jsx/fields/Rating/index.native.js +1 -1
  477. package/dist/jsx/fields/Rating/index.native.js.map +1 -1
  478. package/dist/jsx/fields/Rating/ratingMath.native.js.map +1 -1
  479. package/dist/jsx/fields/Rating/types.native.js.map +1 -1
  480. package/dist/jsx/fields/SearchInput/index.mjs.map +1 -1
  481. package/dist/jsx/fields/SearchInput/index.native.js +2 -2
  482. package/dist/jsx/fields/SearchInput/index.native.js.map +1 -1
  483. package/dist/jsx/fields/Select/index.native.js +4 -4
  484. package/dist/jsx/fields/Select/index.native.js.map +1 -1
  485. package/dist/jsx/fields/Signature/index.native.js +2 -2
  486. package/dist/jsx/fields/Signature/index.native.js.map +1 -1
  487. package/dist/jsx/fields/Slider/index.native.js +1 -1
  488. package/dist/jsx/fields/Slider/index.native.js.map +1 -1
  489. package/dist/jsx/fields/Slider/jumpMotion.native.js.map +1 -1
  490. package/dist/jsx/fields/Stepper/index.native.js +2 -2
  491. package/dist/jsx/fields/Stepper/index.native.js.map +1 -1
  492. package/dist/jsx/fields/Stepper/resolveStepperPlacement.native.js.map +1 -1
  493. package/dist/jsx/fields/Switch/index.native.js +2 -2
  494. package/dist/jsx/fields/Switch/index.native.js.map +1 -1
  495. package/dist/jsx/fields/TextArea/index.native.js +2 -2
  496. package/dist/jsx/fields/TextArea/index.native.js.map +1 -1
  497. package/dist/jsx/fields/TimePicker/index.native.js +3 -3
  498. package/dist/jsx/fields/TimePicker/index.native.js.map +1 -1
  499. package/dist/jsx/fields/TimePicker/parts.native.js +1 -1
  500. package/dist/jsx/fields/TimePicker/parts.native.js.map +1 -1
  501. package/dist/jsx/fields/TimeRangeScrubber/geometry.native.js.map +1 -1
  502. package/dist/jsx/fields/TimeRangeScrubber/index.native.js +2 -2
  503. package/dist/jsx/fields/TimeRangeScrubber/index.native.js.map +1 -1
  504. package/dist/jsx/fields/ToggleGroup/index.native.js +1 -1
  505. package/dist/jsx/fields/ToggleGroup/index.native.js.map +1 -1
  506. package/dist/jsx/fields/selectedOrder.native.js.map +1 -1
  507. package/dist/jsx/formSpacing.native.js.map +1 -1
  508. package/dist/jsx/hooks/useFocusManagement.native.js.map +1 -1
  509. package/dist/jsx/index.native.js +43 -43
  510. package/dist/jsx/index.native.js.map +1 -1
  511. package/dist/jsx/requiredMarking.native.js.map +1 -1
  512. package/dist/jsx/shared/TimeColumn.native.js +1 -1
  513. package/dist/jsx/shared/TimeColumn.native.js.map +1 -1
  514. package/dist/jsx/shared/capabilityPreflight.native.js.map +1 -1
  515. package/dist/jsx/shared/colorRamps.native.js.map +1 -1
  516. package/dist/jsx/shared/devWarn.native.js.map +1 -1
  517. package/dist/jsx/shared/floatingList.native.js +1 -1
  518. package/dist/jsx/shared/floatingList.native.js.map +1 -1
  519. package/dist/jsx/shared/focusManagement.native.js.map +1 -1
  520. package/dist/jsx/shared/groupContext.native.js.map +1 -1
  521. package/dist/jsx/shared/i18n.native.js.map +1 -1
  522. package/dist/jsx/shared/t.native.js.map +1 -1
  523. package/dist/jsx/shared/tableCellContext.native.js.map +1 -1
  524. package/dist/jsx/shared/useDragScroll.native.js.map +1 -1
  525. package/dist/jsx/shared/useKeyboardInset.native.js.map +1 -1
  526. package/dist/jsx/shared/useSheetEscapeDismiss.native.js.map +1 -1
  527. package/dist/jsx/shared/useWheelIncrement.native.js.map +1 -1
  528. package/dist/jsx/shared/utils.mjs +4 -14
  529. package/dist/jsx/shared/utils.mjs.map +1 -1
  530. package/dist/jsx/shared/utils.native.js +7 -15
  531. package/dist/jsx/shared/utils.native.js.map +1 -1
  532. package/dist/jsx/shared/zIndex.native.js.map +1 -1
  533. package/dist/jsx/themedPrimitives.native.js.map +1 -1
  534. package/dist/jsx/types.native.js.map +1 -1
  535. package/dist/jsx/utils/LinkCell.native.js.map +1 -1
  536. package/package.json +7 -7
  537. package/src/Button/Button.density.spec.tsx +118 -32
  538. package/src/Button/Button.labelInk.spec.tsx +72 -19
  539. package/src/Button/Button.lc71.spec.tsx +10 -3
  540. package/src/Button/Button.stories.tsx +7 -6
  541. package/src/Button/index.tsx +22 -12
  542. package/src/ContextualSaveBar/UnsavedChangesDialog.tsx +0 -1
  543. package/src/FieldDisplay/FieldDisplay.spec.tsx +11 -2
  544. package/src/FieldDisplay/index.tsx +5 -0
  545. package/src/FloatingPanel/index.tsx +22 -1
  546. package/src/FloatingPanel/panelWidthContract.spec.ts +1 -0
  547. package/src/InputParts/index.tsx +100 -3
  548. package/src/fields/Barcode/BarcodePreview.spec.tsx +139 -5
  549. package/src/fields/Barcode/BarcodePreview.tsx +47 -15
  550. package/src/fields/Combobox/Combobox.spec.tsx +64 -1
  551. package/src/fields/Combobox/index.tsx +22 -11
  552. package/src/fields/FileUpload/FileUpload.spec.tsx +28 -0
  553. package/src/fields/FileUpload/index.tsx +26 -1
  554. package/src/fields/Icon/Icon.stories.tsx +1 -1
  555. package/src/fields/Icon/index.tsx +1 -0
  556. package/src/fields/Input/index.tsx +180 -81
  557. package/src/fields/MentionInput/index.tsx +9 -1
  558. package/src/fields/OTPInput/OtpInput.spec.tsx +36 -4
  559. package/src/fields/OTPInput/index.tsx +18 -3
  560. package/src/fields/OTPInput/otpCellHeightTouch.spec.ts +44 -0
  561. package/src/fields/PhoneInput/index.tsx +1 -0
  562. package/src/fields/SearchInput/index.tsx +5 -3
  563. package/src/shared/utils.spec.ts +46 -0
  564. package/src/shared/utils.ts +31 -16
  565. package/types/Button/index.d.ts +8 -3
  566. package/types/Button/index.d.ts.map +1 -1
  567. package/types/ContextualSaveBar/UnsavedChangesDialog.d.ts.map +1 -1
  568. package/types/FieldDisplay/index.d.ts.map +1 -1
  569. package/types/InputParts/index.d.ts +9 -5
  570. package/types/InputParts/index.d.ts.map +1 -1
  571. package/types/fields/Barcode/BarcodePreview.d.ts +20 -9
  572. package/types/fields/Barcode/BarcodePreview.d.ts.map +1 -1
  573. package/types/fields/Checkbox/index.d.ts +3 -3
  574. package/types/fields/Combobox/index.d.ts.map +1 -1
  575. package/types/fields/FileUpload/index.d.ts.map +1 -1
  576. package/types/fields/Icon/index.d.ts.map +1 -1
  577. package/types/fields/Input/index.d.ts +18 -6
  578. package/types/fields/Input/index.d.ts.map +1 -1
  579. package/types/fields/MentionInput/index.d.ts.map +1 -1
  580. package/types/fields/OTPInput/index.d.ts +12 -0
  581. package/types/fields/OTPInput/index.d.ts.map +1 -1
  582. package/types/fields/PhoneInput/index.d.ts.map +1 -1
  583. package/types/fields/RadioGroup/index.d.ts +2 -2
  584. package/types/fields/SearchInput/index.d.ts.map +1 -1
  585. package/types/fields/ToggleGroup/index.d.ts +1 -1
  586. package/types/shared/utils.d.ts.map +1 -1
@@ -819,6 +819,7 @@ const InputAreaImpl = InputFrame.styleable<{
819
819
  {...knobProps.body}
820
820
  type={secureTextEntry ? "password" : props.type}
821
821
  padding={0}
822
+ // size-recipe-escape: zero-reset — Input.Box owns the inset (LC-71); the inner field paints no padding
822
823
  paddingHorizontal={0}
823
824
  paddingVertical={0}
824
825
  keyboardType={resolvedKeyboardType}
@@ -907,24 +908,115 @@ const InputButton = styled(TButton, {
907
908
  } as const,
908
909
  });
909
910
 
910
- const InputButtonImpl = InputButton.styleable((buttonProps, ref) => {
911
+ /**
912
+ * LC-71 RING-ANATOMY / LC-49 ONE-TAB-STOP — the `glyphRing` end cap.
913
+ *
914
+ * A bare Input.Button is DECORATIVE: the Box rings for it and it takes no
915
+ * tab stop of its own (Stepper carets, Select/Combobox chevrons). Pass
916
+ * `glyphRing` to promote it to the field's SECOND focusable — the Password
917
+ * reveal, the CopyField copy — where it must ring its own GLYPH, not the
918
+ * 44px hit box. A band on the box would double with the Box's composite
919
+ * ring; a band on the glyph is the chip-dismiss recipe
920
+ * (`.mp-chip-dismiss` + `.mp-chip-dismiss-ring`, keyboardFocusRing.ts).
921
+ *
922
+ * It renders a View rather than TButton because TButton swallows a consumer
923
+ * className and pins its own tabIndex, so the ring class never reaches the
924
+ * node that actually receives focus. SearchInput hand-rolled exactly this
925
+ * pair for that reason (fields/SearchInput/index.tsx:348-380) and left a
926
+ * note saying the classes "cannot ride Input.Button until glyphRing" lands.
927
+ * This is that pair made reusable, so the square comes from the size recipe
928
+ * (LC-70) instead of every call site measuring its own.
929
+ */
930
+ const InputGlyphButton = styled(View, {
931
+ name: "InputGlyphButton",
932
+ context: InputContext,
933
+ justifyContent: "center",
934
+ alignItems: "center",
935
+ backgroundColor: "transparent",
936
+ borderWidth: 0,
937
+ borderRadius: 0,
938
+ cursor: "pointer",
939
+ flexShrink: 0,
940
+ outlineWidth: 0,
941
+ focusStyle: { outlineWidth: 0 },
942
+ focusVisibleStyle: { outlineWidth: 0 },
943
+
944
+ variants: {
945
+ scaleIcon: {
946
+ ":number": {} as any,
947
+ },
948
+ size: {
949
+ ...sizeRecipeEndCapVariants,
950
+ "...size": sizeRecipeEndCapFallback,
951
+ },
952
+ } as const,
953
+ });
954
+
955
+ const InputButtonImpl = InputButton.styleable<{ glyphRing?: boolean }>((buttonProps, ref) => {
911
956
  const {
912
957
  children,
913
958
  color: colorProp,
959
+ glyphRing,
960
+ size: sizeProp,
961
+ tabIndex: tabIndexProp,
962
+ className,
914
963
  ...props
915
964
  } = buttonProps as typeof buttonProps & {
916
965
  color?: string;
966
+ glyphRing?: boolean;
967
+ size?: FontSizeTokens;
968
+ tabIndex?: number;
969
+ className?: string;
917
970
  };
918
- const { size, color: contextColor } = InputContext.useStyledContext();
971
+ const { size: contextSize, color: contextColor } = InputContext.useStyledContext();
919
972
  const { knobProps } = useResolvedKnobs();
920
973
  const theme = useTheme();
921
- const square = knobProps.control.height;
974
+ const size = (sizeProp ?? contextSize) as FontSizeTokens;
922
975
  const paint = resolveGlyphPaint(theme as never, colorProp ?? contextColor);
923
976
  const getThemedIcon = useGetThemedIcon({
924
977
  size: knobProps.controlIcon.width,
925
978
  color: paint as never,
926
979
  });
927
980
 
981
+ if (glyphRing) {
982
+ // A real tab stop must square off the token it was HANDED, not the
983
+ // knob's: a $2 field inside a $4 knob would otherwise ship a 44px stop
984
+ // on a 32px frame. LC-77 keeps the sub-floor case pressable via the
985
+ // caller's hitSlop, never by inflating the cap.
986
+ const square = sizeRecipeForToken(String(size ?? "$true"), { touch: isTouchSurface() }).height;
987
+ const disabled = (props as { disabled?: boolean }).disabled === true;
988
+ if (isWeb) ensureCompositeFocusRing();
989
+ return (
990
+ <InputGlyphButton
991
+ ref={ref as never}
992
+ role="button"
993
+ size={size}
994
+ height={square}
995
+ width={square}
996
+ paddingHorizontal={0} // size-recipe-escape: square end-cap; pad lives on Input.Box
997
+ opacity={disabled ? 0.5 : 1}
998
+ {...props}
999
+ aria-disabled={disabled || undefined}
1000
+ tabIndex={tabIndexProp ?? (disabled ? -1 : 0)}
1001
+ className={
1002
+ isWeb
1003
+ ? ["mp-chip-dismiss", className].filter(Boolean).join(" ")
1004
+ : (className ?? undefined)
1005
+ }
1006
+ data-end-cap={square}
1007
+ >
1008
+ <View
1009
+ className={isWeb ? "mp-chip-dismiss-ring" : undefined}
1010
+ alignItems="center"
1011
+ justifyContent="center"
1012
+ >
1013
+ {children}
1014
+ </View>
1015
+ </InputGlyphButton>
1016
+ );
1017
+ }
1018
+
1019
+ const square = knobProps.control.height;
928
1020
  return (
929
1021
  <InputButton
930
1022
  ref={ref}
@@ -933,7 +1025,12 @@ const InputButtonImpl = InputButton.styleable((buttonProps, ref) => {
933
1025
  width={square}
934
1026
  paddingHorizontal={0} // size-recipe-escape: square end-cap; pad lives on Input.Box
935
1027
  color={paint}
1028
+ // LC-49: the decorative cap is not a tab stop. tabIndex alone is not
1029
+ // enough — TButton re-derives focusability and stamps tabindex="0".
1030
+ focusable={false}
936
1031
  tabIndex={-1}
1032
+ className={className}
1033
+ data-end-cap={square}
937
1034
  {...props}
938
1035
  >
939
1036
  {getThemedIcon(children)}
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
2
2
  import { renderWithProviders } from "@multiplatform.one/test-utils";
3
3
  import { BarcodePreview, barcodePreviewSymbology } from "./BarcodePreview";
4
4
  import { countModules, encodeCode128B } from "./code128";
5
- import { encodeQr } from "./qr";
5
+ import { QR_QUIET_ZONE_MODULES, encodeQr } from "./qr";
6
6
  import { resolveHtml5FormatIds, resolveNativeBarcodeTypes } from "./scannerTypes";
7
7
 
8
8
  /** Rebuild the module string ("1" = bar) from the encoder's runs. */
@@ -101,8 +101,13 @@ describe("barcodePreviewSymbology — scanner round trip", () => {
101
101
  });
102
102
 
103
103
  describe("BarcodePreview — qr format", () => {
104
+ /** The field's own default bound (Barcode/index.tsx): 36 comfortable, 24 compact. */
105
+ const formHeight = 36;
106
+
104
107
  it("draws the QR matrix canvas-free (labeled image, real module rows)", () => {
105
- const result = renderWithProviders(<BarcodePreview value="SKU-001234" format="qr" />);
108
+ const result = renderWithProviders(
109
+ <BarcodePreview value="SKU-001234" format="qr" height={formHeight} />,
110
+ );
106
111
  const preview = result.container.querySelector('[data-testid="barcode-preview"]');
107
112
  expect(preview).not.toBeNull();
108
113
  expect(preview?.getAttribute("aria-label")).toContain("SKU-001234");
@@ -114,12 +119,16 @@ describe("BarcodePreview — qr format", () => {
114
119
  });
115
120
 
116
121
  it("draws QR for the Frappe fieldtype's qrcode token via the shared alias table", () => {
117
- const result = renderWithProviders(<BarcodePreview value="SKU-001234" format="qrcode" />);
122
+ const result = renderWithProviders(
123
+ <BarcodePreview value="SKU-001234" format="qrcode" height={formHeight} />,
124
+ );
118
125
  expect(result.container.querySelector('[data-testid="barcode-preview-qr"]')).not.toBeNull();
119
126
  });
120
127
 
121
128
  it("draws values the 1-D strip cannot encode (the closed asymmetry)", () => {
122
- const result = renderWithProviders(<BarcodePreview value="héllo" format="qr" />);
129
+ const result = renderWithProviders(
130
+ <BarcodePreview value="héllo" format="qr" height={formHeight} />,
131
+ );
123
132
  expect(result.container.querySelector('[data-testid="barcode-preview-qr"]')).not.toBeNull();
124
133
  });
125
134
 
@@ -130,7 +139,9 @@ describe("BarcodePreview — qr format", () => {
130
139
 
131
140
  it("falls back to honest mono text past version 10 capacity", () => {
132
141
  const long = "x".repeat(214);
133
- const result = renderWithProviders(<BarcodePreview value={long} format="qr" />);
142
+ const result = renderWithProviders(
143
+ <BarcodePreview value={long} format="qr" height={formHeight} />,
144
+ );
134
145
  expect(result.container.querySelector('[data-testid="barcode-preview-qr"]')).toBeNull();
135
146
  expect(result.container.textContent).toContain(long);
136
147
  });
@@ -141,3 +152,126 @@ describe("BarcodePreview — qr format", () => {
141
152
  expect(result.container.querySelector('[data-testid="barcode-preview"]')).not.toBeNull();
142
153
  });
143
154
  });
155
+
156
+ /**
157
+ * Whole-pixel modules. Measured on the media-11 board at DPR 2 BEFORE this
158
+ * rule existed: bounds 33, 72 and 96 decoded and bounds 18, 24, 44 and 56 did
159
+ * not — not a size floor (33 read, 44 did not) but a resampling one. 33/33
160
+ * modules is exactly 1.000 px per module; 44/33 is 1.333, and a fractional
161
+ * module rounds to different widths across the grid. It reached the field's
162
+ * own default path: at height 36 / moduleWidth 1 a payload over 26 bytes
163
+ * clamps under one pixel per module and stops reading, which is precisely the
164
+ * scan-to-draw round trip MPO-53 AC-9 exists to close.
165
+ */
166
+ describe("BarcodePreview — qr geometry is whole-pixel or nothing", () => {
167
+ const qrSquare = (ui: React.ReactElement) =>
168
+ renderWithProviders(ui).container.querySelector(
169
+ '[data-testid="barcode-preview-qr"]',
170
+ ) as HTMLElement | null;
171
+
172
+ /**
173
+ * Tamagui compiles geometry to atomic classes (`_w-87px`, `_pt-12px`), not
174
+ * inline style, so the measurement reads the class list. Same numbers, and
175
+ * it is the class the browser actually applies.
176
+ */
177
+ const px = (el: HTMLElement, prefix: string) => {
178
+ const hit = (el.getAttribute("class") ?? "")
179
+ .split(/\s+/)
180
+ .find((c) => c.startsWith(`_${prefix}-`));
181
+ return hit ? Number.parseFloat(hit.slice(prefix.length + 2)) : Number.NaN;
182
+ };
183
+ const edgeOf = (el: HTMLElement) => px(el, "w");
184
+ const quietOf = (el: HTMLElement) => px(el, "pt");
185
+
186
+ /** Modules per side including the 4-module quiet zone on each side. */
187
+ const totalModules = (value: string) => encodeQr(value)!.size + 2 * QR_QUIET_ZONE_MODULES;
188
+
189
+ it("draws at the natural size when moduleWidth fits under the bound", () => {
190
+ // 6 bytes → version 1 → 21 + 8 = 29 modules. moduleWidth 3 asks for 3px
191
+ // modules and the 120px bound allows 4, so 3 wins: 29 × 3 = 87.
192
+ const value = "SHC-42";
193
+ expect(totalModules(value)).toBe(29);
194
+ const square = qrSquare(
195
+ <BarcodePreview value={value} format="qr" height={120} moduleWidth={3} />,
196
+ );
197
+ expect(square).not.toBeNull();
198
+ expect(edgeOf(square!)).toBe(87);
199
+ expect(px(square!, "h")).toBe(87);
200
+ expect(quietOf(square!)).toBe(12); // 4 modules × 3px
201
+ });
202
+
203
+ it("treats the height bound as a CEILING, never a target", () => {
204
+ // 18 bytes → version 2 → 25 + 8 = 33 modules at moduleWidth 1 = 33px. A
205
+ // 44px bound does not stretch it to 44 and a fractional 1.333px module.
206
+ const value = "SHC-COMPOSE01-0417";
207
+ expect(totalModules(value)).toBe(33);
208
+ for (const height of [36, 44, 56]) {
209
+ const square = qrSquare(<BarcodePreview value={value} format="qr" height={height} />);
210
+ expect(edgeOf(square!)).toBe(33);
211
+ expect(quietOf(square!)).toBe(4);
212
+ }
213
+ });
214
+
215
+ it("snaps the module DOWN to a whole pixel rather than draw a fractional one", () => {
216
+ // 33 modules under a 96px bound would be 2.909px per module. Snap to 2.
217
+ const square = qrSquare(
218
+ <BarcodePreview value="SHC-COMPOSE01-0417" format="qr" height={96} moduleWidth={9} />,
219
+ );
220
+ expect(edgeOf(square!)).toBe(66);
221
+ expect(quietOf(square!)).toBe(8);
222
+ });
223
+
224
+ it("never draws a module narrower than one whole pixel — every bound, every payload", () => {
225
+ for (const value of ["SHC-42", "SHC-COMPOSE01-0417", "SHC-COMPOSE01-BACKUP-2026-08-28"]) {
226
+ for (const height of [18, 24, 29, 33, 36, 37, 44, 66, 96, 120]) {
227
+ for (const moduleWidth of [1, 2, 3]) {
228
+ const square = qrSquare(
229
+ <BarcodePreview value={value} format="qr" height={height} moduleWidth={moduleWidth} />,
230
+ );
231
+ if (!square) continue; // honest text fallback — asserted below
232
+ const edge = edgeOf(square);
233
+ const pad = quietOf(square);
234
+ const cell = edge / totalModules(value);
235
+ expect(Number.isInteger(cell)).toBe(true);
236
+ expect(cell).toBeGreaterThanOrEqual(1);
237
+ expect(cell).toBeLessThanOrEqual(moduleWidth);
238
+ expect(edge).toBeLessThanOrEqual(height); // LC-10 containment
239
+ expect(pad).toBe(cell * QR_QUIET_ZONE_MODULES);
240
+ }
241
+ }
242
+ }
243
+ });
244
+
245
+ it("falls back to honest text under one whole pixel per module", () => {
246
+ // compact (24) cannot hold 33 modules at a whole pixel each.
247
+ const value = "SHC-COMPOSE01-0417";
248
+ const result = renderWithProviders(<BarcodePreview value={value} format="qr" height={24} />);
249
+ expect(result.container.querySelector('[data-testid="barcode-preview-qr"]')).toBeNull();
250
+ expect(result.container.textContent).toContain(value);
251
+ });
252
+
253
+ it("falls back to honest text when the payload outgrows the form bound", () => {
254
+ // 31 bytes → version 3 → 29 + 8 = 37 modules, which does not fit 36px at
255
+ // one whole pixel each. This is the case that silently shipped unreadable.
256
+ const value = "SHC-COMPOSE01-BACKUP-2026-08-28";
257
+ expect(totalModules(value)).toBe(37);
258
+ const result = renderWithProviders(<BarcodePreview value={value} format="qr" height={36} />);
259
+ expect(result.container.querySelector('[data-testid="barcode-preview-qr"]')).toBeNull();
260
+ expect(result.container.textContent).toContain(value);
261
+ });
262
+
263
+ it("draws nothing at all when the host already shows the value (textFallback false)", () => {
264
+ const value = "SHC-COMPOSE01-0417";
265
+ const result = renderWithProviders(
266
+ <BarcodePreview value={value} format="qr" height={24} textFallback={false} />,
267
+ );
268
+ expect(result.container.querySelector('[data-testid="barcode-preview-qr"]')).toBeNull();
269
+ expect(result.container.textContent).not.toContain(value);
270
+ });
271
+
272
+ it("leaves the 1-D strip's geometry untouched", () => {
273
+ const result = renderWithProviders(<BarcodePreview value="SKU-001234" height={18} />);
274
+ expect(result.container.querySelector('[data-testid="barcode-preview"]')).not.toBeNull();
275
+ expect(result.container.querySelector('[data-testid="barcode-preview-qr"]')).toBeNull();
276
+ });
277
+ });
@@ -11,15 +11,16 @@
11
11
  *
12
12
  * Containment contract (LC-10): the symbol never exceeds its host. The strip
13
13
  * caps width at 100% and bars shrink proportionally (preserving relative
14
- * module widths) instead of painting past the frame; the QR square renders at
15
- * its natural module size and shrinks uniformly once the `height` bound
16
- * clamps it — always square, never letterboxed or clipped. Hosts bound the
17
- * height via the `height` prop (table cells keep it under the row height).
14
+ * module widths) instead of painting past the frame; the QR square is drawn at
15
+ * a WHOLE number of pixels per module, capped by `moduleWidth` and by the
16
+ * `height` bound — always square, never letterboxed or clipped. Hosts bound
17
+ * the height via the `height` prop (table cells keep it under the row height).
18
18
  *
19
19
  * Honest states: an empty value renders nothing (hosts show their own empty
20
20
  * marker); a value the symbology cannot encode (non-ASCII for Code 128 B,
21
- * over version 10 capacity for QR) falls back to the raw value as mono text —
22
- * never a fake or truncated symbol.
21
+ * over version 10 capacity for QR), or a QR whose modules would be under one
22
+ * whole pixel at the host's bound, falls back to the raw value as mono text —
23
+ * never a fake, truncated or unreadable symbol.
23
24
  */
24
25
 
25
26
  import { Text, View, XStack, YStack } from "tamagui";
@@ -44,10 +45,11 @@ export interface BarcodePreviewProps {
44
45
  value?: string;
45
46
  /**
46
47
  * Symbol height bound in px — content geometry, bounded by the host. The
47
- * 1-D strip always fills it; the QR square uses it as a maximum edge.
48
+ * 1-D strip always fills it; the QR square uses it as a CEILING and draws at
49
+ * the largest whole-pixel module that fits under it.
48
50
  */
49
51
  height?: number;
50
- /** Width of one barcode module in px. */
52
+ /** Width of one barcode module in px. Fractional values floor for QR. */
51
53
  moduleWidth?: number;
52
54
  /** Render the human-readable value under the symbol. */
53
55
  showText?: boolean;
@@ -56,6 +58,15 @@ export interface BarcodePreviewProps {
56
58
  * alias of `qr` draws the QR matrix; others draw the Code 128 strip.
57
59
  */
58
60
  format?: string;
61
+ /**
62
+ * Render the raw value as mono text when the symbology cannot draw it —
63
+ * non-ASCII for Code 128 B, over capacity or under one whole pixel per
64
+ * module for QR. Default true, which is right for a standalone preview:
65
+ * disappearing silently would be worse than an honest string. A host that
66
+ * ALREADY shows the value beside the symbol (FieldDisplay) passes false, so
67
+ * an undrawable symbol contributes nothing instead of printing it twice.
68
+ */
69
+ textFallback?: boolean;
59
70
  }
60
71
 
61
72
  /** Mono value text (LC-07 CODE-KNOB-IMMUNE) — both the honest fallback for
@@ -74,15 +85,22 @@ export function BarcodePreview({
74
85
  moduleWidth = 1,
75
86
  showText = false,
76
87
  format,
88
+ textFallback = true,
77
89
  }: BarcodePreviewProps) {
78
90
  if (!value) return null;
79
91
  if (barcodePreviewSymbology(format) === "qr") {
80
92
  return (
81
- <QrPreview value={value} height={height} moduleWidth={moduleWidth} showText={showText} />
93
+ <QrPreview
94
+ value={value}
95
+ height={height}
96
+ moduleWidth={moduleWidth}
97
+ showText={showText}
98
+ textFallback={textFallback}
99
+ />
82
100
  );
83
101
  }
84
102
  const runs = encodeCode128B(value);
85
- if (!runs) return <MonoValue value={value} />;
103
+ if (!runs) return textFallback ? <MonoValue value={value} /> : null;
86
104
  const quietZone = moduleWidth * 10;
87
105
  return (
88
106
  <View
@@ -126,19 +144,33 @@ function QrPreview({
126
144
  height,
127
145
  moduleWidth,
128
146
  showText,
147
+ textFallback,
129
148
  }: {
130
149
  value: string;
131
150
  height: number;
132
151
  moduleWidth: number;
133
152
  showText: boolean;
153
+ textFallback: boolean;
134
154
  }) {
135
155
  const matrix = encodeQr(value);
136
- if (!matrix) return <MonoValue value={value} />;
137
- // Natural module size until the host's height bound clamps the square
138
- // then every module shrinks uniformly so the symbol stays square (LC-10).
156
+ if (!matrix) return textFallback ? <MonoValue value={value} /> : null;
157
+ // A module must land on a WHOLE pixel. A fractional module width rounds to
158
+ // different widths across the grid, so a decoder cannot resample the symbol
159
+ // measured on the media-11 board at DPR 2: the 33px square (1.000 px/module)
160
+ // decoded and the 44px one (1.333 px/module) did not, in either scheme. So
161
+ // the module is the largest whole pixel that fits, capped by `moduleWidth`
162
+ // and by the host's `height` bound (LC-10 — the square never exceeds its
163
+ // host, and the bound is a ceiling, never a target).
139
164
  const totalModules = matrix.size + 2 * QR_QUIET_ZONE_MODULES;
140
- const edge = Math.min(totalModules * moduleWidth, height);
141
- const cell = edge / totalModules;
165
+ const cell = Math.floor(Math.min(moduleWidth, height / totalModules));
166
+ // Under one whole pixel there is no readable symbol to draw at all. Fall
167
+ // back to the value as text, the same honest contract the over-capacity and
168
+ // non-ASCII cases have: a symbol no reader can resample is decoration, and
169
+ // decoration that looks like data is the one thing this component refuses to
170
+ // paint. This is what a `compact` bound (24) or a table-row bound does to
171
+ // anything past a short SKU.
172
+ if (cell < 1) return textFallback ? <MonoValue value={value} /> : null;
173
+ const edge = cell * totalModules;
142
174
  const quietZone = cell * QR_QUIET_ZONE_MODULES;
143
175
  const rows = qrRowRuns(matrix);
144
176
  return (
@@ -1,5 +1,5 @@
1
1
  import { act, fireEvent } from "@testing-library/react";
2
- import { describe, expect, it, vi } from "vitest";
2
+ import { beforeEach, describe, expect, it, vi } from "vitest";
3
3
  import { renderWithProviders } from "@multiplatform.one/test-utils";
4
4
  import { Form } from "../../Form";
5
5
  import { Combobox } from "./index";
@@ -313,5 +313,68 @@ describe("Combobox", () => {
313
313
  expect(activeOption(result.container)?.textContent).toContain("Carrot");
314
314
  expect(activeOption(result.container)?.getAttribute("role")).toBe("option");
315
315
  });
316
+
317
+ // The sheet core (<= OVERLAY_BREAKPOINT, and every native render) used to
318
+ // build headers itself from source order, so interleaved groups emitted a
319
+ // REPEAT header and the rows stayed unclustered — two different lists from
320
+ // one set of props. Both cores now go through groupComboboxOptions.
321
+ it("the sheet renders the same headers and row order as the desktop panel", async () => {
322
+ function shot(root: HTMLElement) {
323
+ return {
324
+ headers: [...root.querySelectorAll("[data-combobox-group-header]")].map(
325
+ (el) => el.textContent,
326
+ ),
327
+ rows: [...root.querySelectorAll('[role="option"]')].map((el) => ({
328
+ label: el.textContent,
329
+ index: el.getAttribute("data-combobox-index"),
330
+ })),
331
+ };
332
+ }
333
+
334
+ window.innerWidth = 1200;
335
+ const desktop = renderWithProviders(
336
+ <Combobox label="Produce" name="produce" options={groupedOptions} multiple open />,
337
+ );
338
+ await act(async () => {});
339
+ const onDesktop = shot(document.body);
340
+ desktop.unmount();
341
+
342
+ window.innerWidth = 500;
343
+ renderWithProviders(
344
+ <Combobox label="Produce" name="produce" options={groupedOptions} multiple open />,
345
+ );
346
+ await act(async () => {});
347
+ const onSheet = shot(document.body);
348
+
349
+ expect(onDesktop.headers).toEqual(["Fruit", "Vegetable"]);
350
+ expect(onSheet.headers).toEqual(onDesktop.headers);
351
+ expect(onSheet.rows).toEqual(onDesktop.rows);
352
+ // One header per group: a repeated label is the defect this guards.
353
+ expect(new Set(onSheet.headers).size).toBe(onSheet.headers.length);
354
+ });
355
+
356
+ // The sheet's activeIndex indexes the same grouped list the sheet renders,
357
+ // so arrows land on the row the user sees rather than the source-order row.
358
+ it("sheet ArrowDown follows the rendered row order, not source order", async () => {
359
+ window.innerWidth = 500;
360
+ renderWithProviders(
361
+ <Combobox label="Produce" name="produce" options={groupedOptions} multiple open />,
362
+ );
363
+ await act(async () => {});
364
+
365
+ const rows = [...document.body.querySelectorAll('[role="option"]')];
366
+ expect(rows.map((el) => el.textContent?.trim())).toEqual(["Apple", "Banana", "Carrot"]);
367
+
368
+ const search = document.body.querySelector("input");
369
+ expect(search).toBeTruthy();
370
+ // activeIndex starts at 0 (Apple); one ArrowDown must highlight the row
371
+ // rendered second (Banana), which is sortedFiltered[2], not [1].
372
+ await act(async () => {
373
+ fireEvent.keyDown(search!, { key: "ArrowDown" });
374
+ });
375
+ const active = document.body.querySelector('[data-active="true"]');
376
+ expect(active?.textContent).toContain("Banana");
377
+ expect(active?.getAttribute("data-combobox-index")).toBe("1");
378
+ });
316
379
  });
317
380
  });
@@ -1918,6 +1918,17 @@ function NativeComboboxCore({
1918
1918
  return orderOptionsBySelected(filtered, current, selectedOrder);
1919
1919
  }, [filtered, value, filter, selectedOrder]);
1920
1920
 
1921
+ // Same grouping the floating core uses (`groupComboboxOptions`, the mechanism
1922
+ // mpo-floating-measured.md §2.3 names as ours): rows cluster by group so each
1923
+ // group gets exactly ONE header. Rendering source order here emitted a repeat
1924
+ // header for interleaved groups and disagreed with the desktop panel for
1925
+ // identical props. `activeIndex` indexes `navigableOptions`, which IS the
1926
+ // render order, so arrows still land on the row the user sees (MPO-38 AC-6).
1927
+ const { flatOptions: navigableOptions } = useMemo(
1928
+ () => groupComboboxOptions(sortedFiltered),
1929
+ [sortedFiltered],
1930
+ );
1931
+
1921
1932
  const searchCleanupRef = useRef<(() => void) | null>(null);
1922
1933
  useEffect(() => {
1923
1934
  if (!onSearch || !open) return;
@@ -1942,8 +1953,8 @@ function NativeComboboxCore({
1942
1953
  }
1943
1954
  }, [open]);
1944
1955
 
1945
- const totalItems = sortedFiltered.length + (showCreateOption ? 1 : 0);
1946
- const createOptionIndex = showCreateOption ? sortedFiltered.length : -1;
1956
+ const totalItems = navigableOptions.length + (showCreateOption ? 1 : 0);
1957
+ const createOptionIndex = showCreateOption ? navigableOptions.length : -1;
1947
1958
  const listboxId = comboboxListboxId(id);
1948
1959
  const activeDescendant =
1949
1960
  open && activeIndex != null && activeIndex >= 0 ? comboboxOptionId(id, activeIndex) : undefined;
@@ -2028,8 +2039,8 @@ function NativeComboboxCore({
2028
2039
  e.preventDefault();
2029
2040
  if (activeIndex === createOptionIndex && showCreateOption) {
2030
2041
  handleCreate();
2031
- } else if (activeIndex != null && activeIndex >= 0 && sortedFiltered[activeIndex]) {
2032
- handleSelect(sortedFiltered[activeIndex]);
2042
+ } else if (activeIndex != null && activeIndex >= 0 && navigableOptions[activeIndex]) {
2043
+ handleSelect(navigableOptions[activeIndex]);
2033
2044
  if (e.key === "Enter" || !multiple) setOpen(false);
2034
2045
  }
2035
2046
  }
@@ -2039,7 +2050,7 @@ function NativeComboboxCore({
2039
2050
  createOptionIndex,
2040
2051
  showCreateOption,
2041
2052
  activeIndex,
2042
- sortedFiltered,
2053
+ navigableOptions,
2043
2054
  handleCreate,
2044
2055
  handleSelect,
2045
2056
  multiple,
@@ -2066,8 +2077,8 @@ function NativeComboboxCore({
2066
2077
  e.stopPropagation();
2067
2078
  if (activeIndex === createOptionIndex && showCreateOption) {
2068
2079
  handleCreate();
2069
- } else if (activeIndex != null && activeIndex >= 0 && sortedFiltered[activeIndex]) {
2070
- handleSelect(sortedFiltered[activeIndex]);
2080
+ } else if (activeIndex != null && activeIndex >= 0 && navigableOptions[activeIndex]) {
2081
+ handleSelect(navigableOptions[activeIndex]);
2071
2082
  if (e.key === "Enter" || !multiple) setOpen(false);
2072
2083
  } else {
2073
2084
  setOpen(false);
@@ -2081,7 +2092,7 @@ function NativeComboboxCore({
2081
2092
  activeIndex,
2082
2093
  createOptionIndex,
2083
2094
  showCreateOption,
2084
- sortedFiltered,
2095
+ navigableOptions,
2085
2096
  handleCreate,
2086
2097
  handleSelect,
2087
2098
  multiple,
@@ -2138,12 +2149,12 @@ function NativeComboboxCore({
2138
2149
  {searchError}
2139
2150
  </Text>
2140
2151
  </View>
2141
- ) : sortedFiltered.length > 0 ? (
2152
+ ) : navigableOptions.length > 0 ? (
2142
2153
  <>
2143
- {sortedFiltered.map((option, i) => {
2154
+ {navigableOptions.map((option, i) => {
2144
2155
  const selected = isSelectedFn(option.value);
2145
2156
  const active = i === activeIndex;
2146
- const prevGroup = i > 0 ? sortedFiltered[i - 1].group : undefined;
2157
+ const prevGroup = i > 0 ? navigableOptions[i - 1].group : undefined;
2147
2158
  const showGroupHeader = option.group && option.group !== prevGroup;
2148
2159
  const optionRow = (
2149
2160
  <View
@@ -134,6 +134,34 @@ describe("FileUpload", () => {
134
134
  expect(dropzone?.getAttribute("data-kb-ring")).toBe("true");
135
135
  });
136
136
 
137
+ // MPO-57 regression. `data-kb-ring="true"` proved the STATE, never the paint.
138
+ // The frame's LC-71 kill is a `:focus-visible` rule; a keyboard-origin focus
139
+ // matches `:focus-visible` too, so the base-state ring atom lost on
140
+ // specificity and the browser computed outline-width 0px while every
141
+ // assertion passed. Measured on the Storybook harness, not read off source.
142
+ // The ring must therefore also win INSIDE the focus-visible layer.
143
+ it("beats its own LC-71 focus-visible kill — the ring wins in the layer that suppresses it", () => {
144
+ const { container } = renderWithHouseThemes(
145
+ <FileUpload label="Attachment" name="attachment" />,
146
+ );
147
+ const zone = getZone(container);
148
+ fireEvent.keyDown(document.body, { key: "Tab", code: "Tab" });
149
+ fireEvent.focus(zone);
150
+ expect(zone.getAttribute("data-kb-ring")).toBe("true");
151
+
152
+ // Base-state ring (2px solid $outlineColor at offset 0).
153
+ expect(zone.className).toMatch(/_outlineWidth-2px/);
154
+ expect(zone.className).toMatch(/_outlineStyle-solid/);
155
+ expect(zone.className).toMatch(/_outlineOffset-0px/);
156
+
157
+ // …restated in the focus-visible layer, so the kill cannot outrank it.
158
+ expect(zone.className).toMatch(/_outlineWidth-0focus-visible-2px/);
159
+ expect(zone.className).toMatch(/_outlineStyle-0focus-visible-solid/);
160
+ // …and the zeroing atoms are gone from that layer while the ring is up.
161
+ expect(zone.className).not.toMatch(/_outlineWidth-0focus-visible-0px/);
162
+ expect(zone.className).not.toMatch(/_outlineStyle-0focus-visible-none/);
163
+ });
164
+
137
165
  it("keeps Choose File out of the tab order so the dropzone is the one stop", () => {
138
166
  const result = renderWithProviders(
139
167
  <FileUpload label="Attachment" name="attachment" buttonText="Pick file" />,