@multiplatform.one/forms 7.71.0 → 7.73.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 (381) hide show
  1. package/dist/cjs/Button/circleGlyph.cjs +28 -0
  2. package/dist/cjs/Button/circleGlyph.native.js +31 -0
  3. package/dist/cjs/Button/circleGlyph.native.js.map +1 -0
  4. package/dist/cjs/Button/index.cjs +19 -3
  5. package/dist/cjs/Button/index.native.js +19 -3
  6. package/dist/cjs/Button/index.native.js.map +1 -1
  7. package/dist/cjs/FloatingPanel/PanelHeader.cjs +49 -0
  8. package/dist/cjs/FloatingPanel/PanelHeader.native.js +53 -0
  9. package/dist/cjs/FloatingPanel/PanelHeader.native.js.map +1 -0
  10. package/dist/cjs/FloatingPanel/echoContext.cjs +67 -0
  11. package/dist/cjs/FloatingPanel/echoContext.native.js +71 -0
  12. package/dist/cjs/FloatingPanel/echoContext.native.js.map +1 -0
  13. package/dist/cjs/FloatingPanel/iconEcho.cjs +104 -0
  14. package/dist/cjs/FloatingPanel/iconEcho.native.js +114 -0
  15. package/dist/cjs/FloatingPanel/iconEcho.native.js.map +1 -0
  16. package/dist/cjs/FloatingPanel/index.cjs +371 -86
  17. package/dist/cjs/FloatingPanel/index.native.js +164 -20
  18. package/dist/cjs/FloatingPanel/index.native.js.map +1 -1
  19. package/dist/cjs/FloatingPanel/paintedBox.cjs +80 -0
  20. package/dist/cjs/FloatingPanel/paintedBox.native.js +85 -0
  21. package/dist/cjs/FloatingPanel/paintedBox.native.js.map +1 -0
  22. package/dist/cjs/FloatingPanel/panelWidth.cjs +92 -0
  23. package/dist/cjs/FloatingPanel/panelWidth.native.js +99 -0
  24. package/dist/cjs/FloatingPanel/panelWidth.native.js.map +1 -0
  25. package/dist/cjs/FloatingPanel/pointAnchor.cjs +34 -5
  26. package/dist/cjs/FloatingPanel/pointAnchor.native.js +37 -8
  27. package/dist/cjs/FloatingPanel/pointAnchor.native.js.map +1 -1
  28. package/dist/cjs/FloatingPanel/useFloatingPanel.cjs +60 -5
  29. package/dist/cjs/FloatingPanel/useFloatingPanel.native.js +72 -5
  30. package/dist/cjs/FloatingPanel/useFloatingPanel.native.js.map +1 -1
  31. package/dist/cjs/InputParts/index.cjs +18 -0
  32. package/dist/cjs/InputParts/index.native.js +19 -1
  33. package/dist/cjs/InputParts/index.native.js.map +1 -1
  34. package/dist/cjs/Wheel/NativeWheel.native.js +1 -1
  35. package/dist/cjs/Wheel/NativeWheel.native.js.map +1 -1
  36. package/dist/cjs/Wheel/index.cjs +2 -1
  37. package/dist/cjs/Wheel/index.native.js +4 -1
  38. package/dist/cjs/Wheel/index.native.js.map +1 -1
  39. package/dist/cjs/Wheel/wheelShared.cjs +6 -1
  40. package/dist/cjs/Wheel/wheelShared.native.js +7 -1
  41. package/dist/cjs/Wheel/wheelShared.native.js.map +1 -1
  42. package/dist/cjs/fields/Combobox/index.cjs +1 -0
  43. package/dist/cjs/fields/Combobox/index.native.js +1 -0
  44. package/dist/cjs/fields/Combobox/index.native.js.map +1 -1
  45. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.cjs +6 -30
  46. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js +11 -34
  47. package/dist/cjs/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  48. package/dist/cjs/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  49. package/dist/cjs/fields/DatePicker/catalog.cjs +2 -28
  50. package/dist/cjs/fields/DatePicker/catalog.native.js +2 -30
  51. package/dist/cjs/fields/DatePicker/catalog.native.js.map +1 -1
  52. package/dist/cjs/fields/DatePicker/index.native.js.map +1 -1
  53. package/dist/cjs/fields/DatePicker/parts.cjs +11 -20
  54. package/dist/cjs/fields/DatePicker/parts.native.js +13 -22
  55. package/dist/cjs/fields/DatePicker/parts.native.js.map +1 -1
  56. package/dist/cjs/fields/Select/index.cjs +65 -44
  57. package/dist/cjs/fields/Select/index.native.js +69 -47
  58. package/dist/cjs/fields/Select/index.native.js.map +1 -1
  59. package/dist/cjs/fields/Select/shouldInlineChoices.cjs +3 -1
  60. package/dist/cjs/fields/Select/shouldInlineChoices.native.js +3 -1
  61. package/dist/cjs/fields/Select/shouldInlineChoices.native.js.map +1 -1
  62. package/dist/cjs/fields/TimePicker/catalog.cjs +4 -25
  63. package/dist/cjs/fields/TimePicker/catalog.native.js +7 -29
  64. package/dist/cjs/fields/TimePicker/catalog.native.js.map +1 -1
  65. package/dist/cjs/fields/TimePicker/index.native.js.map +1 -1
  66. package/dist/cjs/fields/TimePicker/parts.cjs +8 -21
  67. package/dist/cjs/fields/TimePicker/parts.native.js +8 -21
  68. package/dist/cjs/fields/TimePicker/parts.native.js.map +1 -1
  69. package/dist/cjs/index.cjs +2 -0
  70. package/dist/cjs/index.native.js +2 -0
  71. package/dist/cjs/index.native.js.map +1 -1
  72. package/dist/cjs/shared/floatingList.cjs +13 -4
  73. package/dist/cjs/shared/floatingList.native.js +15 -4
  74. package/dist/cjs/shared/floatingList.native.js.map +1 -1
  75. package/dist/esm/Button/circleGlyph.mjs +3 -0
  76. package/dist/esm/Button/circleGlyph.mjs.map +1 -0
  77. package/dist/esm/Button/circleGlyph.native.js +3 -0
  78. package/dist/esm/Button/circleGlyph.native.js.map +1 -0
  79. package/dist/esm/Button/index.mjs +18 -2
  80. package/dist/esm/Button/index.mjs.map +1 -1
  81. package/dist/esm/Button/index.native.js +18 -2
  82. package/dist/esm/Button/index.native.js.map +1 -1
  83. package/dist/esm/FloatingPanel/PanelHeader.mjs +24 -0
  84. package/dist/esm/FloatingPanel/PanelHeader.mjs.map +1 -0
  85. package/dist/esm/FloatingPanel/PanelHeader.native.js +25 -0
  86. package/dist/esm/FloatingPanel/PanelHeader.native.js.map +1 -0
  87. package/dist/esm/FloatingPanel/echoContext.mjs +35 -0
  88. package/dist/esm/FloatingPanel/echoContext.mjs.map +1 -0
  89. package/dist/esm/FloatingPanel/echoContext.native.js +36 -0
  90. package/dist/esm/FloatingPanel/echoContext.native.js.map +1 -0
  91. package/dist/esm/FloatingPanel/iconEcho.mjs +77 -0
  92. package/dist/esm/FloatingPanel/iconEcho.mjs.map +1 -0
  93. package/dist/esm/FloatingPanel/iconEcho.native.js +84 -0
  94. package/dist/esm/FloatingPanel/iconEcho.native.js.map +1 -0
  95. package/dist/esm/FloatingPanel/index.mjs +373 -90
  96. package/dist/esm/FloatingPanel/index.mjs.map +1 -1
  97. package/dist/esm/FloatingPanel/index.native.js +165 -23
  98. package/dist/esm/FloatingPanel/index.native.js.map +1 -1
  99. package/dist/esm/FloatingPanel/paintedBox.mjs +52 -0
  100. package/dist/esm/FloatingPanel/paintedBox.mjs.map +1 -0
  101. package/dist/esm/FloatingPanel/paintedBox.native.js +54 -0
  102. package/dist/esm/FloatingPanel/paintedBox.native.js.map +1 -0
  103. package/dist/esm/FloatingPanel/panelWidth.mjs +63 -0
  104. package/dist/esm/FloatingPanel/panelWidth.mjs.map +1 -0
  105. package/dist/esm/FloatingPanel/panelWidth.native.js +67 -0
  106. package/dist/esm/FloatingPanel/panelWidth.native.js.map +1 -0
  107. package/dist/esm/FloatingPanel/pointAnchor.mjs +34 -5
  108. package/dist/esm/FloatingPanel/pointAnchor.mjs.map +1 -1
  109. package/dist/esm/FloatingPanel/pointAnchor.native.js +37 -8
  110. package/dist/esm/FloatingPanel/pointAnchor.native.js.map +1 -1
  111. package/dist/esm/FloatingPanel/useFloatingPanel.mjs +60 -6
  112. package/dist/esm/FloatingPanel/useFloatingPanel.mjs.map +1 -1
  113. package/dist/esm/FloatingPanel/useFloatingPanel.native.js +72 -6
  114. package/dist/esm/FloatingPanel/useFloatingPanel.native.js.map +1 -1
  115. package/dist/esm/InputParts/index.mjs +19 -1
  116. package/dist/esm/InputParts/index.mjs.map +1 -1
  117. package/dist/esm/InputParts/index.native.js +20 -2
  118. package/dist/esm/InputParts/index.native.js.map +1 -1
  119. package/dist/esm/Wheel/NativeWheel.native.js +1 -1
  120. package/dist/esm/Wheel/NativeWheel.native.js.map +1 -1
  121. package/dist/esm/Wheel/index.mjs +2 -1
  122. package/dist/esm/Wheel/index.mjs.map +1 -1
  123. package/dist/esm/Wheel/index.native.js +4 -1
  124. package/dist/esm/Wheel/index.native.js.map +1 -1
  125. package/dist/esm/Wheel/wheelShared.mjs +6 -1
  126. package/dist/esm/Wheel/wheelShared.mjs.map +1 -1
  127. package/dist/esm/Wheel/wheelShared.native.js +7 -1
  128. package/dist/esm/Wheel/wheelShared.native.js.map +1 -1
  129. package/dist/esm/fields/Combobox/index.mjs +1 -0
  130. package/dist/esm/fields/Combobox/index.mjs.map +1 -1
  131. package/dist/esm/fields/Combobox/index.native.js +1 -0
  132. package/dist/esm/fields/Combobox/index.native.js.map +1 -1
  133. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.mjs +6 -30
  134. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.mjs.map +1 -1
  135. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.native.js +11 -34
  136. package/dist/esm/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  137. package/dist/esm/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  138. package/dist/esm/fields/DatePicker/catalog.mjs +2 -28
  139. package/dist/esm/fields/DatePicker/catalog.mjs.map +1 -1
  140. package/dist/esm/fields/DatePicker/catalog.native.js +2 -30
  141. package/dist/esm/fields/DatePicker/catalog.native.js.map +1 -1
  142. package/dist/esm/fields/DatePicker/index.native.js.map +1 -1
  143. package/dist/esm/fields/DatePicker/parts.mjs +11 -20
  144. package/dist/esm/fields/DatePicker/parts.mjs.map +1 -1
  145. package/dist/esm/fields/DatePicker/parts.native.js +13 -22
  146. package/dist/esm/fields/DatePicker/parts.native.js.map +1 -1
  147. package/dist/esm/fields/Select/index.mjs +66 -45
  148. package/dist/esm/fields/Select/index.mjs.map +1 -1
  149. package/dist/esm/fields/Select/index.native.js +70 -48
  150. package/dist/esm/fields/Select/index.native.js.map +1 -1
  151. package/dist/esm/fields/Select/shouldInlineChoices.mjs +3 -1
  152. package/dist/esm/fields/Select/shouldInlineChoices.mjs.map +1 -1
  153. package/dist/esm/fields/Select/shouldInlineChoices.native.js +3 -1
  154. package/dist/esm/fields/Select/shouldInlineChoices.native.js.map +1 -1
  155. package/dist/esm/fields/TimePicker/catalog.mjs +4 -25
  156. package/dist/esm/fields/TimePicker/catalog.mjs.map +1 -1
  157. package/dist/esm/fields/TimePicker/catalog.native.js +7 -29
  158. package/dist/esm/fields/TimePicker/catalog.native.js.map +1 -1
  159. package/dist/esm/fields/TimePicker/index.native.js.map +1 -1
  160. package/dist/esm/fields/TimePicker/parts.mjs +8 -21
  161. package/dist/esm/fields/TimePicker/parts.mjs.map +1 -1
  162. package/dist/esm/fields/TimePicker/parts.native.js +8 -21
  163. package/dist/esm/fields/TimePicker/parts.native.js.map +1 -1
  164. package/dist/esm/index.mjs +2 -1
  165. package/dist/esm/index.mjs.map +1 -1
  166. package/dist/esm/index.native.js +2 -1
  167. package/dist/esm/index.native.js.map +1 -1
  168. package/dist/esm/shared/floatingList.mjs +14 -5
  169. package/dist/esm/shared/floatingList.mjs.map +1 -1
  170. package/dist/esm/shared/floatingList.native.js +16 -5
  171. package/dist/esm/shared/floatingList.native.js.map +1 -1
  172. package/dist/jsx/Button/circleGlyph.mjs +3 -0
  173. package/dist/jsx/Button/circleGlyph.mjs.map +1 -0
  174. package/dist/jsx/Button/circleGlyph.native.js +31 -0
  175. package/dist/jsx/Button/circleGlyph.native.js.map +1 -0
  176. package/dist/jsx/Button/index.mjs +18 -2
  177. package/dist/jsx/Button/index.mjs.map +1 -1
  178. package/dist/jsx/Button/index.native.js +19 -3
  179. package/dist/jsx/Button/index.native.js.map +1 -1
  180. package/dist/jsx/FloatingPanel/PanelHeader.mjs +24 -0
  181. package/dist/jsx/FloatingPanel/PanelHeader.mjs.map +1 -0
  182. package/dist/jsx/FloatingPanel/PanelHeader.native.js +53 -0
  183. package/dist/jsx/FloatingPanel/PanelHeader.native.js.map +1 -0
  184. package/dist/jsx/FloatingPanel/echoContext.mjs +35 -0
  185. package/dist/jsx/FloatingPanel/echoContext.mjs.map +1 -0
  186. package/dist/jsx/FloatingPanel/echoContext.native.js +71 -0
  187. package/dist/jsx/FloatingPanel/echoContext.native.js.map +1 -0
  188. package/dist/jsx/FloatingPanel/iconEcho.mjs +77 -0
  189. package/dist/jsx/FloatingPanel/iconEcho.mjs.map +1 -0
  190. package/dist/jsx/FloatingPanel/iconEcho.native.js +114 -0
  191. package/dist/jsx/FloatingPanel/iconEcho.native.js.map +1 -0
  192. package/dist/jsx/FloatingPanel/index.mjs +373 -90
  193. package/dist/jsx/FloatingPanel/index.mjs.map +1 -1
  194. package/dist/jsx/FloatingPanel/index.native.js +164 -20
  195. package/dist/jsx/FloatingPanel/index.native.js.map +1 -1
  196. package/dist/jsx/FloatingPanel/paintedBox.mjs +52 -0
  197. package/dist/jsx/FloatingPanel/paintedBox.mjs.map +1 -0
  198. package/dist/jsx/FloatingPanel/paintedBox.native.js +85 -0
  199. package/dist/jsx/FloatingPanel/paintedBox.native.js.map +1 -0
  200. package/dist/jsx/FloatingPanel/panelWidth.mjs +63 -0
  201. package/dist/jsx/FloatingPanel/panelWidth.mjs.map +1 -0
  202. package/dist/jsx/FloatingPanel/panelWidth.native.js +99 -0
  203. package/dist/jsx/FloatingPanel/panelWidth.native.js.map +1 -0
  204. package/dist/jsx/FloatingPanel/pointAnchor.mjs +34 -5
  205. package/dist/jsx/FloatingPanel/pointAnchor.mjs.map +1 -1
  206. package/dist/jsx/FloatingPanel/pointAnchor.native.js +37 -8
  207. package/dist/jsx/FloatingPanel/pointAnchor.native.js.map +1 -1
  208. package/dist/jsx/FloatingPanel/useFloatingPanel.mjs +60 -6
  209. package/dist/jsx/FloatingPanel/useFloatingPanel.mjs.map +1 -1
  210. package/dist/jsx/FloatingPanel/useFloatingPanel.native.js +72 -5
  211. package/dist/jsx/FloatingPanel/useFloatingPanel.native.js.map +1 -1
  212. package/dist/jsx/InputParts/index.mjs +19 -1
  213. package/dist/jsx/InputParts/index.mjs.map +1 -1
  214. package/dist/jsx/InputParts/index.native.js +19 -1
  215. package/dist/jsx/InputParts/index.native.js.map +1 -1
  216. package/dist/jsx/Wheel/NativeWheel.native.js +1 -1
  217. package/dist/jsx/Wheel/NativeWheel.native.js.map +1 -1
  218. package/dist/jsx/Wheel/index.mjs +2 -1
  219. package/dist/jsx/Wheel/index.mjs.map +1 -1
  220. package/dist/jsx/Wheel/index.native.js +4 -1
  221. package/dist/jsx/Wheel/index.native.js.map +1 -1
  222. package/dist/jsx/Wheel/wheelShared.mjs +6 -1
  223. package/dist/jsx/Wheel/wheelShared.mjs.map +1 -1
  224. package/dist/jsx/Wheel/wheelShared.native.js +7 -1
  225. package/dist/jsx/Wheel/wheelShared.native.js.map +1 -1
  226. package/dist/jsx/fields/Combobox/index.mjs +1 -0
  227. package/dist/jsx/fields/Combobox/index.mjs.map +1 -1
  228. package/dist/jsx/fields/Combobox/index.native.js +1 -0
  229. package/dist/jsx/fields/Combobox/index.native.js.map +1 -1
  230. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.mjs +6 -30
  231. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.mjs.map +1 -1
  232. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.native.js +11 -34
  233. package/dist/jsx/fields/DatePicker/DatetimePicker.catalog.native.js.map +1 -1
  234. package/dist/jsx/fields/DatePicker/DatetimePicker.native.js.map +1 -1
  235. package/dist/jsx/fields/DatePicker/catalog.mjs +2 -28
  236. package/dist/jsx/fields/DatePicker/catalog.mjs.map +1 -1
  237. package/dist/jsx/fields/DatePicker/catalog.native.js +2 -30
  238. package/dist/jsx/fields/DatePicker/catalog.native.js.map +1 -1
  239. package/dist/jsx/fields/DatePicker/index.native.js.map +1 -1
  240. package/dist/jsx/fields/DatePicker/parts.mjs +11 -20
  241. package/dist/jsx/fields/DatePicker/parts.mjs.map +1 -1
  242. package/dist/jsx/fields/DatePicker/parts.native.js +13 -22
  243. package/dist/jsx/fields/DatePicker/parts.native.js.map +1 -1
  244. package/dist/jsx/fields/Select/index.mjs +66 -45
  245. package/dist/jsx/fields/Select/index.mjs.map +1 -1
  246. package/dist/jsx/fields/Select/index.native.js +69 -47
  247. package/dist/jsx/fields/Select/index.native.js.map +1 -1
  248. package/dist/jsx/fields/Select/shouldInlineChoices.mjs +3 -1
  249. package/dist/jsx/fields/Select/shouldInlineChoices.mjs.map +1 -1
  250. package/dist/jsx/fields/Select/shouldInlineChoices.native.js +3 -1
  251. package/dist/jsx/fields/Select/shouldInlineChoices.native.js.map +1 -1
  252. package/dist/jsx/fields/TimePicker/catalog.mjs +4 -25
  253. package/dist/jsx/fields/TimePicker/catalog.mjs.map +1 -1
  254. package/dist/jsx/fields/TimePicker/catalog.native.js +7 -29
  255. package/dist/jsx/fields/TimePicker/catalog.native.js.map +1 -1
  256. package/dist/jsx/fields/TimePicker/index.native.js.map +1 -1
  257. package/dist/jsx/fields/TimePicker/parts.mjs +8 -21
  258. package/dist/jsx/fields/TimePicker/parts.mjs.map +1 -1
  259. package/dist/jsx/fields/TimePicker/parts.native.js +8 -21
  260. package/dist/jsx/fields/TimePicker/parts.native.js.map +1 -1
  261. package/dist/jsx/index.js +2 -1
  262. package/dist/jsx/index.js.map +1 -1
  263. package/dist/jsx/index.mjs +2 -1
  264. package/dist/jsx/index.mjs.map +1 -1
  265. package/dist/jsx/index.native.js +2 -0
  266. package/dist/jsx/index.native.js.map +1 -1
  267. package/dist/jsx/shared/floatingList.mjs +14 -5
  268. package/dist/jsx/shared/floatingList.mjs.map +1 -1
  269. package/dist/jsx/shared/floatingList.native.js +15 -4
  270. package/dist/jsx/shared/floatingList.native.js.map +1 -1
  271. package/package.json +8 -8
  272. package/src/Button/circleGlyph.ts +6 -0
  273. package/src/Button/index.tsx +25 -7
  274. package/src/FloatingPanel/FloatingPanel.echoStretch.spec.tsx +67 -0
  275. package/src/FloatingPanel/FloatingPanel.iconEcho.spec.tsx +297 -0
  276. package/src/FloatingPanel/FloatingPanel.menuFace.native.spec.tsx +280 -3
  277. package/src/FloatingPanel/FloatingPanel.seamlessCover.spec.tsx +237 -0
  278. package/src/FloatingPanel/PanelHeader.tsx +26 -0
  279. package/src/FloatingPanel/echoContext.ts +67 -0
  280. package/src/FloatingPanel/iconEcho.tsx +118 -0
  281. package/src/FloatingPanel/index.native.tsx +220 -12
  282. package/src/FloatingPanel/index.tsx +539 -109
  283. package/src/FloatingPanel/paintedBox.spec.ts +95 -0
  284. package/src/FloatingPanel/paintedBox.ts +75 -0
  285. package/src/FloatingPanel/panelWidth.spec.ts +158 -0
  286. package/src/FloatingPanel/panelWidth.ts +122 -0
  287. package/src/FloatingPanel/panelWidthContract.spec.ts +10 -10
  288. package/src/FloatingPanel/pointAnchor.spec.ts +111 -2
  289. package/src/FloatingPanel/pointAnchor.ts +56 -3
  290. package/src/FloatingPanel/useFloatingPanel.spec.tsx +124 -4
  291. package/src/FloatingPanel/useFloatingPanel.ts +112 -34
  292. package/src/InputParts/index.tsx +26 -0
  293. package/src/Wheel/NativeWheel.native.tsx +1 -1
  294. package/src/Wheel/Wheel.spec.tsx +9 -0
  295. package/src/Wheel/index.tsx +12 -3
  296. package/src/Wheel/wheelShared.ts +6 -2
  297. package/src/fields/Combobox/index.tsx +1 -0
  298. package/src/fields/DatePicker/DatePicker.stories.tsx +3 -3
  299. package/src/fields/DatePicker/DatetimePicker.catalog.tsx +17 -45
  300. package/src/fields/DatePicker/DatetimePicker.native.tsx +3 -0
  301. package/src/fields/DatePicker/catalog.tsx +8 -39
  302. package/src/fields/DatePicker/index.native.tsx +3 -0
  303. package/src/fields/DatePicker/parts.tsx +13 -23
  304. package/src/fields/DatePicker/seamlessCover.spec.tsx +180 -0
  305. package/src/fields/DatePicker/touchWeb.spec.tsx +109 -167
  306. package/src/fields/Select/Select.containingBlock.spec.tsx +191 -0
  307. package/src/fields/Select/Select.stories.tsx +43 -0
  308. package/src/fields/Select/index.tsx +109 -45
  309. package/src/fields/Select/shouldInlineChoices.spec.ts +13 -0
  310. package/src/fields/Select/shouldInlineChoices.ts +6 -0
  311. package/src/fields/TimePicker/catalog.tsx +12 -33
  312. package/src/fields/TimePicker/index.native.tsx +2 -0
  313. package/src/fields/TimePicker/parts.tsx +6 -20
  314. package/src/index.ts +3 -0
  315. package/src/shared/floatingList.tsx +21 -5
  316. package/types/Button/circleGlyph.d.ts +7 -0
  317. package/types/Button/circleGlyph.d.ts.map +1 -0
  318. package/types/Button/index.d.ts +2 -6
  319. package/types/Button/index.d.ts.map +1 -1
  320. package/types/FloatingPanel/PanelHeader.d.ts +9 -0
  321. package/types/FloatingPanel/PanelHeader.d.ts.map +1 -0
  322. package/types/FloatingPanel/echoContext.d.ts +38 -0
  323. package/types/FloatingPanel/echoContext.d.ts.map +1 -0
  324. package/types/FloatingPanel/iconEcho.d.ts +29 -0
  325. package/types/FloatingPanel/iconEcho.d.ts.map +1 -0
  326. package/types/FloatingPanel/index.d.ts +69 -0
  327. package/types/FloatingPanel/index.d.ts.map +1 -1
  328. package/types/FloatingPanel/index.native.d.ts +9 -1
  329. package/types/FloatingPanel/index.native.d.ts.map +1 -1
  330. package/types/FloatingPanel/paintedBox.d.ts +29 -0
  331. package/types/FloatingPanel/paintedBox.d.ts.map +1 -0
  332. package/types/FloatingPanel/panelWidth.d.ts +71 -0
  333. package/types/FloatingPanel/panelWidth.d.ts.map +1 -0
  334. package/types/FloatingPanel/pointAnchor.d.ts +17 -1
  335. package/types/FloatingPanel/pointAnchor.d.ts.map +1 -1
  336. package/types/FloatingPanel/useFloatingPanel.d.ts +33 -2
  337. package/types/FloatingPanel/useFloatingPanel.d.ts.map +1 -1
  338. package/types/InputParts/index.d.ts.map +1 -1
  339. package/types/Wheel/index.d.ts.map +1 -1
  340. package/types/Wheel/wheelShared.d.ts +2 -1
  341. package/types/Wheel/wheelShared.d.ts.map +1 -1
  342. package/types/fields/Combobox/index.d.ts.map +1 -1
  343. package/types/fields/DatePicker/DatetimePicker.catalog.d.ts +6 -0
  344. package/types/fields/DatePicker/DatetimePicker.catalog.d.ts.map +1 -1
  345. package/types/fields/DatePicker/DatetimePicker.native.d.ts +3 -0
  346. package/types/fields/DatePicker/DatetimePicker.native.d.ts.map +1 -1
  347. package/types/fields/DatePicker/catalog.d.ts +6 -0
  348. package/types/fields/DatePicker/catalog.d.ts.map +1 -1
  349. package/types/fields/DatePicker/index.native.d.ts +3 -0
  350. package/types/fields/DatePicker/index.native.d.ts.map +1 -1
  351. package/types/fields/DatePicker/parts.d.ts +5 -7
  352. package/types/fields/DatePicker/parts.d.ts.map +1 -1
  353. package/types/fields/Select/index.d.ts +8 -1
  354. package/types/fields/Select/index.d.ts.map +1 -1
  355. package/types/fields/Select/shouldInlineChoices.d.ts +5 -1
  356. package/types/fields/Select/shouldInlineChoices.d.ts.map +1 -1
  357. package/types/fields/TimePicker/catalog.d.ts +7 -1
  358. package/types/fields/TimePicker/catalog.d.ts.map +1 -1
  359. package/types/fields/TimePicker/index.native.d.ts +2 -0
  360. package/types/fields/TimePicker/index.native.d.ts.map +1 -1
  361. package/types/fields/TimePicker/parts.d.ts +1 -3
  362. package/types/fields/TimePicker/parts.d.ts.map +1 -1
  363. package/types/index.d.ts +3 -0
  364. package/types/index.d.ts.map +1 -1
  365. package/types/shared/floatingList.d.ts +5 -1
  366. package/types/shared/floatingList.d.ts.map +1 -1
  367. package/dist/cjs/shared/touchWebPicker.cjs +0 -136
  368. package/dist/cjs/shared/touchWebPicker.native.js +0 -154
  369. package/dist/cjs/shared/touchWebPicker.native.js.map +0 -1
  370. package/dist/esm/shared/touchWebPicker.mjs +0 -105
  371. package/dist/esm/shared/touchWebPicker.mjs.map +0 -1
  372. package/dist/esm/shared/touchWebPicker.native.js +0 -120
  373. package/dist/esm/shared/touchWebPicker.native.js.map +0 -1
  374. package/dist/jsx/shared/touchWebPicker.mjs +0 -105
  375. package/dist/jsx/shared/touchWebPicker.mjs.map +0 -1
  376. package/dist/jsx/shared/touchWebPicker.native.js +0 -154
  377. package/dist/jsx/shared/touchWebPicker.native.js.map +0 -1
  378. package/src/shared/touchWebPicker.spec.ts +0 -98
  379. package/src/shared/touchWebPicker.tsx +0 -158
  380. package/types/shared/touchWebPicker.d.ts +0 -40
  381. package/types/shared/touchWebPicker.d.ts.map +0 -1
@@ -52,6 +52,8 @@ import {
52
52
  import { ScrollArrow } from "../../shared/floatingList";
53
53
  import {
54
54
  FloatingPanel,
55
+ TriggerEchoRow,
56
+ placeEchoOverTrigger,
55
57
  useFloatingPanel,
56
58
  panelViewportPadding,
57
59
  useViewportGtSm,
@@ -59,6 +61,7 @@ import {
59
61
  import { pickerCompactFace, resolveCompactFace } from "../../FloatingPanel/compactFace";
60
62
  import { PanelPortal } from "../../FloatingPanel/PanelPortal";
61
63
  import { fixedContainingBlockOrigin } from "../../FloatingPanel/containingBlock";
64
+ import type { PanelWidth } from "../../FloatingPanel/panelWidth";
62
65
  import { useInsideOverlay, useOverlayZIndex } from "../../shared/overlayStack";
63
66
  import { useDragScroll } from "../../shared/useDragScroll";
64
67
  import { useIsInTableCell } from "../../shared/tableCellContext";
@@ -131,6 +134,12 @@ export interface SelectProps {
131
134
  * `multiple` is set, and on Android (the catalog sheet stays). Default false.
132
135
  */
133
136
  native?: boolean;
137
+ /**
138
+ * How wide the open list is (LC-112, FZ-8438 r3): `"content"`, `"trigger"`,
139
+ * `"screen"` or a fixed width. Unset keeps the default: at least the field's
140
+ * width on the web, the native pull-down's floor on a phone menu.
141
+ */
142
+ panelWidth?: PanelWidth;
134
143
  }
135
144
 
136
145
  // ── Lightweight item row (replaces heavy ListItem-based DropdownItem) ──
@@ -511,6 +520,7 @@ interface FloatingSelectCoreProps {
511
520
  selectedOrder?: SelectedOrder;
512
521
  dismissible?: boolean;
513
522
  native?: boolean;
523
+ panelWidth?: PanelWidth;
514
524
  }
515
525
  function FloatingSelectCore({
516
526
  options,
@@ -527,6 +537,7 @@ function FloatingSelectCore({
527
537
  multiple,
528
538
  selectedOrder,
529
539
  dismissible,
540
+ panelWidth,
530
541
  }: FloatingSelectCoreProps) {
531
542
  const overlayZIndex = useOverlayZIndex("dropdown");
532
543
  const { style: elevatedSurfaceStyle, ...elevatedSurfaceProps } = knobProps.elevatedSurface;
@@ -608,6 +619,10 @@ function FloatingSelectCore({
608
619
  const growUpOnlyRef = useRef(false);
609
620
  const growDownOnlyRef = useRef(false);
610
621
  const lastScrollTopRef = useRef(0);
622
+ // LC-112 drop-up (FZ-8438 r3): a field too low for its list opens upward,
623
+ // the panel's bottom edge on the field's, the echo its last row.
624
+ const dropUpRef = useRef(false);
625
+ const [dropUp, setDropUp] = useState(false);
611
626
 
612
627
  const repositionRef = useRef<(() => void) | null>(null);
613
628
 
@@ -627,7 +642,9 @@ function FloatingSelectCore({
627
642
  growDownOnlyRef.current = false;
628
643
  lastScrollTopRef.current = 0;
629
644
  programmaticScrollRef.current = 0;
645
+ dropUpRef.current = false;
630
646
  },
647
+ panelWidth,
631
648
  });
632
649
 
633
650
  const { scrollRef: dragScrollRef, dragProps } = useDragScroll({
@@ -700,6 +717,10 @@ function FloatingSelectCore({
700
717
 
701
718
  const triggerBounds = trigger.getBoundingClientRect();
702
719
  const viewportHeight = window.innerHeight;
720
+ // The math runs in viewport coordinates; a panel hosted in a transformed
721
+ // sheet lays out against that sheet, so the written top is offset by it
722
+ // (FZ-8438: an iPad Select inside a SheetModal opened far below its field).
723
+ const originTop = fixedContainingBlockOrigin(dropdownElement).top;
703
724
  const computedStyle = getComputedStyle(dropdownElement);
704
725
  const borderTopWidth = parseFloat(computedStyle.borderTopWidth) || 0;
705
726
  const borderBottomWidth = parseFloat(computedStyle.borderBottomWidth) || 0;
@@ -707,26 +728,27 @@ function FloatingSelectCore({
707
728
  const scrollContentHeight = dropdownElement.scrollHeight;
708
729
  const totalContentHeight = scrollContentHeight + totalBorderWidth;
709
730
 
710
- // Cover-alignment (OVERLAY_ANCHOR_GAP rule): the panel's border-box top
711
- // coincides with the trigger's border-box top EXACTLY, so frame, corner
712
- // arc and row text all line up (panel border draws over trigger border;
713
- // row content = panel.top + border + offsetTop lands on the trigger's
714
- // content edge). Subtracting the border here shifted the whole panel 1px
715
- // up and made the corner arcs visibly diverge from the trigger's.
716
- let idealTop: number;
717
- if (selectedIndex >= 0) {
718
- idealTop = triggerBounds.top - selectedItem.offsetTop;
719
- } else if (panel.placement.startsWith("top")) {
720
- idealTop = triggerBounds.bottom - totalContentHeight;
721
- } else {
722
- idealTop = triggerBounds.top - (selectedItem.offsetTop ?? 0);
731
+ // LC-112 seamless cover (FZ-8438): the panel's top edge is the trigger's,
732
+ // the trigger echoed as its first row, the list below it. A field too low
733
+ // for its list, with more room above it, opens upward instead: the
734
+ // panel's bottom edge on the field's bottom edge and the echo its last
735
+ // row, so the echo still sits on the field (FZ-8438 r3).
736
+ const firstPlacement = pinnedTopRef.current === 0 && pinnedHeightRef.current === 0;
737
+ const roomBelow = viewportHeight - panelViewportPadding - triggerBounds.top;
738
+ const roomAbove = triggerBounds.bottom - panelViewportPadding;
739
+ if (firstPlacement) {
740
+ dropUpRef.current = totalContentHeight > roomBelow && roomAbove > roomBelow;
741
+ setDropUp(dropUpRef.current);
723
742
  }
724
- const idealBottom = idealTop + totalContentHeight;
743
+ const idealTop = dropUpRef.current
744
+ ? triggerBounds.bottom - totalContentHeight
745
+ : triggerBounds.top;
746
+ const idealBottom = dropUpRef.current ? triggerBounds.bottom : idealTop + totalContentHeight;
725
747
  const pinnedTop = Math.max(panelViewportPadding, idealTop);
726
748
  const pinnedBottom = Math.min(viewportHeight - panelViewportPadding, idealBottom);
727
749
  const pinnedHeight = Math.max(120, pinnedBottom - pinnedTop);
728
750
 
729
- if (pinnedTopRef.current === 0 && pinnedHeightRef.current === 0) {
751
+ if (firstPlacement) {
730
752
  pinnedTopRef.current = pinnedTop;
731
753
  pinnedHeightRef.current = pinnedHeight;
732
754
  }
@@ -735,7 +757,10 @@ function FloatingSelectCore({
735
757
  let height = pinnedHeightRef.current;
736
758
 
737
759
  if (grownRef.current) {
738
- const canGrowDown = Math.max(0, viewportHeight - panelViewportPadding - (top + height));
760
+ // A drop-up keeps its echo on the field: it grows upward only.
761
+ const canGrowDown = dropUpRef.current
762
+ ? 0
763
+ : Math.max(0, viewportHeight - panelViewportPadding - (top + height));
739
764
  height += canGrowDown;
740
765
  const canGrowUp = Math.max(0, top - panelViewportPadding);
741
766
  top -= canGrowUp;
@@ -747,7 +772,7 @@ function FloatingSelectCore({
747
772
  top -= canGrowUp;
748
773
  height += canGrowUp;
749
774
  }
750
- if (growDownOnlyRef.current) {
775
+ if (growDownOnlyRef.current && !dropUpRef.current) {
751
776
  const canGrowDown = Math.max(0, viewportHeight - panelViewportPadding - (top + height));
752
777
  height += canGrowDown;
753
778
  }
@@ -773,43 +798,59 @@ function FloatingSelectCore({
773
798
 
774
799
  if (
775
800
  !cachedOverlayStyle ||
776
- cachedOverlayStyle.top !== top ||
801
+ cachedOverlayStyle.top !== top - originTop ||
777
802
  cachedOverlayStyle.maxHeight !== height
778
803
  ) {
779
- dropdownElement.style.top = `${top}px`;
804
+ dropdownElement.style.top = `${top - originTop}px`;
780
805
  dropdownElement.style.maxHeight = `${height}px`;
781
806
  dropdownElement.style.height = "";
782
- overlayStyle.current = { top, maxHeight: height };
807
+ overlayStyle.current = { top: top - originTop, maxHeight: height };
783
808
  void dropdownElement.offsetHeight;
784
809
  }
785
810
 
786
- if (!grownRef.current && !growUpOnlyRef.current && !growDownOnlyRef.current) {
787
- const maxScrollTop = dropdownElement.scrollHeight - dropdownElement.clientHeight;
788
- if (selectedIndex >= 0) {
789
- // Row-over-trigger: row y (top + border + offsetTop − scroll) must
790
- // land on the trigger's content edge (trigger.top + border).
791
- const neededScroll = top + selectedItem.offsetTop - triggerBounds.top;
792
- const clampedScrollTop = Math.max(0, Math.min(neededScroll, maxScrollTop));
793
- if (Math.abs(dropdownElement.scrollTop - clampedScrollTop) > 0.5) {
811
+ if (
812
+ isInitial &&
813
+ selectedIndex >= 0 &&
814
+ !grownRef.current &&
815
+ !growUpOnlyRef.current &&
816
+ !growDownOnlyRef.current
817
+ ) {
818
+ // The selected row starts in view, just under the sticky echo row (or
819
+ // just above it in a drop-up, where the echo is the last row).
820
+ const echoHeight = triggerBounds.height;
821
+ const rowBottom = selectedItem.offsetTop + selectedItem.offsetHeight;
822
+ if (dropUpRef.current) {
823
+ const maxScrollTop = dropdownElement.scrollHeight - dropdownElement.clientHeight;
824
+ const wanted = rowBottom - (dropdownElement.clientHeight - echoHeight);
825
+ if (wanted > 0) {
794
826
  programmaticScrollRef.current++;
795
- dropdownElement.scrollTop = clampedScrollTop;
796
- }
797
- if (Math.abs(neededScroll - clampedScrollTop) > 0.5) {
798
- const scrollDeficit = neededScroll - clampedScrollTop;
799
- top -= scrollDeficit;
800
- top = Math.max(panelViewportPadding, top);
801
- const remainingContentHeight = totalContentHeight - clampedScrollTop;
802
- const adjustedMaxHeight = Math.min(
803
- remainingContentHeight,
804
- viewportHeight - top - panelViewportPadding,
805
- );
806
- dropdownElement.style.top = `${top}px`;
807
- dropdownElement.style.maxHeight = `${adjustedMaxHeight}px`;
808
- overlayStyle.current = { top, maxHeight: adjustedMaxHeight };
827
+ dropdownElement.scrollTop = Math.min(wanted, maxScrollTop);
809
828
  }
829
+ } else if (rowBottom > dropdownElement.clientHeight) {
830
+ const maxScrollTop = dropdownElement.scrollHeight - dropdownElement.clientHeight;
831
+ programmaticScrollRef.current++;
832
+ dropdownElement.scrollTop = Math.max(
833
+ 0,
834
+ Math.min(selectedItem.offsetTop - echoHeight, maxScrollTop),
835
+ );
810
836
  }
811
837
  }
812
838
 
839
+ // A screen-wide or fixed-width list slides inside the margins; its echo
840
+ // stays on the field (LC-112 r3). The scale origin is the left edge, so
841
+ // the client rect's left is the layout left.
842
+ placeEchoOverTrigger(
843
+ dropdownElement,
844
+ {
845
+ triggerLeft: triggerBounds.left,
846
+ triggerRight: triggerBounds.right,
847
+ panelLeft: dropdownElement.getBoundingClientRect().left,
848
+ panelWidth: dropdownElement.offsetWidth,
849
+ rtl: getComputedStyle(trigger).direction === "rtl",
850
+ },
851
+ { stretch: panelWidth !== undefined },
852
+ );
853
+
813
854
  panel.initializingRef.current = false;
814
855
 
815
856
  void dropdownElement.offsetHeight;
@@ -837,7 +878,7 @@ function FloatingSelectCore({
837
878
  useLayoutEffect(() => {
838
879
  if (!open || !panel.mounted) return;
839
880
  repositionOverlay();
840
- }, [open, panel.mounted, selectedIndex, repositionOverlay, panel.y]);
881
+ }, [open, panel.mounted, selectedIndex, repositionOverlay, panel.x, panel.y]);
841
882
 
842
883
  const onMatch = useCallback(
843
884
  (index: number) => {
@@ -1163,7 +1204,8 @@ function FloatingSelectCore({
1163
1204
  opacity: panel.visible ? 1 : 0,
1164
1205
  transform: panel.visible ? "scale(1)" : "scale(0.96)",
1165
1206
  transition: panel.panelTransition,
1166
- transformOrigin: panel.placement.startsWith("top") ? "bottom left" : "top left",
1207
+ transformOrigin:
1208
+ dropUp || panel.placement.startsWith("top") ? "bottom left" : "top left",
1167
1209
  ...dragProps.style,
1168
1210
  },
1169
1211
  onPointerDown: dragProps.onPointerDown,
@@ -1204,12 +1246,27 @@ function FloatingSelectCore({
1204
1246
  borderRadius={panel.dropdownRadius}
1205
1247
  data-testid="select-dropdown"
1206
1248
  paddingVertical={0}
1249
+ paddingBottom={panel.coverCornerInset || 0}
1207
1250
  >
1251
+ {!beside && (
1252
+ <TriggerEchoRow
1253
+ sourceRef={panel.triggerRef}
1254
+ source={selectedOption?.label ?? placeholder}
1255
+ onPress={() => setOpen(false)}
1256
+ presentational
1257
+ edge={dropUp ? "bottom" : "top"}
1258
+ />
1259
+ )}
1208
1260
  <ScrollArrow
1209
1261
  direction="up"
1210
1262
  scrollRef={panel.refs.floating}
1211
1263
  visible={panel.arrowUp}
1212
1264
  arrowScrollDirRef={panel.arrowScrollDirRef}
1265
+ topOffset={
1266
+ dropUp || beside
1267
+ ? 0
1268
+ : (panel.triggerRef.current?.getBoundingClientRect().height ?? 0)
1269
+ }
1213
1270
  />
1214
1271
  {groupLabel && (
1215
1272
  <GroupHeader color={textColor} paddingHorizontal={knobProps.panelPadding.padding}>
@@ -1260,6 +1317,9 @@ function FloatingSelectCore({
1260
1317
  scrollRef={panel.refs.floating}
1261
1318
  visible={panel.arrowDown}
1262
1319
  arrowScrollDirRef={panel.arrowScrollDirRef}
1320
+ bottomOffset={
1321
+ dropUp ? (panel.triggerRef.current?.getBoundingClientRect().height ?? 0) : 0
1322
+ }
1263
1323
  />
1264
1324
  </YStack>
1265
1325
  </FloatingFocusManager>
@@ -1287,6 +1347,7 @@ function NativeSelectCore({
1287
1347
  selectedOrder,
1288
1348
  dismissible,
1289
1349
  native,
1350
+ panelWidth,
1290
1351
  }: FloatingSelectCoreProps) {
1291
1352
  const insideOverlay = useInsideOverlay();
1292
1353
  const compactFace = pickerCompactFace(options.length);
@@ -1591,6 +1652,7 @@ function NativeSelectCore({
1591
1652
  // A short list opens as a menu over its trigger; a long one keeps its
1592
1653
  // sheet at page level and opens as a menu inside another overlay (FZ-7830).
1593
1654
  compactFace={compactFace}
1655
+ panelWidth={panelWidth}
1594
1656
  {...(asMenu && insideOverlay && opensBesideTrigger(options.length)
1595
1657
  ? { anchorMode: "attach" as const, triggerEcho: false }
1596
1658
  : null)}
@@ -1740,6 +1802,7 @@ export function Select({
1740
1802
  dismissible,
1741
1803
  skeleton,
1742
1804
  native,
1805
+ panelWidth,
1743
1806
  "aria-label": ariaLabel,
1744
1807
  ...rest
1745
1808
  }: SelectProps) {
@@ -1781,7 +1844,7 @@ export function Select({
1781
1844
  !inline &&
1782
1845
  !inTableCell &&
1783
1846
  Boolean(rowLabel) &&
1784
- shouldPushChoices({ inSheet: Boolean(sheetNavigation), multiple, options });
1847
+ shouldPushChoices({ inSheet: Boolean(sheetNavigation), multiple, options, panelWidth });
1785
1848
  // DG-CTRL-01 / DG-CTRL-05 — short single-select lists prefer RadioGroup,
1786
1849
  // which the inline face already is.
1787
1850
  if (!inline) {
@@ -1920,6 +1983,7 @@ export function Select({
1920
1983
  selectedOrder={selectedOrder}
1921
1984
  dismissible={dismissible}
1922
1985
  native={native}
1986
+ panelWidth={panelWidth}
1923
1987
  />
1924
1988
  );
1925
1989
  };
@@ -37,6 +37,19 @@ describe("shouldPushChoices and opensBesideTrigger (LC-262, FZ-7830 round 3)", (
37
37
  expect(shouldPushChoices({ inSheet: true, multiple: true, options: withIcons(8) })).toBe(false);
38
38
  });
39
39
 
40
+ it("never pushes a list whose panel width is trigger or screen: it covers its trigger (FZ-8438)", () => {
41
+ expect(shouldPushChoices({ inSheet: true, options: withIcons(8), panelWidth: "trigger" })).toBe(
42
+ false,
43
+ );
44
+ expect(shouldPushChoices({ inSheet: true, options: withIcons(8), panelWidth: "screen" })).toBe(
45
+ false,
46
+ );
47
+ expect(shouldPushChoices({ inSheet: true, options: withIcons(8), panelWidth: "content" })).toBe(
48
+ true,
49
+ );
50
+ expect(shouldPushChoices({ inSheet: true, options: withIcons(8), panelWidth: 300 })).toBe(true);
51
+ });
52
+
40
53
  it("opens a list of five or fewer beside its field", () => {
41
54
  expect(opensBesideTrigger(5)).toBe(true);
42
55
  expect(opensBesideTrigger(6)).toBe(false);
@@ -1,4 +1,5 @@
1
1
  import type { ReactNode } from "react";
2
+ import type { PanelWidth } from "../../FloatingPanel/panelWidth";
2
3
 
3
4
  /** The most options a Select inside a sheet lays out inline (LC-262). */
4
5
  export const INLINE_CHOICES_MAX = 5;
@@ -25,17 +26,22 @@ export function shouldInlineChoices({
25
26
  * A single-choice Select inside a sheet with more options than the inline
26
27
  * list holds pushes its checkmark list onto the sheet's navigation stack from
27
28
  * a Settings row (LC-262, FZ-7830 round 3), instead of a menu over the field.
29
+ * An explicit `"trigger"` or `"screen"` panel width asks for a cover over the
30
+ * trigger (LC-112, FZ-8438 r3), so that Select is never pushed.
28
31
  */
29
32
  export function shouldPushChoices({
30
33
  inSheet,
31
34
  multiple,
32
35
  options,
36
+ panelWidth,
33
37
  }: {
34
38
  inSheet: boolean;
35
39
  multiple?: boolean;
36
40
  options: ReadonlyArray<unknown> | undefined;
41
+ panelWidth?: PanelWidth;
37
42
  }): boolean {
38
43
  if (!inSheet || multiple || !options?.length) return false;
44
+ if (panelWidth === "trigger" || panelWidth === "screen") return false;
39
45
  return options.length > INLINE_CHOICES_MAX;
40
46
  }
41
47
 
@@ -5,6 +5,7 @@ import { isWeb } from "tamagui";
5
5
  import { Skeleton } from "../../Skeleton";
6
6
  import { Field, FieldLayout } from "../../fieldLayout";
7
7
  import { FloatingPanel } from "../../FloatingPanel";
8
+ import type { PanelWidth } from "../../FloatingPanel/panelWidth";
8
9
  import { Input as InputParts } from "../../InputParts";
9
10
  import { t } from "../../shared/t";
10
11
  import {
@@ -14,12 +15,6 @@ import {
14
15
  useResolvedValidators,
15
16
  } from "../../shared/utils";
16
17
  import type { AnyFormApi } from "../../types";
17
- import {
18
- fromTimeInputValue,
19
- toTimeInputValue,
20
- TouchWebPickerInput,
21
- useCoarsePointer,
22
- } from "../../shared/touchWebPicker";
23
18
  import {
24
19
  TimePanel,
25
20
  TimePickerClearButton,
@@ -62,6 +57,11 @@ export interface TimePickerProps {
62
57
  skeleton?: boolean;
63
58
  /** Native only. Omit for the OS time wheel; `false` keeps the catalog panel. */
64
59
  native?: boolean;
60
+ /**
61
+ * How wide the open wheels are (LC-112, FZ-8438 r3): `"content"`,
62
+ * `"trigger"`, `"screen"` or a fixed width. Unset: at least the field.
63
+ */
64
+ panelWidth?: PanelWidth;
65
65
  }
66
66
 
67
67
  export function TimePicker({
@@ -87,13 +87,13 @@ export function TimePicker({
87
87
  placeholder = t("Select time"),
88
88
  clockIcon,
89
89
  skeleton,
90
+ panelWidth,
90
91
  }: TimePickerProps) {
91
92
  const { resolvedForm, knobProps, id } = useFormField({
92
93
  form: formProp,
93
94
  id: idProp,
94
95
  });
95
96
  const resolvedValidators = useResolvedValidators(required, validators, label, name);
96
- const touchWeb = useCoarsePointer();
97
97
  const [open, setOpen] = useState(false);
98
98
  const [internalValue, setInternalValue] = useState<string>(() => valueProp ?? defaultValue ?? "");
99
99
  useEffect(() => {
@@ -174,32 +174,6 @@ export function TimePicker({
174
174
  if (readOnly) {
175
175
  return renderTrigger(triggerValue, hasError, undefined, true);
176
176
  }
177
- if (touchWeb) {
178
- return (
179
- <TimePickerInputTrigger
180
- value={triggerValue}
181
- placeholder={placeholder}
182
- disabled={disabled}
183
- clockIcon={clockIcon}
184
- onOpen={() => {}}
185
- onClear={() => handleClear(fieldChange)}
186
- touchInput={
187
- <TouchWebPickerInput
188
- kind="time"
189
- id={id}
190
- value={toTimeInputValue(fieldValue ?? value, showSeconds)}
191
- showSeconds={showSeconds}
192
- disabled={disabled}
193
- required={required}
194
- invalid={hasError}
195
- aria-label={label ? undefined : t("Time")}
196
- onValue={(next) => handleChange(fromTimeInputValue(next, showSeconds), fieldChange)}
197
- onBlur={blurHandler}
198
- />
199
- }
200
- />
201
- );
202
- }
203
177
  return (
204
178
  <FloatingPanel
205
179
  open={open}
@@ -210,7 +184,12 @@ export function TimePicker({
210
184
  disabled={disabled}
211
185
  sizing="grow"
212
186
  widthMode="at-least-trigger"
187
+ panelWidth={panelWidth}
213
188
  contentPadding="none"
189
+ // LC-112 seamless cover (FZ-8438): touch and narrow web open the same
190
+ // wheels over the field, never the browser's own popover; a field too
191
+ // low for the panel takes MPO's bottom sheet (LC-105 collision).
192
+ compactFace={isWeb ? "menu" : undefined}
214
193
  triggerA11y={{
215
194
  label: (typeof label === "string" && label) || t("Time"),
216
195
  value: triggerValue || placeholder,
@@ -49,6 +49,8 @@ export type TimePickerProps = {
49
49
  clockIcon?: import("react").ReactNode;
50
50
  skeleton?: boolean;
51
51
  native?: boolean;
52
+ /** How wide the catalog picker opens (`native={false}`), LC-112. */
53
+ panelWidth?: import("../../FloatingPanel/panelWidth").PanelWidth;
52
54
  };
53
55
 
54
56
  export type { TimeFormat } from "./parts";
@@ -124,8 +124,6 @@ interface TimePickerInputTriggerProps {
124
124
  "aria-readonly"?: boolean;
125
125
  /** FZ-7853: same shell, no clear action, nothing opens. */
126
126
  readOnly?: boolean;
127
- /** Touch web (LC-266): the browser's time input, laid over the box; it owns tap, focus and name. */
128
- touchInput?: ReactNode;
129
127
  }
130
128
 
131
129
  export function TimePickerInputTrigger({
@@ -141,9 +139,8 @@ export function TimePickerInputTrigger({
141
139
  "aria-invalid": ariaInvalid,
142
140
  "aria-readonly": ariaReadonly,
143
141
  readOnly,
144
- touchInput,
145
142
  }: TimePickerInputTriggerProps) {
146
- const interactive = !disabled && !readOnly && !touchInput;
143
+ const interactive = !disabled && !readOnly;
147
144
  return (
148
145
  <View
149
146
  flexDirection="row"
@@ -160,11 +157,9 @@ export function TimePickerInputTrigger({
160
157
  flex={1}
161
158
  minWidth={0}
162
159
  elevation={undefined}
163
- position={touchInput ? "relative" : undefined}
164
160
  onPress={isWeb && interactive ? onOpen : undefined}
165
161
  {...(disabled ? { opacity: 0.5, pointerEvents: "none" as const } : undefined)}
166
162
  >
167
- {touchInput}
168
163
  <InputParts.Section data-testid="time-picker-glyph">
169
164
  <InputParts.Icon adornment="leading" color={formCommonColors.muted}>
170
165
  {clockIcon ?? <ClockIcon />}
@@ -174,17 +169,15 @@ export function TimePickerInputTrigger({
174
169
  <InputParts.Area
175
170
  readOnly
176
171
  {...(readOnly ? undefined : { pointerEvents: "none" as const })}
177
- id={touchInput ? undefined : id}
172
+ id={id}
178
173
  value={value}
179
174
  placeholder={placeholder}
180
175
  disabled={disabled}
181
176
  color={formCommonColors.text}
182
177
  placeholderTextColor={formCommonColors.muted}
183
- tabIndex={touchInput ? -1 : undefined}
184
- aria-hidden={touchInput ? true : undefined}
185
- aria-label={touchInput ? undefined : ariaLabel}
186
- aria-required={touchInput ? undefined : ariaRequired}
187
- aria-invalid={touchInput ? undefined : ariaInvalid}
178
+ aria-label={ariaLabel}
179
+ aria-required={ariaRequired}
180
+ aria-invalid={ariaInvalid}
188
181
  aria-readonly={readOnly || ariaReadonly || undefined}
189
182
  onKeyPress={
190
183
  !interactive
@@ -205,14 +198,7 @@ export function TimePickerInputTrigger({
205
198
  </InputParts.Section>
206
199
  {value && isWeb && !readOnly ? (
207
200
  <InputParts.Section>
208
- {touchInput ? (
209
- // Above the touch input, so Clear stays reachable on the box.
210
- <View zIndex={2}>
211
- <TimePickerClearButton onClear={onClear} disabled={disabled} />
212
- </View>
213
- ) : (
214
- <TimePickerClearButton onClear={onClear} disabled={disabled} />
215
- )}
201
+ <TimePickerClearButton onClear={onClear} disabled={disabled} />
216
202
  </InputParts.Section>
217
203
  ) : null}
218
204
  </InputParts.Box>
package/src/index.ts CHANGED
@@ -307,6 +307,7 @@ export {
307
307
  panelTransition,
308
308
  panelViewportPadding,
309
309
  } from "./FloatingPanel";
310
+ export { PanelHeader } from "./FloatingPanel/PanelHeader";
310
311
  export { PanelPortal } from "./FloatingPanel/PanelPortal";
311
312
  export type { PanelPortalProps } from "./FloatingPanel/PanelPortal";
312
313
  export { containsAcrossPanels } from "./shared/panelPortal";
@@ -316,6 +317,8 @@ export type {
316
317
  UseFloatingPanelOptions,
317
318
  UseFloatingPanelReturn,
318
319
  } from "./FloatingPanel";
320
+ export type { PanelWidth } from "./FloatingPanel/panelWidth";
321
+ export type { IconEcho } from "./FloatingPanel/iconEcho";
319
322
 
320
323
  // ── Adaptive Popup (Dialog / Drawer on desktop, Sheet on mobile) ─
321
324
  export { AdaptivePopup, pickAdaptivePopupFace } from "./AdaptivePopup";
@@ -1,5 +1,5 @@
1
1
  import { transitionProps } from "@multiplatform.one/theme";
2
- import { type RefObject, useCallback, useEffect, useRef } from "react";
2
+ import { type RefObject, useCallback, useEffect, useRef, useState } from "react";
3
3
  import { CaretDownIcon, CaretUpIcon } from "@phosphor-icons/react";
4
4
  import { useResolvedKnobs } from "@multiplatform.one/theme";
5
5
  import { View } from "tamagui";
@@ -33,11 +33,17 @@ export function ScrollArrow({
33
33
  scrollRef,
34
34
  visible,
35
35
  arrowScrollDirRef,
36
+ topOffset = 0,
37
+ bottomOffset = 0,
36
38
  }: {
37
39
  direction: "up" | "down";
38
40
  scrollRef: RefObject<HTMLElement | null>;
39
41
  visible: boolean;
40
42
  arrowScrollDirRef: RefObject<"up" | "down" | null>;
43
+ /** Below a sticky echo row (LC-112 seamless cover), the up arrow sits under it. */
44
+ topOffset?: number;
45
+ /** Above a sticky echo row at the bottom (a drop-up), the down arrow sits over it. */
46
+ bottomOffset?: number;
41
47
  }) {
42
48
  const isUp = direction === "up";
43
49
  const animationFrameRef = useRef(0);
@@ -137,6 +143,14 @@ export function ScrollArrow({
137
143
  [handlePointerLeave],
138
144
  );
139
145
 
146
+ const [panelFill, setPanelFill] = useState("var(--background)");
147
+ useEffect(() => {
148
+ if (!visible || typeof getComputedStyle !== "function") return;
149
+ const el = scrollRef.current;
150
+ const fill = el ? getComputedStyle(el).backgroundColor : "";
151
+ if (fill && fill !== "transparent" && fill !== "rgba(0, 0, 0, 0)") setPanelFill(fill);
152
+ }, [visible, scrollRef]);
153
+
140
154
  const Icon = isUp ? CaretUpIcon : CaretDownIcon;
141
155
  const { knobProps } = useResolvedKnobs();
142
156
  const iconSize = knobProps.controlIcon.width;
@@ -144,8 +158,8 @@ export function ScrollArrow({
144
158
  return (
145
159
  <View
146
160
  position="sticky"
147
- top={isUp ? 0 : undefined}
148
- bottom={isUp ? undefined : 0}
161
+ top={isUp ? topOffset : undefined}
162
+ bottom={isUp ? undefined : bottomOffset}
149
163
  height={0}
150
164
  zIndex={2}
151
165
  >
@@ -165,10 +179,12 @@ export function ScrollArrow({
165
179
  pointerEvents={visible ? "auto" : "none"}
166
180
  opacity={visible ? 1 : 0}
167
181
  {...transitionProps(knobProps.motion.control)}
182
+ // The fade is the panel's own fill: an elevated dark panel is a step
183
+ // above the theme ground, and a ground-coloured fade read as a band.
168
184
  style={{
169
185
  background: isUp
170
- ? "linear-gradient(to bottom, var(--background) 40%, transparent)"
171
- : "linear-gradient(to top, var(--background) 40%, transparent)",
186
+ ? `linear-gradient(to bottom, ${panelFill} 40%, transparent)`
187
+ : `linear-gradient(to top, ${panelFill} 40%, transparent)`,
172
188
  }}
173
189
  onPointerEnter={visible ? handlePointerEnter : undefined}
174
190
  onPointerLeave={handlePointerLeave}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * LC-176: a glyph on a circle the caller asked for (`circular`, `outlined`)
3
+ * fills this share of the circle, the iOS Settings and Contacts leading-icon
4
+ * ratio, never a small glyph lost in a big plate.
5
+ */
6
+ export declare const ICON_BUTTON_CIRCLE_GLYPH_RATIO = 0.58;
7
+ //# sourceMappingURL=circleGlyph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circleGlyph.d.ts","sourceRoot":"","sources":["../../src/Button/circleGlyph.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,OAAO,CAAC"}
@@ -3,6 +3,8 @@ import { type RecipeFamilyName, type SizeRecipe } from "@multiplatform.one/theme
3
3
  import { type ButtonProps as TamaguiButtonProps } from "tamagui";
4
4
  import type { AnyFormApi } from "../types";
5
5
  import type { SizeTokens } from "@tamagui/web";
6
+ import { ICON_BUTTON_CIRCLE_GLYPH_RATIO } from "./circleGlyph";
7
+ export { ICON_BUTTON_CIRCLE_GLYPH_RATIO };
6
8
  /**
7
9
  * Coordinated size recipe (Polaris slim/medium/large, Primer s/m/l, Linear
8
10
  * 28/32/40, Spectrum S/M, M3 XS/S). Height, pad, type, icon, gap and radius
@@ -171,12 +173,6 @@ export declare const ICON_BUTTON_NEUTRAL_GLYPH_PX = 24;
171
173
  * target.
172
174
  */
173
175
  export declare function iconButtonGlyphPx(rowLinePx: number | undefined): number;
174
- /**
175
- * LC-176: a glyph on a circle the caller asked for (`circular`, `outlined`)
176
- * fills this share of the circle, the iOS Settings and Contacts leading-icon
177
- * ratio, never a small glyph lost in a big plate.
178
- */
179
- export declare const ICON_BUTTON_CIRCLE_GLYPH_RATIO = 0.58;
180
176
  export declare function Button({ children, action, form: formProp, loading, accent, error, warning, success, skeleton, outlined, disabled, theme, onPress, onKeyDown, tabIndex, icon, iconAfter, selected, nested, circular: circularProp, chromeless, edge, accentInk, plate, inline, glyphWeight, verb, noun, actionRole, disabledReason, disabledReasonPlacement, sizeRecipeEscape, recipeFamily, height: heightProp, paddingHorizontal: paddingHorizontalProp, ...props }: ButtonProps): import("react/jsx-runtime").JSX.Element;
181
177
  export declare namespace Button {
182
178
  var Icon: (props: {