@multiplatform.one/forms 7.65.2 → 7.67.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 (367) hide show
  1. package/dist/cjs/FloatingPanel/RegularPanel.cjs +164 -0
  2. package/dist/cjs/FloatingPanel/RegularPanel.native.js +169 -0
  3. package/dist/cjs/FloatingPanel/RegularPanel.native.js.map +1 -0
  4. package/dist/cjs/FloatingPanel/compactFace.cjs +6 -0
  5. package/dist/cjs/FloatingPanel/compactFace.native.js +6 -0
  6. package/dist/cjs/FloatingPanel/compactFace.native.js.map +1 -1
  7. package/dist/cjs/FloatingPanel/containingBlock.cjs +46 -0
  8. package/dist/cjs/FloatingPanel/containingBlock.native.js +51 -0
  9. package/dist/cjs/FloatingPanel/containingBlock.native.js.map +1 -0
  10. package/dist/cjs/FloatingPanel/index.cjs +2 -20
  11. package/dist/cjs/FloatingPanel/index.native.js +79 -45
  12. package/dist/cjs/FloatingPanel/index.native.js.map +1 -1
  13. package/dist/cjs/FloatingPanel/pointAnchor.cjs +25 -0
  14. package/dist/cjs/FloatingPanel/pointAnchor.native.js +26 -0
  15. package/dist/cjs/FloatingPanel/pointAnchor.native.js.map +1 -1
  16. package/dist/cjs/FloatingPanel/regularPlacement.cjs +61 -0
  17. package/dist/cjs/FloatingPanel/regularPlacement.native.js +65 -0
  18. package/dist/cjs/FloatingPanel/regularPlacement.native.js.map +1 -0
  19. package/dist/cjs/fields/Combobox/index.cjs +8 -10
  20. package/dist/cjs/fields/Combobox/index.native.js +10 -10
  21. package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
  22. package/dist/cjs/fields/DatePicker/parts.cjs +1 -0
  23. package/dist/cjs/fields/DatePicker/parts.native.js +3 -0
  24. package/dist/cjs/fields/DatePicker/parts.native.js.map +1 -1
  25. package/dist/cjs/fields/Input/index.cjs +5 -0
  26. package/dist/cjs/fields/Input/index.native.js +5 -0
  27. package/dist/cjs/fields/Input/index.native.js.map +1 -1
  28. package/dist/cjs/fields/Select/InlineChoices.cjs +3 -2
  29. package/dist/cjs/fields/Select/InlineChoices.native.js +5 -2
  30. package/dist/cjs/fields/Select/InlineChoices.native.js.map +1 -1
  31. package/dist/cjs/fields/Select/SheetPickerRow.cjs +154 -0
  32. package/dist/cjs/fields/Select/SheetPickerRow.native.js +165 -0
  33. package/dist/cjs/fields/Select/SheetPickerRow.native.js.map +1 -0
  34. package/dist/cjs/fields/Select/index.cjs +64 -5
  35. package/dist/cjs/fields/Select/index.native.js +86 -27
  36. package/dist/cjs/fields/Select/index.native.js.map +1 -1
  37. package/dist/cjs/fields/Select/shouldInlineChoices.cjs +14 -1
  38. package/dist/cjs/fields/Select/shouldInlineChoices.native.js +15 -1
  39. package/dist/cjs/fields/Select/shouldInlineChoices.native.js.map +1 -1
  40. package/dist/cjs/fields/Slider/index.cjs +96 -4
  41. package/dist/cjs/fields/Slider/index.native.js +103 -5
  42. package/dist/cjs/fields/Slider/index.native.js.map +1 -1
  43. package/dist/cjs/fields/Switch/index.cjs +71 -1
  44. package/dist/cjs/fields/Switch/index.native.js +72 -1
  45. package/dist/cjs/fields/Switch/index.native.js.map +1 -1
  46. package/dist/cjs/fields/TimePicker/parts.cjs +1 -0
  47. package/dist/cjs/fields/TimePicker/parts.native.js +1 -0
  48. package/dist/cjs/fields/TimePicker/parts.native.js.map +1 -1
  49. package/dist/cjs/fields/ToggleGroup/index.cjs +67 -1
  50. package/dist/cjs/fields/ToggleGroup/index.native.js +75 -1
  51. package/dist/cjs/fields/ToggleGroup/index.native.js.map +1 -1
  52. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.cjs +34 -19
  53. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js +44 -21
  54. package/dist/cjs/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  55. package/dist/cjs/fields/nativeDateTime/sheetKeyboard.cjs +54 -0
  56. package/dist/cjs/fields/nativeDateTime/sheetKeyboard.native.js +57 -0
  57. package/dist/cjs/fields/nativeDateTime/sheetKeyboard.native.js.map +1 -0
  58. package/dist/cjs/index.cjs +11 -0
  59. package/dist/cjs/index.native.js +11 -0
  60. package/dist/cjs/index.native.js.map +1 -1
  61. package/dist/cjs/shared/overlaySizeClass.cjs +42 -0
  62. package/dist/cjs/shared/overlaySizeClass.native.js +45 -0
  63. package/dist/cjs/shared/overlaySizeClass.native.js.map +1 -0
  64. package/dist/cjs/shared/sheetNavigation.cjs +76 -0
  65. package/dist/cjs/shared/sheetNavigation.native.js +129 -0
  66. package/dist/cjs/shared/sheetNavigation.native.js.map +1 -0
  67. package/dist/cjs/shared/systemControlModules.cjs +34 -0
  68. package/dist/cjs/shared/systemControlModules.gnome.cjs +34 -0
  69. package/dist/cjs/shared/systemControlModules.gnome.native.js +37 -0
  70. package/dist/cjs/shared/systemControlModules.gnome.native.js.map +1 -0
  71. package/dist/cjs/shared/systemControlModules.native.js +77 -0
  72. package/dist/cjs/shared/systemControlModules.native.js.map +1 -0
  73. package/dist/cjs/shared/systemControls.cjs +47 -0
  74. package/dist/cjs/shared/systemControls.native.js +51 -0
  75. package/dist/cjs/shared/systemControls.native.js.map +1 -0
  76. package/dist/esm/FloatingPanel/RegularPanel.mjs +139 -0
  77. package/dist/esm/FloatingPanel/RegularPanel.mjs.map +1 -0
  78. package/dist/esm/FloatingPanel/RegularPanel.native.js +141 -0
  79. package/dist/esm/FloatingPanel/RegularPanel.native.js.map +1 -0
  80. package/dist/esm/FloatingPanel/compactFace.mjs +5 -1
  81. package/dist/esm/FloatingPanel/compactFace.mjs.map +1 -1
  82. package/dist/esm/FloatingPanel/compactFace.native.js +5 -1
  83. package/dist/esm/FloatingPanel/compactFace.native.js.map +1 -1
  84. package/dist/esm/FloatingPanel/containingBlock.mjs +21 -0
  85. package/dist/esm/FloatingPanel/containingBlock.mjs.map +1 -0
  86. package/dist/esm/FloatingPanel/containingBlock.native.js +23 -0
  87. package/dist/esm/FloatingPanel/containingBlock.native.js.map +1 -0
  88. package/dist/esm/FloatingPanel/index.mjs +1 -19
  89. package/dist/esm/FloatingPanel/index.mjs.map +1 -1
  90. package/dist/esm/FloatingPanel/index.native.js +83 -49
  91. package/dist/esm/FloatingPanel/index.native.js.map +1 -1
  92. package/dist/esm/FloatingPanel/pointAnchor.mjs +25 -1
  93. package/dist/esm/FloatingPanel/pointAnchor.mjs.map +1 -1
  94. package/dist/esm/FloatingPanel/pointAnchor.native.js +26 -1
  95. package/dist/esm/FloatingPanel/pointAnchor.native.js.map +1 -1
  96. package/dist/esm/FloatingPanel/regularPlacement.mjs +35 -0
  97. package/dist/esm/FloatingPanel/regularPlacement.mjs.map +1 -0
  98. package/dist/esm/FloatingPanel/regularPlacement.native.js +36 -0
  99. package/dist/esm/FloatingPanel/regularPlacement.native.js.map +1 -0
  100. package/dist/esm/fields/Combobox/index.mjs +9 -11
  101. package/dist/esm/fields/Combobox/index.mjs.map +1 -1
  102. package/dist/esm/fields/Combobox/index.native.js +11 -11
  103. package/dist/esm/fields/Combobox/index.native.js.map +1 -1
  104. package/dist/esm/fields/DatePicker/parts.mjs +1 -0
  105. package/dist/esm/fields/DatePicker/parts.mjs.map +1 -1
  106. package/dist/esm/fields/DatePicker/parts.native.js +3 -0
  107. package/dist/esm/fields/DatePicker/parts.native.js.map +1 -1
  108. package/dist/esm/fields/Input/index.mjs +6 -1
  109. package/dist/esm/fields/Input/index.mjs.map +1 -1
  110. package/dist/esm/fields/Input/index.native.js +6 -1
  111. package/dist/esm/fields/Input/index.native.js.map +1 -1
  112. package/dist/esm/fields/Select/InlineChoices.mjs +3 -2
  113. package/dist/esm/fields/Select/InlineChoices.mjs.map +1 -1
  114. package/dist/esm/fields/Select/InlineChoices.native.js +5 -2
  115. package/dist/esm/fields/Select/InlineChoices.native.js.map +1 -1
  116. package/dist/esm/fields/Select/SheetPickerRow.mjs +129 -0
  117. package/dist/esm/fields/Select/SheetPickerRow.mjs.map +1 -0
  118. package/dist/esm/fields/Select/SheetPickerRow.native.js +137 -0
  119. package/dist/esm/fields/Select/SheetPickerRow.native.js.map +1 -0
  120. package/dist/esm/fields/Select/index.mjs +66 -7
  121. package/dist/esm/fields/Select/index.mjs.map +1 -1
  122. package/dist/esm/fields/Select/index.native.js +88 -29
  123. package/dist/esm/fields/Select/index.native.js.map +1 -1
  124. package/dist/esm/fields/Select/shouldInlineChoices.mjs +12 -1
  125. package/dist/esm/fields/Select/shouldInlineChoices.mjs.map +1 -1
  126. package/dist/esm/fields/Select/shouldInlineChoices.native.js +13 -1
  127. package/dist/esm/fields/Select/shouldInlineChoices.native.js.map +1 -1
  128. package/dist/esm/fields/Slider/index.mjs +96 -4
  129. package/dist/esm/fields/Slider/index.mjs.map +1 -1
  130. package/dist/esm/fields/Slider/index.native.js +103 -5
  131. package/dist/esm/fields/Slider/index.native.js.map +1 -1
  132. package/dist/esm/fields/Switch/index.mjs +71 -1
  133. package/dist/esm/fields/Switch/index.mjs.map +1 -1
  134. package/dist/esm/fields/Switch/index.native.js +72 -1
  135. package/dist/esm/fields/Switch/index.native.js.map +1 -1
  136. package/dist/esm/fields/TimePicker/parts.mjs +1 -0
  137. package/dist/esm/fields/TimePicker/parts.mjs.map +1 -1
  138. package/dist/esm/fields/TimePicker/parts.native.js +1 -0
  139. package/dist/esm/fields/TimePicker/parts.native.js.map +1 -1
  140. package/dist/esm/fields/ToggleGroup/index.mjs +67 -1
  141. package/dist/esm/fields/ToggleGroup/index.mjs.map +1 -1
  142. package/dist/esm/fields/ToggleGroup/index.native.js +75 -1
  143. package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
  144. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs +36 -21
  145. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
  146. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js +46 -23
  147. package/dist/esm/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  148. package/dist/esm/fields/nativeDateTime/sheetKeyboard.mjs +21 -0
  149. package/dist/esm/fields/nativeDateTime/sheetKeyboard.mjs.map +1 -0
  150. package/dist/esm/fields/nativeDateTime/sheetKeyboard.native.js +21 -0
  151. package/dist/esm/fields/nativeDateTime/sheetKeyboard.native.js.map +1 -0
  152. package/dist/esm/index.mjs +3 -1
  153. package/dist/esm/index.mjs.map +1 -1
  154. package/dist/esm/index.native.js +3 -1
  155. package/dist/esm/index.native.js.map +1 -1
  156. package/dist/esm/shared/overlaySizeClass.mjs +14 -0
  157. package/dist/esm/shared/overlaySizeClass.mjs.map +1 -0
  158. package/dist/esm/shared/overlaySizeClass.native.js +14 -0
  159. package/dist/esm/shared/overlaySizeClass.native.js.map +1 -0
  160. package/dist/esm/shared/sheetNavigation.mjs +47 -0
  161. package/dist/esm/shared/sheetNavigation.mjs.map +1 -0
  162. package/dist/esm/shared/sheetNavigation.native.js +97 -0
  163. package/dist/esm/shared/sheetNavigation.native.js.map +1 -0
  164. package/dist/esm/shared/systemControlModules.gnome.mjs +8 -0
  165. package/dist/esm/shared/systemControlModules.gnome.mjs.map +1 -0
  166. package/dist/esm/shared/systemControlModules.gnome.native.js +8 -0
  167. package/dist/esm/shared/systemControlModules.gnome.native.js.map +1 -0
  168. package/dist/esm/shared/systemControlModules.mjs +8 -0
  169. package/dist/esm/shared/systemControlModules.mjs.map +1 -0
  170. package/dist/esm/shared/systemControlModules.native.js +47 -0
  171. package/dist/esm/shared/systemControlModules.native.js.map +1 -0
  172. package/dist/esm/shared/systemControls.mjs +19 -0
  173. package/dist/esm/shared/systemControls.mjs.map +1 -0
  174. package/dist/esm/shared/systemControls.native.js +20 -0
  175. package/dist/esm/shared/systemControls.native.js.map +1 -0
  176. package/dist/jsx/FloatingPanel/RegularPanel.mjs +139 -0
  177. package/dist/jsx/FloatingPanel/RegularPanel.mjs.map +1 -0
  178. package/dist/jsx/FloatingPanel/RegularPanel.native.js +169 -0
  179. package/dist/jsx/FloatingPanel/RegularPanel.native.js.map +1 -0
  180. package/dist/jsx/FloatingPanel/compactFace.mjs +5 -1
  181. package/dist/jsx/FloatingPanel/compactFace.mjs.map +1 -1
  182. package/dist/jsx/FloatingPanel/compactFace.native.js +6 -0
  183. package/dist/jsx/FloatingPanel/compactFace.native.js.map +1 -1
  184. package/dist/jsx/FloatingPanel/containingBlock.mjs +21 -0
  185. package/dist/jsx/FloatingPanel/containingBlock.mjs.map +1 -0
  186. package/dist/jsx/FloatingPanel/containingBlock.native.js +51 -0
  187. package/dist/jsx/FloatingPanel/containingBlock.native.js.map +1 -0
  188. package/dist/jsx/FloatingPanel/index.mjs +1 -19
  189. package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
  190. package/dist/jsx/FloatingPanel/index.native.js +79 -45
  191. package/dist/jsx/FloatingPanel/index.native.js.map +1 -1
  192. package/dist/jsx/FloatingPanel/pointAnchor.mjs +25 -1
  193. package/dist/jsx/FloatingPanel/pointAnchor.mjs.map +1 -1
  194. package/dist/jsx/FloatingPanel/pointAnchor.native.js +26 -0
  195. package/dist/jsx/FloatingPanel/pointAnchor.native.js.map +1 -1
  196. package/dist/jsx/FloatingPanel/regularPlacement.mjs +35 -0
  197. package/dist/jsx/FloatingPanel/regularPlacement.mjs.map +1 -0
  198. package/dist/jsx/FloatingPanel/regularPlacement.native.js +65 -0
  199. package/dist/jsx/FloatingPanel/regularPlacement.native.js.map +1 -0
  200. package/dist/jsx/fields/Combobox/index.mjs +9 -11
  201. package/dist/jsx/fields/Combobox/index.mjs.map +1 -1
  202. package/dist/jsx/fields/Combobox/index.native.js +10 -10
  203. package/dist/jsx/fields/Combobox/index.native.js.map +1 -1
  204. package/dist/jsx/fields/DatePicker/parts.mjs +1 -0
  205. package/dist/jsx/fields/DatePicker/parts.mjs.map +1 -1
  206. package/dist/jsx/fields/DatePicker/parts.native.js +3 -0
  207. package/dist/jsx/fields/DatePicker/parts.native.js.map +1 -1
  208. package/dist/jsx/fields/Input/index.mjs +6 -1
  209. package/dist/jsx/fields/Input/index.mjs.map +1 -1
  210. package/dist/jsx/fields/Input/index.native.js +5 -0
  211. package/dist/jsx/fields/Input/index.native.js.map +1 -1
  212. package/dist/jsx/fields/Select/InlineChoices.mjs +3 -2
  213. package/dist/jsx/fields/Select/InlineChoices.mjs.map +1 -1
  214. package/dist/jsx/fields/Select/InlineChoices.native.js +5 -2
  215. package/dist/jsx/fields/Select/InlineChoices.native.js.map +1 -1
  216. package/dist/jsx/fields/Select/SheetPickerRow.mjs +129 -0
  217. package/dist/jsx/fields/Select/SheetPickerRow.mjs.map +1 -0
  218. package/dist/jsx/fields/Select/SheetPickerRow.native.js +165 -0
  219. package/dist/jsx/fields/Select/SheetPickerRow.native.js.map +1 -0
  220. package/dist/jsx/fields/Select/index.mjs +66 -7
  221. package/dist/jsx/fields/Select/index.mjs.map +1 -1
  222. package/dist/jsx/fields/Select/index.native.js +86 -27
  223. package/dist/jsx/fields/Select/index.native.js.map +1 -1
  224. package/dist/jsx/fields/Select/shouldInlineChoices.mjs +12 -1
  225. package/dist/jsx/fields/Select/shouldInlineChoices.mjs.map +1 -1
  226. package/dist/jsx/fields/Select/shouldInlineChoices.native.js +15 -1
  227. package/dist/jsx/fields/Select/shouldInlineChoices.native.js.map +1 -1
  228. package/dist/jsx/fields/Slider/index.mjs +96 -4
  229. package/dist/jsx/fields/Slider/index.mjs.map +1 -1
  230. package/dist/jsx/fields/Slider/index.native.js +103 -5
  231. package/dist/jsx/fields/Slider/index.native.js.map +1 -1
  232. package/dist/jsx/fields/Switch/index.mjs +71 -1
  233. package/dist/jsx/fields/Switch/index.mjs.map +1 -1
  234. package/dist/jsx/fields/Switch/index.native.js +72 -1
  235. package/dist/jsx/fields/Switch/index.native.js.map +1 -1
  236. package/dist/jsx/fields/TimePicker/parts.mjs +1 -0
  237. package/dist/jsx/fields/TimePicker/parts.mjs.map +1 -1
  238. package/dist/jsx/fields/TimePicker/parts.native.js +1 -0
  239. package/dist/jsx/fields/TimePicker/parts.native.js.map +1 -1
  240. package/dist/jsx/fields/ToggleGroup/index.mjs +67 -1
  241. package/dist/jsx/fields/ToggleGroup/index.mjs.map +1 -1
  242. package/dist/jsx/fields/ToggleGroup/index.native.js +75 -1
  243. package/dist/jsx/fields/ToggleGroup/index.native.js.map +1 -1
  244. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs +36 -21
  245. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.mjs.map +1 -1
  246. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js +44 -21
  247. package/dist/jsx/fields/nativeDateTime/OsDateTimeSheet.native.js.map +1 -1
  248. package/dist/jsx/fields/nativeDateTime/sheetKeyboard.mjs +21 -0
  249. package/dist/jsx/fields/nativeDateTime/sheetKeyboard.mjs.map +1 -0
  250. package/dist/jsx/fields/nativeDateTime/sheetKeyboard.native.js +57 -0
  251. package/dist/jsx/fields/nativeDateTime/sheetKeyboard.native.js.map +1 -0
  252. package/dist/jsx/index.js +3 -1
  253. package/dist/jsx/index.js.map +1 -1
  254. package/dist/jsx/index.mjs +3 -1
  255. package/dist/jsx/index.mjs.map +1 -1
  256. package/dist/jsx/index.native.js +11 -0
  257. package/dist/jsx/index.native.js.map +1 -1
  258. package/dist/jsx/shared/overlaySizeClass.mjs +14 -0
  259. package/dist/jsx/shared/overlaySizeClass.mjs.map +1 -0
  260. package/dist/jsx/shared/overlaySizeClass.native.js +45 -0
  261. package/dist/jsx/shared/overlaySizeClass.native.js.map +1 -0
  262. package/dist/jsx/shared/sheetNavigation.mjs +47 -0
  263. package/dist/jsx/shared/sheetNavigation.mjs.map +1 -0
  264. package/dist/jsx/shared/sheetNavigation.native.js +129 -0
  265. package/dist/jsx/shared/sheetNavigation.native.js.map +1 -0
  266. package/dist/jsx/shared/systemControlModules.gnome.mjs +8 -0
  267. package/dist/jsx/shared/systemControlModules.gnome.mjs.map +1 -0
  268. package/dist/jsx/shared/systemControlModules.gnome.native.js +37 -0
  269. package/dist/jsx/shared/systemControlModules.gnome.native.js.map +1 -0
  270. package/dist/jsx/shared/systemControlModules.mjs +8 -0
  271. package/dist/jsx/shared/systemControlModules.mjs.map +1 -0
  272. package/dist/jsx/shared/systemControlModules.native.js +77 -0
  273. package/dist/jsx/shared/systemControlModules.native.js.map +1 -0
  274. package/dist/jsx/shared/systemControls.mjs +19 -0
  275. package/dist/jsx/shared/systemControls.mjs.map +1 -0
  276. package/dist/jsx/shared/systemControls.native.js +51 -0
  277. package/dist/jsx/shared/systemControls.native.js.map +1 -0
  278. package/package.json +16 -8
  279. package/src/FloatingPanel/FloatingPanel.menuFace.native.spec.tsx +73 -3
  280. package/src/FloatingPanel/FloatingPanel.regularWidth.native.spec.tsx +193 -0
  281. package/src/FloatingPanel/RegularPanel.tsx +159 -0
  282. package/src/FloatingPanel/compactFace.spec.ts +24 -1
  283. package/src/FloatingPanel/compactFace.ts +16 -0
  284. package/src/FloatingPanel/containingBlock.ts +32 -0
  285. package/src/FloatingPanel/index.native.tsx +80 -35
  286. package/src/FloatingPanel/index.tsx +1 -33
  287. package/src/FloatingPanel/pointAnchor.spec.ts +29 -0
  288. package/src/FloatingPanel/pointAnchor.ts +30 -0
  289. package/src/FloatingPanel/regularPlacement.spec.ts +65 -0
  290. package/src/FloatingPanel/regularPlacement.ts +40 -0
  291. package/src/fields/Combobox/Combobox.regularWidth.native.spec.tsx +94 -0
  292. package/src/fields/Combobox/index.tsx +11 -34
  293. package/src/fields/DatePicker/parts.tsx +3 -0
  294. package/src/fields/DatePicker/touchWeb.spec.tsx +13 -0
  295. package/src/fields/Input/Input.formName.spec.tsx +53 -0
  296. package/src/fields/Input/index.tsx +6 -1
  297. package/src/fields/Select/InlineChoices.tsx +6 -3
  298. package/src/fields/Select/SheetPickerRow.tsx +160 -0
  299. package/src/fields/Select/index.tsx +67 -5
  300. package/src/fields/Select/shouldInlineChoices.spec.ts +21 -1
  301. package/src/fields/Select/shouldInlineChoices.ts +26 -0
  302. package/src/fields/Slider/Slider.system.native.spec.tsx +168 -0
  303. package/src/fields/Slider/index.tsx +166 -30
  304. package/src/fields/Switch/Switch.system.native.spec.tsx +162 -0
  305. package/src/fields/Switch/index.tsx +98 -0
  306. package/src/fields/TimePicker/parts.tsx +1 -0
  307. package/src/fields/ToggleGroup/ToggleGroup.system.native.spec.tsx +192 -0
  308. package/src/fields/ToggleGroup/index.tsx +111 -0
  309. package/src/fields/nativeDateTime/OsDateTimeSheet.presentation.spec.tsx +167 -0
  310. package/src/fields/nativeDateTime/OsDateTimeSheet.tsx +36 -18
  311. package/src/fields/nativeDateTime/sheetKeyboard.spec.ts +60 -0
  312. package/src/fields/nativeDateTime/sheetKeyboard.ts +45 -0
  313. package/src/index.ts +15 -0
  314. package/src/shared/overlaySizeClass.spec.ts +27 -0
  315. package/src/shared/overlaySizeClass.ts +36 -0
  316. package/src/shared/sheetNavigation.ts +82 -0
  317. package/src/shared/systemControlModules.gnome.ts +10 -0
  318. package/src/shared/systemControlModules.native.spec.ts +52 -0
  319. package/src/shared/systemControlModules.native.ts +66 -0
  320. package/src/shared/systemControlModules.ts +10 -0
  321. package/src/shared/systemControls.ts +70 -0
  322. package/types/FloatingPanel/RegularPanel.d.ts +29 -0
  323. package/types/FloatingPanel/RegularPanel.d.ts.map +1 -0
  324. package/types/FloatingPanel/compactFace.d.ts +12 -0
  325. package/types/FloatingPanel/compactFace.d.ts.map +1 -1
  326. package/types/FloatingPanel/containingBlock.d.ts +14 -0
  327. package/types/FloatingPanel/containingBlock.d.ts.map +1 -0
  328. package/types/FloatingPanel/index.d.ts.map +1 -1
  329. package/types/FloatingPanel/index.native.d.ts +6 -1
  330. package/types/FloatingPanel/index.native.d.ts.map +1 -1
  331. package/types/FloatingPanel/pointAnchor.d.ts +12 -0
  332. package/types/FloatingPanel/pointAnchor.d.ts.map +1 -1
  333. package/types/FloatingPanel/regularPlacement.d.ts +20 -0
  334. package/types/FloatingPanel/regularPlacement.d.ts.map +1 -0
  335. package/types/fields/Combobox/index.d.ts.map +1 -1
  336. package/types/fields/DatePicker/parts.d.ts.map +1 -1
  337. package/types/fields/Input/index.d.ts.map +1 -1
  338. package/types/fields/Select/InlineChoices.d.ts.map +1 -1
  339. package/types/fields/Select/SheetPickerRow.d.ts +23 -0
  340. package/types/fields/Select/SheetPickerRow.d.ts.map +1 -0
  341. package/types/fields/Select/index.d.ts.map +1 -1
  342. package/types/fields/Select/shouldInlineChoices.d.ts +15 -0
  343. package/types/fields/Select/shouldInlineChoices.d.ts.map +1 -1
  344. package/types/fields/Slider/index.d.ts +7 -1
  345. package/types/fields/Slider/index.d.ts.map +1 -1
  346. package/types/fields/Switch/index.d.ts +7 -1
  347. package/types/fields/Switch/index.d.ts.map +1 -1
  348. package/types/fields/TimePicker/parts.d.ts.map +1 -1
  349. package/types/fields/ToggleGroup/index.d.ts +8 -1
  350. package/types/fields/ToggleGroup/index.d.ts.map +1 -1
  351. package/types/fields/nativeDateTime/OsDateTimeSheet.d.ts.map +1 -1
  352. package/types/fields/nativeDateTime/sheetKeyboard.d.ts +20 -0
  353. package/types/fields/nativeDateTime/sheetKeyboard.d.ts.map +1 -0
  354. package/types/index.d.ts +4 -0
  355. package/types/index.d.ts.map +1 -1
  356. package/types/shared/overlaySizeClass.d.ts +24 -0
  357. package/types/shared/overlaySizeClass.d.ts.map +1 -0
  358. package/types/shared/sheetNavigation.d.ts +31 -0
  359. package/types/shared/sheetNavigation.d.ts.map +1 -0
  360. package/types/shared/systemControlModules.d.ts +5 -0
  361. package/types/shared/systemControlModules.d.ts.map +1 -0
  362. package/types/shared/systemControlModules.gnome.d.ts +5 -0
  363. package/types/shared/systemControlModules.gnome.d.ts.map +1 -0
  364. package/types/shared/systemControlModules.native.d.ts +20 -0
  365. package/types/shared/systemControlModules.native.d.ts.map +1 -0
  366. package/types/shared/systemControls.d.ts +53 -0
  367. package/types/shared/systemControls.d.ts.map +1 -0
@@ -0,0 +1,193 @@
1
+ /**
2
+ * FZ-8116 (LC-266): the window's size class picks the native FloatingPanel's
3
+ * form. At regular width (an iPad, a wide Android window) a picker opens over
4
+ * its field the way the web float does; at compact width (iPhone, Slide Over)
5
+ * it keeps the bottom sheet.
6
+ */
7
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
8
+ import { act } from "@testing-library/react";
9
+ import { useState, type ReactNode } from "react";
10
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
11
+ import { Text } from "tamagui";
12
+ import { FloatingPanel } from "./index.native";
13
+ import type { FloatingPanelProps } from "./index";
14
+ import { regularFillHeight } from "./regularPlacement";
15
+ import { panelViewportPadding } from "./useFloatingPanel";
16
+
17
+ const screen = vi.hoisted(() => ({ width: 820, height: 1180 }));
18
+ vi.mock("react-native-web", async (importOriginal) => {
19
+ const actual = await importOriginal<typeof import("react-native")>();
20
+ return {
21
+ ...actual,
22
+ ActionSheetIOS: undefined,
23
+ Modal: ({ children, visible }: { children: ReactNode; visible: boolean }) =>
24
+ visible ? children : null,
25
+ useWindowDimensions: () => ({ ...screen, scale: 2, fontScale: 1 }),
26
+ };
27
+ });
28
+
29
+ let field = { x: 40, y: 300, width: 360, height: 44 };
30
+ beforeEach(() => {
31
+ vi.useFakeTimers();
32
+ field = { x: 40, y: 300, width: 360, height: 44 };
33
+ vi.spyOn(HTMLElement.prototype, "getBoundingClientRect").mockImplementation(() => ({
34
+ x: field.x,
35
+ y: field.y,
36
+ left: field.x,
37
+ top: field.y,
38
+ width: field.width,
39
+ height: field.height,
40
+ right: field.x + field.width,
41
+ bottom: field.y + field.height,
42
+ toJSON: () => ({}),
43
+ }));
44
+ });
45
+ afterEach(() => {
46
+ vi.restoreAllMocks();
47
+ vi.useRealTimers();
48
+ screen.width = 820;
49
+ screen.height = 1180;
50
+ });
51
+
52
+ function Picker(props: Partial<FloatingPanelProps>) {
53
+ const [open, setOpen] = useState(false);
54
+ return (
55
+ <FloatingPanel
56
+ open={open}
57
+ onOpenChange={setOpen}
58
+ trigger={<Text>Colour</Text>}
59
+ triggerA11y={{ label: "Colour" }}
60
+ {...props}
61
+ >
62
+ <Text>Red</Text>
63
+ <Text>Green</Text>
64
+ </FloatingPanel>
65
+ );
66
+ }
67
+
68
+ function tap(target: Element) {
69
+ act(() => {
70
+ target.dispatchEvent(new MouseEvent("mousedown", { bubbles: true, button: 0 }));
71
+ target.dispatchEvent(new MouseEvent("mouseup", { bubbles: true, button: 0 }));
72
+ target.dispatchEvent(new MouseEvent("click", { bubbles: true, button: 0 }));
73
+ });
74
+ act(() => {
75
+ vi.advanceTimersByTime(1);
76
+ });
77
+ }
78
+
79
+ function layout(node: Element, width: number, height: number) {
80
+ const onLayout = (node as unknown as { __reactLayoutHandler?: (event: unknown) => void })
81
+ .__reactLayoutHandler;
82
+ expect(onLayout).toBeTypeOf("function");
83
+ act(() => {
84
+ onLayout?.({ nativeEvent: { layout: { x: 0, y: 0, width, height } } });
85
+ });
86
+ }
87
+
88
+ const regular = () => document.querySelector<HTMLElement>('[data-testid="floating-panel-regular"]');
89
+ const sheet = () => document.querySelector('[data-testid="floating-panel-sheet"]');
90
+ const echo = () =>
91
+ document.querySelector<HTMLElement>('[data-testid="floating-panel-regular-echo"]');
92
+ const scroll = () => document.querySelector('[data-testid="floating-panel-regular-scroll"]');
93
+
94
+ function open(props: Partial<FloatingPanelProps> = {}) {
95
+ const result = renderWithProviders(<Picker {...props} />);
96
+ tap(result.getByRole("button", { name: "Colour" }));
97
+ return result;
98
+ }
99
+
100
+ describe("FloatingPanel native at regular width (FZ-8116)", () => {
101
+ it("opens over its field on an iPad-wide window, not as a bottom sheet", () => {
102
+ open();
103
+ const panel = regular();
104
+ expect(panel).not.toBeNull();
105
+ expect(sheet()).toBeNull();
106
+ expect(panel?.style.opacity).toBe("0");
107
+ layout(panel as HTMLElement, 240, 200);
108
+ expect(panel?.style.left).toBe("40px");
109
+ expect(panel?.style.top).toBe("300px");
110
+ expect(panel?.style.opacity).toBe("1");
111
+ });
112
+
113
+ it("keeps its shadow: an inner view clips, not the elevated surface", () => {
114
+ open();
115
+ const surface = document.querySelector('[data-testid="floating-panel-regular-surface"]');
116
+ const clip = document.querySelector('[data-testid="floating-panel-regular-clip"]');
117
+ expect(surface?.contains(clip)).toBe(true);
118
+ expect(surface?.className).not.toContain("_ox-hidden");
119
+ expect(clip?.className).toContain("_ox-hidden");
120
+ });
121
+
122
+ it("is at least the field's width by default", () => {
123
+ open();
124
+ expect(regular()?.style.minWidth).toBe("360px");
125
+ });
126
+
127
+ it("is the field's width exactly for match-trigger", () => {
128
+ open({ widthMode: "match-trigger" });
129
+ expect(regular()?.style.width).toBe("360px");
130
+ });
131
+
132
+ it("hugs its content for fit-content, from the field's start edge", () => {
133
+ open({ widthMode: "fit-content" });
134
+ const panel = regular() as HTMLElement;
135
+ expect(panel.style.minWidth).toBe("");
136
+ expect(panel.style.width).toBe("");
137
+ layout(panel, 300, 320);
138
+ expect(panel.style.left).toBe("40px");
139
+ });
140
+
141
+ it("echoes the field as its first row, and pressing it closes the panel", () => {
142
+ open();
143
+ const row = echo() as HTMLElement;
144
+ expect(row.textContent).toBe("Colour");
145
+ expect(row.style.height).toBe("44px");
146
+ act(() => {
147
+ vi.advanceTimersByTime(1000);
148
+ });
149
+ tap(row);
150
+ expect(regular()).toBeNull();
151
+ });
152
+
153
+ it("slides up inside the padded window when the field sits near the bottom", () => {
154
+ field = { x: 40, y: 1080, width: 360, height: 44 };
155
+ open();
156
+ const panel = regular() as HTMLElement;
157
+ layout(panel, 360, 300);
158
+ const top = parseFloat(panel.style.top);
159
+ expect(top + 300).toBeLessThanOrEqual(1180 - panelViewportPadding);
160
+ });
161
+
162
+ it("gives a gesture editor no scrollport (LC-83)", () => {
163
+ open();
164
+ expect(scroll()).toBeNull();
165
+ });
166
+
167
+ it("scrolls a scrollable list", () => {
168
+ open({ scrollable: true });
169
+ expect(scroll()).not.toBeNull();
170
+ });
171
+
172
+ it("opens a search list (sheetFill) at a definite height", () => {
173
+ open({ scrollable: true, sheetFill: true });
174
+ expect(regular()?.style.height).toBe(`${regularFillHeight}px`);
175
+ });
176
+
177
+ it("keeps the bottom sheet when the caller forces it", () => {
178
+ open({ sheet: true });
179
+ expect(regular()).toBeNull();
180
+ expect(sheet()).not.toBeNull();
181
+ });
182
+
183
+ it.each([
184
+ ["an iPhone", 390, 844],
185
+ ["iPad Slide Over", 320, 1180],
186
+ ])("keeps the bottom sheet on %s", (_name, width, height) => {
187
+ screen.width = width;
188
+ screen.height = height;
189
+ open();
190
+ expect(regular()).toBeNull();
191
+ expect(sheet()).not.toBeNull();
192
+ });
193
+ });
@@ -0,0 +1,159 @@
1
+ import { useResolvedKnobs } from "@multiplatform.one/theme";
2
+ import { type ReactNode, useState } from "react";
3
+ import {
4
+ I18nManager,
5
+ Pressable,
6
+ ScrollView as RNScrollView,
7
+ StyleSheet,
8
+ View as RNView,
9
+ } from "react-native";
10
+ import { YStack } from "tamagui";
11
+ import { t } from "../shared/t";
12
+ import type { PanelBounds, TriggerRect } from "./pointAnchor";
13
+ import { placeRegularPanel, regularFillHeight } from "./regularPlacement";
14
+ import type { PanelWidthMode } from "./useFloatingPanel";
15
+
16
+ /**
17
+ * A FloatingPanel at regular width (FZ-8116): over its field instead of a
18
+ * bottom sheet. Measured once per open at its natural size, then placed on
19
+ * the field's window rect. The field is echoed as the first row, as the web
20
+ * float's named close row is, and pressing it closes the panel.
21
+ *
22
+ * Only a `scrollable` panel gets a scrollport: a gesture editor (ColorPicker,
23
+ * DatePicker) must take its own drags (LC-83).
24
+ */
25
+ export function RegularPanel({
26
+ anchor,
27
+ bounds,
28
+ widthMode,
29
+ echo,
30
+ echoLabel,
31
+ header,
32
+ scrollable,
33
+ fill,
34
+ scrollViewProps,
35
+ framePadding,
36
+ frameGap,
37
+ onBackdropPress,
38
+ onClose,
39
+ children,
40
+ }: {
41
+ anchor: TriggerRect | null;
42
+ bounds: PanelBounds;
43
+ widthMode: PanelWidthMode;
44
+ echo: ReactNode;
45
+ echoLabel?: string;
46
+ header?: ReactNode;
47
+ scrollable: boolean;
48
+ fill: boolean;
49
+ scrollViewProps?: Record<string, unknown>;
50
+ framePadding: string;
51
+ frameGap: string | undefined;
52
+ onBackdropPress: () => void;
53
+ onClose: () => void;
54
+ children: ReactNode;
55
+ }) {
56
+ const { knobProps } = useResolvedKnobs({ painted: false });
57
+ const [size, setSize] = useState<{ width: number; height: number } | null>(null);
58
+ const room = Math.max(0, bounds.bottom - bounds.top);
59
+ const fillHeight = fill ? Math.min(regularFillHeight, room) : undefined;
60
+ const placement =
61
+ anchor && size
62
+ ? placeRegularPanel({
63
+ trigger: anchor,
64
+ width: size.width,
65
+ height: fillHeight ?? size.height,
66
+ bounds,
67
+ widthMode,
68
+ rtl: I18nManager.isRTL,
69
+ })
70
+ : null;
71
+ const widthStyle =
72
+ widthMode === "match-trigger"
73
+ ? { width: anchor?.width }
74
+ : widthMode === "at-least-trigger"
75
+ ? { minWidth: anchor?.width ?? 0 }
76
+ : undefined;
77
+ const echoRow =
78
+ echo != null && anchor && anchor.height > 0 ? (
79
+ <Pressable
80
+ testID="floating-panel-regular-echo"
81
+ onPress={onClose}
82
+ accessibilityRole="button"
83
+ {...(echoLabel ? { accessibilityLabel: echoLabel } : undefined)}
84
+ aria-expanded
85
+ style={{ height: anchor.height, justifyContent: "center" }}
86
+ >
87
+ <RNView pointerEvents="none">{echo}</RNView>
88
+ </Pressable>
89
+ ) : null;
90
+ return (
91
+ <RNView style={StyleSheet.absoluteFill}>
92
+ <Pressable
93
+ style={StyleSheet.absoluteFill}
94
+ onPress={onBackdropPress}
95
+ accessibilityRole="button"
96
+ accessibilityLabel={t("Close")}
97
+ />
98
+ <RNView
99
+ testID="floating-panel-regular"
100
+ onLayout={(e) => {
101
+ if (size) return;
102
+ const { width, height } = e.nativeEvent.layout;
103
+ if (width > 0 && height > 0) setSize({ width, height });
104
+ }}
105
+ style={{
106
+ position: "absolute",
107
+ left: placement?.left ?? bounds.left,
108
+ top: placement?.top ?? bounds.top,
109
+ ...widthStyle,
110
+ maxWidth: bounds.right - bounds.left,
111
+ maxHeight: placement?.maxHeight ?? room,
112
+ ...(fillHeight ? { height: Math.min(fillHeight, placement?.maxHeight ?? room) } : null),
113
+ opacity: placement ? 1 : 0,
114
+ }}
115
+ >
116
+ <YStack
117
+ testID="floating-panel-regular-surface"
118
+ {...knobProps.elevatedSurface}
119
+ flexShrink={1}
120
+ minHeight={0}
121
+ {...(fill ? { flex: 1 } : undefined)}
122
+ onAccessibilityEscape={onClose}
123
+ >
124
+ <YStack
125
+ testID="floating-panel-regular-clip"
126
+ borderRadius={knobProps.elevatedSurface.borderRadius}
127
+ overflow="hidden"
128
+ flexShrink={1}
129
+ minHeight={0}
130
+ {...(fill ? { flex: 1 } : undefined)}
131
+ >
132
+ {echoRow}
133
+ <YStack
134
+ padding={framePadding}
135
+ gap={frameGap}
136
+ flexShrink={1}
137
+ minHeight={0}
138
+ {...(fill ? { flex: 1 } : undefined)}
139
+ >
140
+ {header}
141
+ {scrollable ? (
142
+ <RNScrollView
143
+ testID="floating-panel-regular-scroll"
144
+ style={fill ? { flex: 1 } : { flexGrow: 0, flexShrink: 1 }}
145
+ keyboardShouldPersistTaps="handled"
146
+ {...(scrollViewProps as object)}
147
+ >
148
+ {children}
149
+ </RNScrollView>
150
+ ) : (
151
+ children
152
+ )}
153
+ </YStack>
154
+ </YStack>
155
+ </YStack>
156
+ </RNView>
157
+ </RNView>
158
+ );
159
+ }
@@ -1,5 +1,11 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { pickerCompactFace, resolveCompactFace, SHORT_LIST_MAX } from "./compactFace";
2
+ import {
3
+ MENU_MIN_WIDTH,
4
+ menuMinWidth,
5
+ pickerCompactFace,
6
+ resolveCompactFace,
7
+ SHORT_LIST_MAX,
8
+ } from "./compactFace";
3
9
 
4
10
  describe("resolveCompactFace (FZ-7830)", () => {
5
11
  it("keeps the sheet by default, at page level and inside an overlay", () => {
@@ -38,3 +44,20 @@ describe("pickerCompactFace (FZ-7830)", () => {
38
44
  expect(resolveCompactFace(pickerCompactFace(3, true), false)).toBe("sheet");
39
45
  });
40
46
  });
47
+
48
+ describe("menuMinWidth (FZ-8220)", () => {
49
+ it("never opens a menu narrower than the platform floor", () => {
50
+ expect(menuMinWidth(44, 370)).toBe(MENU_MIN_WIDTH);
51
+ expect(menuMinWidth(0, 370)).toBe(MENU_MIN_WIDTH);
52
+ });
53
+
54
+ it("keeps a wider trigger's width", () => {
55
+ expect(menuMinWidth(320, 370)).toBe(320);
56
+ });
57
+
58
+ it("clamps to the room between the screen's margins", () => {
59
+ expect(menuMinWidth(44, 220)).toBe(220);
60
+ expect(menuMinWidth(400, 370)).toBe(370);
61
+ expect(menuMinWidth(44, -5)).toBe(0);
62
+ });
63
+ });
@@ -30,3 +30,19 @@ export const SHORT_LIST_MAX = 7;
30
30
  export function pickerCompactFace(optionCount: number, searchable = false): CompactFace {
31
31
  return !searchable && optionCount <= SHORT_LIST_MAX ? "menu" : "auto";
32
32
  }
33
+
34
+ /**
35
+ * The narrowest a menu-faced panel opens on native (FZ-8220): the iOS
36
+ * pull-down's floor, inside Material's 112–280 menu range. A menu's rows
37
+ * fill their width and have none of their own, so without a floor the panel
38
+ * took its trigger's width and an avatar's 44pt squeezed the text away.
39
+ */
40
+ export const MENU_MIN_WIDTH = 250;
41
+
42
+ /**
43
+ * A menu face's minimum width: at least its trigger and the platform floor,
44
+ * never wider than the room between the screen's margins.
45
+ */
46
+ export function menuMinWidth(triggerWidth: number, availableWidth: number): number {
47
+ return Math.max(0, Math.min(Math.max(triggerWidth, MENU_MIN_WIDTH), availableWidth));
48
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Viewport origin of the box a `position: fixed` panel is laid out against.
3
+ * The top/left math is in viewport coordinates, which is only right while that
4
+ * box is the viewport. An ancestor with a transform, filter, perspective,
5
+ * paint containment or container query becomes the containing block instead.
6
+ * PanelPortal lifts the panel out of scroll views, but a panel hosted in a
7
+ * transformed dialog still lays out against that dialog. A `display: contents`
8
+ * node has no box, so its computed `contain` (Tamagui's theme span) is ignored.
9
+ */
10
+ export function fixedContainingBlockOrigin(element: HTMLElement): { top: number; left: number } {
11
+ for (let node = element.parentElement; node; node = node.parentElement) {
12
+ const cs = getComputedStyle(node);
13
+ if (cs.display === "contents") continue;
14
+ const set = (value: string | undefined, initial: string) => !!value && value !== initial;
15
+ const captures =
16
+ set(cs.transform, "none") ||
17
+ set(cs.perspective, "none") ||
18
+ set(cs.filter, "none") ||
19
+ set(cs.backdropFilter, "none") ||
20
+ set(cs.containerType, "normal") ||
21
+ /transform|perspective|filter/.test(cs.willChange) ||
22
+ /paint|layout|strict|content/.test(cs.contain);
23
+ if (captures) {
24
+ const rect = node.getBoundingClientRect();
25
+ return {
26
+ top: rect.top + node.clientTop - node.scrollTop,
27
+ left: rect.left + node.clientLeft - node.scrollLeft,
28
+ };
29
+ }
30
+ }
31
+ return { top: 0, left: 0 };
32
+ }
@@ -55,6 +55,11 @@
55
55
  * than OVERLAY_BREAKPOINT (a tablet) it opens at the long-press point, the
56
56
  * same free overlay the web draws at the pointer; a phone keeps the sheet,
57
57
  * as web does at ≤640.
58
+ *
59
+ * Regular width (FZ-8116, LC-266): on an iPad or any window wider than
60
+ * OVERLAY_BREAKPOINT the sheet is the wrong form. The panel opens over its
61
+ * field the way the web float does (LC-105, LC-112), sized by `widthMode`;
62
+ * compact windows (iPhone, Slide Over) keep the sheet. `sheet` forces it.
58
63
  */
59
64
 
60
65
  import { nativeAnimationConfig, type MotionStop } from "@multiplatform.one/theme";
@@ -83,27 +88,25 @@ import {
83
88
  type GestureResponderEvent,
84
89
  } from "react-native";
85
90
  import { SafeAreaInsetsContext, initialWindowMetrics } from "react-native-safe-area-context";
86
- import {
87
- OVERLAY_BREAKPOINT,
88
- Surface,
89
- useResolvedKnobs,
90
- motionDurationMs,
91
- } from "@multiplatform.one/theme";
91
+ import { Surface, useResolvedKnobs, motionDurationMs } from "@multiplatform.one/theme";
92
92
  import { View, YStack } from "tamagui";
93
93
  import { useInsideOverlay, useOverlayZIndex } from "../shared/overlayStack";
94
94
  import { OverlayWindow } from "../shared/OverlayWindow";
95
95
  import { t } from "../shared/t";
96
+ import { overlaySizeClass } from "../shared/overlaySizeClass";
96
97
  import { useKeyboardInset } from "../shared/useKeyboardInset";
97
98
  import type { FloatingPanelProps } from "./index";
98
- import { resolveCompactFace } from "./compactFace";
99
+ import { menuMinWidth, resolveCompactFace } from "./compactFace";
99
100
  import {
100
101
  placeAtPoint,
102
+ placeBesideTrigger,
101
103
  placeOverTrigger,
102
104
  type PanelBounds,
103
105
  type PanelPoint,
104
106
  type TriggerRect,
105
107
  } from "./pointAnchor";
106
- import { panelViewportPadding } from "./useFloatingPanel";
108
+ import { RegularPanel } from "./RegularPanel";
109
+ import { panelViewportPadding, resolvePanelWidthMode } from "./useFloatingPanel";
107
110
  import { TrailingActionOverlay, TriggerWithTrailingAction } from "./trailingAction";
108
111
 
109
112
  // Re-export the hook + constants so Select / Combobox / external consumers
@@ -160,6 +163,9 @@ export function FloatingPanel({
160
163
  triggerRow,
161
164
  triggerEcho = true,
162
165
  anchorMode,
166
+ sheet,
167
+ widthMode,
168
+ fitContent,
163
169
  }: FloatingPanelProps) {
164
170
  // The panel floats over the page: it never inherits a painted ancestor.
165
171
  const { knobProps } = useResolvedKnobs({ painted: false });
@@ -202,15 +208,18 @@ export function FloatingPanel({
202
208
  [disabled, onOpenChange],
203
209
  );
204
210
  const isContextMenu = openOn === "contextmenu";
205
- const atPoint = isContextMenu && pressPoint !== null && windowWidth > OVERLAY_BREAKPOINT;
211
+ const regular = overlaySizeClass(windowWidth) === "regular";
212
+ const atPoint = isContextMenu && pressPoint !== null && regular;
206
213
  const insideOverlay = useInsideOverlay();
207
214
  const asMenu = !isContextMenu && resolveCompactFace(compactFace, insideOverlay) === "menu";
215
+ const asRegular = regular && !asMenu && !isContextMenu && sheet !== true;
216
+ const anchored = asMenu || asRegular;
208
217
  const triggerRef = useRef<RNView | null>(null);
209
218
  const [anchor, setAnchor] = useState<TriggerRect | null>(null);
210
219
  // The trigger's window rect, read each time the menu opens: it may have
211
220
  // moved (a scrolled sheet) since the last open.
212
221
  useLayoutEffect(() => {
213
- if (!asMenu || !open) {
222
+ if (!anchored || !open) {
214
223
  setAnchor(null);
215
224
  return;
216
225
  }
@@ -230,7 +239,7 @@ export function FloatingPanel({
230
239
  return () => {
231
240
  live = false;
232
241
  };
233
- }, [asMenu, open]);
242
+ }, [anchored, open]);
234
243
 
235
244
  const handleBackdropPress = useCallback(() => {
236
245
  if (backdropArmed) close();
@@ -582,11 +591,8 @@ export function FloatingPanel({
582
591
  <TriggerMenuPanel
583
592
  // An attached menu (an icon trigger, no echo row) opens under its
584
593
  // trigger instead of over it, the UIMenu pull-down (LC-262).
585
- anchor={
586
- anchor && anchorMode === "attach"
587
- ? { ...anchor, y: anchor.y + anchor.height }
588
- : anchor
589
- }
594
+ anchor={anchor}
595
+ attach={anchorMode === "attach"}
590
596
  bounds={{
591
597
  top: topInset + panelViewportPadding,
592
598
  left: (safeArea?.left ?? 0) + panelViewportPadding,
@@ -627,6 +633,32 @@ export function FloatingPanel({
627
633
  {header}
628
634
  {children}
629
635
  </PointPanel>
636
+ ) : asRegular ? (
637
+ <RegularPanel
638
+ anchor={anchor}
639
+ bounds={{
640
+ top: topInset + panelViewportPadding,
641
+ left: (safeArea?.left ?? 0) + panelViewportPadding,
642
+ right: windowWidth - (safeArea?.right ?? 0) - panelViewportPadding,
643
+ bottom:
644
+ windowHeight -
645
+ Math.max(safeArea?.bottom ?? 0, keyboardInset) -
646
+ panelViewportPadding,
647
+ }}
648
+ widthMode={resolvePanelWidthMode(widthMode, fitContent)}
649
+ echo={triggerEcho ? (triggerRow ?? trigger) : null}
650
+ echoLabel={triggerA11y?.label}
651
+ header={header}
652
+ scrollable={!!scrollable}
653
+ fill={!!sheetFill}
654
+ scrollViewProps={scrollViewProps}
655
+ framePadding={framePadding}
656
+ frameGap={frameGap}
657
+ onBackdropPress={handleBackdropPress}
658
+ onClose={close}
659
+ >
660
+ {children}
661
+ </RegularPanel>
630
662
  ) : (
631
663
  /*
632
664
  A plain padded column, not KeyboardAvoidingView: inside a Modal the
@@ -732,6 +764,7 @@ export function FloatingPanel({
732
764
  */
733
765
  function TriggerMenuPanel({
734
766
  anchor,
767
+ attach = false,
735
768
  bounds,
736
769
  echo,
737
770
  echoLabel,
@@ -742,6 +775,7 @@ function TriggerMenuPanel({
742
775
  children,
743
776
  }: {
744
777
  anchor: TriggerRect | null;
778
+ attach?: boolean;
745
779
  bounds: PanelBounds;
746
780
  echo: ReactNode;
747
781
  echoLabel?: string;
@@ -755,7 +789,7 @@ function TriggerMenuPanel({
755
789
  const [size, setSize] = useState<{ width: number; height: number } | null>(null);
756
790
  const placement =
757
791
  anchor && size
758
- ? placeOverTrigger({
792
+ ? (attach ? placeBesideTrigger : placeOverTrigger)({
759
793
  trigger: anchor,
760
794
  width: size.width,
761
795
  height: size.height,
@@ -782,36 +816,47 @@ function TriggerMenuPanel({
782
816
  position: "absolute",
783
817
  left: placement?.left ?? bounds.left,
784
818
  top: placement?.top ?? bounds.top,
785
- minWidth: anchor?.width ?? 0,
819
+ minWidth: menuMinWidth(anchor?.width ?? 0, bounds.right - bounds.left),
786
820
  maxWidth: bounds.right - bounds.left,
787
821
  maxHeight: placement?.maxHeight ?? bounds.bottom - bounds.top,
788
822
  opacity: placement ? 1 : 0,
789
823
  }}
790
824
  >
791
825
  <YStack
826
+ testID="floating-panel-menu-surface"
792
827
  {...knobProps.elevatedSurface}
793
828
  flexShrink={1}
794
829
  minHeight={0}
795
- overflow="hidden"
796
830
  onAccessibilityEscape={onClose}
797
831
  >
798
- {echo != null && anchor && anchor.height > 0 ? (
799
- <Pressable
800
- testID="floating-panel-menu-echo"
801
- onPress={onClose}
802
- accessibilityRole="button"
803
- {...(echoLabel ? { accessibilityLabel: echoLabel } : undefined)}
804
- aria-expanded
805
- style={{ height: anchor.height, minWidth: anchor.width, justifyContent: "center" }}
832
+ <YStack
833
+ testID="floating-panel-menu-clip"
834
+ borderRadius={knobProps.elevatedSurface.borderRadius}
835
+ overflow="hidden"
836
+ flexShrink={1}
837
+ minHeight={0}
838
+ >
839
+ {echo != null && anchor && anchor.height > 0 ? (
840
+ <Pressable
841
+ testID="floating-panel-menu-echo"
842
+ onPress={onClose}
843
+ accessibilityRole="button"
844
+ {...(echoLabel ? { accessibilityLabel: echoLabel } : undefined)}
845
+ aria-expanded
846
+ style={{ height: anchor.height, minWidth: anchor.width, justifyContent: "center" }}
847
+ >
848
+ <RNView pointerEvents="none">{echo}</RNView>
849
+ </Pressable>
850
+ ) : null}
851
+ <RNScrollView
852
+ style={{ flexGrow: 0, flexShrink: 1 }}
853
+ keyboardShouldPersistTaps="handled"
806
854
  >
807
- <RNView pointerEvents="none">{echo}</RNView>
808
- </Pressable>
809
- ) : null}
810
- <RNScrollView style={{ flexGrow: 0, flexShrink: 1 }} keyboardShouldPersistTaps="handled">
811
- <YStack padding={framePadding} gap={frameGap}>
812
- {children}
813
- </YStack>
814
- </RNScrollView>
855
+ <YStack padding={framePadding} gap={frameGap}>
856
+ {children}
857
+ </YStack>
858
+ </RNScrollView>
859
+ </YStack>
815
860
  </YStack>
816
861
  </RNView>
817
862
  </RNView>