@passui/react 0.0.0-stage → 0.1.15

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 +130 -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,67 @@
1
+ import {
2
+ ProfileImage,
3
+ ProfileImageContent,
4
+ ProfileImageFallback,
5
+ } from "@passui/react/profile-image"
6
+ import {
7
+ Table,
8
+ TableBody,
9
+ TableCell,
10
+ TableHead,
11
+ TableHeader,
12
+ TableRow,
13
+ } from "@passui/react/table"
14
+
15
+ const members = [
16
+ {
17
+ name: "Aiko Kamado",
18
+ initials: "AK",
19
+ src: "/avatars/aiko.svg",
20
+ role: "Owner",
21
+ },
22
+ {
23
+ name: "Kenji Mori",
24
+ initials: "KM",
25
+ src: "/avatars/kenji.svg",
26
+ role: "Admin",
27
+ },
28
+ ]
29
+
30
+ export function TableUsage() {
31
+ return (
32
+ <div className="w-full max-w-md rounded-4xl bg-elevated p-4 shadow-sm ring-1 ring-separator/60">
33
+ <Table>
34
+ <TableHeader>
35
+ <TableRow>
36
+ <TableHead>Member</TableHead>
37
+ <TableHead>Role</TableHead>
38
+ </TableRow>
39
+ </TableHeader>
40
+ <TableBody>
41
+ {members.map((member) => (
42
+ <TableRow key={member.name}>
43
+ <TableCell>
44
+ <div className="flex items-center gap-3">
45
+ <ProfileImage className="size-8">
46
+ <ProfileImageContent
47
+ src={member.src}
48
+ />
49
+ <ProfileImageFallback>
50
+ {member.initials}
51
+ </ProfileImageFallback>
52
+ </ProfileImage>
53
+ <span className="text-subheadline font-medium text-label">
54
+ {member.name}
55
+ </span>
56
+ </div>
57
+ </TableCell>
58
+ <TableCell>
59
+ {member.role}
60
+ </TableCell>
61
+ </TableRow>
62
+ ))}
63
+ </TableBody>
64
+ </Table>
65
+ </div>
66
+ )
67
+ }
@@ -0,0 +1,75 @@
1
+ import {
2
+ Table,
3
+ TableBody,
4
+ TableCell,
5
+ TableHead,
6
+ TableHeader,
7
+ TableRow,
8
+ } from "@passui/react/table"
9
+
10
+ const events = [
11
+ {
12
+ time: "09:41",
13
+ event: "Signed in",
14
+ person: "aiko@example.com",
15
+ app: "Pass console",
16
+ device: "MacBook Air",
17
+ place: "Lisbon, PT",
18
+ },
19
+ {
20
+ time: "09:12",
21
+ event: "Passkey added",
22
+ person: "kenji@example.com",
23
+ app: "Accounts",
24
+ device: "iPhone 16",
25
+ place: "Porto, PT",
26
+ },
27
+ {
28
+ time: "08:57",
29
+ event: "Password changed",
30
+ person: "mira@example.com",
31
+ app: "Accounts",
32
+ device: "Pixel 9",
33
+ place: "Madrid, ES",
34
+ },
35
+ ]
36
+
37
+ export function TableWide() {
38
+ // Table scrolls sideways inside its card when it's too wide
39
+ return (
40
+ <div className="w-full max-w-md rounded-4xl bg-elevated p-4 shadow-sm ring-1 ring-separator/60">
41
+ <Table>
42
+ <TableHeader>
43
+ <TableRow>
44
+ <TableHead>Time</TableHead>
45
+ <TableHead>Event</TableHead>
46
+ <TableHead>Person</TableHead>
47
+ <TableHead>App</TableHead>
48
+ <TableHead>Device</TableHead>
49
+ <TableHead>Location</TableHead>
50
+ </TableRow>
51
+ </TableHeader>
52
+ <TableBody>
53
+ {events.map((row) => (
54
+ <TableRow key={row.time}>
55
+ <TableCell className="tabular-nums text-label-secondary">
56
+ {row.time}
57
+ </TableCell>
58
+ <TableCell className="font-medium text-label">
59
+ {row.event}
60
+ </TableCell>
61
+ <TableCell>
62
+ {row.person}
63
+ </TableCell>
64
+ <TableCell>{row.app}</TableCell>
65
+ <TableCell>
66
+ {row.device}
67
+ </TableCell>
68
+ <TableCell>{row.place}</TableCell>
69
+ </TableRow>
70
+ ))}
71
+ </TableBody>
72
+ </Table>
73
+ </div>
74
+ )
75
+ }
@@ -0,0 +1,131 @@
1
+ import { jsxText } from "../../docs/snippet"
2
+ import { defineDocs } from "../../docs/types"
3
+ import { TableEmpty } from "./examples/table-empty"
4
+ import { TableInvoices } from "./examples/table-invoices"
5
+ import { TableSelection } from "./examples/table-selection"
6
+ import { TableWide } from "./examples/table-wide"
7
+ import { TableShowcase } from "./examples/table-showcase"
8
+ import { TableUsage } from "./examples/table-usage"
9
+ import {
10
+ Table,
11
+ TableBody,
12
+ TableCaption,
13
+ TableCell,
14
+ TableFooter,
15
+ TableHead,
16
+ TableHeader,
17
+ TableRow,
18
+ } from "./table"
19
+
20
+ // The caption and footer are parts inside Table, so the snippet writes
21
+ // them into the children.
22
+ type DemoProps = {
23
+ caption: string
24
+ footer: boolean
25
+ }
26
+
27
+ const invoices = [
28
+ { id: "INV-104", status: "Paid", amount: "€120.00" },
29
+ { id: "INV-105", status: "Pending", amount: "€48.50" },
30
+ { id: "INV-106", status: "Paid", amount: "€310.00" },
31
+ ]
32
+
33
+ export const tableDocs = defineDocs<DemoProps>()({
34
+ slug: "table",
35
+ name: "Table",
36
+ importPath: "@passui/react/table",
37
+ controls: {
38
+ caption: { kind: "text", default: "Recent invoices" },
39
+ footer: { kind: "boolean", default: true },
40
+ },
41
+ render: ({ caption, footer }) => (
42
+ <div className="w-full max-w-md rounded-4xl bg-elevated p-4 shadow-sm ring-1 ring-separator/60">
43
+ <Table>
44
+ {caption && (
45
+ <TableCaption>{caption}</TableCaption>
46
+ )}
47
+ <TableHeader>
48
+ <TableRow>
49
+ <TableHead>Invoice</TableHead>
50
+ <TableHead>Status</TableHead>
51
+ <TableHead className="text-right">
52
+ Amount
53
+ </TableHead>
54
+ </TableRow>
55
+ </TableHeader>
56
+ <TableBody>
57
+ {invoices.map((invoice) => (
58
+ <TableRow key={invoice.id}>
59
+ <TableCell>
60
+ {invoice.id}
61
+ </TableCell>
62
+ <TableCell>
63
+ {invoice.status}
64
+ </TableCell>
65
+ <TableCell className="text-right tabular-nums">
66
+ {invoice.amount}
67
+ </TableCell>
68
+ </TableRow>
69
+ ))}
70
+ </TableBody>
71
+ {footer && (
72
+ <TableFooter>
73
+ <TableRow>
74
+ <TableCell colSpan={2}>
75
+ Total
76
+ </TableCell>
77
+ <TableCell className="text-right tabular-nums">
78
+ €478.50
79
+ </TableCell>
80
+ </TableRow>
81
+ </TableFooter>
82
+ )}
83
+ </Table>
84
+ </div>
85
+ ),
86
+ childrenSnippet: ({ caption, footer }) => ({
87
+ imports: [
88
+ `import { TableBody, ${caption ? "TableCaption, " : ""}TableCell, ${footer ? "TableFooter, " : ""}TableHead, TableHeader, TableRow } from "@passui/react/table"`,
89
+ ],
90
+ omit: ["caption", "footer"],
91
+ children: [
92
+ "",
93
+ ...(caption
94
+ ? [
95
+ ` <TableCaption>${jsxText(caption)}</TableCaption>`,
96
+ ]
97
+ : []),
98
+ " <TableHeader>",
99
+ " <TableRow>",
100
+ " <TableHead>Invoice</TableHead>",
101
+ ' <TableHead className="text-right">Amount</TableHead>',
102
+ " </TableRow>",
103
+ " </TableHeader>",
104
+ " <TableBody>",
105
+ " <TableRow>",
106
+ " <TableCell>INV-104</TableCell>",
107
+ ' <TableCell className="text-right">€120.00</TableCell>',
108
+ " </TableRow>",
109
+ " </TableBody>",
110
+ ...(footer
111
+ ? [
112
+ " <TableFooter>",
113
+ " <TableRow>",
114
+ " <TableCell>Total</TableCell>",
115
+ ' <TableCell className="text-right">€120.00</TableCell>',
116
+ " </TableRow>",
117
+ " </TableFooter>",
118
+ ]
119
+ : []),
120
+ "",
121
+ ].join("\n"),
122
+ }),
123
+ usage: TableUsage,
124
+ showcase: TableShowcase,
125
+ examples: [
126
+ { id: "invoices", component: TableInvoices },
127
+ { id: "selection", component: TableSelection },
128
+ { id: "wide", component: TableWide },
129
+ { id: "empty", component: TableEmpty },
130
+ ],
131
+ })
@@ -0,0 +1,149 @@
1
+ import type * as React from "react"
2
+
3
+ import { cn } from "../../lib/class-names"
4
+
5
+ function Table({
6
+ className,
7
+ ...props
8
+ }: React.ComponentProps<"table">) {
9
+ return (
10
+ <div
11
+ data-slot="table-container"
12
+ className="relative w-full overflow-x-auto"
13
+ >
14
+ <table
15
+ data-slot="table"
16
+ className={cn(
17
+ "w-full caption-bottom text-subheadline text-label",
18
+ className
19
+ )}
20
+ {...props}
21
+ />
22
+ </div>
23
+ )
24
+ }
25
+
26
+ function TableHeader({
27
+ className,
28
+ ...props
29
+ }: React.ComponentProps<"thead">) {
30
+ return (
31
+ <thead
32
+ data-slot="table-header"
33
+ className={cn(
34
+ "[&_tr]:border-separator [&_tr]:border-b",
35
+ className
36
+ )}
37
+ {...props}
38
+ />
39
+ )
40
+ }
41
+
42
+ function TableBody({
43
+ className,
44
+ ...props
45
+ }: React.ComponentProps<"tbody">) {
46
+ return (
47
+ <tbody
48
+ data-slot="table-body"
49
+ className={cn(
50
+ "[&_tr:last-child]:border-0",
51
+ className
52
+ )}
53
+ {...props}
54
+ />
55
+ )
56
+ }
57
+
58
+ function TableFooter({
59
+ className,
60
+ ...props
61
+ }: React.ComponentProps<"tfoot">) {
62
+ return (
63
+ <tfoot
64
+ data-slot="table-footer"
65
+ className={cn(
66
+ "border-separator border-t bg-fill/50 font-semibold [&>tr]:last:border-b-0",
67
+ className
68
+ )}
69
+ {...props}
70
+ />
71
+ )
72
+ }
73
+
74
+ function TableRow({
75
+ className,
76
+ ...props
77
+ }: React.ComponentProps<"tr">) {
78
+ return (
79
+ <tr
80
+ data-slot="table-row"
81
+ className={cn(
82
+ "border-separator border-b transition-colors duration-fast hover:bg-fill/50 has-aria-expanded:bg-fill/50",
83
+ "data-[state=selected]:bg-accent-soft/60",
84
+ className
85
+ )}
86
+ {...props}
87
+ />
88
+ )
89
+ }
90
+
91
+ function TableHead({
92
+ className,
93
+ ...props
94
+ }: React.ComponentProps<"th">) {
95
+ return (
96
+ <th
97
+ data-slot="table-head"
98
+ className={cn(
99
+ "h-10 px-3 text-start align-middle text-footnote font-semibold whitespace-nowrap",
100
+ "text-label-secondary has-[[role=checkbox]]:pe-0",
101
+ className
102
+ )}
103
+ {...props}
104
+ />
105
+ )
106
+ }
107
+
108
+ function TableCell({
109
+ className,
110
+ ...props
111
+ }: React.ComponentProps<"td">) {
112
+ return (
113
+ <td
114
+ data-slot="table-cell"
115
+ className={cn(
116
+ "px-3 py-2.5 align-middle whitespace-nowrap has-[[role=checkbox]]:pe-0",
117
+ className
118
+ )}
119
+ {...props}
120
+ />
121
+ )
122
+ }
123
+
124
+ function TableCaption({
125
+ className,
126
+ ...props
127
+ }: React.ComponentProps<"caption">) {
128
+ return (
129
+ <caption
130
+ data-slot="table-caption"
131
+ className={cn(
132
+ "mt-4 text-footnote text-label-secondary",
133
+ className
134
+ )}
135
+ {...props}
136
+ />
137
+ )
138
+ }
139
+
140
+ export {
141
+ Table,
142
+ TableBody,
143
+ TableCaption,
144
+ TableCell,
145
+ TableFooter,
146
+ TableHead,
147
+ TableHeader,
148
+ TableRow,
149
+ }
@@ -0,0 +1,48 @@
1
+ import { toast } from "@passui/react"
2
+ import { Button } from "@passui/react/button"
3
+ import { TextEditor } from "@passui/react/text-editor"
4
+ import { useId, useState } from "react"
5
+
6
+ export function TextEditorComment() {
7
+ const commentId = useId()
8
+ const [comment, setComment] = useState("")
9
+
10
+ return (
11
+ <div className="flex w-full max-w-sm flex-col gap-3 rounded-4xl bg-elevated p-5 shadow-sm ring-1 ring-separator/60">
12
+ <label
13
+ htmlFor={commentId}
14
+ className="text-subheadline font-semibold"
15
+ >
16
+ Add a comment
17
+ </label>
18
+ <TextEditor
19
+ id={commentId}
20
+ placeholder="Share your thoughts"
21
+ value={comment}
22
+ onChange={(event) =>
23
+ setComment(event.target.value)
24
+ }
25
+ />
26
+ <div className="flex justify-end gap-2">
27
+ <Button
28
+ variant="secondary"
29
+ size="sm"
30
+ onClick={() => setComment("")}
31
+ >
32
+ Cancel
33
+ </Button>
34
+ <Button
35
+ variant="accent"
36
+ size="sm"
37
+ disabled={!comment.trim()}
38
+ onClick={() => {
39
+ setComment("")
40
+ toast.success("Comment posted")
41
+ }}
42
+ >
43
+ Post
44
+ </Button>
45
+ </div>
46
+ </div>
47
+ )
48
+ }
@@ -0,0 +1,38 @@
1
+ import { TextEditor } from "@passui/react/text-editor"
2
+ import { useId, useState } from "react"
3
+
4
+ const limit = 160
5
+
6
+ export function TextEditorCount() {
7
+ const statusId = useId()
8
+ const [status, setStatus] = useState(
9
+ "Out hiking until Sunday."
10
+ )
11
+ const countId = useId()
12
+
13
+ return (
14
+ <div className="flex w-full max-w-sm flex-col gap-2">
15
+ <label
16
+ htmlFor={statusId}
17
+ className="text-subheadline font-semibold"
18
+ >
19
+ Status
20
+ </label>
21
+ <TextEditor
22
+ id={statusId}
23
+ maxLength={limit}
24
+ aria-describedby={countId}
25
+ value={status}
26
+ onChange={(event) =>
27
+ setStatus(event.target.value)
28
+ }
29
+ />
30
+ <span
31
+ id={countId}
32
+ className="self-end text-caption text-label-tertiary tabular-nums"
33
+ >
34
+ {status.length} / {limit}
35
+ </span>
36
+ </div>
37
+ )
38
+ }
@@ -0,0 +1,58 @@
1
+ import { toast } from "@passui/react"
2
+ import { Button } from "@passui/react/button"
3
+ import { TextEditor } from "@passui/react/text-editor"
4
+ import { TextField } from "@passui/react/text-field"
5
+ import { useId, useState } from "react"
6
+
7
+ export function TextEditorShowcase() {
8
+ const messageId = useId()
9
+ const [subject, setSubject] = useState("")
10
+ const [message, setMessage] = useState("")
11
+
12
+ return (
13
+ <form
14
+ className="flex w-full max-w-sm flex-col gap-4 rounded-4xl bg-elevated p-6 shadow-sm ring-1 ring-separator/60"
15
+ onSubmit={(event) => {
16
+ event.preventDefault()
17
+ toast.success("Thanks, we got your message")
18
+ setSubject("")
19
+ setMessage("")
20
+ }}
21
+ >
22
+ <h2 className="text-headline font-semibold text-label">
23
+ Contact support
24
+ </h2>
25
+ <TextField
26
+ label="Subject"
27
+ placeholder="I can't sign in on my tablet"
28
+ value={subject}
29
+ onChange={(event) =>
30
+ setSubject(event.target.value)
31
+ }
32
+ />
33
+ <div className="flex flex-col gap-2">
34
+ <label
35
+ htmlFor={messageId}
36
+ className="text-subheadline font-semibold"
37
+ >
38
+ Message
39
+ </label>
40
+ <TextEditor
41
+ id={messageId}
42
+ placeholder="What happened, and what did you expect?"
43
+ value={message}
44
+ onChange={(event) =>
45
+ setMessage(event.target.value)
46
+ }
47
+ />
48
+ </div>
49
+ <Button
50
+ type="submit"
51
+ variant="accent"
52
+ disabled={!subject || !message}
53
+ >
54
+ Send
55
+ </Button>
56
+ </form>
57
+ )
58
+ }
@@ -0,0 +1,25 @@
1
+ import { TextEditor } from "@passui/react/text-editor"
2
+ import { useId, useState } from "react"
3
+
4
+ export function TextEditorUsage() {
5
+ const bioId = useId()
6
+ const [bio, setBio] = useState("")
7
+ return (
8
+ <div className="flex w-full max-w-sm flex-col gap-2">
9
+ <label
10
+ htmlFor={bioId}
11
+ className="text-subheadline font-semibold"
12
+ >
13
+ Bio
14
+ </label>
15
+ <TextEditor
16
+ id={bioId}
17
+ placeholder="A few words about you"
18
+ value={bio}
19
+ onChange={(event) =>
20
+ setBio(event.target.value)
21
+ }
22
+ />
23
+ </div>
24
+ )
25
+ }
@@ -0,0 +1,61 @@
1
+ import { TextEditorComment } from "./examples/text-editor-comment"
2
+ import type { ComponentProps } from "react"
3
+ import { useState } from "react"
4
+ import { defineDocs } from "../../docs/types"
5
+ import { TextEditorCount } from "./examples/text-editor-count"
6
+ import { TextEditorShowcase } from "./examples/text-editor-showcase"
7
+ import { TextEditorUsage } from "./examples/text-editor-usage"
8
+ import { TextEditor } from "./text-editor"
9
+
10
+ type TextEditorProps = ComponentProps<typeof TextEditor>
11
+ type DemoProps = Pick<
12
+ TextEditorProps,
13
+ "placeholder" | "disabled" | "readOnly"
14
+ >
15
+
16
+ function TextEditorDemo(props: DemoProps) {
17
+ const [bio, setBio] = useState("")
18
+ return (
19
+ <div className="w-full max-w-sm">
20
+ <TextEditor
21
+ {...props}
22
+ aria-label="Bio"
23
+ value={bio}
24
+ onChange={(event) =>
25
+ setBio(event.target.value)
26
+ }
27
+ />
28
+ </div>
29
+ )
30
+ }
31
+
32
+ export const textEditorDocs = defineDocs<TextEditorProps>()({
33
+ slug: "text-editor",
34
+ name: "TextEditor",
35
+ importPath: "@passui/react/text-editor",
36
+ controls: {
37
+ placeholder: {
38
+ kind: "text",
39
+ default: "A few words about you",
40
+ },
41
+ disabled: { kind: "boolean", default: false },
42
+ readOnly: { kind: "boolean", default: false },
43
+ },
44
+ render: (values) => <TextEditorDemo {...values} />,
45
+ childrenSnippet: () => ({
46
+ imports: ['import { useState } from "react"'],
47
+ setup: ['const [bio, setBio] = useState("")'],
48
+ children: "",
49
+ extraProps: { "aria-label": "Bio" },
50
+ expressionProps: {
51
+ value: "bio",
52
+ onChange: "(event) => setBio(event.target.value)",
53
+ },
54
+ }),
55
+ usage: TextEditorUsage,
56
+ showcase: TextEditorShowcase,
57
+ examples: [
58
+ { id: "count", component: TextEditorCount },
59
+ { id: "comment", component: TextEditorComment },
60
+ ],
61
+ })
@@ -0,0 +1,19 @@
1
+ import type { ComponentProps } from "react"
2
+ import { cn } from "../../lib/class-names"
3
+ import { textControlClasses } from "../text-field/text-field"
4
+
5
+ export function TextEditor({
6
+ className,
7
+ ...props
8
+ }: ComponentProps<"textarea">) {
9
+ return (
10
+ <textarea
11
+ {...props}
12
+ className={cn(
13
+ textControlClasses,
14
+ "min-h-28 resize-y",
15
+ className
16
+ )}
17
+ />
18
+ )
19
+ }