@passui/react 0.1.17 → 0.1.20

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 (408) hide show
  1. package/README.md +140 -1
  2. package/THIRD_PARTY_NOTICES.md +25 -0
  3. package/dist/types/src/appearance/index.d.ts +2 -0
  4. package/dist/types/src/appearance/platform.d.ts +9 -0
  5. package/dist/types/src/appearance/theme.d.ts +71 -0
  6. package/dist/types/src/components/accordion/accordion.d.ts +19 -0
  7. package/dist/types/src/components/ambient/ambient.d.ts +12 -0
  8. package/dist/types/src/components/ambient/index.d.ts +1 -0
  9. package/dist/types/src/components/aspect-ratio/aspect-ratio.d.ts +7 -0
  10. package/dist/types/src/components/breadcrumb/breadcrumb.d.ts +16 -0
  11. package/dist/types/src/components/button/button-styles.d.ts +12 -0
  12. package/dist/types/src/components/button/button.d.ts +32 -0
  13. package/dist/types/src/components/button/icon-button.d.ts +10 -0
  14. package/dist/types/src/components/button/pending-spinner.d.ts +5 -0
  15. package/dist/types/src/components/button/use-pending-indicator.d.ts +2 -0
  16. package/dist/types/src/components/chip/chip.d.ts +7 -0
  17. package/dist/types/src/components/code-block/code-block.d.ts +10 -0
  18. package/dist/types/src/components/combo-box/combo-box.d.ts +9 -0
  19. package/dist/types/src/components/command/command.d.ts +18 -0
  20. package/dist/types/src/components/compact-date-picker/calendar-month.d.ts +25 -0
  21. package/dist/types/src/components/compact-date-picker/compact-date-picker.d.ts +27 -0
  22. package/dist/types/src/components/compact-time-picker/compact-time-picker.d.ts +26 -0
  23. package/dist/types/src/components/compact-time-picker/time-value.d.ts +18 -0
  24. package/dist/types/src/components/content-unavailable-view/content-unavailable-view.d.ts +9 -0
  25. package/dist/types/src/components/content-view/content-view.d.ts +48 -0
  26. package/dist/types/src/components/content-view/index.d.ts +1 -0
  27. package/dist/types/src/components/context-menu/conceal-menu-source.d.ts +2 -0
  28. package/dist/types/src/components/context-menu/context-menu-host.d.ts +2 -0
  29. package/dist/types/src/components/context-menu/context-menu-store.d.ts +57 -0
  30. package/dist/types/src/components/context-menu/menu-navigation.d.ts +6 -0
  31. package/dist/types/src/components/context-menu/menu-position.d.ts +21 -0
  32. package/dist/types/src/components/context-menu/menu-reveal.d.ts +17 -0
  33. package/dist/types/src/components/context-menu/use-context-menu.d.ts +14 -0
  34. package/dist/types/src/components/conversation/conversation.d.ts +43 -0
  35. package/dist/types/src/components/conversation/index.d.ts +1 -0
  36. package/dist/types/src/components/date-picker/date-picker.d.ts +16 -0
  37. package/dist/types/src/components/date-picker/date-value.d.ts +2 -0
  38. package/dist/types/src/components/dialog/dialog-host.d.ts +6 -0
  39. package/dist/types/src/components/dialog/dialog-store.d.ts +23 -0
  40. package/dist/types/src/components/dialog/dialog.d.ts +30 -0
  41. package/dist/types/src/components/dialog/index.d.ts +1 -0
  42. package/dist/types/src/components/disclosure-group/disclosure-group.d.ts +15 -0
  43. package/dist/types/src/components/divider/divider.d.ts +9 -0
  44. package/dist/types/src/components/inline-disclosure/inline-disclosure.d.ts +15 -0
  45. package/dist/types/src/components/keyboard-shortcut/keyboard-shortcut.d.ts +5 -0
  46. package/dist/types/src/components/labeled-content/labeled-content.d.ts +19 -0
  47. package/dist/types/src/components/locale-switcher/index.d.ts +1 -0
  48. package/dist/types/src/components/locale-switcher/locale-switcher.d.ts +10 -0
  49. package/dist/types/src/components/menu/menu.d.ts +16 -0
  50. package/dist/types/src/components/one-time-code/one-time-code.d.ts +18 -0
  51. package/dist/types/src/components/picker/picker-trigger.d.ts +2 -0
  52. package/dist/types/src/components/picker/picker.d.ts +43 -0
  53. package/dist/types/src/components/popover/anchored-surface.d.ts +13 -0
  54. package/dist/types/src/components/popover/popover-fit.d.ts +21 -0
  55. package/dist/types/src/components/popover/popover.d.ts +18 -0
  56. package/dist/types/src/components/profile-image/profile-image.d.ts +4 -0
  57. package/dist/types/src/components/progress-view/progress-view.d.ts +13 -0
  58. package/dist/types/src/components/progress-view/use-liquid-progress.d.ts +3 -0
  59. package/dist/types/src/components/radio-group/radio-group.d.ts +17 -0
  60. package/dist/types/src/components/search-field/expanding-search-field.d.ts +5 -0
  61. package/dist/types/src/components/search-field/search-field.d.ts +6 -0
  62. package/dist/types/src/components/search-list/search-list.d.ts +19 -0
  63. package/dist/types/src/components/section/section.d.ts +15 -0
  64. package/dist/types/src/components/secure-field/secure-field.d.ts +4 -0
  65. package/dist/types/src/components/segmented-control/segmented-control.d.ts +20 -0
  66. package/dist/types/src/components/sheet/modal-environment.d.ts +2 -0
  67. package/dist/types/src/components/sheet/sheet-portal.d.ts +5 -0
  68. package/dist/types/src/components/sheet/sheet.d.ts +21 -0
  69. package/dist/types/src/components/sheet/use-sheet-focus.d.ts +3 -0
  70. package/dist/types/src/components/sidebar/sidebar.d.ts +19 -0
  71. package/dist/types/src/components/skeleton/skeleton.d.ts +6 -0
  72. package/dist/types/src/components/slider/slider.d.ts +14 -0
  73. package/dist/types/src/components/slosh-slider/liquid-step.d.ts +6 -0
  74. package/dist/types/src/components/slosh-slider/slosh-slider.d.ts +18 -0
  75. package/dist/types/src/components/stat-tile/index.d.ts +1 -0
  76. package/dist/types/src/components/stat-tile/stat-tile.d.ts +15 -0
  77. package/dist/types/src/components/status-indicator/status-indicator.d.ts +14 -0
  78. package/dist/types/src/components/stepper/rolling-digit.d.ts +11 -0
  79. package/dist/types/src/components/stepper/stepper.d.ts +19 -0
  80. package/dist/types/src/components/swatch-picker/swatch-picker.d.ts +17 -0
  81. package/dist/types/src/components/tab-bar/tab-bar.d.ts +40 -0
  82. package/dist/types/src/components/tab-view/tab-view.d.ts +24 -0
  83. package/dist/types/src/components/table/table.d.ts +10 -0
  84. package/dist/types/src/components/text-editor/text-editor.d.ts +2 -0
  85. package/dist/types/src/components/text-field/text-field.d.ts +20 -0
  86. package/dist/types/src/components/toast/toast-store.d.ts +47 -0
  87. package/dist/types/src/components/toast/toaster.d.ts +10 -0
  88. package/dist/types/src/components/toggle/toggle.d.ts +17 -0
  89. package/dist/types/src/components/tooltip/tooltip-host.d.ts +6 -0
  90. package/dist/types/src/components/view-controller/index.d.ts +1 -0
  91. package/dist/types/src/components/view-controller/view-controller.d.ts +21 -0
  92. package/dist/types/src/components/wake-slider/wake-slider.d.ts +12 -0
  93. package/dist/types/src/hooks/scroll/minimize-decision.d.ts +2 -0
  94. package/dist/types/src/hooks/use-anchored-disclosure.d.ts +9 -0
  95. package/dist/types/src/hooks/use-anchored-placement.d.ts +7 -0
  96. package/dist/types/src/hooks/use-dismiss.d.ts +9 -0
  97. package/dist/types/src/hooks/use-floating-dismiss.d.ts +3 -0
  98. package/dist/types/src/hooks/use-media-query.d.ts +21 -0
  99. package/dist/types/src/hooks/use-minimize-on-scroll.d.ts +6 -0
  100. package/dist/types/src/hooks/use-visual-viewport.d.ts +4 -0
  101. package/dist/types/src/hooks/viewport/types.d.ts +19 -0
  102. package/dist/types/src/hooks/viewport/viewport-metrics.d.ts +3 -0
  103. package/dist/types/src/icons/icons.d.ts +612 -0
  104. package/dist/types/src/index.d.ts +71 -0
  105. package/dist/types/src/lib/anchored-placement.d.ts +39 -0
  106. package/dist/types/src/lib/class-names.d.ts +2 -0
  107. package/dist/types/src/lib/clipboard.d.ts +6 -0
  108. package/dist/types/src/lib/date.d.ts +50 -0
  109. package/dist/types/src/lib/floating-layers.d.ts +8 -0
  110. package/dist/types/src/lib/haptics.d.ts +8 -0
  111. package/dist/types/src/lib/language.d.ts +4 -0
  112. package/dist/types/src/lib/range-value.d.ts +4 -0
  113. package/dist/types/src/lib/screen-edges.d.ts +12 -0
  114. package/dist/types/src/lib/shapes.d.ts +17 -0
  115. package/dist/types/src/motion/transitions.d.ts +97 -0
  116. package/dist/types/src/tokens.d.ts +1 -0
  117. package/package.json +248 -40
  118. package/src/appearance/platform.tsx +10 -47
  119. package/src/appearance/theme.tsx +42 -142
  120. package/src/components/accordion/accordion.tsx +48 -0
  121. package/src/components/ambient/ambient.tsx +2 -10
  122. package/src/components/aspect-ratio/aspect-ratio.tsx +22 -0
  123. package/src/components/breadcrumb/breadcrumb.tsx +53 -0
  124. package/src/components/button/button-styles.ts +13 -31
  125. package/src/components/button/button.tsx +24 -15
  126. package/src/components/button/icon-button.tsx +14 -56
  127. package/src/components/button/use-pending-indicator.ts +2 -7
  128. package/src/components/chip/chip.tsx +8 -13
  129. package/src/components/code-block/code-block.tsx +41 -0
  130. package/src/components/combo-box/combo-box.tsx +13 -0
  131. package/src/components/command/command.tsx +119 -0
  132. package/src/components/compact-date-picker/calendar-month.ts +13 -57
  133. package/src/components/compact-date-picker/compact-date-picker.tsx +72 -195
  134. package/src/components/compact-time-picker/compact-time-picker.tsx +74 -195
  135. package/src/components/compact-time-picker/time-value.ts +4 -16
  136. package/src/components/content-unavailable-view/content-unavailable-view.tsx +37 -0
  137. package/src/components/content-view/content-view.tsx +13 -56
  138. package/src/components/context-menu/conceal-menu-source.ts +1 -4
  139. package/src/components/context-menu/context-menu-host.tsx +132 -198
  140. package/src/components/context-menu/context-menu-store.ts +5 -14
  141. package/src/components/context-menu/menu-navigation.ts +29 -0
  142. package/src/components/context-menu/menu-position.ts +6 -27
  143. package/src/components/context-menu/menu-reveal.ts +14 -52
  144. package/src/components/context-menu/use-context-menu.ts +6 -30
  145. package/src/components/conversation/conversation.tsx +26 -72
  146. package/src/components/date-picker/date-picker.tsx +8 -37
  147. package/src/components/date-picker/date-value.ts +5 -30
  148. package/src/components/dialog/dialog-host.tsx +37 -76
  149. package/src/components/dialog/dialog-store.ts +16 -7
  150. package/src/components/dialog/dialog.tsx +23 -80
  151. package/src/components/disclosure-group/disclosure-group.tsx +79 -0
  152. package/src/components/divider/divider.tsx +31 -0
  153. package/src/components/inline-disclosure/inline-disclosure.tsx +49 -0
  154. package/src/components/keyboard-shortcut/keyboard-shortcut.tsx +17 -0
  155. package/src/components/labeled-content/labeled-content.tsx +24 -18
  156. package/src/components/locale-switcher/locale-switcher.tsx +20 -70
  157. package/src/components/menu/menu.tsx +68 -0
  158. package/src/components/one-time-code/one-time-code.tsx +168 -0
  159. package/src/components/picker/picker-trigger.ts +10 -0
  160. package/src/components/picker/picker.tsx +165 -283
  161. package/src/components/popover/anchored-surface.tsx +223 -0
  162. package/src/components/popover/popover-fit.ts +69 -0
  163. package/src/components/popover/popover.tsx +209 -63
  164. package/src/components/profile-image/profile-image.tsx +6 -28
  165. package/src/components/progress-view/progress-view.tsx +70 -0
  166. package/src/components/progress-view/use-liquid-progress.ts +43 -0
  167. package/src/components/radio-group/radio-group.tsx +63 -0
  168. package/src/components/search-field/expanding-search-field.tsx +183 -0
  169. package/src/components/search-field/search-field.tsx +25 -7
  170. package/src/components/search-list/search-list.tsx +58 -75
  171. package/src/components/section/section.tsx +18 -17
  172. package/src/components/secure-field/secure-field.tsx +5 -7
  173. package/src/components/segmented-control/segmented-control.tsx +20 -29
  174. package/src/components/sheet/modal-environment.ts +16 -54
  175. package/src/components/sheet/sheet-portal.tsx +10 -42
  176. package/src/components/sheet/sheet.tsx +17 -25
  177. package/src/components/sheet/use-sheet-focus.ts +15 -51
  178. package/src/components/sidebar/sidebar.tsx +44 -38
  179. package/src/components/skeleton/skeleton.tsx +19 -0
  180. package/src/components/slider/slider.tsx +76 -0
  181. package/src/components/slosh-slider/liquid-step.ts +42 -0
  182. package/src/components/slosh-slider/slosh-slider.tsx +251 -0
  183. package/src/components/stat-tile/stat-tile.tsx +9 -30
  184. package/src/components/status-indicator/status-indicator.tsx +12 -19
  185. package/src/components/stepper/rolling-digit.tsx +77 -0
  186. package/src/components/stepper/stepper.tsx +101 -0
  187. package/src/components/swatch-picker/swatch-picker.tsx +19 -15
  188. package/src/components/tab-bar/tab-bar.tsx +59 -59
  189. package/src/components/tab-view/tab-view.tsx +52 -57
  190. package/src/components/table/table.tsx +14 -62
  191. package/src/components/text-editor/text-editor.tsx +2 -12
  192. package/src/components/text-field/text-field.tsx +53 -44
  193. package/src/components/toast/toast-store.ts +9 -30
  194. package/src/components/toast/toaster.tsx +90 -104
  195. package/src/components/toggle/toggle.tsx +165 -44
  196. package/src/components/tooltip/tooltip-host.tsx +70 -67
  197. package/src/components/view-controller/view-controller.tsx +4 -21
  198. package/src/components/wake-slider/wake-slider.tsx +237 -0
  199. package/src/hooks/scroll/minimize-decision.ts +1 -5
  200. package/src/hooks/use-anchored-disclosure.ts +23 -0
  201. package/src/hooks/use-anchored-placement.ts +7 -14
  202. package/src/hooks/use-dismiss.ts +5 -23
  203. package/src/hooks/use-floating-dismiss.ts +28 -0
  204. package/src/hooks/use-media-query.ts +12 -31
  205. package/src/hooks/use-minimize-on-scroll.ts +10 -34
  206. package/src/hooks/use-visual-viewport.ts +5 -14
  207. package/src/hooks/viewport/viewport-metrics.ts +4 -16
  208. package/src/icons/icons.tsx +229 -183
  209. package/src/index.ts +27 -1
  210. package/src/lib/anchored-placement.ts +12 -18
  211. package/src/lib/class-names.ts +1 -2
  212. package/src/lib/clipboard.ts +14 -0
  213. package/src/lib/date.ts +4 -15
  214. package/src/lib/floating-layers.ts +18 -8
  215. package/src/lib/haptics.ts +1 -3
  216. package/src/lib/language.ts +2 -7
  217. package/src/lib/range-value.ts +32 -0
  218. package/src/lib/screen-edges.ts +2 -6
  219. package/src/lib/shapes.ts +5 -20
  220. package/src/motion/transitions.ts +18 -12
  221. package/src/styles/code-block.css +33 -0
  222. package/src/styles/motion-controls.css +189 -0
  223. package/src/styles/styles.css +3 -0
  224. package/src/components/ambient/ambient.docs.tsx +0 -68
  225. package/src/components/ambient/examples/ambient-images.tsx +0 -30
  226. package/src/components/ambient/examples/ambient-now-playing.tsx +0 -55
  227. package/src/components/ambient/examples/ambient-showcase.tsx +0 -33
  228. package/src/components/ambient/examples/ambient-usage.tsx +0 -19
  229. package/src/components/button/button.docs.tsx +0 -116
  230. package/src/components/button/examples/button-disabled.tsx +0 -19
  231. package/src/components/button/examples/button-icon.tsx +0 -39
  232. package/src/components/button/examples/button-link.tsx +0 -12
  233. package/src/components/button/examples/button-pending.tsx +0 -27
  234. package/src/components/button/examples/button-showcase.tsx +0 -115
  235. package/src/components/button/examples/button-sizes.tsx +0 -12
  236. package/src/components/button/examples/button-usage.tsx +0 -12
  237. package/src/components/button/examples/button-variants.tsx +0 -15
  238. package/src/components/button/examples/button-with-icon.tsx +0 -32
  239. package/src/components/button/examples/icon-button-player.tsx +0 -38
  240. package/src/components/button/examples/icon-button-showcase.tsx +0 -83
  241. package/src/components/button/examples/icon-button-usage.tsx +0 -11
  242. package/src/components/button/examples/icon-button-variants.tsx +0 -39
  243. package/src/components/button/icon-button.docs.tsx +0 -68
  244. package/src/components/chip/chip.docs.tsx +0 -37
  245. package/src/components/chip/examples/chip-in-rows.tsx +0 -19
  246. package/src/components/chip/examples/chip-showcase.tsx +0 -51
  247. package/src/components/chip/examples/chip-tones.tsx +0 -13
  248. package/src/components/chip/examples/chip-usage.tsx +0 -5
  249. package/src/components/compact-date-picker/compact-date-picker.docs.tsx +0 -81
  250. package/src/components/compact-date-picker/examples/compact-date-picker-showcase.tsx +0 -35
  251. package/src/components/compact-date-picker/examples/compact-date-picker-usage.tsx +0 -22
  252. package/src/components/compact-time-picker/compact-time-picker.docs.tsx +0 -80
  253. package/src/components/compact-time-picker/examples/compact-time-picker-showcase.tsx +0 -31
  254. package/src/components/compact-time-picker/examples/compact-time-picker-usage.tsx +0 -21
  255. package/src/components/content-view/content-view.docs.tsx +0 -61
  256. package/src/components/content-view/examples/content-view-header-action.tsx +0 -33
  257. package/src/components/content-view/examples/content-view-showcase.tsx +0 -65
  258. package/src/components/content-view/examples/content-view-stats.tsx +0 -35
  259. package/src/components/content-view/examples/content-view-usage.tsx +0 -14
  260. package/src/components/context-menu/context-menu.docs.tsx +0 -92
  261. package/src/components/context-menu/examples/context-menu-checked.tsx +0 -37
  262. package/src/components/context-menu/examples/context-menu-list.tsx +0 -85
  263. package/src/components/context-menu/examples/context-menu-showcase.tsx +0 -56
  264. package/src/components/context-menu/examples/context-menu-toolbar.tsx +0 -63
  265. package/src/components/context-menu/examples/context-menu-usage.tsx +0 -24
  266. package/src/components/conversation/conversation.docs.tsx +0 -88
  267. package/src/components/conversation/examples/conversation-composer.tsx +0 -36
  268. package/src/components/conversation/examples/conversation-days.tsx +0 -48
  269. package/src/components/conversation/examples/conversation-showcase.tsx +0 -71
  270. package/src/components/conversation/examples/conversation-usage.tsx +0 -28
  271. package/src/components/date-picker/date-picker.docs.tsx +0 -88
  272. package/src/components/date-picker/examples/date-picker-locales.tsx +0 -41
  273. package/src/components/date-picker/examples/date-picker-past-only.tsx +0 -29
  274. package/src/components/date-picker/examples/date-picker-showcase.tsx +0 -49
  275. package/src/components/date-picker/examples/date-picker-usage.tsx +0 -22
  276. package/src/components/dialog/dialog.docs.tsx +0 -114
  277. package/src/components/dialog/examples/dialog-confirm.tsx +0 -24
  278. package/src/components/dialog/examples/dialog-form.tsx +0 -46
  279. package/src/components/dialog/examples/dialog-inline.tsx +0 -48
  280. package/src/components/dialog/examples/dialog-showcase.tsx +0 -53
  281. package/src/components/dialog/examples/dialog-usage.tsx +0 -31
  282. package/src/components/labeled-content/examples/labeled-content-descriptions.tsx +0 -37
  283. package/src/components/labeled-content/examples/labeled-content-showcase.tsx +0 -54
  284. package/src/components/labeled-content/examples/labeled-content-usage.tsx +0 -22
  285. package/src/components/labeled-content/examples/labeled-content-values.tsx +0 -26
  286. package/src/components/labeled-content/examples/labeled-content-wide.tsx +0 -46
  287. package/src/components/labeled-content/labeled-content.docs.tsx +0 -69
  288. package/src/components/locale-switcher/examples/locale-switcher-native-names.tsx +0 -30
  289. package/src/components/locale-switcher/examples/locale-switcher-showcase.tsx +0 -46
  290. package/src/components/locale-switcher/examples/locale-switcher-translated-page.tsx +0 -35
  291. package/src/components/locale-switcher/examples/locale-switcher-usage.tsx +0 -20
  292. package/src/components/locale-switcher/locale-switcher.docs.tsx +0 -91
  293. package/src/components/picker/examples/picker-details.tsx +0 -44
  294. package/src/components/picker/examples/picker-searchable.tsx +0 -48
  295. package/src/components/picker/examples/picker-showcase.tsx +0 -66
  296. package/src/components/picker/examples/picker-usage.tsx +0 -20
  297. package/src/components/picker/picker.docs.tsx +0 -68
  298. package/src/components/popover/examples/popover-help.tsx +0 -57
  299. package/src/components/popover/examples/popover-menu.tsx +0 -51
  300. package/src/components/popover/examples/popover-showcase.tsx +0 -61
  301. package/src/components/popover/examples/popover-usage.tsx +0 -31
  302. package/src/components/popover/popover.docs.tsx +0 -84
  303. package/src/components/profile-image/examples/profile-image-fallbacks.tsx +0 -29
  304. package/src/components/profile-image/examples/profile-image-group.tsx +0 -34
  305. package/src/components/profile-image/examples/profile-image-showcase.tsx +0 -30
  306. package/src/components/profile-image/examples/profile-image-usage.tsx +0 -14
  307. package/src/components/profile-image/profile-image.docs.tsx +0 -81
  308. package/src/components/search-field/examples/search-field-filter.tsx +0 -53
  309. package/src/components/search-field/examples/search-field-showcase.tsx +0 -56
  310. package/src/components/search-field/examples/search-field-toolbar.tsx +0 -27
  311. package/src/components/search-field/examples/search-field-usage.tsx +0 -18
  312. package/src/components/search-field/search-field.docs.tsx +0 -58
  313. package/src/components/search-list/examples/search-list-dropdown.tsx +0 -53
  314. package/src/components/search-list/examples/search-list-groups.tsx +0 -64
  315. package/src/components/search-list/examples/search-list-showcase.tsx +0 -67
  316. package/src/components/search-list/examples/search-list-usage.tsx +0 -27
  317. package/src/components/search-list/search-list.docs.tsx +0 -87
  318. package/src/components/section/examples/section-actions.tsx +0 -35
  319. package/src/components/section/examples/section-groups.tsx +0 -41
  320. package/src/components/section/examples/section-showcase.tsx +0 -63
  321. package/src/components/section/examples/section-usage.tsx +0 -19
  322. package/src/components/section/section.docs.tsx +0 -51
  323. package/src/components/secure-field/examples/secure-field-new-password.tsx +0 -56
  324. package/src/components/secure-field/examples/secure-field-reveal.tsx +0 -20
  325. package/src/components/secure-field/examples/secure-field-showcase.tsx +0 -62
  326. package/src/components/secure-field/examples/secure-field-usage.tsx +0 -19
  327. package/src/components/secure-field/secure-field.docs.tsx +0 -72
  328. package/src/components/segmented-control/examples/segmented-control-overflow.tsx +0 -28
  329. package/src/components/segmented-control/examples/segmented-control-showcase.tsx +0 -59
  330. package/src/components/segmented-control/examples/segmented-control-usage.tsx +0 -20
  331. package/src/components/segmented-control/examples/segmented-control-views.tsx +0 -32
  332. package/src/components/segmented-control/segmented-control.docs.tsx +0 -61
  333. package/src/components/sheet/examples/sheet-choices.tsx +0 -58
  334. package/src/components/sheet/examples/sheet-share.tsx +0 -51
  335. package/src/components/sheet/examples/sheet-showcase.tsx +0 -74
  336. package/src/components/sheet/examples/sheet-usage.tsx +0 -32
  337. package/src/components/sheet/sheet.docs.tsx +0 -75
  338. package/src/components/sidebar/examples/sidebar-groups.tsx +0 -133
  339. package/src/components/sidebar/examples/sidebar-showcase.tsx +0 -123
  340. package/src/components/sidebar/examples/sidebar-unread.tsx +0 -66
  341. package/src/components/sidebar/examples/sidebar-usage.tsx +0 -52
  342. package/src/components/sidebar/sidebar.docs.tsx +0 -135
  343. package/src/components/stat-tile/examples/stat-tile-filters.tsx +0 -32
  344. package/src/components/stat-tile/examples/stat-tile-grid.tsx +0 -21
  345. package/src/components/stat-tile/examples/stat-tile-showcase.tsx +0 -52
  346. package/src/components/stat-tile/examples/stat-tile-usage.tsx +0 -13
  347. package/src/components/stat-tile/stat-tile.docs.tsx +0 -60
  348. package/src/components/status-indicator/examples/status-indicator-live.tsx +0 -34
  349. package/src/components/status-indicator/examples/status-indicator-showcase.tsx +0 -39
  350. package/src/components/status-indicator/examples/status-indicator-states.tsx +0 -17
  351. package/src/components/status-indicator/examples/status-indicator-usage.tsx +0 -9
  352. package/src/components/status-indicator/status-indicator.docs.tsx +0 -43
  353. package/src/components/swatch-picker/examples/swatch-picker-accents.tsx +0 -42
  354. package/src/components/swatch-picker/examples/swatch-picker-labels.tsx +0 -45
  355. package/src/components/swatch-picker/examples/swatch-picker-showcase.tsx +0 -70
  356. package/src/components/swatch-picker/examples/swatch-picker-usage.tsx +0 -39
  357. package/src/components/swatch-picker/swatch-picker.docs.tsx +0 -60
  358. package/src/components/tab-bar/examples/tab-bar-five-tabs.tsx +0 -66
  359. package/src/components/tab-bar/examples/tab-bar-minimize.tsx +0 -71
  360. package/src/components/tab-bar/examples/tab-bar-showcase.tsx +0 -82
  361. package/src/components/tab-bar/examples/tab-bar-usage.tsx +0 -54
  362. package/src/components/tab-bar/tab-bar.docs.tsx +0 -136
  363. package/src/components/tab-view/examples/tab-view-keyboard.tsx +0 -39
  364. package/src/components/tab-view/examples/tab-view-settings.tsx +0 -56
  365. package/src/components/tab-view/examples/tab-view-showcase.tsx +0 -53
  366. package/src/components/tab-view/examples/tab-view-usage.tsx +0 -23
  367. package/src/components/tab-view/tab-view.docs.tsx +0 -77
  368. package/src/components/table/examples/table-empty.tsx +0 -53
  369. package/src/components/table/examples/table-invoices.tsx +0 -102
  370. package/src/components/table/examples/table-selection.tsx +0 -150
  371. package/src/components/table/examples/table-showcase.tsx +0 -115
  372. package/src/components/table/examples/table-usage.tsx +0 -67
  373. package/src/components/table/examples/table-wide.tsx +0 -75
  374. package/src/components/table/table.docs.tsx +0 -131
  375. package/src/components/text-editor/examples/text-editor-comment.tsx +0 -48
  376. package/src/components/text-editor/examples/text-editor-count.tsx +0 -38
  377. package/src/components/text-editor/examples/text-editor-showcase.tsx +0 -58
  378. package/src/components/text-editor/examples/text-editor-usage.tsx +0 -25
  379. package/src/components/text-editor/text-editor.docs.tsx +0 -61
  380. package/src/components/text-field/examples/text-field-icons.tsx +0 -72
  381. package/src/components/text-field/examples/text-field-showcase.tsx +0 -50
  382. package/src/components/text-field/examples/text-field-usage.tsx +0 -18
  383. package/src/components/text-field/examples/text-field-validation.tsx +0 -27
  384. package/src/components/text-field/text-field.docs.tsx +0 -118
  385. package/src/components/toast/examples/toast-action.tsx +0 -32
  386. package/src/components/toast/examples/toast-promise.tsx +0 -45
  387. package/src/components/toast/examples/toast-showcase.tsx +0 -49
  388. package/src/components/toast/examples/toast-usage.tsx +0 -13
  389. package/src/components/toast/toast.docs.tsx +0 -79
  390. package/src/components/toggle/examples/toggle-checkboxes.tsx +0 -43
  391. package/src/components/toggle/examples/toggle-settings.tsx +0 -31
  392. package/src/components/toggle/examples/toggle-showcase.tsx +0 -59
  393. package/src/components/toggle/examples/toggle-usage.tsx +0 -13
  394. package/src/components/toggle/toggle.docs.tsx +0 -69
  395. package/src/components/tooltip/examples/tooltip-icon-buttons.tsx +0 -27
  396. package/src/components/tooltip/examples/tooltip-shortcuts.tsx +0 -38
  397. package/src/components/tooltip/examples/tooltip-showcase.tsx +0 -44
  398. package/src/components/tooltip/examples/tooltip-usage.tsx +0 -13
  399. package/src/components/tooltip/tooltip.docs.tsx +0 -56
  400. package/src/components/view-controller/examples/view-controller-action.tsx +0 -27
  401. package/src/components/view-controller/examples/view-controller-settings.tsx +0 -31
  402. package/src/components/view-controller/examples/view-controller-showcase.tsx +0 -45
  403. package/src/components/view-controller/examples/view-controller-usage.tsx +0 -19
  404. package/src/components/view-controller/view-controller.docs.tsx +0 -71
  405. package/src/docs/index.ts +0 -3
  406. package/src/docs/registry.ts +0 -113
  407. package/src/docs/snippet.ts +0 -17
  408. package/src/docs/types.ts +0 -180
@@ -1,6 +1,6 @@
1
- import { AnimatePresence, motion } from "motion/react"
1
+ import { AnimatePresence, motion, useReducedMotion } from "motion/react"
2
2
  import { spring } from "../../motion/transitions"
3
- import { useEffect, useState } from "react"
3
+ import { useEffect, useId, useState } from "react"
4
4
 
5
5
  interface Tip {
6
6
  text: string
@@ -22,30 +22,33 @@ const MARGIN = 8
22
22
  */
23
23
  export function TooltipHost() {
24
24
  const [tip, setTip] = useState<Tip | null>(null)
25
+ const tooltipId = useId()
26
+ const reducedMotion = useReducedMotion()
25
27
 
26
28
  useEffect(() => {
27
- if (
28
- !window.matchMedia(
29
- "(hover: hover) and (pointer: fine)"
30
- ).matches
31
- )
32
- return
29
+ const canHover = window.matchMedia("(hover: hover) and (pointer: fine)").matches
33
30
  let timer: ReturnType<typeof setTimeout> | undefined
34
31
  let current: Element | null = null
35
32
  let lastShown = 0
33
+ let described: Element | null = null
34
+ let previousDescription: string | null = null
35
+
36
+ const restoreDescription = () => {
37
+ if (!described) return
38
+ if (previousDescription === null) described.removeAttribute("aria-describedby")
39
+ else described.setAttribute("aria-describedby", previousDescription)
40
+ described = null
41
+ }
36
42
 
37
43
  const show = (element: Element) => {
38
44
  const text = element.getAttribute("data-tooltip")
39
45
  if (!text) return
40
46
  const rect = element.getBoundingClientRect()
41
- const above =
42
- rect.bottom + 40 > window.innerHeight
47
+ const above = rect.bottom + 40 > window.innerHeight
43
48
  setTip({
44
49
  text,
45
50
  x: rect.left + rect.width / 2,
46
- y: above
47
- ? rect.top - MARGIN
48
- : rect.bottom + MARGIN,
51
+ y: above ? rect.top - MARGIN : rect.bottom + MARGIN,
49
52
  above,
50
53
  })
51
54
  lastShown = Date.now()
@@ -54,13 +57,12 @@ export function TooltipHost() {
54
57
  clearTimeout(timer)
55
58
  if (current) lastShown = Date.now()
56
59
  current = null
60
+ restoreDescription()
57
61
  setTip(null)
58
62
  }
59
63
  const onOver = (event: PointerEvent) => {
60
- const element =
61
- (event.target as Element | null)?.closest?.(
62
- "[data-tooltip]"
63
- ) ?? null
64
+ if (!canHover) return
65
+ const element = (event.target as Element | null)?.closest?.("[data-tooltip]") ?? null
64
66
  if (element === current) return
65
67
  clearTimeout(timer)
66
68
  current = element
@@ -72,80 +74,81 @@ export function TooltipHost() {
72
74
  if (warm) show(element)
73
75
  else {
74
76
  setTip(null)
75
- timer = setTimeout(
76
- () =>
77
- current === element && show(element),
78
- DELAY
79
- )
77
+ timer = setTimeout(() => current === element && show(element), DELAY)
80
78
  }
81
79
  }
80
+ const onFocus = (event: FocusEvent) => {
81
+ const element = (event.target as Element | null)?.closest?.("[data-tooltip]") ?? null
82
+ if (!element) return
83
+ hide()
84
+ current = element
85
+ described = element
86
+ previousDescription = element.getAttribute("aria-describedby")
87
+ element.setAttribute(
88
+ "aria-describedby",
89
+ [previousDescription, tooltipId].filter(Boolean).join(" ")
90
+ )
91
+ show(element)
92
+ }
93
+ const onBlur = (event: FocusEvent) => {
94
+ if (described && !described.contains(event.relatedTarget as Node | null)) hide()
95
+ }
82
96
 
83
- window.document.addEventListener(
84
- "pointerover",
85
- onOver
86
- )
87
- window.document.addEventListener(
88
- "pointerdown",
89
- hide,
90
- true
91
- )
92
- window.document.addEventListener(
93
- "keydown",
94
- hide,
95
- true
96
- )
97
+ window.document.addEventListener("pointerover", onOver)
98
+ window.document.addEventListener("focusin", onFocus)
99
+ window.document.addEventListener("focusout", onBlur)
100
+ window.document.addEventListener("pointerdown", hide, true)
101
+ window.document.addEventListener("keydown", hide, true)
97
102
  window.addEventListener("scroll", hide, true)
98
103
  window.addEventListener("blur", hide)
99
104
  return () => {
100
105
  clearTimeout(timer)
101
- window.document.removeEventListener(
102
- "pointerover",
103
- onOver
104
- )
105
- window.document.removeEventListener(
106
- "pointerdown",
107
- hide,
108
- true
109
- )
110
- window.document.removeEventListener(
111
- "keydown",
112
- hide,
113
- true
114
- )
106
+ restoreDescription()
107
+ window.document.removeEventListener("pointerover", onOver)
108
+ window.document.removeEventListener("focusin", onFocus)
109
+ window.document.removeEventListener("focusout", onBlur)
110
+ window.document.removeEventListener("pointerdown", hide, true)
111
+ window.document.removeEventListener("keydown", hide, true)
115
112
  window.removeEventListener("scroll", hide, true)
116
113
  window.removeEventListener("blur", hide)
117
114
  }
118
- }, [])
115
+ }, [tooltipId])
119
116
 
120
117
  return (
121
118
  <AnimatePresence>
122
119
  {tip && (
123
120
  <motion.div
121
+ id={tooltipId}
124
122
  key={tip.text + tip.x}
125
123
  role="tooltip"
126
124
  className="pointer-events-none fixed z-[80] max-w-[240px] rounded-md bg-inverse px-2.5 py-1.5 text-center text-caption leading-tight font-medium text-on-inverse shadow-lg"
127
125
  style={{
128
- left: Math.min(
129
- Math.max(tip.x, 128),
130
- window.innerWidth - 128
131
- ),
126
+ left: Math.min(Math.max(tip.x, 128), window.innerWidth - 128),
132
127
  top: tip.y,
133
128
  translateX: "-50%",
134
129
  translateY: tip.above ? "-100%" : 0,
135
130
  }}
136
- initial={{
137
- opacity: 0,
138
- scale: 0.92,
139
- y: tip.above ? 4 : -4,
140
- }}
131
+ initial={
132
+ reducedMotion
133
+ ? false
134
+ : {
135
+ opacity: 0,
136
+ scale: 0.92,
137
+ y: tip.above ? 4 : -4,
138
+ }
139
+ }
141
140
  animate={{ opacity: 1, scale: 1, y: 0 }}
142
- exit={{
143
- opacity: 0,
144
- scale: 0.96,
145
- y: tip.above ? 2 : -2,
146
- transition: spring.snappy,
147
- }}
148
- transition={spring.snappy}
141
+ exit={
142
+ reducedMotion
143
+ ? { opacity: 0 }
144
+ : {
145
+ opacity: 0,
146
+ scale: 0.96,
147
+ y: tip.above ? 2 : -2,
148
+ transition: spring.snappy,
149
+ }
150
+ }
151
+ transition={reducedMotion ? { duration: 0 } : spring.snappy}
149
152
  >
150
153
  {tip.text}
151
154
  </motion.div>
@@ -19,11 +19,7 @@ const titleSizes = {
19
19
  compact: "text-[1.75rem] font-semibold tracking-tight",
20
20
  } as const
21
21
 
22
- export function ViewController({
23
- heading,
24
- className,
25
- children,
26
- }: ViewControllerProps) {
22
+ export function ViewController({ heading, className, children }: ViewControllerProps) {
27
23
  return (
28
24
  <article
29
25
  className={cn(
@@ -38,12 +34,7 @@ export function ViewController({
38
34
  )
39
35
  }
40
36
 
41
- function Heading({
42
- title,
43
- description,
44
- action,
45
- size = "default",
46
- }: HeadingProps) {
37
+ function Heading({ title, description, action, size = "default" }: HeadingProps) {
47
38
  const centered = size === "compact"
48
39
  return (
49
40
  <>
@@ -53,22 +44,14 @@ function Heading({
53
44
  centered && "justify-center text-center"
54
45
  )}
55
46
  >
56
- <h1
57
- className={cn(
58
- "min-w-0 wrap-anywhere",
59
- titleSizes[size]
60
- )}
61
- >
62
- {title}
63
- </h1>
47
+ <h1 className={cn("min-w-0 wrap-anywhere", titleSizes[size])}>{title}</h1>
64
48
  {action}
65
49
  </div>
66
50
  {description && (
67
51
  <p
68
52
  className={cn(
69
53
  "mt-2 max-w-prose text-subheadline leading-relaxed text-label-secondary",
70
- centered &&
71
- "mt-1 text-center text-[15px]"
54
+ centered && "mt-1 text-center text-[15px]"
72
55
  )}
73
56
  >
74
57
  {description}
@@ -0,0 +1,237 @@
1
+ import { clampRange as clamp } from "../../lib/range-value"
2
+ // Adapted from Bencho. See THIRD_PARTY_NOTICES.md for the MIT notice.
3
+ import { type CSSProperties, useEffect, useRef, useState } from "react"
4
+ import { useMediaQuery } from "../../hooks/use-media-query"
5
+ import { cn } from "../../lib/class-names"
6
+
7
+ /* ══ Wake slider ══════════════════════════════════════════
8
+ A range with no thumb: a row of thin bars, solid up to the
9
+ value and faint after it, with the reading beside them. Drag
10
+ anywhere along it. Drag slowly and the bars simply fill; drag
11
+ fast and every bar the value sweeps past springs up, taller the
12
+ faster you went, and settles back — a wake left behind the hand.
13
+
14
+ ── EACH BAR HOLDS A LITTLE ENERGY ──────────────────────
15
+ When the value crosses a bar, that bar takes energy from the
16
+ speed of the drag. Every frame all of it decays at the same
17
+ rate, so the bars crossed longest ago have fallen furthest: the
18
+ tallest ones are always at the hand and the run tails off
19
+ behind it. That falloff IS the wake; nothing draws it.
20
+
21
+ ── WRITTEN, NOT RENDERED ───────────────────────────────
22
+ The heights change every frame, so they go straight onto each
23
+ bar's transform from a ref. React renders when the value
24
+ changes, which is what the reading and the colours need, and
25
+ the loop runs only while some bar still has energy. */
26
+
27
+ const H = 20 // a bar at rest, px
28
+
29
+ export interface WakeSliderProps {
30
+ label: string
31
+ value?: number
32
+ defaultValue?: number
33
+ onChange?: (value: number) => void
34
+ bars?: number
35
+ wake?: number
36
+ disabled?: boolean
37
+ className?: string
38
+ formatValue?: (value: number) => string
39
+ }
40
+
41
+ export function WakeSlider({
42
+ label,
43
+ value: controlledValue,
44
+ defaultValue = 50,
45
+ onChange,
46
+ disabled = false,
47
+ className,
48
+ formatValue,
49
+ /* how many bars make the track */
50
+ bars = 36,
51
+ /* how high the wake rises, 0..100 */
52
+ wake = 60,
53
+ }: WakeSliderProps) {
54
+ const n = Math.round(clamp(Number.isFinite(bars) ? bars : 36, 12, 64))
55
+ const reduced = useMediaQuery("(prefers-reduced-motion: reduce)")
56
+ const [value, setValue] = useState(() => clamp(controlledValue ?? defaultValue, 0, 100))
57
+ const track = useRef<HTMLDivElement | null>(null)
58
+ const els = useRef<(HTMLSpanElement | null)[]>([])
59
+ const st = useRef({
60
+ energy: new Float32Array(n),
61
+ down: false,
62
+ lastX: 0,
63
+ lastT: 0,
64
+ speed: 0,
65
+ raf: 0,
66
+ at: value / 100, // the value as a fraction, without React in the way
67
+ lastBar: -1,
68
+ })
69
+ const knob = useRef(wake)
70
+ knob.current = reduced ? 0 : clamp(wake, 0, 100)
71
+ useEffect(() => {
72
+ if (controlledValue === undefined) return
73
+ const next = clamp(controlledValue, 0, 100)
74
+ st.current.at = next / 100
75
+ setValue(next)
76
+ }, [controlledValue])
77
+
78
+ useEffect(() => {
79
+ if (!reduced) return
80
+ cancelAnimationFrame(st.current.raf)
81
+ st.current.raf = 0
82
+ st.current.energy.fill(0)
83
+ for (const bar of els.current) if (bar) bar.style.transform = "none"
84
+ }, [reduced])
85
+
86
+ /* a new bar count is a new row */
87
+ useEffect(() => {
88
+ st.current.energy = new Float32Array(n)
89
+ }, [n])
90
+
91
+ const loop = () => {
92
+ const s = st.current
93
+ if (s.raf) return
94
+ let prev = performance.now()
95
+ const run = (now: number) => {
96
+ const dt = Math.min(0.05, (now - prev) / 1000)
97
+ prev = now
98
+ let live = false
99
+ const fall = Math.exp(-dt * 6.5)
100
+ for (let i = 0; i < s.energy.length; i++) {
101
+ s.energy[i] *= fall
102
+ if (s.energy[i] < 0.002) s.energy[i] = 0
103
+ else live = true
104
+ const b = els.current[i]
105
+ /* up to 2.6 times as tall at the very top of the knob */
106
+ if (b) b.style.transform = `scaleY(${(1 + s.energy[i] * 1.6).toFixed(3)})`
107
+ }
108
+ s.raf = live ? requestAnimationFrame(run) : 0
109
+ }
110
+ s.raf = requestAnimationFrame(run)
111
+ }
112
+
113
+ useEffect(() => () => cancelAnimationFrame(st.current.raf), [])
114
+
115
+ /* move the value to a fraction, waking every bar it passes */
116
+ const to = (f: number, speed: number) => {
117
+ const s = st.current
118
+ f = clamp(f, 0, 1)
119
+ const from = s.at
120
+ s.at = f
121
+ const a = Math.round(from * (n - 1)),
122
+ b = Math.round(f * (n - 1))
123
+ /* how hard: the drag's speed in bars per second, through a
124
+ curve that saturates, scaled by the knob */
125
+ const push = (1 - Math.exp(-speed / 900)) * (knob.current / 60)
126
+ const lo = Math.min(a, b),
127
+ hi = Math.max(a, b)
128
+ for (let i = lo; i <= hi; i++) s.energy[i] = Math.max(s.energy[i], push)
129
+ if (b !== s.lastBar) {
130
+ s.lastBar = b
131
+ }
132
+ const next = Math.round(f * 100)
133
+ setValue(next)
134
+ onChange?.(next)
135
+ if (!reduced && knob.current > 0) loop()
136
+ }
137
+
138
+ const frac = (clientX: number) => {
139
+ const r = track.current!.getBoundingClientRect()
140
+ const fraction = r.width ? (clientX - r.left) / r.width : 0
141
+ return getComputedStyle(track.current!).direction === "rtl" ? 1 - fraction : fraction
142
+ }
143
+
144
+ const lit = Math.round((value / 100) * (n - 1))
145
+
146
+ return (
147
+ <div className={cn("passui-wake-slider not-typeset", disabled && "opacity-40", className)}>
148
+ <div
149
+ ref={track}
150
+ className="passui-wake-track"
151
+ role="slider"
152
+ tabIndex={disabled ? -1 : 0}
153
+ aria-label={label}
154
+ aria-disabled={disabled || undefined}
155
+ aria-valuetext={formatValue?.(value)}
156
+ aria-valuemin={0}
157
+ aria-valuemax={100}
158
+ aria-valuenow={value}
159
+ style={{ height: H * 2.6, "--wake-bars": n } as CSSProperties}
160
+ onPointerDown={(e) => {
161
+ if (disabled || e.button !== 0) return
162
+ e.currentTarget.focus()
163
+ const s = st.current
164
+ try {
165
+ e.currentTarget.setPointerCapture(e.pointerId)
166
+ } catch {
167
+ /* a scripted pointer */
168
+ }
169
+ s.down = true
170
+ s.lastX = e.clientX
171
+ s.lastT = performance.now()
172
+ s.speed = 0
173
+ to(frac(e.clientX), 0)
174
+ }}
175
+ onPointerMove={(e) => {
176
+ const s = st.current
177
+ if (!s.down || disabled) return
178
+ const now = performance.now()
179
+ const dt = Math.max(0.008, (now - s.lastT) / 1000)
180
+ /* speed in px per second, smoothed so one jittery frame
181
+ cannot fake a fling */
182
+ const v = Math.abs(e.clientX - s.lastX) / dt
183
+ s.speed = s.speed * 0.5 + v * 0.5
184
+ s.lastX = e.clientX
185
+ s.lastT = now
186
+ to(frac(e.clientX), s.speed)
187
+ }}
188
+ onPointerUp={(e) => {
189
+ st.current.down = false
190
+ try {
191
+ e.currentTarget.releasePointerCapture(e.pointerId)
192
+ } catch {
193
+ /* never captured */
194
+ }
195
+ }}
196
+ onLostPointerCapture={() => {
197
+ st.current.down = false
198
+ }}
199
+ onPointerCancel={() => {
200
+ st.current.down = false
201
+ }}
202
+ onKeyDown={(e) => {
203
+ if (disabled) return
204
+ const step = e.shiftKey ? 10 : 1
205
+ let next: number | null = null
206
+ const rtl = getComputedStyle(e.currentTarget).direction === "rtl"
207
+ if (e.key === "ArrowUp" || e.key === (rtl ? "ArrowLeft" : "ArrowRight"))
208
+ next = value + step
209
+ if (e.key === "ArrowDown" || e.key === (rtl ? "ArrowRight" : "ArrowLeft"))
210
+ next = value - step
211
+ if (e.key === "Home") next = 0
212
+ if (e.key === "End") next = 100
213
+ if (next === null) return
214
+ e.preventDefault()
215
+ /* a key press is a small, quick step: a little wake */
216
+ to(clamp(next, 0, 100) / 100, 600)
217
+ }}
218
+ >
219
+ {Array.from({ length: n }, (_, i) => (
220
+ <span
221
+ key={i}
222
+ ref={(b) => {
223
+ els.current[i] = b
224
+ }}
225
+ aria-hidden="true"
226
+ className="passui-wake-bar"
227
+ data-on={(value > 0 && i <= lit) || undefined}
228
+ style={{ height: H }}
229
+ />
230
+ ))}
231
+ </div>
232
+ <span aria-hidden="true" className="passui-wake-value">
233
+ {formatValue?.(value) ?? value}
234
+ </span>
235
+ </div>
236
+ )
237
+ }
@@ -1,9 +1,5 @@
1
1
  /** Programmatic restoration does not collapse chrome; reaching the top always restores it. */
2
- export function minimizeDecision(
3
- top: number,
4
- anchor: number,
5
- userDriven: boolean
6
- ): boolean | null {
2
+ export function minimizeDecision(top: number, anchor: number, userDriven: boolean): boolean | null {
7
3
  if (top < 24) return false
8
4
  if (!userDriven) return null
9
5
  const delta = top - anchor
@@ -0,0 +1,23 @@
1
+ import { useCallback, useEffect, useState } from "react"
2
+
3
+ /** Keep the panel mounted until its material has returned to the trigger. */
4
+ export function useAnchoredDisclosure(disabled = false) {
5
+ const [open, setOpen] = useState(false)
6
+ const [mounted, setMounted] = useState(false)
7
+ useEffect(() => {
8
+ if (disabled) setOpen(false)
9
+ }, [disabled])
10
+ const show = useCallback(() => {
11
+ setMounted(true)
12
+ setOpen(true)
13
+ }, [])
14
+ const toggle = useCallback(() => {
15
+ setMounted(true)
16
+ setOpen((current) => !current)
17
+ }, [])
18
+ const close = useCallback(() => setOpen(false), [])
19
+ const onExited = useCallback(() => {
20
+ if (!open || disabled) setMounted(false)
21
+ }, [open, disabled])
22
+ return { open: open && !disabled, mounted, show, toggle, close, onExited }
23
+ }
@@ -1,8 +1,5 @@
1
1
  import { useLayoutEffect, useState } from "react"
2
- import {
3
- type AnchoredPlacement,
4
- placeAnchored,
5
- } from "../lib/anchored-placement"
2
+ import { type AnchoredPlacement, placeAnchored } from "../lib/anchored-placement"
6
3
 
7
4
  /**
8
5
  * Places a panel of `width` and `needed` height under its anchor and
@@ -12,15 +9,15 @@ import {
12
9
  export function useAnchoredPlacement(
13
10
  anchor: HTMLElement,
14
11
  width: number,
15
- needed: number
12
+ needed: number,
13
+ overlap = false
16
14
  ): AnchoredPlacement {
17
15
  const [placement, setPlacement] = useState(() =>
18
- placeAnchored(anchor, width, needed)
16
+ placeAnchored(anchor, width, needed, 6, overlap)
19
17
  )
20
18
 
21
19
  useLayoutEffect(() => {
22
- const replace = () =>
23
- setPlacement(placeAnchored(anchor, width, needed))
20
+ const replace = () => setPlacement(placeAnchored(anchor, width, needed, 6, overlap))
24
21
  replace()
25
22
  const viewport = window.visualViewport
26
23
  viewport?.addEventListener("resize", replace)
@@ -31,13 +28,9 @@ export function useAnchoredPlacement(
31
28
  viewport?.removeEventListener("resize", replace)
32
29
  viewport?.removeEventListener("scroll", replace)
33
30
  window.removeEventListener("resize", replace)
34
- window.removeEventListener(
35
- "scroll",
36
- replace,
37
- true
38
- )
31
+ window.removeEventListener("scroll", replace, true)
39
32
  }
40
- }, [anchor, width, needed])
33
+ }, [anchor, width, needed, overlap])
41
34
 
42
35
  return placement
43
36
  }
@@ -1,5 +1,5 @@
1
1
  import { type RefObject, useEffect } from "react"
2
- import { ownsFloatingLayer } from "../lib/floating-layers"
2
+ import { belongsToFloatingSurface, ownsFloatingLayer } from "../lib/floating-layers"
3
3
 
4
4
  /** Marks a floating layer (a pop-up list, a menu) whose clicks belong to what opened it. */
5
5
  export { FLOATING_LAYER } from "../lib/floating-layers"
@@ -19,39 +19,21 @@ export function useDismiss(
19
19
  const onPointerDown = (event: PointerEvent) => {
20
20
  const target = event.target as Element
21
21
  const surface = ref.current
22
- if (
23
- surface &&
24
- (surface.contains(target) ||
25
- ownsFloatingLayer(surface, target))
26
- )
27
- return
22
+ if (surface && belongsToFloatingSurface(surface, target)) return
28
23
  onDismiss()
29
24
  }
30
25
  const onKeyDown = (event: KeyboardEvent) => {
31
26
  if (event.defaultPrevented) return
32
- if (
33
- ref.current &&
34
- ownsFloatingLayer(
35
- ref.current,
36
- document.activeElement
37
- )
38
- )
39
- return
27
+ if (ref.current && ownsFloatingLayer(ref.current, document.activeElement)) return
40
28
  if (event.key === "Escape") {
41
29
  event.preventDefault()
42
30
  onDismiss()
43
31
  }
44
32
  }
45
- document.addEventListener(
46
- "pointerdown",
47
- onPointerDown
48
- )
33
+ document.addEventListener("pointerdown", onPointerDown)
49
34
  window.addEventListener("keydown", onKeyDown)
50
35
  return () => {
51
- document.removeEventListener(
52
- "pointerdown",
53
- onPointerDown
54
- )
36
+ document.removeEventListener("pointerdown", onPointerDown)
55
37
  window.removeEventListener("keydown", onKeyDown)
56
38
  }
57
39
  }, [ref, active, onDismiss])
@@ -0,0 +1,28 @@
1
+ import { type RefObject, useEffect } from "react"
2
+ import { isOutsideFloatingSurface } from "../lib/floating-layers"
3
+
4
+ /** Dismiss an anchored portal without stealing focus from outside pointer interactions. */
5
+ export function useFloatingDismiss(
6
+ surface: RefObject<HTMLElement | null>,
7
+ anchor: HTMLElement,
8
+ onDismiss: (restoreFocus: boolean) => void
9
+ ) {
10
+ useEffect(() => {
11
+ const onPointer = (event: PointerEvent) => {
12
+ if (isOutsideFloatingSurface(surface.current, anchor, event.target)) onDismiss(false)
13
+ }
14
+ const onFocus = (event: FocusEvent) => {
15
+ if (isOutsideFloatingSurface(surface.current, anchor, event.target)) onDismiss(false)
16
+ }
17
+ const onBlur = () => onDismiss(false)
18
+
19
+ document.addEventListener("pointerdown", onPointer, true)
20
+ document.addEventListener("focusin", onFocus, true)
21
+ window.addEventListener("blur", onBlur)
22
+ return () => {
23
+ document.removeEventListener("pointerdown", onPointer, true)
24
+ document.removeEventListener("focusin", onFocus, true)
25
+ window.removeEventListener("blur", onBlur)
26
+ }
27
+ }, [surface, anchor, onDismiss])
28
+ }