@passui/react 0.1.16 → 0.1.19

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 (366) hide show
  1. package/README.md +102 -1
  2. package/dist/types/src/appearance/index.d.ts +2 -0
  3. package/dist/types/src/appearance/platform.d.ts +9 -0
  4. package/dist/types/src/appearance/theme.d.ts +71 -0
  5. package/dist/types/src/components/ambient/ambient.d.ts +12 -0
  6. package/dist/types/src/components/ambient/index.d.ts +1 -0
  7. package/dist/types/src/components/button/button-styles.d.ts +12 -0
  8. package/dist/types/src/components/button/button.d.ts +30 -0
  9. package/dist/types/src/components/button/icon-button.d.ts +10 -0
  10. package/dist/types/src/components/button/pending-spinner.d.ts +5 -0
  11. package/dist/types/src/components/button/use-pending-indicator.d.ts +2 -0
  12. package/dist/types/src/components/chip/chip.d.ts +7 -0
  13. package/dist/types/src/components/compact-date-picker/calendar-month.d.ts +25 -0
  14. package/dist/types/src/components/compact-date-picker/compact-date-picker.d.ts +27 -0
  15. package/dist/types/src/components/compact-time-picker/compact-time-picker.d.ts +26 -0
  16. package/dist/types/src/components/compact-time-picker/time-value.d.ts +18 -0
  17. package/dist/types/src/components/content-view/content-view.d.ts +48 -0
  18. package/dist/types/src/components/content-view/index.d.ts +1 -0
  19. package/dist/types/src/components/context-menu/conceal-menu-source.d.ts +2 -0
  20. package/dist/types/src/components/context-menu/context-menu-host.d.ts +2 -0
  21. package/dist/types/src/components/context-menu/context-menu-store.d.ts +57 -0
  22. package/dist/types/src/components/context-menu/menu-navigation.d.ts +6 -0
  23. package/dist/types/src/components/context-menu/menu-position.d.ts +21 -0
  24. package/dist/types/src/components/context-menu/menu-reveal.d.ts +22 -0
  25. package/dist/types/src/components/context-menu/use-context-menu.d.ts +14 -0
  26. package/dist/types/src/components/conversation/conversation.d.ts +43 -0
  27. package/dist/types/src/components/conversation/index.d.ts +1 -0
  28. package/dist/types/src/components/date-picker/date-picker.d.ts +16 -0
  29. package/dist/types/src/components/date-picker/date-value.d.ts +2 -0
  30. package/dist/types/src/components/dialog/dialog-host.d.ts +6 -0
  31. package/dist/types/src/components/dialog/dialog-store.d.ts +21 -0
  32. package/dist/types/src/components/dialog/dialog.d.ts +30 -0
  33. package/dist/types/src/components/dialog/index.d.ts +1 -0
  34. package/dist/types/src/components/disclosure-group/disclosure-group.d.ts +13 -0
  35. package/dist/types/src/components/divider/divider.d.ts +9 -0
  36. package/dist/types/src/components/inline-disclosure/inline-disclosure.d.ts +15 -0
  37. package/dist/types/src/components/labeled-content/labeled-content.d.ts +19 -0
  38. package/dist/types/src/components/locale-switcher/index.d.ts +1 -0
  39. package/dist/types/src/components/locale-switcher/locale-switcher.d.ts +10 -0
  40. package/dist/types/src/components/menu/menu.d.ts +16 -0
  41. package/dist/types/src/components/picker/picker-trigger.d.ts +2 -0
  42. package/dist/types/src/components/picker/picker.d.ts +37 -0
  43. package/dist/types/src/components/popover/popover-fit.d.ts +21 -0
  44. package/dist/types/src/components/popover/popover.d.ts +14 -0
  45. package/dist/types/src/components/profile-image/profile-image.d.ts +4 -0
  46. package/dist/types/src/components/progress-view/progress-view.d.ts +13 -0
  47. package/dist/types/src/components/search-field/search-field.d.ts +2 -0
  48. package/dist/types/src/components/search-list/search-list.d.ts +19 -0
  49. package/dist/types/src/components/section/section.d.ts +15 -0
  50. package/dist/types/src/components/secure-field/secure-field.d.ts +4 -0
  51. package/dist/types/src/components/segmented-control/segmented-control.d.ts +20 -0
  52. package/dist/types/src/components/sheet/modal-environment.d.ts +2 -0
  53. package/dist/types/src/components/sheet/sheet-portal.d.ts +5 -0
  54. package/dist/types/src/components/sheet/sheet.d.ts +21 -0
  55. package/dist/types/src/components/sheet/use-sheet-focus.d.ts +3 -0
  56. package/dist/types/src/components/sidebar/sidebar.d.ts +18 -0
  57. package/dist/types/src/components/slider/slider.d.ts +14 -0
  58. package/dist/types/src/components/stat-tile/index.d.ts +1 -0
  59. package/dist/types/src/components/stat-tile/stat-tile.d.ts +15 -0
  60. package/dist/types/src/components/status-indicator/status-indicator.d.ts +14 -0
  61. package/dist/types/src/components/stepper/stepper.d.ts +19 -0
  62. package/dist/types/src/components/swatch-picker/swatch-picker.d.ts +17 -0
  63. package/dist/types/src/components/tab-bar/tab-bar.d.ts +40 -0
  64. package/dist/types/src/components/tab-view/tab-view.d.ts +24 -0
  65. package/dist/types/src/components/table/table.d.ts +10 -0
  66. package/dist/types/src/components/text-editor/text-editor.d.ts +2 -0
  67. package/dist/types/src/components/text-field/text-field.d.ts +18 -0
  68. package/dist/types/src/components/toast/toast-store.d.ts +47 -0
  69. package/dist/types/src/components/toast/toaster.d.ts +10 -0
  70. package/dist/types/src/components/toggle/toggle.d.ts +17 -0
  71. package/dist/types/src/components/tooltip/tooltip-host.d.ts +6 -0
  72. package/dist/types/src/components/view-controller/index.d.ts +1 -0
  73. package/dist/types/src/components/view-controller/view-controller.d.ts +21 -0
  74. package/dist/types/src/hooks/scroll/minimize-decision.d.ts +2 -0
  75. package/dist/types/src/hooks/use-anchored-placement.d.ts +7 -0
  76. package/dist/types/src/hooks/use-dismiss.d.ts +9 -0
  77. package/dist/types/src/hooks/use-floating-dismiss.d.ts +3 -0
  78. package/dist/types/src/hooks/use-media-query.d.ts +21 -0
  79. package/dist/types/src/hooks/use-minimize-on-scroll.d.ts +6 -0
  80. package/dist/types/src/hooks/use-visual-viewport.d.ts +4 -0
  81. package/dist/types/src/hooks/viewport/types.d.ts +19 -0
  82. package/dist/types/src/hooks/viewport/viewport-metrics.d.ts +3 -0
  83. package/dist/types/src/icons/icons.d.ts +612 -0
  84. package/dist/types/src/index.d.ts +58 -0
  85. package/dist/types/src/lib/anchored-placement.d.ts +39 -0
  86. package/dist/types/src/lib/class-names.d.ts +2 -0
  87. package/dist/types/src/lib/clipboard.d.ts +6 -0
  88. package/dist/types/src/lib/date.d.ts +50 -0
  89. package/dist/types/src/lib/floating-layers.d.ts +8 -0
  90. package/dist/types/src/lib/haptics.d.ts +8 -0
  91. package/dist/types/src/lib/language.d.ts +4 -0
  92. package/dist/types/src/lib/range-value.d.ts +4 -0
  93. package/dist/types/src/lib/screen-edges.d.ts +12 -0
  94. package/dist/types/src/lib/shapes.d.ts +17 -0
  95. package/dist/types/src/motion/transitions.d.ts +97 -0
  96. package/dist/types/src/tokens.d.ts +1 -0
  97. package/package.json +192 -40
  98. package/src/appearance/platform.tsx +10 -47
  99. package/src/appearance/theme.tsx +42 -142
  100. package/src/components/ambient/ambient.tsx +2 -10
  101. package/src/components/button/button-styles.ts +13 -31
  102. package/src/components/button/button.tsx +19 -14
  103. package/src/components/button/icon-button.tsx +14 -56
  104. package/src/components/button/use-pending-indicator.ts +2 -7
  105. package/src/components/chip/chip.tsx +8 -13
  106. package/src/components/compact-date-picker/calendar-month.ts +13 -57
  107. package/src/components/compact-date-picker/compact-date-picker.tsx +44 -123
  108. package/src/components/compact-time-picker/compact-time-picker.tsx +46 -130
  109. package/src/components/compact-time-picker/time-value.ts +4 -16
  110. package/src/components/content-view/content-view.tsx +13 -56
  111. package/src/components/context-menu/conceal-menu-source.ts +1 -4
  112. package/src/components/context-menu/context-menu-host.tsx +125 -195
  113. package/src/components/context-menu/context-menu-store.ts +3 -11
  114. package/src/components/context-menu/menu-navigation.ts +29 -0
  115. package/src/components/context-menu/menu-position.ts +6 -27
  116. package/src/components/context-menu/menu-reveal.ts +13 -54
  117. package/src/components/context-menu/use-context-menu.ts +6 -30
  118. package/src/components/conversation/conversation.tsx +26 -72
  119. package/src/components/date-picker/date-picker.tsx +8 -37
  120. package/src/components/date-picker/date-value.ts +5 -30
  121. package/src/components/dialog/dialog-host.tsx +31 -76
  122. package/src/components/dialog/dialog-store.ts +1 -3
  123. package/src/components/dialog/dialog.tsx +23 -80
  124. package/src/components/disclosure-group/disclosure-group.tsx +70 -0
  125. package/src/components/divider/divider.tsx +31 -0
  126. package/src/components/inline-disclosure/inline-disclosure.tsx +49 -0
  127. package/src/components/labeled-content/labeled-content.tsx +24 -18
  128. package/src/components/locale-switcher/locale-switcher.tsx +20 -70
  129. package/src/components/menu/menu.tsx +68 -0
  130. package/src/components/picker/picker-trigger.ts +10 -0
  131. package/src/components/picker/picker.tsx +72 -203
  132. package/src/components/popover/popover-fit.ts +69 -0
  133. package/src/components/popover/popover.tsx +94 -77
  134. package/src/components/profile-image/profile-image.tsx +6 -28
  135. package/src/components/progress-view/progress-view.tsx +65 -0
  136. package/src/components/search-field/search-field.tsx +27 -25
  137. package/src/components/search-list/search-list.tsx +43 -69
  138. package/src/components/section/section.tsx +18 -17
  139. package/src/components/secure-field/secure-field.tsx +5 -7
  140. package/src/components/segmented-control/segmented-control.tsx +20 -29
  141. package/src/components/sheet/modal-environment.ts +16 -54
  142. package/src/components/sheet/sheet-portal.tsx +10 -42
  143. package/src/components/sheet/sheet.tsx +17 -25
  144. package/src/components/sheet/use-sheet-focus.ts +15 -51
  145. package/src/components/sidebar/sidebar.tsx +27 -30
  146. package/src/components/slider/slider.tsx +76 -0
  147. package/src/components/stat-tile/stat-tile.tsx +9 -30
  148. package/src/components/status-indicator/status-indicator.tsx +12 -19
  149. package/src/components/stepper/stepper.tsx +80 -0
  150. package/src/components/swatch-picker/swatch-picker.tsx +19 -15
  151. package/src/components/tab-bar/tab-bar.tsx +59 -59
  152. package/src/components/tab-view/tab-view.tsx +52 -57
  153. package/src/components/table/table.tsx +14 -62
  154. package/src/components/text-editor/text-editor.tsx +2 -12
  155. package/src/components/text-field/text-field.tsx +11 -40
  156. package/src/components/toast/toast-store.ts +9 -30
  157. package/src/components/toast/toaster.tsx +90 -104
  158. package/src/components/toggle/toggle.tsx +28 -24
  159. package/src/components/tooltip/tooltip-host.tsx +71 -69
  160. package/src/components/view-controller/view-controller.tsx +4 -21
  161. package/src/hooks/scroll/minimize-decision.ts +1 -5
  162. package/src/hooks/use-anchored-placement.ts +4 -14
  163. package/src/hooks/use-dismiss.ts +5 -23
  164. package/src/hooks/use-floating-dismiss.ts +28 -0
  165. package/src/hooks/use-media-query.ts +12 -31
  166. package/src/hooks/use-minimize-on-scroll.ts +10 -34
  167. package/src/hooks/use-visual-viewport.ts +5 -14
  168. package/src/hooks/viewport/viewport-metrics.ts +4 -16
  169. package/src/icons/icons.tsx +167 -121
  170. package/src/index.ts +9 -1
  171. package/src/lib/anchored-placement.ts +5 -15
  172. package/src/lib/class-names.ts +1 -2
  173. package/src/lib/clipboard.ts +14 -0
  174. package/src/lib/date.ts +4 -15
  175. package/src/lib/floating-layers.ts +18 -8
  176. package/src/lib/haptics.ts +1 -3
  177. package/src/lib/language.ts +2 -7
  178. package/src/lib/range-value.ts +32 -0
  179. package/src/lib/screen-edges.ts +2 -6
  180. package/src/lib/shapes.ts +5 -20
  181. package/src/motion/transitions.ts +18 -12
  182. package/src/components/ambient/ambient.docs.tsx +0 -68
  183. package/src/components/ambient/examples/ambient-images.tsx +0 -30
  184. package/src/components/ambient/examples/ambient-now-playing.tsx +0 -55
  185. package/src/components/ambient/examples/ambient-showcase.tsx +0 -33
  186. package/src/components/ambient/examples/ambient-usage.tsx +0 -19
  187. package/src/components/button/button.docs.tsx +0 -116
  188. package/src/components/button/examples/button-disabled.tsx +0 -19
  189. package/src/components/button/examples/button-icon.tsx +0 -39
  190. package/src/components/button/examples/button-link.tsx +0 -12
  191. package/src/components/button/examples/button-pending.tsx +0 -27
  192. package/src/components/button/examples/button-showcase.tsx +0 -115
  193. package/src/components/button/examples/button-sizes.tsx +0 -12
  194. package/src/components/button/examples/button-usage.tsx +0 -12
  195. package/src/components/button/examples/button-variants.tsx +0 -15
  196. package/src/components/button/examples/button-with-icon.tsx +0 -32
  197. package/src/components/button/examples/icon-button-player.tsx +0 -38
  198. package/src/components/button/examples/icon-button-showcase.tsx +0 -83
  199. package/src/components/button/examples/icon-button-usage.tsx +0 -11
  200. package/src/components/button/examples/icon-button-variants.tsx +0 -39
  201. package/src/components/button/icon-button.docs.tsx +0 -68
  202. package/src/components/chip/chip.docs.tsx +0 -37
  203. package/src/components/chip/examples/chip-in-rows.tsx +0 -19
  204. package/src/components/chip/examples/chip-showcase.tsx +0 -51
  205. package/src/components/chip/examples/chip-tones.tsx +0 -13
  206. package/src/components/chip/examples/chip-usage.tsx +0 -5
  207. package/src/components/compact-date-picker/compact-date-picker.docs.tsx +0 -81
  208. package/src/components/compact-date-picker/examples/compact-date-picker-showcase.tsx +0 -35
  209. package/src/components/compact-date-picker/examples/compact-date-picker-usage.tsx +0 -22
  210. package/src/components/compact-time-picker/compact-time-picker.docs.tsx +0 -80
  211. package/src/components/compact-time-picker/examples/compact-time-picker-showcase.tsx +0 -31
  212. package/src/components/compact-time-picker/examples/compact-time-picker-usage.tsx +0 -21
  213. package/src/components/content-view/content-view.docs.tsx +0 -61
  214. package/src/components/content-view/examples/content-view-header-action.tsx +0 -33
  215. package/src/components/content-view/examples/content-view-showcase.tsx +0 -65
  216. package/src/components/content-view/examples/content-view-stats.tsx +0 -35
  217. package/src/components/content-view/examples/content-view-usage.tsx +0 -14
  218. package/src/components/context-menu/context-menu.docs.tsx +0 -92
  219. package/src/components/context-menu/examples/context-menu-checked.tsx +0 -37
  220. package/src/components/context-menu/examples/context-menu-list.tsx +0 -85
  221. package/src/components/context-menu/examples/context-menu-showcase.tsx +0 -56
  222. package/src/components/context-menu/examples/context-menu-toolbar.tsx +0 -63
  223. package/src/components/context-menu/examples/context-menu-usage.tsx +0 -24
  224. package/src/components/conversation/conversation.docs.tsx +0 -88
  225. package/src/components/conversation/examples/conversation-composer.tsx +0 -36
  226. package/src/components/conversation/examples/conversation-days.tsx +0 -48
  227. package/src/components/conversation/examples/conversation-showcase.tsx +0 -71
  228. package/src/components/conversation/examples/conversation-usage.tsx +0 -28
  229. package/src/components/date-picker/date-picker.docs.tsx +0 -88
  230. package/src/components/date-picker/examples/date-picker-locales.tsx +0 -41
  231. package/src/components/date-picker/examples/date-picker-past-only.tsx +0 -29
  232. package/src/components/date-picker/examples/date-picker-showcase.tsx +0 -49
  233. package/src/components/date-picker/examples/date-picker-usage.tsx +0 -22
  234. package/src/components/dialog/dialog.docs.tsx +0 -114
  235. package/src/components/dialog/examples/dialog-confirm.tsx +0 -24
  236. package/src/components/dialog/examples/dialog-form.tsx +0 -46
  237. package/src/components/dialog/examples/dialog-inline.tsx +0 -48
  238. package/src/components/dialog/examples/dialog-showcase.tsx +0 -53
  239. package/src/components/dialog/examples/dialog-usage.tsx +0 -31
  240. package/src/components/labeled-content/examples/labeled-content-descriptions.tsx +0 -37
  241. package/src/components/labeled-content/examples/labeled-content-showcase.tsx +0 -54
  242. package/src/components/labeled-content/examples/labeled-content-usage.tsx +0 -22
  243. package/src/components/labeled-content/examples/labeled-content-values.tsx +0 -26
  244. package/src/components/labeled-content/examples/labeled-content-wide.tsx +0 -46
  245. package/src/components/labeled-content/labeled-content.docs.tsx +0 -69
  246. package/src/components/locale-switcher/examples/locale-switcher-native-names.tsx +0 -30
  247. package/src/components/locale-switcher/examples/locale-switcher-showcase.tsx +0 -46
  248. package/src/components/locale-switcher/examples/locale-switcher-translated-page.tsx +0 -35
  249. package/src/components/locale-switcher/examples/locale-switcher-usage.tsx +0 -20
  250. package/src/components/locale-switcher/locale-switcher.docs.tsx +0 -91
  251. package/src/components/picker/examples/picker-details.tsx +0 -44
  252. package/src/components/picker/examples/picker-searchable.tsx +0 -48
  253. package/src/components/picker/examples/picker-showcase.tsx +0 -66
  254. package/src/components/picker/examples/picker-usage.tsx +0 -20
  255. package/src/components/picker/picker.docs.tsx +0 -68
  256. package/src/components/popover/examples/popover-help.tsx +0 -57
  257. package/src/components/popover/examples/popover-menu.tsx +0 -51
  258. package/src/components/popover/examples/popover-showcase.tsx +0 -61
  259. package/src/components/popover/examples/popover-usage.tsx +0 -31
  260. package/src/components/popover/popover.docs.tsx +0 -84
  261. package/src/components/profile-image/examples/profile-image-fallbacks.tsx +0 -29
  262. package/src/components/profile-image/examples/profile-image-group.tsx +0 -34
  263. package/src/components/profile-image/examples/profile-image-showcase.tsx +0 -30
  264. package/src/components/profile-image/examples/profile-image-usage.tsx +0 -14
  265. package/src/components/profile-image/profile-image.docs.tsx +0 -81
  266. package/src/components/search-field/examples/search-field-filter.tsx +0 -53
  267. package/src/components/search-field/examples/search-field-showcase.tsx +0 -56
  268. package/src/components/search-field/examples/search-field-toolbar.tsx +0 -27
  269. package/src/components/search-field/examples/search-field-usage.tsx +0 -18
  270. package/src/components/search-field/search-field.docs.tsx +0 -58
  271. package/src/components/search-list/examples/search-list-dropdown.tsx +0 -53
  272. package/src/components/search-list/examples/search-list-groups.tsx +0 -64
  273. package/src/components/search-list/examples/search-list-showcase.tsx +0 -67
  274. package/src/components/search-list/examples/search-list-usage.tsx +0 -27
  275. package/src/components/search-list/search-list.docs.tsx +0 -87
  276. package/src/components/section/examples/section-actions.tsx +0 -35
  277. package/src/components/section/examples/section-groups.tsx +0 -41
  278. package/src/components/section/examples/section-showcase.tsx +0 -63
  279. package/src/components/section/examples/section-usage.tsx +0 -19
  280. package/src/components/section/section.docs.tsx +0 -51
  281. package/src/components/secure-field/examples/secure-field-new-password.tsx +0 -56
  282. package/src/components/secure-field/examples/secure-field-reveal.tsx +0 -20
  283. package/src/components/secure-field/examples/secure-field-showcase.tsx +0 -62
  284. package/src/components/secure-field/examples/secure-field-usage.tsx +0 -19
  285. package/src/components/secure-field/secure-field.docs.tsx +0 -72
  286. package/src/components/segmented-control/examples/segmented-control-overflow.tsx +0 -28
  287. package/src/components/segmented-control/examples/segmented-control-showcase.tsx +0 -59
  288. package/src/components/segmented-control/examples/segmented-control-usage.tsx +0 -20
  289. package/src/components/segmented-control/examples/segmented-control-views.tsx +0 -32
  290. package/src/components/segmented-control/segmented-control.docs.tsx +0 -61
  291. package/src/components/sheet/examples/sheet-choices.tsx +0 -58
  292. package/src/components/sheet/examples/sheet-share.tsx +0 -51
  293. package/src/components/sheet/examples/sheet-showcase.tsx +0 -74
  294. package/src/components/sheet/examples/sheet-usage.tsx +0 -32
  295. package/src/components/sheet/sheet.docs.tsx +0 -75
  296. package/src/components/sidebar/examples/sidebar-groups.tsx +0 -133
  297. package/src/components/sidebar/examples/sidebar-showcase.tsx +0 -123
  298. package/src/components/sidebar/examples/sidebar-unread.tsx +0 -66
  299. package/src/components/sidebar/examples/sidebar-usage.tsx +0 -52
  300. package/src/components/sidebar/sidebar.docs.tsx +0 -135
  301. package/src/components/stat-tile/examples/stat-tile-filters.tsx +0 -32
  302. package/src/components/stat-tile/examples/stat-tile-grid.tsx +0 -21
  303. package/src/components/stat-tile/examples/stat-tile-showcase.tsx +0 -52
  304. package/src/components/stat-tile/examples/stat-tile-usage.tsx +0 -13
  305. package/src/components/stat-tile/stat-tile.docs.tsx +0 -60
  306. package/src/components/status-indicator/examples/status-indicator-live.tsx +0 -34
  307. package/src/components/status-indicator/examples/status-indicator-showcase.tsx +0 -39
  308. package/src/components/status-indicator/examples/status-indicator-states.tsx +0 -17
  309. package/src/components/status-indicator/examples/status-indicator-usage.tsx +0 -9
  310. package/src/components/status-indicator/status-indicator.docs.tsx +0 -43
  311. package/src/components/swatch-picker/examples/swatch-picker-accents.tsx +0 -42
  312. package/src/components/swatch-picker/examples/swatch-picker-labels.tsx +0 -45
  313. package/src/components/swatch-picker/examples/swatch-picker-showcase.tsx +0 -70
  314. package/src/components/swatch-picker/examples/swatch-picker-usage.tsx +0 -39
  315. package/src/components/swatch-picker/swatch-picker.docs.tsx +0 -60
  316. package/src/components/tab-bar/examples/tab-bar-five-tabs.tsx +0 -66
  317. package/src/components/tab-bar/examples/tab-bar-minimize.tsx +0 -71
  318. package/src/components/tab-bar/examples/tab-bar-showcase.tsx +0 -82
  319. package/src/components/tab-bar/examples/tab-bar-usage.tsx +0 -54
  320. package/src/components/tab-bar/tab-bar.docs.tsx +0 -136
  321. package/src/components/tab-view/examples/tab-view-keyboard.tsx +0 -39
  322. package/src/components/tab-view/examples/tab-view-settings.tsx +0 -56
  323. package/src/components/tab-view/examples/tab-view-showcase.tsx +0 -53
  324. package/src/components/tab-view/examples/tab-view-usage.tsx +0 -23
  325. package/src/components/tab-view/tab-view.docs.tsx +0 -77
  326. package/src/components/table/examples/table-empty.tsx +0 -53
  327. package/src/components/table/examples/table-invoices.tsx +0 -102
  328. package/src/components/table/examples/table-selection.tsx +0 -150
  329. package/src/components/table/examples/table-showcase.tsx +0 -115
  330. package/src/components/table/examples/table-usage.tsx +0 -67
  331. package/src/components/table/examples/table-wide.tsx +0 -75
  332. package/src/components/table/table.docs.tsx +0 -131
  333. package/src/components/text-editor/examples/text-editor-comment.tsx +0 -48
  334. package/src/components/text-editor/examples/text-editor-count.tsx +0 -38
  335. package/src/components/text-editor/examples/text-editor-showcase.tsx +0 -58
  336. package/src/components/text-editor/examples/text-editor-usage.tsx +0 -25
  337. package/src/components/text-editor/text-editor.docs.tsx +0 -61
  338. package/src/components/text-field/examples/text-field-icons.tsx +0 -72
  339. package/src/components/text-field/examples/text-field-showcase.tsx +0 -50
  340. package/src/components/text-field/examples/text-field-usage.tsx +0 -18
  341. package/src/components/text-field/examples/text-field-validation.tsx +0 -27
  342. package/src/components/text-field/text-field.docs.tsx +0 -118
  343. package/src/components/toast/examples/toast-action.tsx +0 -32
  344. package/src/components/toast/examples/toast-promise.tsx +0 -45
  345. package/src/components/toast/examples/toast-showcase.tsx +0 -49
  346. package/src/components/toast/examples/toast-usage.tsx +0 -13
  347. package/src/components/toast/toast.docs.tsx +0 -79
  348. package/src/components/toggle/examples/toggle-checkboxes.tsx +0 -43
  349. package/src/components/toggle/examples/toggle-settings.tsx +0 -31
  350. package/src/components/toggle/examples/toggle-showcase.tsx +0 -59
  351. package/src/components/toggle/examples/toggle-usage.tsx +0 -13
  352. package/src/components/toggle/toggle.docs.tsx +0 -69
  353. package/src/components/tooltip/examples/tooltip-icon-buttons.tsx +0 -27
  354. package/src/components/tooltip/examples/tooltip-shortcuts.tsx +0 -38
  355. package/src/components/tooltip/examples/tooltip-showcase.tsx +0 -44
  356. package/src/components/tooltip/examples/tooltip-usage.tsx +0 -13
  357. package/src/components/tooltip/tooltip.docs.tsx +0 -56
  358. package/src/components/view-controller/examples/view-controller-action.tsx +0 -27
  359. package/src/components/view-controller/examples/view-controller-settings.tsx +0 -31
  360. package/src/components/view-controller/examples/view-controller-showcase.tsx +0 -45
  361. package/src/components/view-controller/examples/view-controller-usage.tsx +0 -19
  362. package/src/components/view-controller/view-controller.docs.tsx +0 -71
  363. package/src/docs/index.ts +0 -3
  364. package/src/docs/registry.ts +0 -113
  365. package/src/docs/snippet.ts +0 -17
  366. package/src/docs/types.ts +0 -180
@@ -1,25 +1,15 @@
1
- import {
2
- AnimatePresence,
3
- motion,
4
- useIsPresent,
5
- useReducedMotion,
6
- } from "motion/react"
7
- import {
8
- useEffect,
9
- useLayoutEffect,
10
- useRef,
11
- useState,
12
- useSyncExternalStore,
13
- } from "react"
1
+ import { AnimatePresence, motion, useIsPresent, useReducedMotion } from "motion/react"
2
+ import { useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react"
14
3
  import { FLOATING_LAYER } from "../../hooks/use-dismiss"
15
4
  import { CheckIcon } from "../../icons/icons"
16
5
  import { cn } from "../../lib/class-names"
17
- import { registerFloatingLayer } from "../../lib/floating-layers"
6
+ import { belongsToFloatingSurface, registerFloatingLayer } from "../../lib/floating-layers"
18
7
  import { screenEdges } from "../../lib/screen-edges"
19
8
  import { spring } from "../../motion/transitions"
20
9
  import { concealMenuSource } from "./conceal-menu-source"
10
+ import { findMenuTypeaheadIndex, isMenuNavigationKey, nextMenuIndex } from "./menu-navigation"
21
11
  import { menuPosition } from "./menu-position"
22
- import { menuReveal, toolbarMenuReveal } from "./menu-reveal"
12
+ import { menuSurfaceReveal } from "./menu-reveal"
23
13
  import {
24
14
  closeContextMenu,
25
15
  getContextMenu,
@@ -29,22 +19,15 @@ import {
29
19
 
30
20
  /** Renders the open context menu. Mount once, near the app root. */
31
21
  export function ContextMenuHost() {
32
- const menu = useSyncExternalStore(
33
- subscribeContextMenu,
34
- getContextMenu,
35
- () => null
36
- )
37
- return (
38
- <AnimatePresence>
39
- {menu && <Menu key={menu.id} menu={menu} />}
40
- </AnimatePresence>
41
- )
22
+ const menu = useSyncExternalStore(subscribeContextMenu, getContextMenu, () => null)
23
+ return <AnimatePresence>{menu && <Menu key={menu.id} menu={menu} />}</AnimatePresence>
42
24
  }
43
25
 
44
26
  function Menu({ menu }: { menu: OpenMenu }) {
45
27
  const present = useIsPresent()
46
28
  const reducedMotion = useReducedMotion()
47
29
  const ref = useRef<HTMLDivElement>(null)
30
+ const content = useRef<HTMLDivElement>(null)
48
31
  const [position, setPosition] = useState({
49
32
  left: menu.x,
50
33
  top: menu.y,
@@ -56,6 +39,7 @@ function Menu({ menu }: { menu: OpenMenu }) {
56
39
  ready: false,
57
40
  })
58
41
  const [focused, setFocused] = useState(-1)
42
+ const typeahead = useRef({ query: "", at: 0 })
59
43
 
60
44
  useLayoutEffect(() => {
61
45
  if (
@@ -66,10 +50,7 @@ function Menu({ menu }: { menu: OpenMenu }) {
66
50
  return
67
51
  const anchor = menu.toolbar ?? menu.anchor
68
52
  const surface = ref.current
69
- const restore = concealMenuSource(
70
- anchor,
71
- Boolean(menu.toolbar)
72
- )
53
+ const restore = concealMenuSource(anchor, Boolean(menu.toolbar))
73
54
  return () => {
74
55
  const restored = restore()
75
56
  if (
@@ -87,9 +68,7 @@ function Menu({ menu }: { menu: OpenMenu }) {
87
68
  useLayoutEffect(() => {
88
69
  const surface = ref.current
89
70
  if (!surface || !present || !position.ready) return
90
- const unregister = menu.anchor
91
- ? registerFloatingLayer(surface, menu.anchor)
92
- : undefined
71
+ const unregister = menu.anchor ? registerFloatingLayer(surface, menu.anchor) : undefined
93
72
  surface.focus()
94
73
  return unregister
95
74
  }, [menu.anchor, present, position.ready])
@@ -106,33 +85,37 @@ function Menu({ menu }: { menu: OpenMenu }) {
106
85
  const edges = screenEdges()
107
86
  const left = viewport?.offsetLeft ?? 0
108
87
  const top = viewport?.offsetTop ?? 0
109
- setPosition({
88
+ const next = {
110
89
  ...menuPosition(
111
90
  menu,
112
91
  {
113
92
  width: element.offsetWidth,
114
93
  height: Math.max(
115
94
  element.offsetHeight,
116
- element.scrollHeight
95
+ (content.current?.scrollHeight ?? 0) + 12
117
96
  ),
118
97
  },
119
98
  {
120
99
  left: left + edges.left,
121
100
  top: top + edges.top,
122
- right:
123
- left +
124
- (viewport?.width ??
125
- window.innerWidth) -
126
- edges.right,
127
- bottom:
128
- top +
129
- (viewport?.height ??
130
- window.innerHeight) -
131
- edges.bottom,
101
+ right: left + (viewport?.width ?? window.innerWidth) - edges.right,
102
+ bottom: top + (viewport?.height ?? window.innerHeight) - edges.bottom,
132
103
  }
133
104
  ),
134
105
  ready: true,
135
- })
106
+ }
107
+ setPosition((current) =>
108
+ current.left === next.left &&
109
+ current.top === next.top &&
110
+ current.originX === next.originX &&
111
+ current.originY === next.originY &&
112
+ current.maxHeight === next.maxHeight &&
113
+ current.width === next.width &&
114
+ current.height === next.height &&
115
+ current.ready === next.ready
116
+ ? current
117
+ : next
118
+ )
136
119
  }
137
120
  const schedule = () => {
138
121
  cancelAnimationFrame(frame)
@@ -153,7 +136,7 @@ function Menu({ menu }: { menu: OpenMenu }) {
153
136
  useEffect(() => {
154
137
  if (!present) return
155
138
  const onPointer = (event: PointerEvent) => {
156
- if (!ref.current?.contains(event.target as Node))
139
+ if (!ref.current || !belongsToFloatingSurface(ref.current, event.target as Element))
157
140
  closeContextMenu(false)
158
141
  }
159
142
  const close = () => closeContextMenu(false)
@@ -163,16 +146,8 @@ function Menu({ menu }: { menu: OpenMenu }) {
163
146
  }
164
147
  const onScrollKey = (event: KeyboardEvent) => {
165
148
  if (
166
- !ref.current?.contains(
167
- event.target as Node
168
- ) &&
169
- [
170
- "PageDown",
171
- "PageUp",
172
- "Home",
173
- "End",
174
- " ",
175
- ].includes(event.key)
149
+ !ref.current?.contains(event.target as Node) &&
150
+ ["PageDown", "PageUp", "Home", "End", " "].includes(event.key)
176
151
  )
177
152
  markScroll()
178
153
  }
@@ -185,11 +160,7 @@ function Menu({ menu }: { menu: OpenMenu }) {
185
160
  }
186
161
  // Opened by a long-press: ignore the finger lifting off.
187
162
  const timer = setTimeout(() => {
188
- window.addEventListener(
189
- "pointerdown",
190
- onPointer,
191
- true
192
- )
163
+ window.addEventListener("pointerdown", onPointer, true)
193
164
  }, 0)
194
165
  window.addEventListener("blur", close)
195
166
  window.addEventListener("wheel", markScroll, {
@@ -204,47 +175,19 @@ function Menu({ menu }: { menu: OpenMenu }) {
204
175
  window.addEventListener("scroll", onScroll, true)
205
176
  return () => {
206
177
  clearTimeout(timer)
207
- window.removeEventListener(
208
- "pointerdown",
209
- onPointer,
210
- true
211
- )
178
+ window.removeEventListener("pointerdown", onPointer, true)
212
179
  window.removeEventListener("blur", close)
213
- window.removeEventListener(
214
- "wheel",
215
- markScroll,
216
- true
217
- )
218
- window.removeEventListener(
219
- "touchmove",
220
- markScroll,
221
- true
222
- )
223
- window.removeEventListener(
224
- "keydown",
225
- onScrollKey,
226
- true
227
- )
228
- window.removeEventListener(
229
- "scroll",
230
- onScroll,
231
- true
232
- )
180
+ window.removeEventListener("wheel", markScroll, true)
181
+ window.removeEventListener("touchmove", markScroll, true)
182
+ window.removeEventListener("keydown", onScrollKey, true)
183
+ window.removeEventListener("scroll", onScroll, true)
233
184
  }
234
185
  }, [present])
235
186
 
236
- const source = menuReveal(
237
- position.ready ? menu.source : undefined,
187
+ const source = menuSurfaceReveal(
188
+ position.ready ? (menu.toolbarRect ?? menu.source) : undefined,
238
189
  position
239
190
  )
240
- const toolbarReveal =
241
- menu.source && menu.toolbarRect
242
- ? toolbarMenuReveal(
243
- menu.source,
244
- menu.toolbarRect,
245
- position
246
- )
247
- : undefined
248
191
  let actionIndex = -1
249
192
  return (
250
193
  <motion.div
@@ -264,41 +207,48 @@ function Menu({ menu }: { menu: OpenMenu }) {
264
207
  closeContextMenu()
265
208
  return
266
209
  }
267
- const keys = [
268
- "ArrowDown",
269
- "ArrowUp",
270
- "Home",
271
- "End",
272
- ]
273
- if (!keys.includes(event.key)) return
274
- event.preventDefault()
275
210
  const controls = Array.from(
276
211
  ref.current?.querySelectorAll<HTMLButtonElement>(
277
212
  "[role=menuitem]:not(:disabled)"
278
213
  ) ?? []
279
214
  )
215
+ if (!isMenuNavigationKey(event.key)) {
216
+ if (
217
+ event.key.length !== 1 ||
218
+ !event.key.trim() ||
219
+ event.altKey ||
220
+ event.ctrlKey ||
221
+ event.metaKey ||
222
+ event.nativeEvent.isComposing
223
+ )
224
+ return
225
+ const now = performance.now()
226
+ const query =
227
+ (now - typeahead.current.at < 700 ? typeahead.current.query : "") +
228
+ event.key
229
+ typeahead.current = { query, at: now }
230
+ const labels = controls.map((control) => control.textContent ?? "")
231
+ const current = controls.indexOf(document.activeElement as HTMLButtonElement)
232
+ let next = findMenuTypeaheadIndex(labels, query, current)
233
+ if (next < 0) {
234
+ typeahead.current.query = event.key
235
+ next = findMenuTypeaheadIndex(labels, event.key, current)
236
+ }
237
+ if (next >= 0) {
238
+ event.preventDefault()
239
+ controls[next]?.focus()
240
+ }
241
+ return
242
+ }
243
+ event.preventDefault()
280
244
  if (!controls.length) return
281
- const current = controls.indexOf(
282
- document.activeElement as HTMLButtonElement
283
- )
284
- const next =
285
- event.key === "Home"
286
- ? 0
287
- : event.key === "End"
288
- ? controls.length - 1
289
- : event.key === "ArrowDown"
290
- ? (current + 1) % controls.length
291
- : current < 0
292
- ? controls.length - 1
293
- : (current -
294
- 1 +
295
- controls.length) %
296
- controls.length
245
+ const current = controls.indexOf(document.activeElement as HTMLButtonElement)
246
+ const next = nextMenuIndex(event.key, current, controls.length)
297
247
  controls[next]?.focus()
298
248
  }}
299
249
  {...{ [FLOATING_LAYER]: "" }}
300
250
  className={cn(
301
- "glass-menu fixed z-75 flex min-w-50 max-w-[min(280px,calc(100vw-24px))] flex-col overflow-y-auto overscroll-contain rounded-3xl p-1.5",
251
+ "fixed z-75 isolate flex min-w-50 max-w-[min(280px,calc(100vw-24px))] flex-col rounded-3xl p-1.5",
302
252
  menu.touch && "min-w-60",
303
253
  !present && "pointer-events-none"
304
254
  )}
@@ -307,65 +257,58 @@ function Menu({ menu }: { menu: OpenMenu }) {
307
257
  top: position.top,
308
258
  maxHeight: position.maxHeight,
309
259
  minWidth: menu.toolbarRect
310
- ? Math.min(
311
- Math.max(
312
- 200,
313
- menu.toolbarRect.width
314
- ),
315
- window.innerWidth - 24
316
- )
260
+ ? Math.min(Math.max(200, menu.toolbarRect.width), window.innerWidth - 24)
317
261
  : undefined,
318
- transformOrigin: menu.source
319
- ? "50% 50%"
320
- : `${position.originX * 100}% ${position.originY * 100}%`,
321
- visibility: position.ready
322
- ? undefined
323
- : "hidden",
262
+ visibility: position.ready ? undefined : "hidden",
324
263
  }}
325
- initial={reducedMotion ? false : source}
326
- animate={
327
- toolbarReveal && !reducedMotion
328
- ? toolbarReveal.enter
329
- : {
330
- opacity: 1,
331
- x: 0,
332
- y: 0,
333
- scaleX: 1,
334
- scaleY: 1,
335
- }
336
- }
337
- exit={
338
- reducedMotion
339
- ? { opacity: 0 }
340
- : (toolbarReveal?.exit ?? source)
341
- }
342
- transition={
343
- reducedMotion
344
- ? { duration: 0 }
345
- : toolbarReveal
346
- ? {
347
- duration: 0.34,
348
- times: present
349
- ? [0, 0.35, 1]
350
- : [0, 0.65, 1],
351
- ease: [0.22, 1, 0.36, 1],
352
- }
353
- : spring.smooth
354
- }
355
264
  onContextMenu={(event) => event.preventDefault()}
356
265
  >
357
266
  <motion.div
358
- className="flex flex-col"
359
- initial={{ opacity: reducedMotion ? 1 : 0 }}
360
- animate={{ opacity: 1 }}
267
+ aria-hidden="true"
268
+ className="glass-menu pointer-events-none absolute top-0 left-0 -z-10 rounded-3xl"
269
+ style={{ width: "100%", height: "100%" }}
270
+ initial={reducedMotion || !position.ready ? false : source}
271
+ animate={
272
+ position.ready
273
+ ? {
274
+ x: 0,
275
+ y: 0,
276
+ width: position.width,
277
+ height: position.height,
278
+ opacity: 1,
279
+ borderRadius: "var(--radius-3xl)",
280
+ }
281
+ : undefined
282
+ }
283
+ exit={reducedMotion ? { opacity: 0 } : source}
284
+ transition={reducedMotion ? { duration: 0 } : spring.smooth}
285
+ />
286
+ <motion.div
287
+ ref={content}
288
+ className="flex flex-col overflow-y-auto overscroll-contain"
289
+ style={{
290
+ maxHeight: position.maxHeight
291
+ ? Math.max(0, position.maxHeight - 12)
292
+ : undefined,
293
+ }}
294
+ initial={
295
+ reducedMotion
296
+ ? false
297
+ : {
298
+ opacity: 0,
299
+ y: menu.source && menu.source.top > position.top ? 4 : -4,
300
+ }
301
+ }
302
+ animate={{ opacity: 1, y: 0 }}
303
+ exit={{
304
+ opacity: 0,
305
+ transition: {
306
+ duration: reducedMotion ? 0 : 0.06,
307
+ },
308
+ }}
361
309
  transition={{
362
- duration: reducedMotion ? 0 : 0.12,
363
- delay:
364
- reducedMotion || !menu.source
365
- ? 0
366
- : menu.toolbar
367
- ? 0.14
368
- : 0.08,
310
+ duration: reducedMotion ? 0 : 0.16,
311
+ delay: reducedMotion || !menu.source ? 0 : 0.06,
369
312
  }}
370
313
  >
371
314
  {menu.items.map((item, index) => {
@@ -380,7 +323,7 @@ function Menu({ menu }: { menu: OpenMenu }) {
380
323
  if ("heading" in item) {
381
324
  return (
382
325
  <span
383
- key={`heading-${item.heading}`}
326
+ key={`heading-${index}`}
384
327
  className="px-2.5 pt-1.5 pb-0.5 text-caption2 font-semibold text-label-tertiary"
385
328
  >
386
329
  {item.heading}
@@ -391,35 +334,24 @@ function Menu({ menu }: { menu: OpenMenu }) {
391
334
  const current = actionIndex
392
335
  return (
393
336
  <button
394
- key={item.label}
337
+ key={`item-${index}`}
395
338
  type="button"
396
339
  role="menuitem"
397
340
  tabIndex={-1}
398
341
  disabled={item.disabled}
399
- onFocus={() =>
400
- setFocused(current)
401
- }
402
- onPointerEnter={() =>
403
- !item.disabled &&
404
- setFocused(current)
405
- }
342
+ onFocus={() => setFocused(current)}
343
+ onPointerEnter={() => !item.disabled && setFocused(current)}
406
344
  onClick={() => {
407
345
  closeContextMenu()
408
346
  item.onSelect()
409
347
  }}
410
348
  className={cn(
411
349
  "flex items-center gap-2.5 rounded-lg px-2.5 text-start text-subheadline transition-colors disabled:opacity-40",
412
- menu.touch
413
- ? "py-2.5"
414
- : "py-1.5",
415
- item.destructive
416
- ? "text-danger"
417
- : "text-label",
350
+ menu.touch ? "py-2.5" : "py-1.5",
351
+ item.destructive ? "text-danger" : "text-label",
418
352
  focused === current &&
419
353
  !item.disabled &&
420
- (item.destructive
421
- ? "bg-danger/10"
422
- : "bg-fill")
354
+ (item.destructive ? "bg-danger/10" : "bg-fill")
423
355
  )}
424
356
  >
425
357
  <span className="flex w-4 shrink-0 justify-center text-label-secondary">
@@ -433,9 +365,7 @@ function Menu({ menu }: { menu: OpenMenu }) {
433
365
  item.icon
434
366
  )}
435
367
  </span>
436
- <span className="grow truncate">
437
- {item.label}
438
- </span>
368
+ <span className="grow truncate">{item.label}</span>
439
369
  </button>
440
370
  )
441
371
  })}
@@ -52,9 +52,7 @@ export function openContextMenu(
52
52
  y: number,
53
53
  items: ContextMenuItem[],
54
54
  touch = false,
55
- anchor: Element | null = typeof document === "undefined"
56
- ? null
57
- : document.activeElement
55
+ anchor: Element | null = typeof document === "undefined" ? null : document.activeElement
58
56
  ) {
59
57
  menu = {
60
58
  id: nextId++,
@@ -111,14 +109,8 @@ export function openMenu(
111
109
  menu = {
112
110
  id: nextId++,
113
111
  anchor,
114
- x: right
115
- ? (toolbarRect ?? rect).right
116
- : (toolbarRect ?? rect).left,
117
- y: toolbar
118
- ? rect.top
119
- : above
120
- ? rect.top - gap
121
- : rect.bottom + gap,
112
+ x: right ? (toolbarRect ?? rect).right : (toolbarRect ?? rect).left,
113
+ y: toolbar ? rect.top : above ? rect.top - gap : rect.bottom + gap,
122
114
  items,
123
115
  touch: false,
124
116
  alignX: right ? "end" : "start",
@@ -0,0 +1,29 @@
1
+ export type MenuNavigationKey = "ArrowDown" | "ArrowUp" | "Home" | "End"
2
+
3
+ export function isMenuNavigationKey(key: string): key is MenuNavigationKey {
4
+ return key === "ArrowDown" || key === "ArrowUp" || key === "Home" || key === "End"
5
+ }
6
+
7
+ /** Index of the next enabled action in a menu, with wrapping arrow navigation. */
8
+ export function nextMenuIndex(key: MenuNavigationKey, current: number, count: number): number {
9
+ if (count <= 0) return -1
10
+ if (key === "Home") return 0
11
+ if (key === "End") return count - 1
12
+ if (key === "ArrowDown") return (current + 1) % count
13
+ return current < 0 ? count - 1 : (current - 1 + count) % count
14
+ }
15
+
16
+ /** Finds a matching label after the current action, wrapping at the end. */
17
+ export function findMenuTypeaheadIndex(
18
+ labels: ReadonlyArray<string>,
19
+ query: string,
20
+ current: number
21
+ ): number {
22
+ if (!labels.length || !query.trim()) return -1
23
+ const needle = query.toLocaleLowerCase()
24
+ for (let offset = 1; offset <= labels.length; offset++) {
25
+ const index = (current + offset + labels.length) % labels.length
26
+ if (labels[index]?.trim().toLocaleLowerCase().startsWith(needle)) return index
27
+ }
28
+ return -1
29
+ }
@@ -1,10 +1,7 @@
1
1
  import type { OpenMenu } from "./context-menu-store"
2
2
  import type { MenuRect } from "./menu-reveal"
3
3
 
4
- type MenuAnchor = Pick<
5
- OpenMenu,
6
- "x" | "y" | "alignX" | "alignY"
7
- >
4
+ type MenuAnchor = Pick<OpenMenu, "x" | "y" | "alignX" | "alignY">
8
5
  type MenuSize = Pick<MenuRect, "width" | "height">
9
6
  type MenuBounds = {
10
7
  left: number
@@ -14,38 +11,20 @@ type MenuBounds = {
14
11
  }
15
12
 
16
13
  /** Fit within the current visible viewport, including a keyboard or Safari pan. */
17
- export function menuPosition(
18
- menu: MenuAnchor,
19
- size: MenuSize,
20
- bounds: MenuBounds
21
- ) {
14
+ export function menuPosition(menu: MenuAnchor, size: MenuSize, bounds: MenuBounds) {
22
15
  const { width, height } = size
23
16
  const { left, top, right, bottom } = bounds
24
17
  const fitsAfterX = menu.x + width <= right
25
18
  const fitsBeforeX = menu.x - width >= left
26
- const endX =
27
- menu.alignX === "end"
28
- ? fitsBeforeX || !fitsAfterX
29
- : !fitsAfterX
19
+ const endX = menu.alignX === "end" ? fitsBeforeX || !fitsAfterX : !fitsAfterX
30
20
  const fitsBelow = menu.y + height <= bottom
31
21
  const fitsAbove = menu.y - height >= top
32
- const endY =
33
- menu.alignY === "bottom"
34
- ? fitsAbove || !fitsBelow
35
- : !fitsBelow
22
+ const endY = menu.alignY === "bottom" ? fitsAbove || !fitsBelow : !fitsBelow
36
23
  const clamp = (value: number, min: number, max: number) =>
37
24
  Math.min(Math.max(value, min), Math.max(min, max))
38
25
  return {
39
- left: clamp(
40
- endX ? menu.x - width : menu.x,
41
- left,
42
- right - width
43
- ),
44
- top: clamp(
45
- endY ? menu.y - height : menu.y,
46
- top,
47
- bottom - height
48
- ),
26
+ left: clamp(endX ? menu.x - width : menu.x, left, right - width),
27
+ top: clamp(endY ? menu.y - height : menu.y, top, bottom - height),
49
28
  originX: endX ? 1 : 0,
50
29
  originY: endY ? 1 : 0,
51
30
  maxHeight: Math.max(0, bottom - top),
@@ -5,71 +5,30 @@ export type MenuRect = {
5
5
  height: number
6
6
  }
7
7
 
8
- /** The closed surface occupies its trigger, even when the final menu flips at an edge. */
9
- export function menuReveal(
10
- source: MenuRect | undefined,
11
- target: MenuRect
12
- ) {
8
+ /** Animate the material's bounds independently so menu text never stretches. */
9
+ export function menuSurfaceReveal(source: MenuRect | undefined, target: MenuRect) {
13
10
  if (
14
11
  !source ||
15
12
  source.width <= 0 ||
16
13
  source.height <= 0 ||
17
14
  target.width <= 0 ||
18
15
  target.height <= 0
19
- )
16
+ ) {
20
17
  return {
21
18
  x: 0,
22
- y: 0,
23
- scaleX: 0.96,
24
- scaleY: 0.96,
19
+ y: -4,
20
+ width: target.width,
21
+ height: target.height,
25
22
  opacity: 0,
23
+ borderRadius: "var(--radius-3xl)",
26
24
  }
27
- return {
28
- x:
29
- source.left +
30
- source.width / 2 -
31
- target.left -
32
- target.width / 2,
33
- y:
34
- source.top +
35
- source.height / 2 -
36
- target.top -
37
- target.height / 2,
38
- scaleX: source.width / target.width,
39
- scaleY: source.height / target.height,
40
- opacity: 1,
41
25
  }
42
- }
43
-
44
- /** Stretch across the action group before opening vertically; reverse on dismissal. */
45
- export function toolbarMenuReveal(
46
- source: MenuRect,
47
- toolbar: MenuRect,
48
- target: MenuRect
49
- ) {
50
- const start = menuReveal(source, target)
51
- const stretched = menuReveal(
52
- {
53
- ...toolbar,
54
- top: source.top,
55
- height: source.height,
56
- },
57
- target
58
- )
59
26
  return {
60
- enter: {
61
- x: [start.x, stretched.x, 0],
62
- y: [start.y, stretched.y, 0],
63
- scaleX: [start.scaleX, stretched.scaleX, 1],
64
- scaleY: [start.scaleY, stretched.scaleY, 1],
65
- opacity: 1,
66
- },
67
- exit: {
68
- x: [0, stretched.x, start.x],
69
- y: [0, stretched.y, start.y],
70
- scaleX: [1, stretched.scaleX, start.scaleX],
71
- scaleY: [1, stretched.scaleY, start.scaleY],
72
- opacity: 1,
73
- },
27
+ x: source.left - target.left,
28
+ y: source.top - target.top,
29
+ width: source.width,
30
+ height: source.height,
31
+ opacity: 1,
32
+ borderRadius: Math.min(source.width, source.height) / 2,
74
33
  }
75
34
  }