@passui/react 0.0.0-stage → 0.1.14

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 (275) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -2
  3. package/package.json +96 -5
  4. package/src/appearance/index.ts +2 -0
  5. package/src/appearance/platform.tsx +123 -0
  6. package/src/appearance/theme.tsx +535 -0
  7. package/src/components/ambient/ambient.docs.tsx +68 -0
  8. package/src/components/ambient/ambient.tsx +43 -0
  9. package/src/components/ambient/examples/ambient-images.tsx +30 -0
  10. package/src/components/ambient/examples/ambient-now-playing.tsx +55 -0
  11. package/src/components/ambient/examples/ambient-showcase.tsx +33 -0
  12. package/src/components/ambient/examples/ambient-usage.tsx +19 -0
  13. package/src/components/ambient/index.ts +1 -0
  14. package/src/components/button/button-styles.ts +60 -0
  15. package/src/components/button/button.docs.tsx +116 -0
  16. package/src/components/button/button.tsx +91 -0
  17. package/src/components/button/examples/button-disabled.tsx +19 -0
  18. package/src/components/button/examples/button-icon.tsx +39 -0
  19. package/src/components/button/examples/button-link.tsx +12 -0
  20. package/src/components/button/examples/button-pending.tsx +27 -0
  21. package/src/components/button/examples/button-showcase.tsx +115 -0
  22. package/src/components/button/examples/button-sizes.tsx +12 -0
  23. package/src/components/button/examples/button-usage.tsx +12 -0
  24. package/src/components/button/examples/button-variants.tsx +15 -0
  25. package/src/components/button/examples/button-with-icon.tsx +32 -0
  26. package/src/components/button/examples/icon-button-player.tsx +38 -0
  27. package/src/components/button/examples/icon-button-showcase.tsx +83 -0
  28. package/src/components/button/examples/icon-button-usage.tsx +11 -0
  29. package/src/components/button/examples/icon-button-variants.tsx +39 -0
  30. package/src/components/button/icon-button.docs.tsx +68 -0
  31. package/src/components/button/icon-button.tsx +73 -0
  32. package/src/components/button/pending-spinner.tsx +14 -0
  33. package/src/components/button/use-pending-indicator.ts +27 -0
  34. package/src/components/chip/chip.docs.tsx +37 -0
  35. package/src/components/chip/chip.tsx +35 -0
  36. package/src/components/chip/examples/chip-in-rows.tsx +19 -0
  37. package/src/components/chip/examples/chip-showcase.tsx +51 -0
  38. package/src/components/chip/examples/chip-tones.tsx +13 -0
  39. package/src/components/chip/examples/chip-usage.tsx +5 -0
  40. package/src/components/compact-date-picker/calendar-month.ts +131 -0
  41. package/src/components/compact-date-picker/compact-date-picker.docs.tsx +81 -0
  42. package/src/components/compact-date-picker/compact-date-picker.tsx +438 -0
  43. package/src/components/compact-date-picker/examples/compact-date-picker-showcase.tsx +35 -0
  44. package/src/components/compact-date-picker/examples/compact-date-picker-usage.tsx +22 -0
  45. package/src/components/compact-time-picker/compact-time-picker.docs.tsx +80 -0
  46. package/src/components/compact-time-picker/compact-time-picker.tsx +432 -0
  47. package/src/components/compact-time-picker/examples/compact-time-picker-showcase.tsx +31 -0
  48. package/src/components/compact-time-picker/examples/compact-time-picker-usage.tsx +21 -0
  49. package/src/components/compact-time-picker/time-value.ts +67 -0
  50. package/src/components/content-view/content-view.docs.tsx +61 -0
  51. package/src/components/content-view/content-view.tsx +197 -0
  52. package/src/components/content-view/examples/content-view-header-action.tsx +33 -0
  53. package/src/components/content-view/examples/content-view-showcase.tsx +65 -0
  54. package/src/components/content-view/examples/content-view-stats.tsx +35 -0
  55. package/src/components/content-view/examples/content-view-usage.tsx +14 -0
  56. package/src/components/content-view/index.ts +1 -0
  57. package/src/components/context-menu/conceal-menu-source.ts +33 -0
  58. package/src/components/context-menu/context-menu-host.tsx +445 -0
  59. package/src/components/context-menu/context-menu-store.ts +165 -0
  60. package/src/components/context-menu/context-menu.docs.tsx +92 -0
  61. package/src/components/context-menu/examples/context-menu-checked.tsx +37 -0
  62. package/src/components/context-menu/examples/context-menu-list.tsx +85 -0
  63. package/src/components/context-menu/examples/context-menu-showcase.tsx +56 -0
  64. package/src/components/context-menu/examples/context-menu-toolbar.tsx +63 -0
  65. package/src/components/context-menu/examples/context-menu-usage.tsx +24 -0
  66. package/src/components/context-menu/menu-position.ts +55 -0
  67. package/src/components/context-menu/menu-reveal.ts +75 -0
  68. package/src/components/context-menu/use-context-menu.ts +90 -0
  69. package/src/components/conversation/conversation.docs.tsx +88 -0
  70. package/src/components/conversation/conversation.tsx +279 -0
  71. package/src/components/conversation/examples/conversation-composer.tsx +36 -0
  72. package/src/components/conversation/examples/conversation-days.tsx +48 -0
  73. package/src/components/conversation/examples/conversation-showcase.tsx +71 -0
  74. package/src/components/conversation/examples/conversation-usage.tsx +28 -0
  75. package/src/components/conversation/index.ts +1 -0
  76. package/src/components/date-picker/date-picker.docs.tsx +88 -0
  77. package/src/components/date-picker/date-picker.tsx +103 -0
  78. package/src/components/date-picker/date-value.ts +37 -0
  79. package/src/components/date-picker/examples/date-picker-locales.tsx +41 -0
  80. package/src/components/date-picker/examples/date-picker-past-only.tsx +29 -0
  81. package/src/components/date-picker/examples/date-picker-showcase.tsx +49 -0
  82. package/src/components/date-picker/examples/date-picker-usage.tsx +22 -0
  83. package/src/components/dialog/dialog-host.tsx +156 -0
  84. package/src/components/dialog/dialog-store.ts +56 -0
  85. package/src/components/dialog/dialog.docs.tsx +114 -0
  86. package/src/components/dialog/dialog.tsx +200 -0
  87. package/src/components/dialog/examples/dialog-confirm.tsx +24 -0
  88. package/src/components/dialog/examples/dialog-form.tsx +46 -0
  89. package/src/components/dialog/examples/dialog-inline.tsx +48 -0
  90. package/src/components/dialog/examples/dialog-showcase.tsx +53 -0
  91. package/src/components/dialog/examples/dialog-usage.tsx +31 -0
  92. package/src/components/dialog/index.ts +1 -0
  93. package/src/components/labeled-content/examples/labeled-content-descriptions.tsx +37 -0
  94. package/src/components/labeled-content/examples/labeled-content-showcase.tsx +54 -0
  95. package/src/components/labeled-content/examples/labeled-content-usage.tsx +22 -0
  96. package/src/components/labeled-content/examples/labeled-content-values.tsx +26 -0
  97. package/src/components/labeled-content/examples/labeled-content-wide.tsx +46 -0
  98. package/src/components/labeled-content/labeled-content.docs.tsx +69 -0
  99. package/src/components/labeled-content/labeled-content.tsx +66 -0
  100. package/src/components/locale-switcher/examples/locale-switcher-native-names.tsx +30 -0
  101. package/src/components/locale-switcher/examples/locale-switcher-showcase.tsx +46 -0
  102. package/src/components/locale-switcher/examples/locale-switcher-translated-page.tsx +35 -0
  103. package/src/components/locale-switcher/examples/locale-switcher-usage.tsx +20 -0
  104. package/src/components/locale-switcher/index.ts +1 -0
  105. package/src/components/locale-switcher/locale-switcher.docs.tsx +91 -0
  106. package/src/components/locale-switcher/locale-switcher.tsx +252 -0
  107. package/src/components/picker/examples/picker-details.tsx +44 -0
  108. package/src/components/picker/examples/picker-searchable.tsx +48 -0
  109. package/src/components/picker/examples/picker-showcase.tsx +66 -0
  110. package/src/components/picker/examples/picker-usage.tsx +20 -0
  111. package/src/components/picker/picker.docs.tsx +68 -0
  112. package/src/components/picker/picker.tsx +493 -0
  113. package/src/components/popover/examples/popover-help.tsx +57 -0
  114. package/src/components/popover/examples/popover-menu.tsx +51 -0
  115. package/src/components/popover/examples/popover-showcase.tsx +61 -0
  116. package/src/components/popover/examples/popover-usage.tsx +31 -0
  117. package/src/components/popover/popover.docs.tsx +84 -0
  118. package/src/components/popover/popover.tsx +138 -0
  119. package/src/components/profile-image/examples/profile-image-fallbacks.tsx +29 -0
  120. package/src/components/profile-image/examples/profile-image-group.tsx +34 -0
  121. package/src/components/profile-image/examples/profile-image-showcase.tsx +30 -0
  122. package/src/components/profile-image/examples/profile-image-usage.tsx +14 -0
  123. package/src/components/profile-image/profile-image.docs.tsx +81 -0
  124. package/src/components/profile-image/profile-image.tsx +80 -0
  125. package/src/components/search-field/examples/search-field-filter.tsx +53 -0
  126. package/src/components/search-field/examples/search-field-showcase.tsx +56 -0
  127. package/src/components/search-field/examples/search-field-toolbar.tsx +27 -0
  128. package/src/components/search-field/examples/search-field-usage.tsx +18 -0
  129. package/src/components/search-field/search-field.docs.tsx +58 -0
  130. package/src/components/search-field/search-field.tsx +29 -0
  131. package/src/components/search-list/examples/search-list-dropdown.tsx +53 -0
  132. package/src/components/search-list/examples/search-list-groups.tsx +64 -0
  133. package/src/components/search-list/examples/search-list-showcase.tsx +67 -0
  134. package/src/components/search-list/examples/search-list-usage.tsx +27 -0
  135. package/src/components/search-list/search-list.docs.tsx +87 -0
  136. package/src/components/search-list/search-list.tsx +265 -0
  137. package/src/components/section/examples/section-actions.tsx +35 -0
  138. package/src/components/section/examples/section-groups.tsx +41 -0
  139. package/src/components/section/examples/section-showcase.tsx +63 -0
  140. package/src/components/section/examples/section-usage.tsx +19 -0
  141. package/src/components/section/section.docs.tsx +51 -0
  142. package/src/components/section/section.tsx +41 -0
  143. package/src/components/secure-field/examples/secure-field-new-password.tsx +56 -0
  144. package/src/components/secure-field/examples/secure-field-reveal.tsx +20 -0
  145. package/src/components/secure-field/examples/secure-field-showcase.tsx +62 -0
  146. package/src/components/secure-field/examples/secure-field-usage.tsx +19 -0
  147. package/src/components/secure-field/secure-field.docs.tsx +72 -0
  148. package/src/components/secure-field/secure-field.tsx +10 -0
  149. package/src/components/segmented-control/examples/segmented-control-overflow.tsx +28 -0
  150. package/src/components/segmented-control/examples/segmented-control-showcase.tsx +59 -0
  151. package/src/components/segmented-control/examples/segmented-control-usage.tsx +20 -0
  152. package/src/components/segmented-control/examples/segmented-control-views.tsx +32 -0
  153. package/src/components/segmented-control/segmented-control.docs.tsx +61 -0
  154. package/src/components/segmented-control/segmented-control.tsx +122 -0
  155. package/src/components/sheet/examples/sheet-choices.tsx +58 -0
  156. package/src/components/sheet/examples/sheet-share.tsx +51 -0
  157. package/src/components/sheet/examples/sheet-showcase.tsx +74 -0
  158. package/src/components/sheet/examples/sheet-usage.tsx +32 -0
  159. package/src/components/sheet/modal-environment.ts +113 -0
  160. package/src/components/sheet/sheet-portal.tsx +89 -0
  161. package/src/components/sheet/sheet.docs.tsx +75 -0
  162. package/src/components/sheet/sheet.tsx +112 -0
  163. package/src/components/sheet/use-sheet-focus.ts +130 -0
  164. package/src/components/sidebar/examples/sidebar-groups.tsx +133 -0
  165. package/src/components/sidebar/examples/sidebar-showcase.tsx +123 -0
  166. package/src/components/sidebar/examples/sidebar-unread.tsx +66 -0
  167. package/src/components/sidebar/examples/sidebar-usage.tsx +52 -0
  168. package/src/components/sidebar/sidebar.docs.tsx +135 -0
  169. package/src/components/sidebar/sidebar.tsx +69 -0
  170. package/src/components/stat-tile/examples/stat-tile-filters.tsx +32 -0
  171. package/src/components/stat-tile/examples/stat-tile-grid.tsx +21 -0
  172. package/src/components/stat-tile/examples/stat-tile-showcase.tsx +52 -0
  173. package/src/components/stat-tile/examples/stat-tile-usage.tsx +13 -0
  174. package/src/components/stat-tile/index.ts +1 -0
  175. package/src/components/stat-tile/stat-tile.docs.tsx +60 -0
  176. package/src/components/stat-tile/stat-tile.tsx +68 -0
  177. package/src/components/status-indicator/examples/status-indicator-live.tsx +34 -0
  178. package/src/components/status-indicator/examples/status-indicator-showcase.tsx +39 -0
  179. package/src/components/status-indicator/examples/status-indicator-states.tsx +17 -0
  180. package/src/components/status-indicator/examples/status-indicator-usage.tsx +9 -0
  181. package/src/components/status-indicator/status-indicator.docs.tsx +43 -0
  182. package/src/components/status-indicator/status-indicator.tsx +35 -0
  183. package/src/components/swatch-picker/examples/swatch-picker-accents.tsx +42 -0
  184. package/src/components/swatch-picker/examples/swatch-picker-labels.tsx +45 -0
  185. package/src/components/swatch-picker/examples/swatch-picker-showcase.tsx +70 -0
  186. package/src/components/swatch-picker/examples/swatch-picker-usage.tsx +39 -0
  187. package/src/components/swatch-picker/swatch-picker.docs.tsx +60 -0
  188. package/src/components/swatch-picker/swatch-picker.tsx +96 -0
  189. package/src/components/tab-bar/examples/tab-bar-five-tabs.tsx +66 -0
  190. package/src/components/tab-bar/examples/tab-bar-minimize.tsx +71 -0
  191. package/src/components/tab-bar/examples/tab-bar-showcase.tsx +82 -0
  192. package/src/components/tab-bar/examples/tab-bar-usage.tsx +54 -0
  193. package/src/components/tab-bar/tab-bar.docs.tsx +136 -0
  194. package/src/components/tab-bar/tab-bar.tsx +148 -0
  195. package/src/components/tab-view/examples/tab-view-keyboard.tsx +39 -0
  196. package/src/components/tab-view/examples/tab-view-settings.tsx +56 -0
  197. package/src/components/tab-view/examples/tab-view-showcase.tsx +53 -0
  198. package/src/components/tab-view/examples/tab-view-usage.tsx +23 -0
  199. package/src/components/tab-view/tab-view.docs.tsx +77 -0
  200. package/src/components/tab-view/tab-view.tsx +117 -0
  201. package/src/components/table/examples/table-empty.tsx +53 -0
  202. package/src/components/table/examples/table-invoices.tsx +102 -0
  203. package/src/components/table/examples/table-selection.tsx +150 -0
  204. package/src/components/table/examples/table-showcase.tsx +115 -0
  205. package/src/components/table/examples/table-usage.tsx +67 -0
  206. package/src/components/table/examples/table-wide.tsx +75 -0
  207. package/src/components/table/table.docs.tsx +131 -0
  208. package/src/components/table/table.tsx +149 -0
  209. package/src/components/text-editor/examples/text-editor-comment.tsx +48 -0
  210. package/src/components/text-editor/examples/text-editor-count.tsx +38 -0
  211. package/src/components/text-editor/examples/text-editor-showcase.tsx +58 -0
  212. package/src/components/text-editor/examples/text-editor-usage.tsx +25 -0
  213. package/src/components/text-editor/text-editor.docs.tsx +61 -0
  214. package/src/components/text-editor/text-editor.tsx +19 -0
  215. package/src/components/text-field/examples/text-field-icons.tsx +72 -0
  216. package/src/components/text-field/examples/text-field-showcase.tsx +50 -0
  217. package/src/components/text-field/examples/text-field-usage.tsx +18 -0
  218. package/src/components/text-field/examples/text-field-validation.tsx +27 -0
  219. package/src/components/text-field/text-field.docs.tsx +118 -0
  220. package/src/components/text-field/text-field.tsx +135 -0
  221. package/src/components/toast/examples/toast-action.tsx +32 -0
  222. package/src/components/toast/examples/toast-promise.tsx +45 -0
  223. package/src/components/toast/examples/toast-showcase.tsx +49 -0
  224. package/src/components/toast/examples/toast-usage.tsx +13 -0
  225. package/src/components/toast/toast-store.ts +166 -0
  226. package/src/components/toast/toast.docs.tsx +79 -0
  227. package/src/components/toast/toaster.tsx +374 -0
  228. package/src/components/toggle/examples/toggle-checkboxes.tsx +43 -0
  229. package/src/components/toggle/examples/toggle-settings.tsx +31 -0
  230. package/src/components/toggle/examples/toggle-showcase.tsx +59 -0
  231. package/src/components/toggle/examples/toggle-usage.tsx +13 -0
  232. package/src/components/toggle/toggle.docs.tsx +69 -0
  233. package/src/components/toggle/toggle.tsx +85 -0
  234. package/src/components/tooltip/examples/tooltip-icon-buttons.tsx +27 -0
  235. package/src/components/tooltip/examples/tooltip-shortcuts.tsx +38 -0
  236. package/src/components/tooltip/examples/tooltip-showcase.tsx +44 -0
  237. package/src/components/tooltip/examples/tooltip-usage.tsx +13 -0
  238. package/src/components/tooltip/tooltip-host.tsx +156 -0
  239. package/src/components/tooltip/tooltip.docs.tsx +56 -0
  240. package/src/components/view-controller/examples/view-controller-action.tsx +27 -0
  241. package/src/components/view-controller/examples/view-controller-settings.tsx +31 -0
  242. package/src/components/view-controller/examples/view-controller-showcase.tsx +45 -0
  243. package/src/components/view-controller/examples/view-controller-usage.tsx +19 -0
  244. package/src/components/view-controller/index.ts +1 -0
  245. package/src/components/view-controller/view-controller.docs.tsx +71 -0
  246. package/src/components/view-controller/view-controller.tsx +81 -0
  247. package/src/docs/index.ts +3 -0
  248. package/src/docs/registry.ts +113 -0
  249. package/src/docs/snippet.ts +17 -0
  250. package/src/docs/types.ts +180 -0
  251. package/src/hooks/scroll/minimize-decision.ts +13 -0
  252. package/src/hooks/use-anchored-placement.ts +43 -0
  253. package/src/hooks/use-dismiss.ts +58 -0
  254. package/src/hooks/use-media-query.ts +106 -0
  255. package/src/hooks/use-minimize-on-scroll.ts +92 -0
  256. package/src/hooks/use-visual-viewport.ts +76 -0
  257. package/src/hooks/viewport/types.ts +19 -0
  258. package/src/hooks/viewport/viewport-metrics.ts +25 -0
  259. package/src/icons/icons.tsx +298 -0
  260. package/src/index.ts +78 -0
  261. package/src/lib/anchored-placement.ts +92 -0
  262. package/src/lib/class-names.ts +21 -0
  263. package/src/lib/date.ts +96 -0
  264. package/src/lib/floating-layers.ts +28 -0
  265. package/src/lib/haptics.ts +25 -0
  266. package/src/lib/language.ts +21 -0
  267. package/src/lib/screen-edges.ts +45 -0
  268. package/src/lib/shapes.ts +70 -0
  269. package/src/motion/transitions.ts +30 -0
  270. package/src/styles/base.css +1 -0
  271. package/src/styles/styles.css +3 -0
  272. package/src/styles/theme.css +1 -0
  273. package/src/styles/typeset.css +1 -0
  274. package/src/styles/utilities.css +1 -0
  275. package/src/tokens.ts +1 -0
@@ -0,0 +1,81 @@
1
+ import type { PropsWithChildren, ReactNode } from "react"
2
+ import { cn } from "../../lib/class-names"
3
+
4
+ type ViewControllerProps = PropsWithChildren<{
5
+ heading: ReactNode
6
+ className?: string
7
+ }>
8
+
9
+ type HeadingProps = {
10
+ title: ReactNode
11
+ description?: ReactNode
12
+ action?: ReactNode
13
+ size?: keyof typeof titleSizes
14
+ }
15
+
16
+ const titleSizes = {
17
+ default: "text-3xl md:text-4xl",
18
+ // sign in style screens: centered, tighter, like a system sheet
19
+ compact: "text-[1.75rem] font-semibold tracking-tight",
20
+ } as const
21
+
22
+ export function ViewController({
23
+ heading,
24
+ className,
25
+ children,
26
+ }: ViewControllerProps) {
27
+ return (
28
+ <article
29
+ className={cn(
30
+ "container mx-auto flex flex-col",
31
+ "w-full gap-5 py-20 md:max-w-3xl",
32
+ className
33
+ )}
34
+ >
35
+ <section>{heading}</section>
36
+ {children}
37
+ </article>
38
+ )
39
+ }
40
+
41
+ function Heading({
42
+ title,
43
+ description,
44
+ action,
45
+ size = "default",
46
+ }: HeadingProps) {
47
+ const centered = size === "compact"
48
+ return (
49
+ <>
50
+ <div
51
+ className={cn(
52
+ "flex flex-wrap items-center gap-3",
53
+ centered && "justify-center text-center"
54
+ )}
55
+ >
56
+ <h1
57
+ className={cn(
58
+ "min-w-0 wrap-anywhere",
59
+ titleSizes[size]
60
+ )}
61
+ >
62
+ {title}
63
+ </h1>
64
+ {action}
65
+ </div>
66
+ {description && (
67
+ <p
68
+ className={cn(
69
+ "mt-2 max-w-prose text-subheadline leading-relaxed text-label-secondary",
70
+ centered &&
71
+ "mt-1 text-center text-[15px]"
72
+ )}
73
+ >
74
+ {description}
75
+ </p>
76
+ )}
77
+ </>
78
+ )
79
+ }
80
+
81
+ ViewController.Heading = Heading
@@ -0,0 +1,3 @@
1
+ export * from "./registry"
2
+ export * from "./types"
3
+ export * from "./snippet"
@@ -0,0 +1,113 @@
1
+ import { buttonDocs } from "../components/button/button.docs"
2
+ import { iconButtonDocs } from "../components/button/icon-button.docs"
3
+ import { chipDocs } from "../components/chip/chip.docs"
4
+ import { labeledContentDocs } from "../components/labeled-content/labeled-content.docs"
5
+ import { pickerDocs } from "../components/picker/picker.docs"
6
+ import { searchFieldDocs } from "../components/search-field/search-field.docs"
7
+ import { secureFieldDocs } from "../components/secure-field/secure-field.docs"
8
+ import { sectionDocs } from "../components/section/section.docs"
9
+ import { segmentedControlDocs } from "../components/segmented-control/segmented-control.docs"
10
+ import { statTileDocs } from "../components/stat-tile/stat-tile.docs"
11
+ import { statusIndicatorDocs } from "../components/status-indicator/status-indicator.docs"
12
+ import { swatchPickerDocs } from "../components/swatch-picker/swatch-picker.docs"
13
+ import { textFieldDocs } from "../components/text-field/text-field.docs"
14
+ import { toggleDocs } from "../components/toggle/toggle.docs"
15
+ import { compactDatePickerDocs } from "../components/compact-date-picker/compact-date-picker.docs"
16
+ import { compactTimePickerDocs } from "../components/compact-time-picker/compact-time-picker.docs"
17
+ import { datePickerDocs } from "../components/date-picker/date-picker.docs"
18
+ import { textEditorDocs } from "../components/text-editor/text-editor.docs"
19
+ import { searchListDocs } from "../components/search-list/search-list.docs"
20
+ import { profileImageDocs } from "../components/profile-image/profile-image.docs"
21
+ import { tabViewDocs } from "../components/tab-view/tab-view.docs"
22
+ import { tabBarDocs } from "../components/tab-bar/tab-bar.docs"
23
+ import { sidebarDocs } from "../components/sidebar/sidebar.docs"
24
+ import { viewControllerDocs } from "../components/view-controller/view-controller.docs"
25
+ import { tableDocs } from "../components/table/table.docs"
26
+ import { contentViewDocs } from "../components/content-view/content-view.docs"
27
+ import { conversationDocs } from "../components/conversation/conversation.docs"
28
+ import { ambientDocs } from "../components/ambient/ambient.docs"
29
+ import { dialogDocs } from "../components/dialog/dialog.docs"
30
+ import { sheetDocs } from "../components/sheet/sheet.docs"
31
+ import { popoverDocs } from "../components/popover/popover.docs"
32
+ import { toastDocs } from "../components/toast/toast.docs"
33
+ import { contextMenuDocs } from "../components/context-menu/context-menu.docs"
34
+ import { tooltipDocs } from "../components/tooltip/tooltip.docs"
35
+ import { localeSwitcherDocs } from "../components/locale-switcher/locale-switcher.docs"
36
+ import type { RegisteredDocs } from "./types"
37
+
38
+ /** Every documented component. Add one line per docs file. */
39
+ export const registry: readonly RegisteredDocs[] = [
40
+ buttonDocs,
41
+ iconButtonDocs,
42
+ chipDocs,
43
+ textFieldDocs,
44
+ secureFieldDocs,
45
+ searchFieldDocs,
46
+ toggleDocs,
47
+ segmentedControlDocs,
48
+ pickerDocs,
49
+ swatchPickerDocs,
50
+ sectionDocs,
51
+ labeledContentDocs,
52
+ statusIndicatorDocs,
53
+ statTileDocs,
54
+ datePickerDocs,
55
+ compactDatePickerDocs,
56
+ compactTimePickerDocs,
57
+ textEditorDocs,
58
+ searchListDocs,
59
+ profileImageDocs,
60
+ tabViewDocs,
61
+ tabBarDocs,
62
+ sidebarDocs,
63
+ viewControllerDocs,
64
+ tableDocs,
65
+ contentViewDocs,
66
+ conversationDocs,
67
+ ambientDocs,
68
+ dialogDocs,
69
+ sheetDocs,
70
+ popoverDocs,
71
+ toastDocs,
72
+ contextMenuDocs,
73
+ tooltipDocs,
74
+ localeSwitcherDocs,
75
+ ]
76
+
77
+ export {
78
+ dialogDocs,
79
+ sheetDocs,
80
+ popoverDocs,
81
+ toastDocs,
82
+ contextMenuDocs,
83
+ tooltipDocs,
84
+ localeSwitcherDocs,
85
+ tableDocs,
86
+ contentViewDocs,
87
+ conversationDocs,
88
+ ambientDocs,
89
+ tabViewDocs,
90
+ tabBarDocs,
91
+ sidebarDocs,
92
+ viewControllerDocs,
93
+ datePickerDocs,
94
+ compactDatePickerDocs,
95
+ compactTimePickerDocs,
96
+ textEditorDocs,
97
+ searchListDocs,
98
+ profileImageDocs,
99
+ buttonDocs,
100
+ chipDocs,
101
+ iconButtonDocs,
102
+ labeledContentDocs,
103
+ pickerDocs,
104
+ searchFieldDocs,
105
+ secureFieldDocs,
106
+ sectionDocs,
107
+ segmentedControlDocs,
108
+ statTileDocs,
109
+ statusIndicatorDocs,
110
+ swatchPickerDocs,
111
+ textFieldDocs,
112
+ toggleDocs,
113
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * A JSX attribute for a string, quoted so the code always parses: a
3
+ * plain `name="value"`, or `name={"value"}` when the value holds a quote,
4
+ * a brace, a backslash or a line break.
5
+ */
6
+ export function jsxAttribute(name: string, value: string) {
7
+ return /["\\{}\n]/.test(value)
8
+ ? `${name}={${JSON.stringify(value)}}`
9
+ : `${name}="${value}"`
10
+ }
11
+
12
+ /** Text as JSX children, wrapped in braces when JSX would misread it. */
13
+ export function jsxText(text: string) {
14
+ return /[{}<>]/.test(text)
15
+ ? `{${JSON.stringify(text)}}`
16
+ : text
17
+ }
@@ -0,0 +1,180 @@
1
+ import type { ComponentType, ReactNode } from "react"
2
+
3
+ /**
4
+ * A choice among fixed options. The options are object keys, so the
5
+ * record must name every member of the prop's union: adding a variant to
6
+ * a component fails the typecheck here until its docs list it too.
7
+ */
8
+ export type SelectControl<T extends string> = {
9
+ kind: "select"
10
+ options: Record<T, true>
11
+ default: T
12
+ }
13
+
14
+ export type BooleanControl = {
15
+ kind: "boolean"
16
+ default: boolean
17
+ }
18
+
19
+ export type TextControl = {
20
+ kind: "text"
21
+ default: string
22
+ /**
23
+ * The prop is required, so the snippet always writes it, even at its
24
+ * default value, and the copied code compiles.
25
+ */
26
+ required?: true
27
+ }
28
+
29
+ export type AnyControl =
30
+ | SelectControl<string>
31
+ | BooleanControl
32
+ | TextControl
33
+
34
+ /** The control that fits a prop's type. */
35
+ export type ControlFor<V> = [NonNullable<V>] extends [boolean]
36
+ ? BooleanControl
37
+ : [NonNullable<V>] extends [string]
38
+ ? string extends NonNullable<V>
39
+ ? TextControl
40
+ : SelectControl<NonNullable<V> & string>
41
+ : never
42
+
43
+ /** Controls for any of a component's props, plus its text children. */
44
+ export type Controls<P> = {
45
+ [K in Exclude<keyof P, "children">]?: ControlFor<P[K]>
46
+ } & { children?: TextControl }
47
+
48
+ /** The current value of every control. */
49
+ export type ControlValues<C> = {
50
+ [K in keyof C]-?: NonNullable<C[K]> extends {
51
+ kind: "select"
52
+ options: infer O
53
+ }
54
+ ? keyof O & string
55
+ : NonNullable<C[K]> extends BooleanControl
56
+ ? boolean
57
+ : string
58
+ }
59
+
60
+ /**
61
+ * An example is a real React function in the component's `examples/`
62
+ * folder, named `<slug>-<id>.tsx`; the site shows that file's source as
63
+ * its code, so the code is always what runs. `playground` values let the
64
+ * site open the example in the playground.
65
+ */
66
+ export type Example<C> = {
67
+ id: string
68
+ component: ComponentType
69
+ playground?: Partial<ControlValues<C>>
70
+ }
71
+
72
+ /** What the code snippet shows for children, when plain text is not enough. */
73
+ export type SnippetChildren = {
74
+ imports: string[]
75
+ children: string
76
+ /** Literal string props, written as name="value". */
77
+ extraProps?: Record<string, string>
78
+ /** Code expressions, written as name={expression}: state and handlers. */
79
+ expressionProps?: Record<string, string>
80
+ /** Objects spread onto the element, written as {...name}. */
81
+ spreadProps?: string[]
82
+ /** Lines placed before the element, such as a useState call. */
83
+ setup?: string[]
84
+ /**
85
+ * Demo-only controls the snippet writes itself, left out of the
86
+ * generated props: a `critical` switch written as `tone="critical"`.
87
+ */
88
+ omit?: string[]
89
+ /**
90
+ * The element to write when it is a part rather than the export
91
+ * itself: `Conversation.Messages` for `Conversation`.
92
+ */
93
+ element?: string
94
+ }
95
+
96
+ export type ComponentDocs<
97
+ C,
98
+ E extends readonly Example<C>[],
99
+ > = {
100
+ /** Kebab case, unique across the registry, used in URLs. */
101
+ slug: string
102
+ /** The component's export name, as written in code. */
103
+ name: string
104
+ /** Where it is imported from, for example `@passui/react/button`. */
105
+ importPath: string
106
+ controls: C
107
+ render: (values: ControlValues<C>) => ReactNode
108
+ childrenSnippet?: (
109
+ values: ControlValues<C>
110
+ ) => SnippetChildren
111
+ /** The smallest real use, shown under Usage (`<slug>-usage.tsx`). */
112
+ usage: ComponentType
113
+ /** A small, realistic interface built with it (`<slug>-showcase.tsx`). */
114
+ showcase: ComponentType
115
+ examples: E
116
+ /**
117
+ * The playground frame's least height in pixels, for components that
118
+ * open something over the page (a sheet, a popover, a menu) that the
119
+ * frame must have room to show.
120
+ */
121
+ previewHeight?: number
122
+ }
123
+
124
+ /**
125
+ * Rejects select options that are not members of the prop's union, so
126
+ * docs cannot offer a value the component does not accept.
127
+ */
128
+ type ExactOptions<C, P> = {
129
+ [K in keyof C]: K extends keyof P
130
+ ? C[K] extends { kind: "select"; options: infer O }
131
+ ? {
132
+ options: {
133
+ [Option in keyof O]: Option extends NonNullable<
134
+ P[K]
135
+ >
136
+ ? true
137
+ : never
138
+ }
139
+ }
140
+ : unknown
141
+ : unknown
142
+ }
143
+
144
+ /**
145
+ * Docs typed against a component's props. Curried so the props type is
146
+ * given once and control keys and example ids stay exact:
147
+ * `defineDocs<ButtonProps>()({ ... })`.
148
+ */
149
+ export function defineDocs<P>() {
150
+ return <
151
+ const C extends Controls<P>,
152
+ const E extends readonly Example<C>[],
153
+ >(
154
+ docs: ComponentDocs<C, E> & {
155
+ controls: ExactOptions<C, P>
156
+ }
157
+ ) => docs
158
+ }
159
+
160
+ /** Any component's docs, as the registry holds them. */
161
+ export type RegisteredDocs = {
162
+ slug: string
163
+ name: string
164
+ importPath: string
165
+ controls: Record<string, AnyControl | undefined>
166
+ examples: readonly {
167
+ id: string
168
+ component: ComponentType
169
+ playground?: Record<string, string | boolean>
170
+ }[]
171
+ usage: ComponentType
172
+ showcase: ComponentType
173
+ previewHeight?: number
174
+ render(
175
+ values: Record<string, string | boolean>
176
+ ): ReactNode
177
+ childrenSnippet?(
178
+ values: Record<string, string | boolean>
179
+ ): SnippetChildren
180
+ }
@@ -0,0 +1,13 @@
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 {
7
+ if (top < 24) return false
8
+ if (!userDriven) return null
9
+ const delta = top - anchor
10
+ if (delta < -12) return false
11
+ if (delta > 12) return true
12
+ return null
13
+ }
@@ -0,0 +1,43 @@
1
+ import { useLayoutEffect, useState } from "react"
2
+ import {
3
+ type AnchoredPlacement,
4
+ placeAnchored,
5
+ } from "../lib/anchored-placement"
6
+
7
+ /**
8
+ * Places a panel of `width` and `needed` height under its anchor and
9
+ * keeps it there: re-places while the viewport resizes or anything
10
+ * scrolls, so it never hangs off the screen.
11
+ */
12
+ export function useAnchoredPlacement(
13
+ anchor: HTMLElement,
14
+ width: number,
15
+ needed: number
16
+ ): AnchoredPlacement {
17
+ const [placement, setPlacement] = useState(() =>
18
+ placeAnchored(anchor, width, needed)
19
+ )
20
+
21
+ useLayoutEffect(() => {
22
+ const replace = () =>
23
+ setPlacement(placeAnchored(anchor, width, needed))
24
+ replace()
25
+ const viewport = window.visualViewport
26
+ viewport?.addEventListener("resize", replace)
27
+ viewport?.addEventListener("scroll", replace)
28
+ window.addEventListener("resize", replace)
29
+ window.addEventListener("scroll", replace, true)
30
+ return () => {
31
+ viewport?.removeEventListener("resize", replace)
32
+ viewport?.removeEventListener("scroll", replace)
33
+ window.removeEventListener("resize", replace)
34
+ window.removeEventListener(
35
+ "scroll",
36
+ replace,
37
+ true
38
+ )
39
+ }
40
+ }, [anchor, width, needed])
41
+
42
+ return placement
43
+ }
@@ -0,0 +1,58 @@
1
+ import { type RefObject, useEffect } from "react"
2
+ import { ownsFloatingLayer } from "../lib/floating-layers"
3
+
4
+ /** Marks a floating layer (a pop-up list, a menu) whose clicks belong to what opened it. */
5
+ export { FLOATING_LAYER } from "../lib/floating-layers"
6
+
7
+ /**
8
+ * Calls `onDismiss` when the user presses Escape or clicks outside `ref`
9
+ * while `active`, for menus, popovers and sheets. Clicks in a floating
10
+ * layer opened from inside, such as a pop-up button's list, don't count.
11
+ */
12
+ export function useDismiss(
13
+ ref: RefObject<HTMLElement | null>,
14
+ active: boolean,
15
+ onDismiss: () => void
16
+ ): void {
17
+ useEffect(() => {
18
+ if (!active) return
19
+ const onPointerDown = (event: PointerEvent) => {
20
+ const target = event.target as Element
21
+ const surface = ref.current
22
+ if (
23
+ surface &&
24
+ (surface.contains(target) ||
25
+ ownsFloatingLayer(surface, target))
26
+ )
27
+ return
28
+ onDismiss()
29
+ }
30
+ const onKeyDown = (event: KeyboardEvent) => {
31
+ if (event.defaultPrevented) return
32
+ if (
33
+ ref.current &&
34
+ ownsFloatingLayer(
35
+ ref.current,
36
+ document.activeElement
37
+ )
38
+ )
39
+ return
40
+ if (event.key === "Escape") {
41
+ event.preventDefault()
42
+ onDismiss()
43
+ }
44
+ }
45
+ document.addEventListener(
46
+ "pointerdown",
47
+ onPointerDown
48
+ )
49
+ window.addEventListener("keydown", onKeyDown)
50
+ return () => {
51
+ document.removeEventListener(
52
+ "pointerdown",
53
+ onPointerDown
54
+ )
55
+ window.removeEventListener("keydown", onKeyDown)
56
+ }
57
+ }, [ref, active, onDismiss])
58
+ }
@@ -0,0 +1,106 @@
1
+ import { useCallback, useSyncExternalStore } from "react"
2
+
3
+ const BREAKPOINTS = {
4
+ "2xl": 1536,
5
+ "3xl": 1600,
6
+ "4xl": 2000,
7
+ lg: 1024,
8
+ md: 800,
9
+ sm: 640,
10
+ xl: 1280,
11
+ } as const
12
+
13
+ export type Breakpoint = keyof typeof BREAKPOINTS
14
+ export type BreakpointQuery =
15
+ | Breakpoint
16
+ | `max-${Breakpoint}`
17
+ | `${Breakpoint}:max-${Breakpoint}`
18
+ function resolveMin(value: Breakpoint | number): string {
19
+ const px =
20
+ typeof value === "number" ? value : BREAKPOINTS[value]
21
+ return `(min-width: ${px}px)`
22
+ }
23
+
24
+ function resolveMax(value: Breakpoint | number): string {
25
+ const px =
26
+ typeof value === "number" ? value : BREAKPOINTS[value]
27
+ return `(max-width: ${px - 1}px)`
28
+ }
29
+
30
+ function parseQuery(
31
+ query: BreakpointQuery | MediaQueryInput | (string & {})
32
+ ): string {
33
+ if (typeof query !== "string") {
34
+ const parts: string[] = []
35
+ if (query.min != null)
36
+ parts.push(resolveMin(query.min))
37
+ if (query.max != null)
38
+ parts.push(resolveMax(query.max))
39
+ if (query.pointer === "coarse")
40
+ parts.push("(pointer: coarse)")
41
+ if (query.pointer === "fine")
42
+ parts.push("(pointer: fine)")
43
+ if (parts.length === 0) return "(min-width: 0px)"
44
+ return parts.join(" and ")
45
+ }
46
+
47
+ if (query.startsWith("(")) return query
48
+
49
+ const parts: string[] = []
50
+ for (const segment of query.split(":")) {
51
+ if (segment.startsWith("max-")) {
52
+ const bp = segment.slice(4)
53
+ if (bp in BREAKPOINTS)
54
+ parts.push(resolveMax(bp as Breakpoint))
55
+ } else if (segment in BREAKPOINTS) {
56
+ parts.push(resolveMin(segment as Breakpoint))
57
+ }
58
+ }
59
+
60
+ return parts.length > 0 ? parts.join(" and ") : query
61
+ }
62
+
63
+ function getServerSnapshot(): boolean {
64
+ return false
65
+ }
66
+
67
+ export type MediaQueryInput = {
68
+ min?: Breakpoint | number
69
+ max?: Breakpoint | number
70
+ /** Touch-like input (finger). Use "fine" for mouse/trackpad. */
71
+ pointer?: PointerPrecision
72
+ }
73
+
74
+ export type PointerPrecision = "coarse" | "fine"
75
+
76
+ export function useMediaQuery(
77
+ query: BreakpointQuery | MediaQueryInput | (string & {})
78
+ ): boolean {
79
+ const mediaQuery = parseQuery(query)
80
+
81
+ const subscribe = useCallback(
82
+ (callback: () => void) => {
83
+ if (typeof window === "undefined") return () => {}
84
+ const mql = window.matchMedia(mediaQuery)
85
+ mql.addEventListener("change", callback)
86
+ return () =>
87
+ mql.removeEventListener("change", callback)
88
+ },
89
+ [mediaQuery]
90
+ )
91
+
92
+ const getSnapshot = useCallback(() => {
93
+ if (typeof window === "undefined") return false
94
+ return window.matchMedia(mediaQuery).matches
95
+ }, [mediaQuery])
96
+
97
+ return useSyncExternalStore(
98
+ subscribe,
99
+ getSnapshot,
100
+ getServerSnapshot
101
+ )
102
+ }
103
+
104
+ export function useIsMobile(): boolean {
105
+ return useMediaQuery("(max-width: 768px)")
106
+ }