@multiplatform.one/forms 7.80.0 → 7.81.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 (587) hide show
  1. package/dist/cjs/AdaptivePopup/index.cjs +1 -1
  2. package/dist/cjs/AdaptivePopup/index.native.js +3 -3
  3. package/dist/cjs/AdaptivePopup/index.native.js.map +1 -1
  4. package/dist/cjs/Button/IconButtonGroup.native.js.map +1 -1
  5. package/dist/cjs/Button/circleGlyph.native.js.map +1 -1
  6. package/dist/cjs/Button/iconButtonGroupContext.native.js.map +1 -1
  7. package/dist/cjs/Button/index.cjs +12 -5
  8. package/dist/cjs/Button/index.native.js +16 -8
  9. package/dist/cjs/Button/index.native.js.map +1 -1
  10. package/dist/cjs/Button/webGlass.native.js.map +1 -1
  11. package/dist/cjs/Chip/index.native.js.map +1 -1
  12. package/dist/cjs/ContextualSaveBar/UnsavedChangesDialog.native.js +1 -1
  13. package/dist/cjs/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
  14. package/dist/cjs/ContextualSaveBar/clientKnownIdentity.native.js.map +1 -1
  15. package/dist/cjs/ContextualSaveBar/commitImmediateField.native.js.map +1 -1
  16. package/dist/cjs/ContextualSaveBar/index.native.js +3 -3
  17. package/dist/cjs/ContextualSaveBar/index.native.js.map +1 -1
  18. package/dist/cjs/ContextualSaveBar/useUnsavedChangesGuard.native.js.map +1 -1
  19. package/dist/cjs/ControlGroup/index.native.js +1 -1
  20. package/dist/cjs/ControlGroup/index.native.js.map +1 -1
  21. package/dist/cjs/DescriptionList/index.native.js +2 -2
  22. package/dist/cjs/DescriptionList/index.native.js.map +1 -1
  23. package/dist/cjs/ErrorSummary.native.js.map +1 -1
  24. package/dist/cjs/FieldDisplay/editMode.native.js.map +1 -1
  25. package/dist/cjs/FieldDisplay/formatters.native.js.map +1 -1
  26. package/dist/cjs/FieldDisplay/index.native.js +1 -1
  27. package/dist/cjs/FieldDisplay/index.native.js.map +1 -1
  28. package/dist/cjs/FieldGroup.native.js.map +1 -1
  29. package/dist/cjs/FloatingPanel/PanelHeader.cjs +3 -8
  30. package/dist/cjs/FloatingPanel/PanelHeader.native.js +3 -8
  31. package/dist/cjs/FloatingPanel/PanelHeader.native.js.map +1 -1
  32. package/dist/cjs/FloatingPanel/RegularPanel.native.js.map +1 -1
  33. package/dist/cjs/FloatingPanel/compactFace.native.js.map +1 -1
  34. package/dist/cjs/FloatingPanel/containingBlock.native.js.map +1 -1
  35. package/dist/cjs/FloatingPanel/coverRect.cjs +0 -8
  36. package/dist/cjs/FloatingPanel/coverRect.native.js +0 -8
  37. package/dist/cjs/FloatingPanel/coverRect.native.js.map +1 -1
  38. package/dist/cjs/FloatingPanel/echoContext.cjs +5 -27
  39. package/dist/cjs/FloatingPanel/echoContext.native.js +5 -28
  40. package/dist/cjs/FloatingPanel/echoContext.native.js.map +1 -1
  41. package/dist/cjs/FloatingPanel/index.cjs +49 -131
  42. package/dist/cjs/FloatingPanel/index.native.js +26 -91
  43. package/dist/cjs/FloatingPanel/index.native.js.map +1 -1
  44. package/dist/cjs/FloatingPanel/nestedAction.native.js.map +1 -1
  45. package/dist/cjs/FloatingPanel/paintedBox.native.js.map +1 -1
  46. package/dist/cjs/FloatingPanel/panelWidth.native.js.map +1 -1
  47. package/dist/cjs/FloatingPanel/pointAnchor.native.js.map +1 -1
  48. package/dist/cjs/FloatingPanel/regularPlacement.native.js.map +1 -1
  49. package/dist/cjs/FloatingPanel/trailingAction.native.js +1 -1
  50. package/dist/cjs/FloatingPanel/trailingAction.native.js.map +1 -1
  51. package/dist/cjs/FloatingPanel/useFloatingPanel.native.js.map +1 -1
  52. package/dist/cjs/Form/index.native.js +1 -1
  53. package/dist/cjs/Form/index.native.js.map +1 -1
  54. package/dist/cjs/Form/submissionController.native.js.map +1 -1
  55. package/dist/cjs/Form/validateOn.native.js.map +1 -1
  56. package/dist/cjs/FormGrid.native.js.map +1 -1
  57. package/dist/cjs/FormSection.native.js.map +1 -1
  58. package/dist/cjs/InputParts/PasswordReveal.native.js.map +1 -1
  59. package/dist/cjs/InputParts/index.native.js.map +1 -1
  60. package/dist/cjs/InputParts/keyboardAppearance.native.js.map +1 -1
  61. package/dist/cjs/Label/index.native.js.map +1 -1
  62. package/dist/cjs/MediaPicker/base64.native.js.map +1 -1
  63. package/dist/cjs/MediaPicker/payload.native.js.map +1 -1
  64. package/dist/cjs/MediaPicker/types.native.js.map +1 -1
  65. package/dist/cjs/MediaPicker/useMediaPicker.native.js.map +1 -1
  66. package/dist/cjs/Skeleton/index.native.js.map +1 -1
  67. package/dist/cjs/Spinner/SpinnerGlyph.native.js.map +1 -1
  68. package/dist/cjs/Spinner/spinnerSize.native.js.map +1 -1
  69. package/dist/cjs/Table/index.native.js.map +1 -1
  70. package/dist/cjs/Wheel/haptic.native.js.map +1 -1
  71. package/dist/cjs/Wheel/index.native.js.map +1 -1
  72. package/dist/cjs/Wheel/wheelShared.native.js.map +1 -1
  73. package/dist/cjs/actionLabel.native.js.map +1 -1
  74. package/dist/cjs/fieldDefaults.native.js.map +1 -1
  75. package/dist/cjs/fieldLayout.native.js +1 -1
  76. package/dist/cjs/fieldLayout.native.js.map +1 -1
  77. package/dist/cjs/fields/Barcode/BarcodePreview.native.js.map +1 -1
  78. package/dist/cjs/fields/Barcode/BarcodeScanner.native.js +1 -1
  79. package/dist/cjs/fields/Barcode/code128.native.js.map +1 -1
  80. package/dist/cjs/fields/Barcode/index.native.js +2 -2
  81. package/dist/cjs/fields/Barcode/index.native.js.map +1 -1
  82. package/dist/cjs/fields/Barcode/qr.native.js.map +1 -1
  83. package/dist/cjs/fields/Barcode/scannerTypes.native.js.map +1 -1
  84. package/dist/cjs/fields/Checkbox/Checkbox.native.js +1 -1
  85. package/dist/cjs/fields/Checkbox/Checkbox.native.js.map +1 -1
  86. package/dist/cjs/fields/Checkbox/CheckboxBox.native.js.map +1 -1
  87. package/dist/cjs/fields/Checkbox/CheckboxCard.native.js.map +1 -1
  88. package/dist/cjs/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  89. package/dist/cjs/fields/Checkbox/CheckboxGroup.native.js +1 -1
  90. package/dist/cjs/fields/Checkbox/CheckboxGroup.native.js.map +1 -1
  91. package/dist/cjs/fields/Checkbox/checkboxGroupContext.native.js.map +1 -1
  92. package/dist/cjs/fields/Checkbox/index.native.js.map +1 -1
  93. package/dist/cjs/fields/ColorPicker/SystemColorField.native.js.map +1 -1
  94. package/dist/cjs/fields/ColorPicker/index.native.js +2 -2
  95. package/dist/cjs/fields/ColorPicker/index.native.js.map +1 -1
  96. package/dist/cjs/fields/ColorPicker/parts.native.js +2 -2
  97. package/dist/cjs/fields/ColorPicker/parts.native.js.map +1 -1
  98. package/dist/cjs/fields/ColorPicker/systemColorWell.gnome.native.js.map +1 -1
  99. package/dist/cjs/fields/Combobox/authorOptions.native.js.map +1 -1
  100. package/dist/cjs/fields/Combobox/index.cjs +3 -10
  101. package/dist/cjs/fields/Combobox/index.native.js +8 -15
  102. package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
  103. package/dist/cjs/fields/DatePicker/Calendar.native.js.map +1 -1
  104. package/dist/cjs/fields/DatePicker/DateRangePicker.native.js +2 -2
  105. package/dist/cjs/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  106. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js +3 -3
  107. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  108. package/dist/cjs/fields/DatePicker/DatetimePicker.native.js +2 -2
  109. package/dist/cjs/fields/DatePicker/MonthPicker.native.js +2 -2
  110. package/dist/cjs/fields/DatePicker/MonthPicker.native.js.map +1 -1
  111. package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js +2 -2
  112. package/dist/cjs/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  113. package/dist/cjs/fields/DatePicker/catalog.native.js +2 -2
  114. package/dist/cjs/fields/DatePicker/catalog.native.js.map +1 -1
  115. package/dist/cjs/fields/DatePicker/fieldValueSync.native.js.map +1 -1
  116. package/dist/cjs/fields/DatePicker/index.native.js +2 -2
  117. package/dist/cjs/fields/DatePicker/parts.native.js +2 -2
  118. package/dist/cjs/fields/DatePicker/parts.native.js.map +1 -1
  119. package/dist/cjs/fields/DatePicker/utils.native.js.map +1 -1
  120. package/dist/cjs/fields/Duration/DurationWheel.native.js +1 -1
  121. package/dist/cjs/fields/Duration/durationMath.native.js.map +1 -1
  122. package/dist/cjs/fields/Duration/durationWheelTypes.native.js.map +1 -1
  123. package/dist/cjs/fields/Duration/index.native.js +3 -3
  124. package/dist/cjs/fields/Duration/index.native.js.map +1 -1
  125. package/dist/cjs/fields/FileUpload/filePickerTypes.native.js.map +1 -1
  126. package/dist/cjs/fields/FileUpload/index.native.js +2 -2
  127. package/dist/cjs/fields/FileUpload/index.native.js.map +1 -1
  128. package/dist/cjs/fields/FileUpload/nativePickerLoader.native.js.map +1 -1
  129. package/dist/cjs/fields/Geolocation/expoMapsLoader.native.js.map +1 -1
  130. package/dist/cjs/fields/Geolocation/geoValue.native.js.map +1 -1
  131. package/dist/cjs/fields/Geolocation/geocoder.native.js.map +1 -1
  132. package/dist/cjs/fields/Geolocation/geocoderContext.native.js.map +1 -1
  133. package/dist/cjs/fields/Geolocation/index.native.js +5 -5
  134. package/dist/cjs/fields/Geolocation/index.native.js.map +1 -1
  135. package/dist/cjs/fields/Geolocation/mapMath.native.js.map +1 -1
  136. package/dist/cjs/fields/Geolocation/mapTypes.native.js.map +1 -1
  137. package/dist/cjs/fields/Geolocation/nativeSearchFocus.native.js.map +1 -1
  138. package/dist/cjs/fields/Geolocation/photonGeocoder.native.js.map +1 -1
  139. package/dist/cjs/fields/Icon/drawnSet.native.js.map +1 -1
  140. package/dist/cjs/fields/Icon/index.native.js +3 -3
  141. package/dist/cjs/fields/Icon/index.native.js.map +1 -1
  142. package/dist/cjs/fields/ImageField/index.native.js +2 -2
  143. package/dist/cjs/fields/ImageField/index.native.js.map +1 -1
  144. package/dist/cjs/fields/Input/index.native.js +3 -3
  145. package/dist/cjs/fields/Input/index.native.js.map +1 -1
  146. package/dist/cjs/fields/MentionInput/index.native.js +3 -3
  147. package/dist/cjs/fields/MentionInput/index.native.js.map +1 -1
  148. package/dist/cjs/fields/OTPInput/index.native.js +3 -3
  149. package/dist/cjs/fields/OTPInput/index.native.js.map +1 -1
  150. package/dist/cjs/fields/OTPInput/otpCellCss.native.js.map +1 -1
  151. package/dist/cjs/fields/PhoneInput/dialCodes.native.js.map +1 -1
  152. package/dist/cjs/fields/PhoneInput/index.native.js +3 -3
  153. package/dist/cjs/fields/PhoneInput/index.native.js.map +1 -1
  154. package/dist/cjs/fields/PhoneInput/phone.native.js.map +1 -1
  155. package/dist/cjs/fields/PhoneInput/regionNames.native.js.map +1 -1
  156. package/dist/cjs/fields/Progress/index.native.js +1 -1
  157. package/dist/cjs/fields/Progress/index.native.js.map +1 -1
  158. package/dist/cjs/fields/RadioGroup/index.native.js +1 -1
  159. package/dist/cjs/fields/RadioGroup/index.native.js.map +1 -1
  160. package/dist/cjs/fields/Rating/index.native.js +1 -1
  161. package/dist/cjs/fields/Rating/index.native.js.map +1 -1
  162. package/dist/cjs/fields/Rating/ratingMath.native.js.map +1 -1
  163. package/dist/cjs/fields/Rating/types.native.js.map +1 -1
  164. package/dist/cjs/fields/SearchInput/index.native.js +2 -2
  165. package/dist/cjs/fields/SearchInput/index.native.js.map +1 -1
  166. package/dist/cjs/fields/Select/InlineChoices.cjs +4 -8
  167. package/dist/cjs/fields/Select/InlineChoices.native.js +4 -8
  168. package/dist/cjs/fields/Select/InlineChoices.native.js.map +1 -1
  169. package/dist/cjs/fields/Select/SheetPickerRow.native.js.map +1 -1
  170. package/dist/cjs/fields/Select/index.cjs +46 -199
  171. package/dist/cjs/fields/Select/index.native.js +56 -211
  172. package/dist/cjs/fields/Select/index.native.js.map +1 -1
  173. package/dist/cjs/fields/Select/shouldInlineChoices.native.js.map +1 -1
  174. package/dist/cjs/fields/Signature/index.native.js +2 -2
  175. package/dist/cjs/fields/Signature/index.native.js.map +1 -1
  176. package/dist/cjs/fields/Slider/index.native.js +1 -1
  177. package/dist/cjs/fields/Slider/index.native.js.map +1 -1
  178. package/dist/cjs/fields/Slider/jumpMotion.native.js.map +1 -1
  179. package/dist/cjs/fields/Stepper/index.native.js +2 -2
  180. package/dist/cjs/fields/Stepper/index.native.js.map +1 -1
  181. package/dist/cjs/fields/Stepper/resolveStepperPlacement.native.js.map +1 -1
  182. package/dist/cjs/fields/Switch/footprint.native.js.map +1 -1
  183. package/dist/cjs/fields/Switch/index.native.js +2 -2
  184. package/dist/cjs/fields/Switch/index.native.js.map +1 -1
  185. package/dist/cjs/fields/TextArea/index.native.js +2 -2
  186. package/dist/cjs/fields/TextArea/index.native.js.map +1 -1
  187. package/dist/cjs/fields/TimePicker/catalog.native.js +3 -3
  188. package/dist/cjs/fields/TimePicker/catalog.native.js.map +1 -1
  189. package/dist/cjs/fields/TimePicker/index.native.js +2 -2
  190. package/dist/cjs/fields/TimePicker/parts.native.js +1 -1
  191. package/dist/cjs/fields/TimePicker/parts.native.js.map +1 -1
  192. package/dist/cjs/fields/TimeRangeScrubber/geometry.native.js.map +1 -1
  193. package/dist/cjs/fields/TimeRangeScrubber/index.native.js +2 -2
  194. package/dist/cjs/fields/TimeRangeScrubber/index.native.js.map +1 -1
  195. package/dist/cjs/fields/ToggleGroup/index.native.js +1 -1
  196. package/dist/cjs/fields/ToggleGroup/index.native.js.map +1 -1
  197. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.cjs +2 -2
  198. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js +3 -3
  199. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  200. package/dist/cjs/fields/nativeDateTime/dateTimePickerLoader.native.js.map +1 -1
  201. package/dist/cjs/fields/nativeDateTime/osDateTimeIosDisplay.native.js.map +1 -1
  202. package/dist/cjs/fields/nativeDateTime/sheetKeyboard.native.js.map +1 -1
  203. package/dist/cjs/fields/nativeSelect.native.js.map +1 -1
  204. package/dist/cjs/fields/selectedOrder.native.js.map +1 -1
  205. package/dist/cjs/formSpacing.native.js.map +1 -1
  206. package/dist/cjs/hooks/useFocusManagement.native.js.map +1 -1
  207. package/dist/cjs/index.cjs +4 -0
  208. package/dist/cjs/index.native.js +49 -45
  209. package/dist/cjs/index.native.js.map +1 -1
  210. package/dist/cjs/keyboard/KeyboardDoneBar.native.js +1 -1
  211. package/dist/cjs/keyboard/chain.native.js.map +1 -1
  212. package/dist/cjs/keyboard/index.native.js.map +1 -1
  213. package/dist/cjs/keyboard/types.native.js.map +1 -1
  214. package/dist/cjs/requiredMarking.native.js.map +1 -1
  215. package/dist/cjs/shared/CheckGlyph.cjs +40 -0
  216. package/dist/cjs/shared/CheckGlyph.native.js +44 -0
  217. package/dist/cjs/shared/CheckGlyph.native.js.map +1 -0
  218. package/dist/cjs/shared/TimeColumn.native.js +1 -1
  219. package/dist/cjs/shared/TimeColumn.native.js.map +1 -1
  220. package/dist/cjs/shared/capabilityPreflight.native.js.map +1 -1
  221. package/dist/cjs/shared/choiceRowPress.native.js.map +1 -1
  222. package/dist/cjs/shared/colorRamps.native.js.map +1 -1
  223. package/dist/cjs/shared/devWarn.native.js.map +1 -1
  224. package/dist/cjs/shared/fieldRowContext.native.js.map +1 -1
  225. package/dist/cjs/shared/floatingList.cjs +82 -3
  226. package/dist/cjs/shared/floatingList.native.js +96 -6
  227. package/dist/cjs/shared/floatingList.native.js.map +1 -1
  228. package/dist/cjs/shared/focusManagement.native.js.map +1 -1
  229. package/dist/cjs/shared/groupContext.native.js.map +1 -1
  230. package/dist/cjs/shared/i18n.native.js.map +1 -1
  231. package/dist/cjs/shared/instantMotion.native.js.map +1 -1
  232. package/dist/cjs/shared/nativeA11y.native.js.map +1 -1
  233. package/dist/cjs/shared/nativeAutoFocus.native.js.map +1 -1
  234. package/dist/cjs/shared/overlaySizeClass.native.js.map +1 -1
  235. package/dist/cjs/shared/overlayStack.native.js.map +1 -1
  236. package/dist/cjs/shared/panelPortal.native.js.map +1 -1
  237. package/dist/cjs/shared/pickerTriggerContract.native.js.map +1 -1
  238. package/dist/cjs/shared/pressSlopProps.native.js.map +1 -1
  239. package/dist/cjs/shared/restoreRetries.native.js.map +1 -1
  240. package/dist/cjs/shared/sheetNavigation.native.js.map +1 -1
  241. package/dist/cjs/shared/systemControlModules.gnome.native.js.map +1 -1
  242. package/dist/cjs/shared/systemControls.native.js.map +1 -1
  243. package/dist/cjs/shared/t.native.js.map +1 -1
  244. package/dist/cjs/shared/tableCellContext.native.js.map +1 -1
  245. package/dist/cjs/shared/useDragScroll.native.js.map +1 -1
  246. package/dist/cjs/shared/useKeyboardInset.native.js.map +1 -1
  247. package/dist/cjs/shared/useSheetEscapeDismiss.native.js.map +1 -1
  248. package/dist/cjs/shared/useWheelIncrement.native.js.map +1 -1
  249. package/dist/cjs/shared/utils.native.js +1 -1
  250. package/dist/cjs/shared/utils.native.js.map +1 -1
  251. package/dist/cjs/shared/zIndex.native.js.map +1 -1
  252. package/dist/cjs/standardActions.native.js.map +1 -1
  253. package/dist/cjs/themedPrimitives.native.js.map +1 -1
  254. package/dist/cjs/types.native.js.map +1 -1
  255. package/dist/cjs/utils/LinkCell.native.js.map +1 -1
  256. package/dist/esm/AdaptivePopup/index.mjs +2 -2
  257. package/dist/esm/AdaptivePopup/index.mjs.map +1 -1
  258. package/dist/esm/AdaptivePopup/index.native.js +2 -2
  259. package/dist/esm/AdaptivePopup/index.native.js.map +1 -1
  260. package/dist/esm/Button/IconButtonGroup.native.js.map +1 -1
  261. package/dist/esm/Button/circleGlyph.native.js.map +1 -1
  262. package/dist/esm/Button/iconButtonGroupContext.native.js.map +1 -1
  263. package/dist/esm/Button/index.mjs +12 -5
  264. package/dist/esm/Button/index.mjs.map +1 -1
  265. package/dist/esm/Button/index.native.js +14 -6
  266. package/dist/esm/Button/index.native.js.map +1 -1
  267. package/dist/esm/Button/webGlass.native.js.map +1 -1
  268. package/dist/esm/Chip/index.native.js.map +1 -1
  269. package/dist/esm/ContextualSaveBar/UnsavedChangesDialog.native.js.map +1 -1
  270. package/dist/esm/ContextualSaveBar/clientKnownIdentity.native.js.map +1 -1
  271. package/dist/esm/ContextualSaveBar/commitImmediateField.native.js.map +1 -1
  272. package/dist/esm/ContextualSaveBar/index.native.js.map +1 -1
  273. package/dist/esm/ContextualSaveBar/useUnsavedChangesGuard.native.js.map +1 -1
  274. package/dist/esm/ControlGroup/index.native.js.map +1 -1
  275. package/dist/esm/DescriptionList/index.native.js.map +1 -1
  276. package/dist/esm/ErrorSummary.native.js.map +1 -1
  277. package/dist/esm/FieldDisplay/editMode.native.js.map +1 -1
  278. package/dist/esm/FieldDisplay/formatters.native.js.map +1 -1
  279. package/dist/esm/FieldDisplay/index.native.js.map +1 -1
  280. package/dist/esm/FieldGroup.native.js.map +1 -1
  281. package/dist/esm/FloatingPanel/PanelHeader.mjs +3 -8
  282. package/dist/esm/FloatingPanel/PanelHeader.mjs.map +1 -1
  283. package/dist/esm/FloatingPanel/PanelHeader.native.js +3 -8
  284. package/dist/esm/FloatingPanel/PanelHeader.native.js.map +1 -1
  285. package/dist/esm/FloatingPanel/RegularPanel.native.js.map +1 -1
  286. package/dist/esm/FloatingPanel/compactFace.native.js.map +1 -1
  287. package/dist/esm/FloatingPanel/containingBlock.native.js.map +1 -1
  288. package/dist/esm/FloatingPanel/coverRect.mjs +1 -8
  289. package/dist/esm/FloatingPanel/coverRect.mjs.map +1 -1
  290. package/dist/esm/FloatingPanel/coverRect.native.js +1 -8
  291. package/dist/esm/FloatingPanel/coverRect.native.js.map +1 -1
  292. package/dist/esm/FloatingPanel/echoContext.mjs +4 -24
  293. package/dist/esm/FloatingPanel/echoContext.mjs.map +1 -1
  294. package/dist/esm/FloatingPanel/echoContext.native.js +4 -25
  295. package/dist/esm/FloatingPanel/echoContext.native.js.map +1 -1
  296. package/dist/esm/FloatingPanel/index.mjs +53 -135
  297. package/dist/esm/FloatingPanel/index.mjs.map +1 -1
  298. package/dist/esm/FloatingPanel/index.native.js +30 -95
  299. package/dist/esm/FloatingPanel/index.native.js.map +1 -1
  300. package/dist/esm/FloatingPanel/nestedAction.native.js.map +1 -1
  301. package/dist/esm/FloatingPanel/paintedBox.native.js.map +1 -1
  302. package/dist/esm/FloatingPanel/panelWidth.native.js.map +1 -1
  303. package/dist/esm/FloatingPanel/pointAnchor.native.js.map +1 -1
  304. package/dist/esm/FloatingPanel/regularPlacement.native.js.map +1 -1
  305. package/dist/esm/FloatingPanel/trailingAction.native.js.map +1 -1
  306. package/dist/esm/FloatingPanel/useFloatingPanel.native.js.map +1 -1
  307. package/dist/esm/Form/index.native.js.map +1 -1
  308. package/dist/esm/Form/submissionController.native.js.map +1 -1
  309. package/dist/esm/Form/validateOn.native.js.map +1 -1
  310. package/dist/esm/FormGrid.native.js.map +1 -1
  311. package/dist/esm/FormSection.native.js.map +1 -1
  312. package/dist/esm/InputParts/PasswordReveal.native.js.map +1 -1
  313. package/dist/esm/InputParts/index.native.js.map +1 -1
  314. package/dist/esm/InputParts/keyboardAppearance.native.js.map +1 -1
  315. package/dist/esm/Label/index.native.js.map +1 -1
  316. package/dist/esm/MediaPicker/base64.native.js.map +1 -1
  317. package/dist/esm/MediaPicker/payload.native.js.map +1 -1
  318. package/dist/esm/MediaPicker/types.native.js.map +1 -1
  319. package/dist/esm/MediaPicker/useMediaPicker.native.js.map +1 -1
  320. package/dist/esm/Skeleton/index.native.js.map +1 -1
  321. package/dist/esm/Spinner/SpinnerGlyph.native.js.map +1 -1
  322. package/dist/esm/Spinner/spinnerSize.native.js.map +1 -1
  323. package/dist/esm/Table/index.native.js.map +1 -1
  324. package/dist/esm/Wheel/haptic.native.js.map +1 -1
  325. package/dist/esm/Wheel/index.native.js.map +1 -1
  326. package/dist/esm/Wheel/wheelShared.native.js.map +1 -1
  327. package/dist/esm/actionLabel.native.js.map +1 -1
  328. package/dist/esm/fieldDefaults.native.js.map +1 -1
  329. package/dist/esm/fieldLayout.native.js.map +1 -1
  330. package/dist/esm/fields/Barcode/BarcodePreview.native.js.map +1 -1
  331. package/dist/esm/fields/Barcode/code128.native.js.map +1 -1
  332. package/dist/esm/fields/Barcode/index.native.js.map +1 -1
  333. package/dist/esm/fields/Barcode/qr.native.js.map +1 -1
  334. package/dist/esm/fields/Barcode/scannerTypes.native.js.map +1 -1
  335. package/dist/esm/fields/Checkbox/Checkbox.native.js.map +1 -1
  336. package/dist/esm/fields/Checkbox/CheckboxBox.native.js.map +1 -1
  337. package/dist/esm/fields/Checkbox/CheckboxCard.native.js.map +1 -1
  338. package/dist/esm/fields/Checkbox/CheckboxFieldFrame.native.js.map +1 -1
  339. package/dist/esm/fields/Checkbox/CheckboxGroup.native.js.map +1 -1
  340. package/dist/esm/fields/Checkbox/checkboxGroupContext.native.js.map +1 -1
  341. package/dist/esm/fields/Checkbox/index.native.js.map +1 -1
  342. package/dist/esm/fields/ColorPicker/SystemColorField.native.js.map +1 -1
  343. package/dist/esm/fields/ColorPicker/index.native.js.map +1 -1
  344. package/dist/esm/fields/ColorPicker/parts.native.js.map +1 -1
  345. package/dist/esm/fields/ColorPicker/systemColorWell.gnome.native.js.map +1 -1
  346. package/dist/esm/fields/Combobox/authorOptions.native.js.map +1 -1
  347. package/dist/esm/fields/Combobox/index.mjs +4 -11
  348. package/dist/esm/fields/Combobox/index.mjs.map +1 -1
  349. package/dist/esm/fields/Combobox/index.native.js +4 -11
  350. package/dist/esm/fields/Combobox/index.native.js.map +1 -1
  351. package/dist/esm/fields/DatePicker/Calendar.native.js.map +1 -1
  352. package/dist/esm/fields/DatePicker/DateRangePicker.native.js.map +1 -1
  353. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  354. package/dist/esm/fields/DatePicker/MonthPicker.native.js.map +1 -1
  355. package/dist/esm/fields/DatePicker/MultiDatePicker.native.js.map +1 -1
  356. package/dist/esm/fields/DatePicker/catalog.native.js.map +1 -1
  357. package/dist/esm/fields/DatePicker/fieldValueSync.native.js.map +1 -1
  358. package/dist/esm/fields/DatePicker/parts.native.js.map +1 -1
  359. package/dist/esm/fields/DatePicker/utils.native.js.map +1 -1
  360. package/dist/esm/fields/Duration/durationMath.native.js.map +1 -1
  361. package/dist/esm/fields/Duration/durationWheelTypes.native.js.map +1 -1
  362. package/dist/esm/fields/Duration/index.native.js.map +1 -1
  363. package/dist/esm/fields/FileUpload/filePickerTypes.native.js.map +1 -1
  364. package/dist/esm/fields/FileUpload/index.native.js.map +1 -1
  365. package/dist/esm/fields/FileUpload/nativePickerLoader.native.js.map +1 -1
  366. package/dist/esm/fields/Geolocation/expoMapsLoader.native.js.map +1 -1
  367. package/dist/esm/fields/Geolocation/geoValue.native.js.map +1 -1
  368. package/dist/esm/fields/Geolocation/geocoder.native.js.map +1 -1
  369. package/dist/esm/fields/Geolocation/geocoderContext.native.js.map +1 -1
  370. package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
  371. package/dist/esm/fields/Geolocation/mapMath.native.js.map +1 -1
  372. package/dist/esm/fields/Geolocation/mapTypes.native.js.map +1 -1
  373. package/dist/esm/fields/Geolocation/nativeSearchFocus.native.js.map +1 -1
  374. package/dist/esm/fields/Geolocation/photonGeocoder.native.js.map +1 -1
  375. package/dist/esm/fields/Icon/drawnSet.native.js.map +1 -1
  376. package/dist/esm/fields/Icon/index.native.js.map +1 -1
  377. package/dist/esm/fields/ImageField/index.native.js.map +1 -1
  378. package/dist/esm/fields/Input/index.native.js.map +1 -1
  379. package/dist/esm/fields/MentionInput/index.native.js.map +1 -1
  380. package/dist/esm/fields/OTPInput/index.native.js.map +1 -1
  381. package/dist/esm/fields/OTPInput/otpCellCss.native.js.map +1 -1
  382. package/dist/esm/fields/PhoneInput/dialCodes.native.js.map +1 -1
  383. package/dist/esm/fields/PhoneInput/index.native.js.map +1 -1
  384. package/dist/esm/fields/PhoneInput/phone.native.js.map +1 -1
  385. package/dist/esm/fields/PhoneInput/regionNames.native.js.map +1 -1
  386. package/dist/esm/fields/Progress/index.native.js.map +1 -1
  387. package/dist/esm/fields/RadioGroup/index.native.js.map +1 -1
  388. package/dist/esm/fields/Rating/index.native.js.map +1 -1
  389. package/dist/esm/fields/Rating/ratingMath.native.js.map +1 -1
  390. package/dist/esm/fields/Rating/types.native.js.map +1 -1
  391. package/dist/esm/fields/SearchInput/index.native.js.map +1 -1
  392. package/dist/esm/fields/Select/InlineChoices.mjs +2 -6
  393. package/dist/esm/fields/Select/InlineChoices.mjs.map +1 -1
  394. package/dist/esm/fields/Select/InlineChoices.native.js +2 -6
  395. package/dist/esm/fields/Select/InlineChoices.native.js.map +1 -1
  396. package/dist/esm/fields/Select/SheetPickerRow.native.js.map +1 -1
  397. package/dist/esm/fields/Select/index.mjs +49 -202
  398. package/dist/esm/fields/Select/index.mjs.map +1 -1
  399. package/dist/esm/fields/Select/index.native.js +55 -210
  400. package/dist/esm/fields/Select/index.native.js.map +1 -1
  401. package/dist/esm/fields/Select/shouldInlineChoices.native.js.map +1 -1
  402. package/dist/esm/fields/Signature/index.native.js.map +1 -1
  403. package/dist/esm/fields/Slider/index.native.js.map +1 -1
  404. package/dist/esm/fields/Slider/jumpMotion.native.js.map +1 -1
  405. package/dist/esm/fields/Stepper/index.native.js.map +1 -1
  406. package/dist/esm/fields/Stepper/resolveStepperPlacement.native.js.map +1 -1
  407. package/dist/esm/fields/Switch/footprint.native.js.map +1 -1
  408. package/dist/esm/fields/Switch/index.native.js.map +1 -1
  409. package/dist/esm/fields/TextArea/index.native.js.map +1 -1
  410. package/dist/esm/fields/TimePicker/catalog.native.js.map +1 -1
  411. package/dist/esm/fields/TimePicker/parts.native.js.map +1 -1
  412. package/dist/esm/fields/TimeRangeScrubber/geometry.native.js.map +1 -1
  413. package/dist/esm/fields/TimeRangeScrubber/index.native.js.map +1 -1
  414. package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
  415. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs +3 -3
  416. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
  417. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js +3 -3
  418. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  419. package/dist/esm/fields/nativeDateTime/dateTimePickerLoader.native.js.map +1 -1
  420. package/dist/esm/fields/nativeDateTime/osDateTimeIosDisplay.native.js.map +1 -1
  421. package/dist/esm/fields/nativeDateTime/sheetKeyboard.native.js.map +1 -1
  422. package/dist/esm/fields/nativeSelect.native.js.map +1 -1
  423. package/dist/esm/fields/selectedOrder.native.js.map +1 -1
  424. package/dist/esm/formSpacing.native.js.map +1 -1
  425. package/dist/esm/hooks/useFocusManagement.native.js.map +1 -1
  426. package/dist/esm/index.mjs +3 -1
  427. package/dist/esm/index.mjs.map +1 -1
  428. package/dist/esm/index.native.js +3 -1
  429. package/dist/esm/index.native.js.map +1 -1
  430. package/dist/esm/keyboard/chain.native.js.map +1 -1
  431. package/dist/esm/keyboard/index.native.js.map +1 -1
  432. package/dist/esm/keyboard/types.native.js.map +1 -1
  433. package/dist/esm/requiredMarking.native.js.map +1 -1
  434. package/dist/esm/shared/CheckGlyph.mjs +15 -0
  435. package/dist/esm/shared/CheckGlyph.mjs.map +1 -0
  436. package/dist/esm/shared/CheckGlyph.native.js +16 -0
  437. package/dist/esm/shared/CheckGlyph.native.js.map +1 -0
  438. package/dist/esm/shared/TimeColumn.native.js.map +1 -1
  439. package/dist/esm/shared/capabilityPreflight.native.js.map +1 -1
  440. package/dist/esm/shared/choiceRowPress.native.js.map +1 -1
  441. package/dist/esm/shared/colorRamps.native.js.map +1 -1
  442. package/dist/esm/shared/devWarn.native.js.map +1 -1
  443. package/dist/esm/shared/fieldRowContext.native.js.map +1 -1
  444. package/dist/esm/shared/floatingList.mjs +80 -4
  445. package/dist/esm/shared/floatingList.mjs.map +1 -1
  446. package/dist/esm/shared/floatingList.native.js +93 -6
  447. package/dist/esm/shared/floatingList.native.js.map +1 -1
  448. package/dist/esm/shared/focusManagement.native.js.map +1 -1
  449. package/dist/esm/shared/groupContext.native.js.map +1 -1
  450. package/dist/esm/shared/i18n.native.js.map +1 -1
  451. package/dist/esm/shared/instantMotion.native.js.map +1 -1
  452. package/dist/esm/shared/nativeA11y.native.js.map +1 -1
  453. package/dist/esm/shared/nativeAutoFocus.native.js.map +1 -1
  454. package/dist/esm/shared/overlaySizeClass.native.js.map +1 -1
  455. package/dist/esm/shared/overlayStack.native.js.map +1 -1
  456. package/dist/esm/shared/panelPortal.native.js.map +1 -1
  457. package/dist/esm/shared/pickerTriggerContract.native.js.map +1 -1
  458. package/dist/esm/shared/pressSlopProps.native.js.map +1 -1
  459. package/dist/esm/shared/restoreRetries.native.js.map +1 -1
  460. package/dist/esm/shared/sheetNavigation.native.js.map +1 -1
  461. package/dist/esm/shared/systemControlModules.gnome.native.js.map +1 -1
  462. package/dist/esm/shared/systemControls.native.js.map +1 -1
  463. package/dist/esm/shared/t.native.js.map +1 -1
  464. package/dist/esm/shared/tableCellContext.native.js.map +1 -1
  465. package/dist/esm/shared/useDragScroll.native.js.map +1 -1
  466. package/dist/esm/shared/useKeyboardInset.native.js.map +1 -1
  467. package/dist/esm/shared/useSheetEscapeDismiss.native.js.map +1 -1
  468. package/dist/esm/shared/useWheelIncrement.native.js.map +1 -1
  469. package/dist/esm/shared/utils.native.js.map +1 -1
  470. package/dist/esm/shared/zIndex.native.js.map +1 -1
  471. package/dist/esm/standardActions.native.js.map +1 -1
  472. package/dist/esm/themedPrimitives.native.js.map +1 -1
  473. package/dist/esm/types.native.js.map +1 -1
  474. package/dist/esm/utils/LinkCell.native.js.map +1 -1
  475. package/dist/jsx/AdaptivePopup/index.mjs +2 -2
  476. package/dist/jsx/AdaptivePopup/index.mjs.map +1 -1
  477. package/dist/jsx/AdaptivePopup/index.native.js +1 -1
  478. package/dist/jsx/AdaptivePopup/index.native.js.map +1 -1
  479. package/dist/jsx/Button/index.mjs +12 -5
  480. package/dist/jsx/Button/index.mjs.map +1 -1
  481. package/dist/jsx/Button/index.native.js +14 -6
  482. package/dist/jsx/Button/index.native.js.map +1 -1
  483. package/dist/jsx/FloatingPanel/PanelHeader.mjs +3 -8
  484. package/dist/jsx/FloatingPanel/PanelHeader.mjs.map +1 -1
  485. package/dist/jsx/FloatingPanel/PanelHeader.native.js +3 -8
  486. package/dist/jsx/FloatingPanel/PanelHeader.native.js.map +1 -1
  487. package/dist/jsx/FloatingPanel/coverRect.mjs +1 -8
  488. package/dist/jsx/FloatingPanel/coverRect.mjs.map +1 -1
  489. package/dist/jsx/FloatingPanel/coverRect.native.js +0 -8
  490. package/dist/jsx/FloatingPanel/coverRect.native.js.map +1 -1
  491. package/dist/jsx/FloatingPanel/echoContext.mjs +4 -24
  492. package/dist/jsx/FloatingPanel/echoContext.mjs.map +1 -1
  493. package/dist/jsx/FloatingPanel/echoContext.native.js +5 -28
  494. package/dist/jsx/FloatingPanel/echoContext.native.js.map +1 -1
  495. package/dist/jsx/FloatingPanel/index.mjs +53 -135
  496. package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
  497. package/dist/jsx/FloatingPanel/index.native.js +26 -91
  498. package/dist/jsx/FloatingPanel/index.native.js.map +1 -1
  499. package/dist/jsx/fields/Combobox/index.mjs +4 -11
  500. package/dist/jsx/fields/Combobox/index.mjs.map +1 -1
  501. package/dist/jsx/fields/Combobox/index.native.js +3 -10
  502. package/dist/jsx/fields/Combobox/index.native.js.map +1 -1
  503. package/dist/jsx/fields/Select/InlineChoices.mjs +2 -6
  504. package/dist/jsx/fields/Select/InlineChoices.mjs.map +1 -1
  505. package/dist/jsx/fields/Select/InlineChoices.native.js +4 -8
  506. package/dist/jsx/fields/Select/InlineChoices.native.js.map +1 -1
  507. package/dist/jsx/fields/Select/index.mjs +49 -202
  508. package/dist/jsx/fields/Select/index.mjs.map +1 -1
  509. package/dist/jsx/fields/Select/index.native.js +52 -207
  510. package/dist/jsx/fields/Select/index.native.js.map +1 -1
  511. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs +3 -3
  512. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
  513. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js +2 -2
  514. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  515. package/dist/jsx/index.js +3 -1
  516. package/dist/jsx/index.js.map +1 -1
  517. package/dist/jsx/index.mjs +3 -1
  518. package/dist/jsx/index.mjs.map +1 -1
  519. package/dist/jsx/index.native.js +4 -0
  520. package/dist/jsx/index.native.js.map +1 -1
  521. package/dist/jsx/shared/CheckGlyph.mjs +15 -0
  522. package/dist/jsx/shared/CheckGlyph.mjs.map +1 -0
  523. package/dist/jsx/shared/CheckGlyph.native.js +44 -0
  524. package/dist/jsx/shared/CheckGlyph.native.js.map +1 -0
  525. package/dist/jsx/shared/floatingList.mjs +80 -4
  526. package/dist/jsx/shared/floatingList.mjs.map +1 -1
  527. package/dist/jsx/shared/floatingList.native.js +95 -5
  528. package/dist/jsx/shared/floatingList.native.js.map +1 -1
  529. package/package.json +8 -8
  530. package/src/AdaptivePopup/index.tsx +2 -2
  531. package/src/Button/Button.iconButton.spec.tsx +39 -0
  532. package/src/Button/index.tsx +20 -8
  533. package/src/FloatingPanel/FloatingPanel.iconCover.spec.tsx +279 -0
  534. package/src/FloatingPanel/FloatingPanel.menuFace.native.spec.tsx +78 -69
  535. package/src/FloatingPanel/FloatingPanel.seamlessCover.spec.tsx +12 -0
  536. package/src/FloatingPanel/PanelHeader.tsx +4 -12
  537. package/src/FloatingPanel/coverRect.ts +2 -15
  538. package/src/FloatingPanel/echoContext.ts +6 -40
  539. package/src/FloatingPanel/index.native.tsx +36 -145
  540. package/src/FloatingPanel/index.tsx +61 -187
  541. package/src/FloatingPanel/pointAnchor.spec.ts +1 -1
  542. package/src/FloatingPanel/pointAnchor.ts +4 -4
  543. package/src/fields/Combobox/index.tsx +4 -9
  544. package/src/fields/Select/InlineChoices.tsx +2 -2
  545. package/src/fields/Select/Select.containingBlock.spec.tsx +131 -130
  546. package/src/fields/Select/Select.stories.tsx +10 -0
  547. package/src/fields/Select/index.tsx +66 -253
  548. package/src/fields/nativeDateTime/OsDateTimeSheet.tsx +3 -3
  549. package/src/index.ts +2 -1
  550. package/src/shared/CheckGlyph.tsx +12 -0
  551. package/src/shared/floatingList.spec.tsx +154 -1
  552. package/src/shared/floatingList.tsx +125 -8
  553. package/types/Button/index.d.ts.map +1 -1
  554. package/types/FloatingPanel/PanelHeader.d.ts +1 -6
  555. package/types/FloatingPanel/PanelHeader.d.ts.map +1 -1
  556. package/types/FloatingPanel/coverRect.d.ts +2 -11
  557. package/types/FloatingPanel/coverRect.d.ts.map +1 -1
  558. package/types/FloatingPanel/echoContext.d.ts +5 -22
  559. package/types/FloatingPanel/echoContext.d.ts.map +1 -1
  560. package/types/FloatingPanel/index.d.ts +6 -8
  561. package/types/FloatingPanel/index.d.ts.map +1 -1
  562. package/types/FloatingPanel/index.native.d.ts +1 -1
  563. package/types/FloatingPanel/index.native.d.ts.map +1 -1
  564. package/types/FloatingPanel/pointAnchor.d.ts +4 -4
  565. package/types/fields/Combobox/index.d.ts.map +1 -1
  566. package/types/fields/Select/index.d.ts.map +1 -1
  567. package/types/index.d.ts +2 -1
  568. package/types/index.d.ts.map +1 -1
  569. package/types/shared/CheckGlyph.d.ts +10 -0
  570. package/types/shared/CheckGlyph.d.ts.map +1 -0
  571. package/types/shared/floatingList.d.ts +55 -1
  572. package/types/shared/floatingList.d.ts.map +1 -1
  573. package/dist/cjs/FloatingPanel/iconEcho.cjs +0 -106
  574. package/dist/cjs/FloatingPanel/iconEcho.native.js +0 -116
  575. package/dist/cjs/FloatingPanel/iconEcho.native.js.map +0 -1
  576. package/dist/esm/FloatingPanel/iconEcho.mjs +0 -79
  577. package/dist/esm/FloatingPanel/iconEcho.mjs.map +0 -1
  578. package/dist/esm/FloatingPanel/iconEcho.native.js +0 -86
  579. package/dist/esm/FloatingPanel/iconEcho.native.js.map +0 -1
  580. package/dist/jsx/FloatingPanel/iconEcho.mjs +0 -79
  581. package/dist/jsx/FloatingPanel/iconEcho.mjs.map +0 -1
  582. package/dist/jsx/FloatingPanel/iconEcho.native.js +0 -116
  583. package/dist/jsx/FloatingPanel/iconEcho.native.js.map +0 -1
  584. package/src/FloatingPanel/FloatingPanel.iconEcho.spec.tsx +0 -357
  585. package/src/FloatingPanel/iconEcho.tsx +0 -124
  586. package/types/FloatingPanel/iconEcho.d.ts +0 -29
  587. package/types/FloatingPanel/iconEcho.d.ts.map +0 -1
@@ -112,6 +112,45 @@ function rest(el: Element, prefix: string): string[] {
112
112
  .sort();
113
113
  }
114
114
 
115
+ describe("LC-176: one ink on a bold glyph (FZ-8649)", () => {
116
+ function Inked({ color, stroke }: { color?: string; stroke?: string }) {
117
+ return <svg data-glyph="" data-color={color} data-stroke={stroke} />;
118
+ }
119
+
120
+ it.each(SCHEMES)("%s: a bar glyph takes the bar tint on its fill and its stroke", (scheme) => {
121
+ houseRender(
122
+ <Surface bar>
123
+ <Button chromeless icon={Inked} aria-label="Menu" />
124
+ <Button chromeless icon={<Inked />} aria-label="Bell" />
125
+ </Surface>,
126
+ scheme,
127
+ );
128
+ for (const label of ["Menu", "Bell"]) {
129
+ const ink = glyphOf(label).getAttribute("data-color");
130
+ expect(ink).toBeTruthy();
131
+ expect(ink).not.toBe("currentColor");
132
+ expect(glyphOf(label).getAttribute("data-stroke")).toBe(ink);
133
+ }
134
+ });
135
+
136
+ it("a caller's colour stays on the fill and the stroke", () => {
137
+ houseRender(
138
+ <Surface bar>
139
+ <Button chromeless icon={<Inked color="red" />} aria-label="Bell" />
140
+ </Surface>,
141
+ "light",
142
+ );
143
+ expect(glyphOf("Bell").getAttribute("data-color")).toBe("red");
144
+ expect(glyphOf("Bell").getAttribute("data-stroke")).toBe("red");
145
+ });
146
+
147
+ it("a content glyph has no bar tint to pass, so it keeps currentColor", () => {
148
+ houseRender(<Button icon={Inked} aria-label="More" />, "light");
149
+ expect(glyphOf("More").hasAttribute("data-color")).toBe(false);
150
+ expect(glyphOf("More").getAttribute("data-stroke")).toBe("currentColor");
151
+ });
152
+ });
153
+
115
154
  describe("LC-176: an icon-only Button is a bare glyph", () => {
116
155
  it.each(SCHEMES)("%s: in a bar, no fill and no border at rest, the bar tint as ink", (scheme) => {
117
156
  houseRender(
@@ -465,28 +465,40 @@ export function iconButtonGlyphPx(rowLinePx: number | undefined): number {
465
465
  /** LC-176: an inline glyph is the text's size; Phosphor's 256 grid pads ~12%. */
466
466
  const INLINE_GLYPH_RATIO = 1.2;
467
467
 
468
+ /**
469
+ * `ink` is the bar tint. It goes to the glyph as well as to its stroke, because
470
+ * a `themed` glyph fills with the theme's text colour unless told otherwise and
471
+ * the stroke would then outline it in a second colour (FZ-8649).
472
+ */
468
473
  function withGlyphWeight(
469
474
  icon: IconLike | undefined,
470
475
  size: number,
471
476
  weight: "regular" | "bold",
472
477
  floor = false,
478
+ ink?: string | null,
473
479
  ): IconLike | undefined {
474
480
  if (icon == null || icon === false) return icon;
481
+ const tint = ink ?? undefined;
475
482
  if (isValidElement<{ size?: number; weight?: string; color?: string }>(icon)) {
476
483
  const resolved = (icon.props.weight ?? weight) as "regular" | "bold";
477
484
  const own = icon.props.size;
478
485
  return cloneElement(icon, {
479
486
  ...(own == null || (floor && typeof own === "number" && own < size) ? { size } : undefined),
480
487
  ...(icon.props.weight == null ? { weight } : undefined),
481
- ...boldStroke(resolved, icon.props.color),
488
+ ...(icon.props.color == null && tint ? { color: tint } : undefined),
489
+ ...boldStroke(resolved, icon.props.color ?? tint),
482
490
  });
483
491
  }
484
492
  if (typeof icon === "function" || (typeof icon === "object" && "$$typeof" in icon)) {
485
- return createElement(icon as ComponentType<{ size?: number; weight?: string }>, {
486
- size,
487
- weight,
488
- ...boldStroke(weight),
489
- });
493
+ return createElement(
494
+ icon as ComponentType<{ size?: number; weight?: string; color?: string }>,
495
+ {
496
+ size,
497
+ weight,
498
+ ...(tint ? { color: tint } : undefined),
499
+ ...boldStroke(weight, tint),
500
+ },
501
+ );
490
502
  }
491
503
  return icon;
492
504
  }
@@ -911,7 +923,7 @@ export function Button({
911
923
  const barGlyphFloor = barGlyph && !framedCircle && !inlineGlyph && !nested;
912
924
  const glyph =
913
925
  barGlyph || inlineGlyph || framedCircle
914
- ? withGlyphWeight(icon, iconSize, resolvedGlyphWeight, barGlyphFloor)
926
+ ? withGlyphWeight(icon, iconSize, resolvedGlyphWeight, barGlyphFloor, barInk)
915
927
  : icon;
916
928
 
917
929
  // LC-158: the frame keeps its recipe height under Dynamic Type, so the
@@ -998,7 +1010,7 @@ export function Button({
998
1010
  ) : null;
999
1011
  const glyphAfter =
1000
1012
  iconAfter && (barGlyph || inlineGlyph || framedCircle)
1001
- ? withGlyphWeight(iconAfter, iconSize, resolvedGlyphWeight, barGlyphFloor)
1013
+ ? withGlyphWeight(iconAfter, iconSize, resolvedGlyphWeight, barGlyphFloor, barInk)
1002
1014
  : iconAfter;
1003
1015
  const iconAfterElement = glyphAfter ? (
1004
1016
  <View flexShrink={0}>
@@ -0,0 +1,279 @@
1
+ /**
2
+ * LC-112 icon trigger cover (FZ-8665 Round 45, reversing Round 37's X): a
3
+ * panel that covers the icon button it opened from sits exactly over the
4
+ * surface that button is seen on and repeats nothing. Its content starts at
5
+ * its top edge, a press outside closes it, and Escape closes it on the web.
6
+ */
7
+ import { PlusIcon } from "@phosphor-icons/react";
8
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
9
+ import { fireEvent, waitFor, within } from "@testing-library/react";
10
+ import { useState } from "react";
11
+ import { MIN_PRESS_TARGET } from "@multiplatform.one/theme";
12
+ import { afterEach, describe, expect, it, vi } from "vitest";
13
+ import { Text, XStack } from "tamagui";
14
+ import { Button } from "../Button";
15
+ import { FloatingPanel } from "./index";
16
+ import { PanelHeader } from "./PanelHeader";
17
+
18
+ type Rect = { x: number; y: number; width: number; height: number };
19
+
20
+ function measure(trigger: Rect, panelWidth = 240, panelHeight = 160, surface?: Rect) {
21
+ const original = HTMLElement.prototype.getBoundingClientRect;
22
+ const rect = {
23
+ ...trigger,
24
+ top: trigger.y,
25
+ left: trigger.x,
26
+ right: trigger.x + trigger.width,
27
+ bottom: trigger.y + trigger.height,
28
+ toJSON: () => ({}),
29
+ };
30
+ vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockImplementation(
31
+ function (this: HTMLElement) {
32
+ if (this.hasAttribute("data-fp-reference")) return rect;
33
+ if (surface && this.hasAttribute("data-fp-cover-surface")) {
34
+ return {
35
+ ...surface,
36
+ top: surface.y,
37
+ left: surface.x,
38
+ right: surface.x + surface.width,
39
+ bottom: surface.y + surface.height,
40
+ toJSON: () => ({}),
41
+ };
42
+ }
43
+ return original.call(this);
44
+ },
45
+ );
46
+ vi.spyOn(HTMLElement.prototype, "offsetWidth", "get").mockImplementation(
47
+ function (this: HTMLElement) {
48
+ return this.hasAttribute("data-fp-panel") ? panelWidth : 0;
49
+ },
50
+ );
51
+ vi.spyOn(HTMLElement.prototype, "scrollHeight", "get").mockImplementation(
52
+ function (this: HTMLElement) {
53
+ return this.hasAttribute("data-fp-panel") ? panelHeight : 0;
54
+ },
55
+ );
56
+ }
57
+
58
+ function AddPanel({ header = false }: { header?: boolean }) {
59
+ const [open, setOpen] = useState(false);
60
+ return (
61
+ <FloatingPanel
62
+ open={open}
63
+ onOpenChange={setOpen}
64
+ anchorMode="cover-trigger"
65
+ compactFace="menu"
66
+ triggerEcho={false}
67
+ iconCover
68
+ coverAlign="auto"
69
+ widthMode="fit-content"
70
+ triggerSizing="content"
71
+ contentPadding="none"
72
+ trigger={<Button icon={PlusIcon} aria-label="Add node" />}
73
+ >
74
+ {header ? (
75
+ <PanelHeader>
76
+ <Text>Add a node</Text>
77
+ </PanelHeader>
78
+ ) : (
79
+ <Text>Add a node</Text>
80
+ )}
81
+ <Button>Copy</Button>
82
+ </FloatingPanel>
83
+ );
84
+ }
85
+
86
+ /** An account menu opened from a 32pt avatar: a trigger with no `icon`. */
87
+ function AvatarPanel() {
88
+ return (
89
+ <FloatingPanel
90
+ open
91
+ onOpenChange={() => {}}
92
+ anchorMode="cover-trigger"
93
+ compactFace="menu"
94
+ triggerEcho={false}
95
+ iconCover
96
+ coverAlign="auto"
97
+ widthMode="fit-content"
98
+ triggerSizing="content"
99
+ contentPadding="none"
100
+ trigger={
101
+ <span role="button" aria-label="Account">
102
+ AD
103
+ </span>
104
+ }
105
+ >
106
+ <Text>Sign out</Text>
107
+ </FloatingPanel>
108
+ );
109
+ }
110
+
111
+ async function open(result: ReturnType<typeof renderWithProviders>) {
112
+ fireEvent.click(result.getByRole("button", { name: "Add node" }), { detail: 0 });
113
+ const panel = (await result.findByTestId("floating-panel-viewport")) as HTMLElement;
114
+ await waitFor(() => expect(panel.style.visibility).toBe("visible"));
115
+ return panel;
116
+ }
117
+
118
+ afterEach(() => {
119
+ vi.restoreAllMocks();
120
+ });
121
+
122
+ const buttonsIn = (panel: HTMLElement) =>
123
+ within(panel)
124
+ .getAllByRole("button")
125
+ .map((button) => button.textContent || button.getAttribute("aria-label"));
126
+
127
+ /** Whatever sits above the content in the panel: a hidden scroll arrow at most. */
128
+ const aboveContent = (panel: HTMLElement) => {
129
+ const children = [...panel.children] as HTMLElement[];
130
+ const content = children.findIndex((child) => child.textContent?.includes("Add a node"));
131
+ expect(content).toBeGreaterThanOrEqual(0);
132
+ return children.slice(0, content);
133
+ };
134
+
135
+ describe("LC-112 icon trigger cover on the web (FZ-8665)", () => {
136
+ const viewportWidth = () => document.documentElement.clientWidth || window.innerWidth;
137
+
138
+ it("covers the + from the button's top trailing corner and repeats nothing", async () => {
139
+ const button = { x: viewportWidth() - 16 - 44, y: 12, width: 44, height: 44 };
140
+ measure(button, 240);
141
+ const result = renderWithProviders(<AddPanel />);
142
+ const panel = await open(result);
143
+ expect(panel.style.top).toBe(`${button.y}px`);
144
+ expect(panel.style.left).toBe(`${button.x + button.width - 240}px`);
145
+ expect(within(panel).queryByRole("button", { name: "Close" })).toBeNull();
146
+ expect(within(panel).queryByRole("button", { name: "Add node" })).toBeNull();
147
+ expect(panel.querySelector("[data-fp-trigger-row]")).toBeNull();
148
+ expect(panel.querySelector("[data-fp-icon-echo]")).toBeNull();
149
+ });
150
+
151
+ it("starts the content at the panel's top edge, with no band above it", async () => {
152
+ measure({ x: 16, y: 12, width: 44, height: 44 });
153
+ const result = renderWithProviders(<AddPanel />);
154
+ const panel = await open(result);
155
+ for (const element of aboveContent(panel)) {
156
+ expect(element.textContent).toBe("");
157
+ expect(element.querySelector("button, [role='button']")).toBeNull();
158
+ expect(element.style.height).toBe("");
159
+ }
160
+ });
161
+
162
+ it("covers a grouped trigger's whole plate, with both edges, and shows none of its buttons", async () => {
163
+ const button = { x: viewportWidth() - 16 - 44, y: 12, width: 44, height: 44 };
164
+ const plate = { x: button.x - 100, y: 12, width: 144, height: 44 };
165
+ measure(button, 120, 160, plate);
166
+ const result = renderWithProviders(
167
+ <div data-fp-cover-surface="">
168
+ <Button icon={PlusIcon} aria-label="Search" />
169
+ <AddPanel />
170
+ </div>,
171
+ );
172
+ const panel = await open(result);
173
+ // The plate is wider than the menu, so the menu takes the plate's width
174
+ // and both edges.
175
+ expect(panel.style.left).toBe(`${plate.x}px`);
176
+ expect(panel.style.top).toBe(`${plate.y}px`);
177
+ expect(panel.style.minWidth).toBe(`${plate.width}px`);
178
+ expect(buttonsIn(panel)).toEqual(["Copy"]);
179
+ });
180
+
181
+ it("closes on a press outside the panel", async () => {
182
+ measure({ x: 16, y: 12, width: 44, height: 44 });
183
+ const result = renderWithProviders(<AddPanel />);
184
+ await open(result);
185
+ fireEvent.click(document.body);
186
+ await waitFor(() => expect(result.queryByTestId("floating-panel-viewport")).toBeNull());
187
+ });
188
+
189
+ it("closes on Escape and hands focus back to the button", async () => {
190
+ measure({ x: 16, y: 12, width: 44, height: 44 });
191
+ const result = renderWithProviders(<AddPanel />);
192
+ const trigger = result.getByRole("button", { name: "Add node" });
193
+ trigger.focus();
194
+ await open(result);
195
+ fireEvent.keyDown(document, { key: "Escape" });
196
+ await waitFor(() => expect(result.queryByTestId("floating-panel-viewport")).toBeNull());
197
+ await waitFor(() => expect(document.activeElement).toBe(trigger));
198
+ });
199
+
200
+ it("puts a panel's title on the panel's normal padding, keeping clear of nothing", async () => {
201
+ const button = { x: viewportWidth() - 16 - 44, y: 12, width: 44, height: 44 };
202
+ measure(button, 240);
203
+ const result = renderWithProviders(
204
+ <>
205
+ <AddPanel header />
206
+ <XStack
207
+ data-testid="normal-padding"
208
+ alignItems="center"
209
+ gap="$2"
210
+ paddingLeft="$4"
211
+ paddingRight="$4"
212
+ paddingTop="$4"
213
+ />
214
+ </>,
215
+ );
216
+ const panel = await open(result);
217
+ const header = panel.querySelector<HTMLElement>("[data-fp-panel-header]") as HTMLElement;
218
+ expect(header.className).toBe(result.getByTestId("normal-padding").className);
219
+ expect(header.style.minHeight).toBe("");
220
+ });
221
+
222
+ it("keeps a content-sized trigger on a centring row's line", async () => {
223
+ measure({ x: 16, y: 12, width: 44, height: 44 });
224
+ const centred = renderWithProviders(
225
+ <div style={{ display: "flex", flexDirection: "row", alignItems: "center", height: 60 }}>
226
+ <AddPanel />
227
+ </div>,
228
+ );
229
+ const inRow = centred.container.querySelector<HTMLElement>(
230
+ "[data-fp-reference]",
231
+ ) as HTMLElement;
232
+ await waitFor(() => expect(getComputedStyle(inRow).alignSelf).not.toBe("flex-start"));
233
+ centred.unmount();
234
+ const column = renderWithProviders(
235
+ <div style={{ display: "flex", flexDirection: "column", alignItems: "stretch" }}>
236
+ <AddPanel />
237
+ </div>,
238
+ );
239
+ const inColumn = column.container.querySelector<HTMLElement>(
240
+ "[data-fp-reference]",
241
+ ) as HTMLElement;
242
+ expect(getComputedStyle(inColumn).alignSelf).toBe("flex-start");
243
+ });
244
+
245
+ it("gives a keyboard its content and no extra stop", async () => {
246
+ measure({ x: 16, y: 12, width: 44, height: 44 });
247
+ const result = renderWithProviders(<AddPanel />);
248
+ const panel = await open(result);
249
+ expect(buttonsIn(panel)).toEqual(["Copy"]);
250
+ });
251
+
252
+ it("opens up from the button's bottom edge near the bottom, still covering it", async () => {
253
+ const button = { x: 16, y: window.innerHeight - 60, width: 44, height: 44 };
254
+ measure(button, 240, 300);
255
+ const result = renderWithProviders(<AddPanel />);
256
+ const panel = await open(result);
257
+ const frame = getComputedStyle(panel);
258
+ const borders =
259
+ (parseFloat(frame.borderTopWidth) || 0) + (parseFloat(frame.borderBottomWidth) || 0);
260
+ expect(parseFloat(panel.style.top) + 300 + borders).toBe(button.y + button.height);
261
+ expect(panel.style.left).toBe(`${button.x}px`);
262
+ expect(panel.style.transformOrigin).toBe("bottom left");
263
+ expect(result.queryByTestId("floating-panel-sheet")).toBeNull();
264
+ });
265
+
266
+ it("covers a 32pt avatar at its 44pt target, its centre on the row-icon column (FZ-8480 GAP)", async () => {
267
+ const avatar = { x: 100, y: 18, width: 32, height: 32 };
268
+ measure(avatar, 240);
269
+ const result = renderWithProviders(<AvatarPanel />);
270
+ const panel = (await result.findByTestId("floating-panel-viewport")) as HTMLElement;
271
+ await waitFor(() => expect(panel.style.visibility).toBe("visible"));
272
+ const inset = (MIN_PRESS_TARGET - avatar.width) / 2;
273
+ expect(panel.style.left).toBe(`${avatar.x - inset}px`);
274
+ expect(panel.style.top).toBe(`${avatar.y - inset}px`);
275
+ // The avatar's centre sits half a press target in, the centre of a menu
276
+ // row's leading glyph slot.
277
+ expect(inset + avatar.width / 2).toBe(MIN_PRESS_TARGET / 2);
278
+ });
279
+ });
@@ -4,8 +4,8 @@
4
4
  * so only inside another overlay, so a sheet never stacks on a sheet.
5
5
  */
6
6
  import { renderWithProviders } from "@multiplatform.one/test-utils";
7
- import { act, render } from "@testing-library/react";
8
- import { PlusIcon, XIcon } from "@phosphor-icons/react";
7
+ import { act } from "@testing-library/react";
8
+ import { PlusIcon } from "@phosphor-icons/react";
9
9
  import { useState, type ReactNode } from "react";
10
10
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
11
11
  import { Text, XStack, YStack, getTokens, getVariableValue } from "tamagui";
@@ -462,7 +462,7 @@ describe("FloatingPanel native menu face panelWidth (LC-112, FZ-8438 r3)", () =>
462
462
  });
463
463
  });
464
464
 
465
- function EchoMenu({ kind }: { kind: "close" | "menu" }) {
465
+ function CoverMenu() {
466
466
  const [open, setOpen] = useState(false);
467
467
  return (
468
468
  <FloatingPanel
@@ -471,7 +471,7 @@ function EchoMenu({ kind }: { kind: "close" | "menu" }) {
471
471
  compactFace="menu"
472
472
  anchorMode="cover-trigger"
473
473
  triggerEcho={false}
474
- iconEcho={kind}
474
+ iconCover
475
475
  coverAlign="auto"
476
476
  triggerSizing="content"
477
477
  contentPadding="none"
@@ -483,67 +483,92 @@ function EchoMenu({ kind }: { kind: "close" | "menu" }) {
483
483
  );
484
484
  }
485
485
 
486
- const iconEcho = () =>
487
- document.querySelector<HTMLElement>('[data-testid="floating-panel-icon-echo"]');
488
- const iconBand = () =>
489
- document.querySelector<HTMLElement>('[data-testid="floating-panel-icon-echo-band"]');
490
- const glyphPath = (node: Element | null) => node?.querySelector("svg path")?.getAttribute("d");
486
+ const clip = () =>
487
+ document.querySelector<HTMLElement>('[data-testid="floating-panel-menu-clip"]') as HTMLElement;
488
+
489
+ /** The live prop a component took: RN-web drops the ones it has no DOM use for. */
490
+ function propOf<T>(node: Element, name: string): T | undefined {
491
+ const key = Object.keys(node).find((candidate) => candidate.startsWith("__reactFiber$"));
492
+ let fiber = (node as unknown as Record<string, FiberLike | undefined>)[key ?? ""];
493
+ while (fiber) {
494
+ const value = fiber.memoizedProps?.[name];
495
+ if (value !== undefined) return value as T;
496
+ fiber = fiber.return;
497
+ }
498
+ return undefined;
499
+ }
500
+ type FiberLike = { memoizedProps?: Record<string, unknown>; return?: FiberLike };
501
+
502
+ function settleMenu() {
503
+ layout(menu() as HTMLElement, MENU_MIN_WIDTH, 180);
504
+ act(() => {
505
+ vi.advanceTimersByTime(1000);
506
+ });
507
+ }
491
508
 
492
- describe("LC-112 icon trigger echo on native (FZ-8480, rv_2607879d3bdaf9bf)", () => {
493
- it("draws the + again as an X in the button's own box, at the menu's top trailing corner", () => {
509
+ describe("LC-112 icon trigger cover on native (FZ-8665, reversing Round 37's X)", () => {
510
+ it("covers the + from the button's top trailing corner and repeats nothing", () => {
494
511
  trigger = { x: 330, y: 60, width: 44, height: 44 };
495
- const result = renderWithProviders(<EchoMenu kind="close" />);
512
+ const result = renderWithProviders(<CoverMenu />);
496
513
  tap(result.getAllByRole("button", { name: "Add node" })[0]!);
497
514
  const panel = menu() as HTMLElement;
498
515
  layout(panel, MENU_MIN_WIDTH, 180);
499
516
  expect(panel.style.top).toBe(`${trigger.y}px`);
500
517
  expect(panel.style.left).toBe(`${trigger.x + trigger.width - MENU_MIN_WIDTH}px`);
501
- const band = iconBand() as HTMLElement;
502
- expect(band.style.height).toBe("44px");
503
- const box = band.firstElementChild as HTMLElement;
504
- expect(box.style.width).toBe("44px");
505
- expect(box.style.height).toBe("44px");
506
- // The box sits where the trigger is: its start offset is the trigger's x
507
- // less the menu's left edge.
508
- expect(box.style.marginInlineStart || box.style.marginLeft).toBe(
509
- `${trigger.x - (trigger.x + trigger.width - MENU_MIN_WIDTH)}px`,
510
- );
511
- const echoButton = iconEcho() as HTMLElement;
512
- expect(echoButton.getAttribute("aria-label")).toBe("Close");
513
- const x = render(<XIcon weight="bold" />);
514
- expect(glyphPath(echoButton)).toBe(glyphPath(x.container));
515
- x.unmount();
516
518
  expect(echo()).toBeNull();
519
+ expect(document.querySelector('[data-testid="floating-panel-icon-echo"]')).toBeNull();
520
+ expect(document.querySelector('[data-testid="floating-panel-icon-echo-band"]')).toBeNull();
517
521
  });
518
522
 
519
- it("closes the menu when the echo is pressed", () => {
523
+ it("starts the rows at the panel's top edge: the scroll view is the panel's only child", () => {
520
524
  trigger = { x: 330, y: 60, width: 44, height: 44 };
521
- const result = renderWithProviders(<EchoMenu kind="close" />);
525
+ const result = renderWithProviders(<CoverMenu />);
522
526
  tap(result.getAllByRole("button", { name: "Add node" })[0]!);
523
527
  layout(menu() as HTMLElement, MENU_MIN_WIDTH, 180);
524
- act(() => {
525
- vi.advanceTimersByTime(1000);
526
- });
527
- tap(iconEcho() as HTMLElement);
528
+ expect(clip().children).toHaveLength(1);
529
+ expect(clip().textContent).toBe("Add a node");
530
+ });
531
+
532
+ it("closes from the backdrop, which a screen reader reads as Close", () => {
533
+ trigger = { x: 330, y: 60, width: 44, height: 44 };
534
+ const result = renderWithProviders(<CoverMenu />);
535
+ tap(result.getAllByRole("button", { name: "Add node" })[0]!);
536
+ settleMenu();
537
+ tap(result.getByRole("button", { name: "Close" }));
538
+ expect(menu()).toBeNull();
539
+ });
540
+
541
+ it("closes from VoiceOver's escape gesture", () => {
542
+ trigger = { x: 330, y: 60, width: 44, height: 44 };
543
+ const result = renderWithProviders(<CoverMenu />);
544
+ tap(result.getAllByRole("button", { name: "Add node" })[0]!);
545
+ settleMenu();
546
+ const escape = propOf<() => void>(frame() as HTMLElement, "onAccessibilityEscape");
547
+ expect(escape).toBeTypeOf("function");
548
+ act(() => escape?.());
528
549
  expect(menu()).toBeNull();
529
550
  });
530
551
 
531
- it("turns a menu trigger into an X too, and opens up from the button's bottom edge near the bottom", () => {
552
+ it("is modal to VoiceOver, holding only its backdrop Close and the panel", () => {
553
+ trigger = { x: 330, y: 60, width: 44, height: 44 };
554
+ const result = renderWithProviders(<CoverMenu />);
555
+ tap(result.getAllByRole("button", { name: "Add node" })[0]!);
556
+ settleMenu();
557
+ const layer = document.querySelector<HTMLElement>('[data-testid="floating-panel-menu-layer"]');
558
+ expect(layer).not.toBeNull();
559
+ expect(propOf<boolean>(layer as HTMLElement, "accessibilityViewIsModal")).toBe(true);
560
+ expect(layer?.contains(result.getByRole("button", { name: "Close" }))).toBe(true);
561
+ expect(layer?.contains(menu())).toBe(true);
562
+ });
563
+
564
+ it("still covers its button when it opens up from the bottom edge", () => {
532
565
  trigger = { x: 20, y: 760, width: 44, height: 44 };
533
- const result = renderWithProviders(<EchoMenu kind="menu" />);
534
- const live = result.getAllByRole("button", { name: "Add node" })[0]!;
535
- tap(live);
566
+ const result = renderWithProviders(<CoverMenu />);
567
+ tap(result.getAllByRole("button", { name: "Add node" })[0]!);
536
568
  const panel = menu() as HTMLElement;
537
569
  layout(panel, MENU_MIN_WIDTH, 300);
538
570
  expect(parseFloat(panel.style.top) + 300).toBe(trigger.y + trigger.height);
539
- const surface = frame() as HTMLElement;
540
- const band = iconBand() as HTMLElement;
541
- const clip = surface.querySelector('[data-testid="floating-panel-menu-clip"]') as HTMLElement;
542
- expect(clip.lastElementChild).toBe(band);
543
- const x = render(<XIcon weight="bold" />);
544
- expect(glyphPath(iconEcho())).toBe(glyphPath(x.container));
545
- x.unmount();
546
- expect(glyphPath(iconEcho())).not.toBe(glyphPath(live));
571
+ expect(clip().children).toHaveLength(1);
547
572
  });
548
573
  });
549
574
 
@@ -554,11 +579,11 @@ const capsuleSurface = (plate: IconButtonGroupPlate): IconButtonGroupSurface =>
554
579
  describe("LC-112 grouped glass capsule on native (FZ-8550, Round 37 second pass)", () => {
555
580
  const plate = { x: 200, y: 50, width: 174, height: 44, radius: 22 };
556
581
 
557
- it("covers the whole capsule from context at its radius; only the pressed trigger shows, as its X", () => {
582
+ it("covers the whole capsule from context at its radius, showing none of its buttons", () => {
558
583
  trigger = { x: 330, y: 50, width: 44, height: 44 };
559
584
  const result = renderWithProviders(
560
585
  <IconButtonGroupSurfaceContext.Provider value={capsuleSurface(plate)}>
561
- <EchoMenu kind="menu" />
586
+ <CoverMenu />
562
587
  </IconButtonGroupSurfaceContext.Provider>,
563
588
  );
564
589
  tap(result.getAllByRole("button", { name: "Add node" })[0]!);
@@ -572,18 +597,8 @@ describe("LC-112 grouped glass capsule on native (FZ-8550, Round 37 second pass)
572
597
  expect(left + MENU_MIN_WIDTH).toBeGreaterThanOrEqual(plate.x + plate.width);
573
598
  expect(left).toBe(plate.x + plate.width - MENU_MIN_WIDTH);
574
599
  expect(corners(frame() as HTMLElement)).toEqual(radiusAtoms(plate.radius));
575
- // The band is the capsule's height; the X keeps the trigger's own box.
576
- const band = iconBand() as HTMLElement;
577
- expect(band.style.height).toBe(`${plate.height}px`);
578
- const box = band.firstElementChild as HTMLElement;
579
- expect(box.style.width).toBe(`${trigger.width}px`);
580
- expect(box.style.marginInlineStart || box.style.marginLeft).toBe(`${trigger.x - left}px`);
581
- // Only the pressed trigger shows, as an X; nothing else of the group.
582
- const echoes = document.querySelectorAll('[data-testid="floating-panel-icon-echo"]');
583
- expect(echoes).toHaveLength(1);
584
- const x = render(<XIcon weight="bold" />);
585
- expect(glyphPath(echoes[0] as Element)).toBe(glyphPath(x.container));
586
- x.unmount();
600
+ expect(clip().children).toHaveLength(1);
601
+ expect(clip().textContent).toBe("Add a node");
587
602
  });
588
603
 
589
604
  it("takes the capsule's width as its floor when the capsule is wider than the menu", () => {
@@ -591,7 +606,7 @@ describe("LC-112 grouped glass capsule on native (FZ-8550, Round 37 second pass)
591
606
  trigger = { x: 330, y: 50, width: 44, height: 44 };
592
607
  const result = renderWithProviders(
593
608
  <IconButtonGroupSurfaceContext.Provider value={capsuleSurface(wide)}>
594
- <EchoMenu kind="menu" />
609
+ <CoverMenu />
595
610
  </IconButtonGroupSurfaceContext.Provider>,
596
611
  );
597
612
  tap(result.getAllByRole("button", { name: "Add node" })[0]!);
@@ -612,7 +627,7 @@ describe("LC-112 grouped glass capsule on native (FZ-8550, Round 37 second pass)
612
627
  },
613
628
  }}
614
629
  >
615
- <EchoMenu kind="menu" />
630
+ <CoverMenu />
616
631
  </IconButtonGroupSurfaceContext.Provider>,
617
632
  );
618
633
  tap(result.getAllByRole("button", { name: "Add node" })[0]!);
@@ -626,20 +641,14 @@ describe("LC-112 grouped glass capsule on native (FZ-8550, Round 37 second pass)
626
641
 
627
642
  it("covers a 32pt avatar at its 44pt target, so its centre is the row-icon column (FZ-8480)", () => {
628
643
  trigger = { x: 100, y: 56, width: 32, height: 32 };
629
- const result = renderWithProviders(<EchoMenu kind="menu" />);
644
+ const result = renderWithProviders(<CoverMenu />);
630
645
  tap(result.getAllByRole("button", { name: "Add node" })[0]!);
631
646
  const panel = menu() as HTMLElement;
632
647
  layout(panel, MENU_MIN_WIDTH, 180);
633
648
  const inset = (MIN_PRESS_TARGET - trigger.width) / 2;
634
649
  expect(panel.style.left).toBe(`${trigger.x - inset}px`);
635
650
  expect(panel.style.top).toBe(`${trigger.y - inset}px`);
636
- const band = iconBand() as HTMLElement;
637
- expect(band.style.height).toBe(`${MIN_PRESS_TARGET}px`);
638
- const box = band.firstElementChild as HTMLElement;
639
- expect(box.style.width).toBe(`${trigger.width}px`);
640
- expect(box.style.marginTop).toBe(`${inset}px`);
641
- expect(box.style.marginInlineStart || box.style.marginLeft).toBe(`${inset}px`);
642
- // The X's centre sits half a press target in: where a row's leading
651
+ // The avatar's centre sits half a press target in: where a row's leading
643
652
  // glyph centres (row inset plus half its 18pt slot, on the frame border).
644
653
  expect(inset + trigger.width / 2).toBe(MIN_PRESS_TARGET / 2);
645
654
  });
@@ -212,6 +212,18 @@ describe("LC-112 icon trigger: the menu opens on its button (rv_d86cc201997dffd4
212
212
  expect(within(panel).queryByRole("button", { name: "Appearance" })).toBeNull();
213
213
  });
214
214
 
215
+ it("lands on a whole pixel when its button sits on a half pixel, so rows reach the far edge (FZ-8557)", async () => {
216
+ const button = { x: 16.5, y: 12, width: 40, height: 40 };
217
+ measure(button, 124.6);
218
+ const result = renderWithProviders(<IconPanel />);
219
+ fireEvent.click(result.getByRole("button", { name: "Appearance" }), { detail: 0 });
220
+ const panel = (await result.findByTestId("floating-panel-viewport")) as HTMLElement;
221
+ await waitFor(() => expect(panel.style.top).toBe(`${button.y}px`));
222
+ const left = parseFloat(panel.style.left);
223
+ expect(Number.isInteger(left)).toBe(true);
224
+ expect(Math.abs(left - button.x)).toBeLessThanOrEqual(0.5);
225
+ });
226
+
215
227
  it("slides up over its button near the bottom edge instead of opening a sheet", async () => {
216
228
  const button = { x: 16, y: window.innerHeight - 60, width: 44, height: 44 };
217
229
  measure(button, 200);