@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
@@ -0,0 +1,95 @@
1
+ /**
2
+ * LC-112 (FZ-8480): a panel covering an icon trigger covers the button as it
3
+ * is drawn. The 1440 + hung 6px past its layout slot on its press slop, and
4
+ * the 390 + sat in a lone glass capsule 6px wider on each side; both left a
5
+ * sliver of the button showing beside the panel.
6
+ */
7
+ import { afterEach, describe, expect, it } from "vitest";
8
+ import { PAINTED_BOX_REACH, paintedTriggerBox } from "./paintedBox";
9
+
10
+ type Rect = [left: number, top: number, width: number, height: number];
11
+
12
+ function el(rect: Rect | null, children: HTMLElement[] = [], style = "") {
13
+ const node = document.createElement("div");
14
+ if (style) node.setAttribute("style", style);
15
+ for (const child of children) node.appendChild(child);
16
+ const [left, top, width, height] = rect ?? [0, 0, 0, 0];
17
+ node.getBoundingClientRect = () =>
18
+ ({
19
+ left,
20
+ top,
21
+ width,
22
+ height,
23
+ x: left,
24
+ y: top,
25
+ right: left + width,
26
+ bottom: top + height,
27
+ toJSON: () => ({}),
28
+ }) as DOMRect;
29
+ return node;
30
+ }
31
+
32
+ const box = ([left, top, width, height]: Rect) => ({
33
+ left,
34
+ top,
35
+ right: left + width,
36
+ bottom: top + height,
37
+ });
38
+
39
+ afterEach(() => {
40
+ document.body.replaceChildren();
41
+ });
42
+
43
+ describe("paintedTriggerBox (FZ-8480)", () => {
44
+ it("takes in a bare glyph's press box that hangs past its layout slot", () => {
45
+ const button = el([1302.5, 61, 40, 40]);
46
+ const reference = el([1302.5, 61, 34, 40], [el(null, [button], "display: contents")]);
47
+ document.body.appendChild(el([1302.5, 61, 34, 40], [reference]));
48
+ expect(paintedTriggerBox(reference, box([1302.5, 61, 34, 40]))).toEqual(
49
+ box([1302.5, 61, 40, 40]),
50
+ );
51
+ });
52
+
53
+ it("takes in a lone button's plate, ignoring the plate's absolute face", () => {
54
+ const reference = el([324, 61, 44, 44]);
55
+ const face = el([318, 61, 56, 44], [], "position: absolute");
56
+ const capsule = el([318, 61, 56, 44], [face, reference]);
57
+ const row = el([16, 61, 358, 44], [el([16, 61, 200, 44]), capsule]);
58
+ document.body.appendChild(row);
59
+ expect(paintedTriggerBox(reference, box([324, 61, 44, 44]))).toEqual(box([318, 61, 56, 44]));
60
+ });
61
+
62
+ it("stops at a wrapper shared with other content", () => {
63
+ const reference = el([290, 0, 44, 44]);
64
+ const pill = el([214, 0, 160, 44], [el([220, 0, 44, 44]), reference]);
65
+ document.body.appendChild(pill);
66
+ expect(paintedTriggerBox(reference, box([290, 0, 44, 44]))).toEqual(box([290, 0, 44, 44]));
67
+ });
68
+
69
+ it("reads a DOMRect layout box, whose sides are prototype getters", () => {
70
+ const reference = el([324, 61, 44, 44]);
71
+ document.body.appendChild(el([16, 61, 358, 44], [el([16, 61, 200, 44]), reference]));
72
+ class Getters {
73
+ get left() {
74
+ return 324;
75
+ }
76
+ get top() {
77
+ return 61;
78
+ }
79
+ get right() {
80
+ return 368;
81
+ }
82
+ get bottom() {
83
+ return 105;
84
+ }
85
+ }
86
+ const layout = new Getters();
87
+ expect(paintedTriggerBox(reference, layout)).toEqual(box([324, 61, 44, 44]));
88
+ });
89
+
90
+ it(`never reaches more than ${PAINTED_BOX_REACH}px past the trigger`, () => {
91
+ const reference = el([324, 61, 44, 44]);
92
+ document.body.appendChild(el([0, 61, 390, 44], [reference]));
93
+ expect(paintedTriggerBox(reference, box([324, 61, 44, 44]))).toEqual(box([324, 61, 44, 44]));
94
+ });
95
+ });
@@ -0,0 +1,75 @@
1
+ export type Box = { left: number; top: number; right: number; bottom: number };
2
+
3
+ /** How far a trigger's plate or press box may reach past its layout box. */
4
+ export const PAINTED_BOX_REACH = 12;
5
+
6
+ function inFlowChildren(element: Element): Element[] {
7
+ return Array.from(element.children).filter((child) => {
8
+ const style = getComputedStyle(child);
9
+ return style.display !== "none" && style.position !== "absolute" && style.position !== "fixed";
10
+ });
11
+ }
12
+
13
+ /**
14
+ * The box an icon trigger is seen in, which a panel covering it has to cover
15
+ * (LC-112, FZ-8480). A bare glyph's press box can hang past its layout slot
16
+ * (the trailing press slop), and a lone button's plate can be a wrapper that
17
+ * holds nothing else (an iOS glass capsule). Both count, up to
18
+ * {@link PAINTED_BOX_REACH} on any side; a wrapper shared with other content
19
+ * ends the walk.
20
+ */
21
+ export function paintedTriggerBox(reference: Element, layout: Box): Box {
22
+ // A DOMRect's sides are prototype getters, so spreading it copies nothing.
23
+ const box = { left: layout.left, top: layout.top, right: layout.right, bottom: layout.bottom };
24
+ const take = (rect: DOMRect) => {
25
+ if (rect.width <= 0 || rect.height <= 0) return true;
26
+ const next = {
27
+ left: Math.min(box.left, rect.left),
28
+ top: Math.min(box.top, rect.top),
29
+ right: Math.max(box.right, rect.right),
30
+ bottom: Math.max(box.bottom, rect.bottom),
31
+ };
32
+ if (
33
+ layout.left - next.left > PAINTED_BOX_REACH ||
34
+ layout.top - next.top > PAINTED_BOX_REACH ||
35
+ next.right - layout.right > PAINTED_BOX_REACH ||
36
+ next.bottom - layout.bottom > PAINTED_BOX_REACH
37
+ ) {
38
+ return false;
39
+ }
40
+ Object.assign(box, next);
41
+ return true;
42
+ };
43
+ let inner: Element | null = reference;
44
+ while (inner) {
45
+ const children = inFlowChildren(inner);
46
+ if (children.length !== 1) break;
47
+ inner = children[0]!;
48
+ if (!take(inner.getBoundingClientRect())) break;
49
+ }
50
+ let outer: Element | null = reference.parentElement;
51
+ let child: Element = reference;
52
+ while (outer && outer.tagName !== "BODY") {
53
+ const children = inFlowChildren(outer);
54
+ if (children.length !== 1 || children[0] !== child) break;
55
+ if (!take(outer.getBoundingClientRect())) break;
56
+ child = outer;
57
+ outer = outer.parentElement;
58
+ }
59
+ return box;
60
+ }
61
+
62
+ /**
63
+ * A plate several buttons share (an iOS glass capsule around a bar's group).
64
+ * `data-fp-cover-surface` marks one explicitly.
65
+ */
66
+ export const GROUP_SURFACE_SELECTOR = "[data-fp-cover-surface], [data-mp-glass-capsule]";
67
+
68
+ /**
69
+ * The shared plate an icon trigger sits on, when it sits in a group (LC-112,
70
+ * FZ-8480 r37): the trigger's surface is the plate under it, so a panel
71
+ * opening from a grouped button covers the whole group.
72
+ */
73
+ export function groupSurfaceOf(reference: Element): HTMLElement | null {
74
+ return reference.parentElement?.closest<HTMLElement>(GROUP_SURFACE_SELECTOR) ?? null;
75
+ }
@@ -0,0 +1,158 @@
1
+ /**
2
+ * LC-112 width setting (FZ-8438 r3, Clay on the desktop Date shot): "it can
3
+ * collapse to the content, it can be the full width of the initial input
4
+ * button, or it can open up to be the full width of the screen, or it can be
5
+ * a fixed size that it opens to."
6
+ */
7
+ import { describe, expect, it } from "vitest";
8
+ import { MENU_MIN_WIDTH } from "./compactFace";
9
+ import {
10
+ echoOffset,
11
+ panelLeftForWidth,
12
+ panelWidthBox,
13
+ screenBounds,
14
+ slidesAlongScreen,
15
+ } from "./panelWidth";
16
+
17
+ describe("panelWidthBox", () => {
18
+ it('"content" floors at an echoed trigger and leaves the width to its rows', () => {
19
+ expect(panelWidthBox("content", { trigger: 240, available: 1000, echo: true })).toEqual({
20
+ minWidth: 240,
21
+ maxWidth: 1000,
22
+ });
23
+ });
24
+
25
+ it('"content" without an echo has no trigger floor', () => {
26
+ expect(panelWidthBox("content", { trigger: 44, available: 1000, echo: false }).minWidth).toBe(
27
+ 0,
28
+ );
29
+ });
30
+
31
+ it('"content" keeps a platform floor (the native 250pt pull-down)', () => {
32
+ expect(
33
+ panelWidthBox("content", { trigger: 44, available: 370, echo: false, floor: MENU_MIN_WIDTH })
34
+ .minWidth,
35
+ ).toBe(MENU_MIN_WIDTH);
36
+ expect(
37
+ panelWidthBox("content", { trigger: 44, available: 220, echo: false, floor: MENU_MIN_WIDTH })
38
+ .minWidth,
39
+ ).toBe(220);
40
+ });
41
+
42
+ it('"trigger" pins min, width and max to the trigger', () => {
43
+ expect(panelWidthBox("trigger", { trigger: 240, available: 1000, echo: true })).toEqual({
44
+ minWidth: 240,
45
+ width: 240,
46
+ maxWidth: 240,
47
+ });
48
+ });
49
+
50
+ it('"screen" pins the box to the room between the margins', () => {
51
+ expect(panelWidthBox("screen", { trigger: 240, available: 370, echo: true })).toEqual({
52
+ minWidth: 370,
53
+ width: 370,
54
+ maxWidth: 370,
55
+ });
56
+ });
57
+
58
+ it("a number is that width, capped at the room", () => {
59
+ expect(panelWidthBox(320, { trigger: 240, available: 1000, echo: true }).width).toBe(320);
60
+ expect(panelWidthBox(180, { trigger: 240, available: 1000, echo: true }).width).toBe(180);
61
+ expect(panelWidthBox(600, { trigger: 240, available: 370, echo: true }).width).toBe(370);
62
+ expect(panelWidthBox(-5, { trigger: 240, available: 370, echo: true }).width).toBe(0);
63
+ });
64
+ });
65
+
66
+ describe("panelLeftForWidth", () => {
67
+ const bounds = { boundsLeft: 10, boundsRight: 1430 };
68
+
69
+ it("keeps the trigger's start edge while the panel fits", () => {
70
+ expect(panelLeftForWidth({ triggerLeft: 200, triggerRight: 440, width: 320, ...bounds })).toBe(
71
+ 200,
72
+ );
73
+ });
74
+
75
+ it("slides back inside the end margin", () => {
76
+ expect(
77
+ panelLeftForWidth({ triggerLeft: 1300, triggerRight: 1420, width: 320, ...bounds }),
78
+ ).toBe(1110);
79
+ });
80
+
81
+ it("a screen-wide panel sits on the start margin", () => {
82
+ expect(panelLeftForWidth({ triggerLeft: 200, triggerRight: 440, width: 1420, ...bounds })).toBe(
83
+ 10,
84
+ );
85
+ });
86
+
87
+ it("right to left keeps the trigger's right edge", () => {
88
+ expect(
89
+ panelLeftForWidth({
90
+ triggerLeft: 1000,
91
+ triggerRight: 1240,
92
+ width: 320,
93
+ rtl: true,
94
+ ...bounds,
95
+ }),
96
+ ).toBe(920);
97
+ });
98
+ });
99
+
100
+ describe("echoOffset", () => {
101
+ it("is the trigger's distance from the panel's start edge", () => {
102
+ expect(
103
+ echoOffset({ triggerLeft: 200, triggerRight: 440, panelLeft: 10, panelWidth: 1420 }),
104
+ ).toBe(190);
105
+ expect(
106
+ echoOffset({ triggerLeft: 200, triggerRight: 440, panelLeft: 200, panelWidth: 320 }),
107
+ ).toBe(0);
108
+ });
109
+
110
+ it("measures from the right edge in right to left", () => {
111
+ expect(
112
+ echoOffset({
113
+ triggerLeft: 1000,
114
+ triggerRight: 1240,
115
+ panelLeft: 10,
116
+ panelWidth: 1420,
117
+ rtl: true,
118
+ }),
119
+ ).toBe(190);
120
+ });
121
+ });
122
+
123
+ describe("slidesAlongScreen", () => {
124
+ it("is true only for the widths not tied to the trigger's start edge", () => {
125
+ expect(slidesAlongScreen("screen")).toBe(true);
126
+ expect(slidesAlongScreen(320)).toBe(true);
127
+ expect(slidesAlongScreen("content")).toBe(false);
128
+ expect(slidesAlongScreen("trigger")).toBe(false);
129
+ expect(slidesAlongScreen(undefined)).toBe(false);
130
+ });
131
+ });
132
+
133
+ describe("screenBounds", () => {
134
+ const bounds = { boundsLeft: 10, boundsRight: 1430 };
135
+
136
+ it("a trigger in the page gutter lends its inset to both sides", () => {
137
+ // Field at the 16pt gutter, margins at 10: the panel spans 16..1424, so
138
+ // its start edge is the trigger's and the rows line up under the echo.
139
+ expect(screenBounds({ triggerLeft: 16, triggerRight: 276, ...bounds })).toEqual({
140
+ left: 16,
141
+ right: 1424,
142
+ });
143
+ });
144
+
145
+ it("a trigger deep in the page keeps the safe margins", () => {
146
+ expect(screenBounds({ triggerLeft: 600, triggerRight: 860, ...bounds })).toEqual({
147
+ left: 10,
148
+ right: 1430,
149
+ });
150
+ });
151
+
152
+ it("right to left measures the gutter from the right edge", () => {
153
+ expect(screenBounds({ triggerLeft: 1164, triggerRight: 1414, rtl: true, ...bounds })).toEqual({
154
+ left: 26,
155
+ right: 1414,
156
+ });
157
+ });
158
+ });
@@ -0,0 +1,122 @@
1
+ /**
2
+ * How wide a panel opens over its trigger (LC-112, FZ-8438 r3). One setting
3
+ * for every picker and menu, on the web and native:
4
+ *
5
+ * - `"content"`: the panel hugs its content. While it echoes its trigger it
6
+ * is never narrower than the trigger, so the echo keeps its box.
7
+ * - `"trigger"`: exactly the trigger's width. Content wraps or scrolls.
8
+ * - `"screen"`: the room between the screen's safe margins. The top edge
9
+ * still sits on the trigger's top edge.
10
+ * - a number: that many points, capped at the room between the margins.
11
+ */
12
+ export type PanelWidth = "content" | "trigger" | "screen" | number;
13
+
14
+ export interface PanelWidthBox {
15
+ minWidth: number;
16
+ /** Set for every mode but `"content"`, which leaves the width to its rows. */
17
+ width?: number;
18
+ maxWidth: number;
19
+ }
20
+
21
+ export function panelWidthBox(
22
+ panelWidth: PanelWidth,
23
+ {
24
+ trigger,
25
+ available,
26
+ echo,
27
+ floor = 0,
28
+ }: {
29
+ /** The trigger's width. */
30
+ trigger: number;
31
+ /** The room between the screen's safe margins. */
32
+ available: number;
33
+ /** The panel's first row repeats the trigger. */
34
+ echo: boolean;
35
+ /** A platform minimum for `"content"` (the native pull-down's 250pt). */
36
+ floor?: number;
37
+ },
38
+ ): PanelWidthBox {
39
+ const room = Math.max(0, available);
40
+ const pinned = (width: number) => {
41
+ const w = Math.max(0, Math.min(width, room));
42
+ return { minWidth: w, width: w, maxWidth: w };
43
+ };
44
+ if (panelWidth === "trigger") return pinned(trigger);
45
+ if (panelWidth === "screen") return pinned(room);
46
+ if (typeof panelWidth === "number") return pinned(panelWidth);
47
+ return { minWidth: Math.min(Math.max(echo ? trigger : 0, floor), room), maxWidth: room };
48
+ }
49
+
50
+ /**
51
+ * A panel whose width is not tied to its trigger's box (`"screen"`, or a fixed
52
+ * width wider than the room from the trigger's start edge) slides along the
53
+ * screen to stay inside the margins. Its echo row is moved back over the
54
+ * trigger by the returned offset, so the trigger's content stays in place.
55
+ */
56
+ export function panelLeftForWidth({
57
+ triggerLeft,
58
+ triggerRight,
59
+ width,
60
+ boundsLeft,
61
+ boundsRight,
62
+ rtl = false,
63
+ }: {
64
+ triggerLeft: number;
65
+ triggerRight: number;
66
+ width: number;
67
+ boundsLeft: number;
68
+ boundsRight: number;
69
+ rtl?: boolean;
70
+ }): number {
71
+ const want = rtl ? triggerRight - width : triggerLeft;
72
+ return Math.max(boundsLeft, Math.min(want, boundsRight - width));
73
+ }
74
+
75
+ /** How far the echo row moves from the panel's start edge to sit on its trigger. */
76
+ export function echoOffset({
77
+ triggerLeft,
78
+ triggerRight,
79
+ panelLeft,
80
+ panelWidth,
81
+ rtl = false,
82
+ }: {
83
+ triggerLeft: number;
84
+ triggerRight: number;
85
+ panelLeft: number;
86
+ panelWidth: number;
87
+ rtl?: boolean;
88
+ }): number {
89
+ return rtl ? panelLeft + panelWidth - triggerRight : triggerLeft - panelLeft;
90
+ }
91
+
92
+ /** True for the widths that are not tied to the trigger's start edge. */
93
+ export function slidesAlongScreen(panelWidth: PanelWidth | undefined): boolean {
94
+ return panelWidth === "screen" || typeof panelWidth === "number";
95
+ }
96
+
97
+ /**
98
+ * The bounds a `"screen"` panel spans. A trigger that sits in the page's start
99
+ * gutter, up to `gutter` points inside the safe margins, lends that inset to
100
+ * both sides, so the panel's start edge stays on the trigger's start edge and
101
+ * the rows line up under the echo. A trigger deeper in the page gets the safe
102
+ * margins as they are.
103
+ */
104
+ export function screenBounds({
105
+ triggerLeft,
106
+ triggerRight,
107
+ boundsLeft,
108
+ boundsRight,
109
+ rtl = false,
110
+ gutter = 32,
111
+ }: {
112
+ triggerLeft: number;
113
+ triggerRight: number;
114
+ boundsLeft: number;
115
+ boundsRight: number;
116
+ rtl?: boolean;
117
+ gutter?: number;
118
+ }): { left: number; right: number } {
119
+ const inset = rtl ? boundsRight - triggerRight : triggerLeft - boundsLeft;
120
+ const margin = inset > 0 && inset <= gutter ? inset : 0;
121
+ return { left: boundsLeft + margin, right: boundsRight - margin };
122
+ }
@@ -7,9 +7,10 @@
7
7
  * DatePicker measured 262px of calendar under a 289px trigger purely because
8
8
  * the call site said `fitContent`.
9
9
  *
10
- * Calendar grids take fit-content (MPO-262): a full-width field wrapper is
11
- * unrelated to seven day columns and must not create a mostly empty popup.
12
- * Text listboxes retain at-least-trigger; icon/button launchers may also hug.
10
+ * Calendar grids opened from a field are the field grown open (LC-112
11
+ * seamless cover, FZ-8438): at least the field's width, superseding MPO-262's
12
+ * fit-content. Text listboxes retain at-least-trigger; icon/button launchers
13
+ * may hug.
13
14
  * The Icon glyph grid pins to its field exactly (match-trigger): fixed 64px
14
15
  * cells wrap into more columns on a wider field instead of stretching.
15
16
  */
@@ -21,13 +22,16 @@ import { describe, expect, it } from "vitest";
21
22
  const fieldsDir = resolve(dirname(fileURLToPath(import.meta.url)), "..", "fields");
22
23
 
23
24
  /** Pickers whose trigger is a form FIELD: the panel may never be narrower. */
24
- const fieldShapedPickers = ["TimePicker/catalog.tsx", "ColorPicker/parts.tsx"];
25
+ const fieldShapedPickers = [
26
+ "TimePicker/catalog.tsx",
27
+ "ColorPicker/parts.tsx",
28
+ "DatePicker/parts.tsx",
29
+ "DatePicker/DatetimePicker.catalog.tsx",
30
+ ];
25
31
 
26
32
  /** Field-triggered pickers pinned to the field's width exactly. */
27
33
  const matchTriggerPickers = ["Icon/index.tsx"];
28
34
 
29
- const intrinsicGridPickers = ["DatePicker/parts.tsx", "DatePicker/DatetimePicker.catalog.tsx"];
30
-
31
35
  /** Panels opened from an icon/button trigger, where fit-content is correct. */
32
36
  const buttonShapedPickers = ["Geolocation/index.tsx"];
33
37
 
@@ -36,10 +40,6 @@ function read(relative: string): string {
36
40
  }
37
41
 
38
42
  describe("FloatingPanel width contract (MPO-38, MPO-262)", () => {
39
- it.each(intrinsicGridPickers)("%s hugs its calendar grid", (relative) => {
40
- expect(read(relative)).toContain('widthMode="fit-content"');
41
- });
42
-
43
43
  it.each(fieldShapedPickers)("%s declares at-least-trigger", (relative) => {
44
44
  const source = read(relative);
45
45
  expect(source).toContain('widthMode="at-least-trigger"');
@@ -154,7 +154,15 @@ describe("placeOverTrigger (FZ-7830, LC-112 where no sheet may take it)", () =>
154
154
  height: 180,
155
155
  bounds: phone,
156
156
  });
157
- expect(placed).toEqual({ left: 20, top: 200, width: 200, maxHeight: 600, shifted: false });
157
+ expect(placed).toEqual({
158
+ left: 20,
159
+ top: 200,
160
+ width: 200,
161
+ maxHeight: 600,
162
+ shifted: false,
163
+ end: false,
164
+ up: false,
165
+ });
158
166
  });
159
167
 
160
168
  it("is at least the trigger's width", () => {
@@ -209,6 +217,54 @@ describe("placeOverTrigger (FZ-7830, LC-112 where no sheet may take it)", () =>
209
217
  expect(placed.maxHeight).toBe(743);
210
218
  });
211
219
 
220
+ it("opens an icon menu from the trigger's top trailing corner at the end edge (FZ-8438)", () => {
221
+ const placed = placeOverTrigger({
222
+ trigger,
223
+ width: 200,
224
+ height: 180,
225
+ bounds: phone,
226
+ align: "auto",
227
+ });
228
+ expect(placed).toMatchObject({ left: 144, top: 200, end: true, shifted: false });
229
+ });
230
+
231
+ it("keeps a bar button's corner inside the viewport margin (FZ-8438)", () => {
232
+ const placed = placeOverTrigger({
233
+ trigger: { x: 342, y: 60, width: 44, height: 44 },
234
+ width: 250,
235
+ height: 180,
236
+ bounds: phone,
237
+ align: "auto",
238
+ });
239
+ expect(placed.left).toBe(342 + 44 - 250);
240
+ expect(placed.end).toBe(true);
241
+ expect(placed.shifted).toBe(false);
242
+ });
243
+
244
+ it("mirrors the icon menu in RTL: a leading-edge button opens from its left corner (FZ-8438)", () => {
245
+ const placed = placeOverTrigger({
246
+ trigger: { x: 4, y: 60, width: 44, height: 44 },
247
+ width: 250,
248
+ height: 180,
249
+ bounds: phone,
250
+ rtl: true,
251
+ align: "auto",
252
+ });
253
+ expect(placed.left).toBe(4);
254
+ expect(placed.end).toBe(true);
255
+ });
256
+
257
+ it("keeps the start corner for an icon menu that fits (FZ-8438)", () => {
258
+ const placed = placeOverTrigger({
259
+ trigger: { x: 20, y: 200, width: 44, height: 44 },
260
+ width: 200,
261
+ height: 180,
262
+ bounds: phone,
263
+ align: "auto",
264
+ });
265
+ expect(placed).toMatchObject({ left: 20, end: false, shifted: false });
266
+ });
267
+
212
268
  it("never grows wider than the bounds", () => {
213
269
  const placed = placeOverTrigger({
214
270
  trigger: { x: 20, y: 200, width: 120, height: 44 },
@@ -221,13 +277,66 @@ describe("placeOverTrigger (FZ-7830, LC-112 where no sheet may take it)", () =>
221
277
  });
222
278
  });
223
279
 
280
+ describe("placeOverTrigger pinned: an echoed icon trigger stays in its spot (LC-112, FZ-8480)", () => {
281
+ const phone: PanelBounds = { top: 57, left: 10, right: 380, bottom: 800 };
282
+
283
+ it("opens down from the button's top edge where the menu fits", () => {
284
+ const button = { x: 326, y: 60, width: 44, height: 44 };
285
+ const placed = placeOverTrigger({
286
+ trigger: button,
287
+ width: 250,
288
+ height: 300,
289
+ bounds: phone,
290
+ align: "auto",
291
+ pinned: true,
292
+ });
293
+ expect(placed).toMatchObject({ top: 60, left: 120, end: true, up: false, maxHeight: 740 });
294
+ });
295
+
296
+ it("opens up from the button's bottom edge near the bottom, never sliding off the button", () => {
297
+ const button = { x: 20, y: 740, width: 44, height: 44 };
298
+ const placed = placeOverTrigger({
299
+ trigger: button,
300
+ width: 250,
301
+ height: 300,
302
+ bounds: phone,
303
+ align: "auto",
304
+ pinned: true,
305
+ });
306
+ expect(placed.up).toBe(true);
307
+ expect(placed.top + 300).toBe(button.y + button.height);
308
+ expect(placed.maxHeight).toBe(button.y + button.height - phone.top);
309
+ });
310
+
311
+ it("scrolls from the button rather than covering past the margin when neither side fits", () => {
312
+ const button = { x: 20, y: 400, width: 44, height: 44 };
313
+ const placed = placeOverTrigger({
314
+ trigger: button,
315
+ width: 250,
316
+ height: 2000,
317
+ bounds: phone,
318
+ align: "auto",
319
+ pinned: true,
320
+ });
321
+ expect(placed).toMatchObject({ top: 400, up: false, maxHeight: 400 });
322
+ });
323
+ });
324
+
224
325
  describe("placeBesideTrigger (FZ-7830 round 3, LC-262: beside the trigger, never over it)", () => {
225
326
  const phone: PanelBounds = { top: 57, left: 10, right: 380, bottom: 800 };
226
327
  const field = { x: 16, y: 300, width: 358, height: 44 };
227
328
 
228
329
  it("opens under the trigger when it fits", () => {
229
330
  const placed = placeBesideTrigger({ trigger: field, width: 200, height: 180, bounds: phone });
230
- expect(placed).toEqual({ left: 16, top: 344, width: 358, maxHeight: 180, shifted: false });
331
+ expect(placed).toEqual({
332
+ left: 16,
333
+ top: 344,
334
+ width: 358,
335
+ maxHeight: 180,
336
+ shifted: false,
337
+ end: false,
338
+ up: false,
339
+ });
231
340
  });
232
341
 
233
342
  it("opens above the trigger when there is more room there, its bottom on the trigger's top", () => {