appos 0.4.3-0 → 0.5.1-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/dist/exports/api/index.d.mts +3 -3
  2. package/dist/exports/api/index.mjs +34 -9
  3. package/dist/exports/api/workflows/index.d.mts +2 -2
  4. package/dist/exports/api/workflows/index.mjs +2 -2
  5. package/dist/exports/{auth-By0xx0MI.d.mts → auth-BCOIpGDO.d.mts} +325 -214
  6. package/dist/exports/cli/index.d.mts +105 -106
  7. package/dist/exports/cli/index.mjs +87 -13
  8. package/dist/exports/{constants-BePPc_yF.mjs → constants-BicCnEiJ.mjs} +7 -1
  9. package/dist/exports/{index-Bpo5QE7k.d.mts → index-CiuTp085.d.mts} +580 -614
  10. package/dist/exports/{openapi-crG3j4xx.mjs → openapi-uisUTLq7.mjs} +45 -102
  11. package/dist/exports/{send-email-Bgcdjy-e.mjs → send-email-CXxlkfFL.mjs} +1 -1
  12. package/dist/exports/{server-BlNxgHUc.mjs → server-CA4aI0U6.mjs} +6 -2
  13. package/dist/exports/storybook/index.d.ts +40 -0
  14. package/dist/exports/storybook/index.js +43 -0
  15. package/dist/exports/tests/api.d.mts +2 -2
  16. package/dist/exports/tests/api.mjs +3 -3
  17. package/dist/exports/vite/index.d.mts +19 -3
  18. package/dist/exports/vite/index.mjs +82 -6
  19. package/dist/exports/web/index.d.ts +2247 -700
  20. package/dist/exports/web/index.js +2445 -754
  21. package/dist/exports/web/routes.d.mts +41 -43
  22. package/dist/exports/web/ssr.d.mts +2 -2
  23. package/package.json +48 -31
  24. package/src/storybook/.storybook/main.ts +119 -0
  25. package/src/storybook/.storybook/manager.ts +75 -0
  26. package/src/storybook/.storybook/preview.tsx +76 -0
  27. package/src/storybook/components/ColorGrid.tsx +324 -0
  28. package/src/storybook/components/IconGallery.tsx +268 -0
  29. package/src/storybook/components/SpacingScale.tsx +236 -0
  30. package/src/storybook/components/TypographyScale.tsx +277 -0
  31. package/src/storybook/components/index.ts +3 -0
  32. package/src/storybook/docs/Introduction.mdx +29 -0
  33. package/src/storybook/docs/foundations/Colors.mdx +27 -0
  34. package/src/storybook/docs/foundations/Icons.mdx +26 -0
  35. package/src/storybook/docs/foundations/Spacing.mdx +23 -0
  36. package/src/storybook/docs/foundations/Typography.mdx +39 -0
  37. package/src/storybook/index.ts +147 -0
  38. package/src/storybook/shims/void-elements.js +18 -0
  39. package/src/web/client/auth-paths.ts +148 -0
  40. package/src/web/client/auth.ts +218 -0
  41. package/src/web/client/i18n.d.ts +9 -0
  42. package/src/web/client/i18n.ts +127 -0
  43. package/src/web/client/react-router.ts +84 -0
  44. package/src/web/hooks/index.ts +1 -0
  45. package/src/web/hooks/use-mobile.ts +19 -0
  46. package/src/web/index.ts +42 -0
  47. package/src/web/lib/colors.ts +220 -0
  48. package/src/web/lib/utils.ts +52 -0
  49. package/src/web/routes/auth/_layout.tsx +5 -11
  50. package/src/web/routes.ts +101 -0
  51. package/src/web/server/context.ts +14 -0
  52. package/src/web/server/render.ts +11 -0
  53. package/src/web/ssr.ts +17 -0
  54. package/src/web/ui/accordion.stories.tsx +183 -0
  55. package/src/web/ui/accordion.tsx +134 -0
  56. package/src/web/ui/alert-dialog.stories.tsx +215 -0
  57. package/src/web/ui/alert-dialog.tsx +328 -0
  58. package/src/web/ui/alert.stories.tsx +224 -0
  59. package/src/web/ui/alert.tsx +136 -0
  60. package/src/web/ui/animated-check.stories.tsx +200 -0
  61. package/src/web/ui/animated-check.tsx +98 -0
  62. package/src/web/ui/aspect-ratio.stories.tsx +204 -0
  63. package/src/web/ui/aspect-ratio.tsx +36 -0
  64. package/src/web/ui/auth/__mocks__/auth-context.tsx +273 -0
  65. package/src/web/ui/auth/auth-card.stories.tsx +295 -0
  66. package/src/web/ui/auth/auth-card.tsx +124 -0
  67. package/src/web/ui/auth/auth-layout.stories.tsx +330 -0
  68. package/src/web/ui/auth/auth-layout.tsx +269 -0
  69. package/src/web/ui/auth/captcha-widget.stories.tsx +200 -0
  70. package/src/web/ui/auth/captcha-widget.tsx +197 -0
  71. package/src/web/ui/auth/context.tsx +87 -0
  72. package/src/web/ui/auth/email-input.stories.tsx +167 -0
  73. package/src/web/ui/auth/email-input.tsx +84 -0
  74. package/src/web/ui/auth/forms/email-otp-form.tsx +377 -0
  75. package/src/web/ui/auth/forms/forgot-password-form.tsx +240 -0
  76. package/src/web/ui/auth/forms/index.ts +40 -0
  77. package/src/web/ui/auth/forms/login-form.tsx +486 -0
  78. package/src/web/ui/auth/forms/phone-otp-form.tsx +388 -0
  79. package/src/web/ui/auth/forms/reset-password-form.tsx +331 -0
  80. package/src/web/ui/auth/forms/signup-form.tsx +499 -0
  81. package/src/web/ui/auth/forms/two-factor-form.tsx +410 -0
  82. package/src/web/ui/auth/forms/verify-email-form.tsx +373 -0
  83. package/src/web/ui/auth/hooks.ts +266 -0
  84. package/src/web/ui/auth/index.ts +31 -0
  85. package/src/web/ui/auth/magic-link-form.tsx +191 -0
  86. package/src/web/ui/auth/otp-input.stories.tsx +199 -0
  87. package/src/web/ui/auth/otp-input.tsx +157 -0
  88. package/src/web/ui/auth/passkey-button.stories.tsx +115 -0
  89. package/src/web/ui/auth/passkey-button.tsx +113 -0
  90. package/src/web/ui/auth/passkey-register-button.stories.tsx +109 -0
  91. package/src/web/ui/auth/passkey-register-button.tsx +106 -0
  92. package/src/web/ui/auth/password-input.stories.tsx +287 -0
  93. package/src/web/ui/auth/password-input.tsx +306 -0
  94. package/src/web/ui/auth/phone-input.stories.tsx +160 -0
  95. package/src/web/ui/auth/phone-input.tsx +89 -0
  96. package/src/web/ui/auth/social-buttons.stories.tsx +217 -0
  97. package/src/web/ui/auth/social-buttons.tsx +196 -0
  98. package/src/web/ui/auth/sso-button.stories.tsx +160 -0
  99. package/src/web/ui/auth/sso-button.tsx +108 -0
  100. package/src/web/ui/auth/trust-signals.stories.tsx +208 -0
  101. package/src/web/ui/auth/trust-signals.tsx +260 -0
  102. package/src/web/ui/avatar.stories.tsx +302 -0
  103. package/src/web/ui/avatar.tsx +189 -0
  104. package/src/web/ui/badge.stories.tsx +225 -0
  105. package/src/web/ui/badge.tsx +66 -0
  106. package/src/web/ui/brand.stories.tsx +266 -0
  107. package/src/web/ui/brand.tsx +162 -0
  108. package/src/web/ui/breadcrumb.stories.tsx +271 -0
  109. package/src/web/ui/breadcrumb.tsx +214 -0
  110. package/src/web/ui/button-group.stories.tsx +251 -0
  111. package/src/web/ui/button-group.tsx +87 -0
  112. package/src/web/ui/button.stories.tsx +264 -0
  113. package/src/web/ui/button.tsx +120 -0
  114. package/src/web/ui/calendar.stories.tsx +235 -0
  115. package/src/web/ui/calendar.tsx +221 -0
  116. package/src/web/ui/card.stories.tsx +262 -0
  117. package/src/web/ui/card.tsx +199 -0
  118. package/src/web/ui/carousel.stories.tsx +244 -0
  119. package/src/web/ui/carousel.tsx +241 -0
  120. package/src/web/ui/chart.stories.tsx +833 -0
  121. package/src/web/ui/chart.tsx +390 -0
  122. package/src/web/ui/checkbox.stories.tsx +208 -0
  123. package/src/web/ui/checkbox.tsx +39 -0
  124. package/src/web/ui/collapsible.stories.tsx +239 -0
  125. package/src/web/ui/collapsible.tsx +21 -0
  126. package/src/web/ui/command.stories.tsx +291 -0
  127. package/src/web/ui/command.tsx +189 -0
  128. package/src/web/ui/context-menu.stories.tsx +255 -0
  129. package/src/web/ui/context-menu.tsx +263 -0
  130. package/src/web/ui/dialog.stories.tsx +263 -0
  131. package/src/web/ui/dialog.tsx +273 -0
  132. package/src/web/ui/drawer.stories.tsx +299 -0
  133. package/src/web/ui/drawer.tsx +130 -0
  134. package/src/web/ui/dropdown-menu.stories.tsx +320 -0
  135. package/src/web/ui/dropdown-menu.tsx +263 -0
  136. package/src/web/ui/empty.stories.tsx +204 -0
  137. package/src/web/ui/empty.tsx +101 -0
  138. package/src/web/ui/error-page.stories.tsx +181 -0
  139. package/src/web/ui/error-page.tsx +136 -0
  140. package/src/web/ui/field.stories.tsx +364 -0
  141. package/src/web/ui/field.tsx +252 -0
  142. package/src/web/ui/globals.css +3 -0
  143. package/src/web/ui/hover-card.stories.tsx +261 -0
  144. package/src/web/ui/hover-card.tsx +50 -0
  145. package/src/web/ui/index.ts +55 -0
  146. package/src/web/ui/input-group.stories.tsx +290 -0
  147. package/src/web/ui/input-group.tsx +157 -0
  148. package/src/web/ui/input-otp.stories.tsx +235 -0
  149. package/src/web/ui/input-otp.tsx +86 -0
  150. package/src/web/ui/input.stories.tsx +205 -0
  151. package/src/web/ui/input.tsx +30 -0
  152. package/src/web/ui/item.stories.tsx +348 -0
  153. package/src/web/ui/item.tsx +200 -0
  154. package/src/web/ui/kbd.stories.tsx +236 -0
  155. package/src/web/ui/kbd.tsx +27 -0
  156. package/src/web/ui/label.stories.tsx +180 -0
  157. package/src/web/ui/label.tsx +32 -0
  158. package/src/web/ui/locales/en/ui.json +13 -30
  159. package/src/web/ui/locales/zh-CN/ui.json +17 -34
  160. package/src/web/ui/locales/zh-TW/ui.json +17 -34
  161. package/src/web/ui/menubar.stories.tsx +385 -0
  162. package/src/web/ui/menubar.tsx +273 -0
  163. package/src/web/ui/navigation-menu.stories.tsx +361 -0
  164. package/src/web/ui/navigation-menu.tsx +168 -0
  165. package/src/web/ui/pagination.stories.tsx +312 -0
  166. package/src/web/ui/pagination.tsx +221 -0
  167. package/src/web/ui/popover.stories.tsx +315 -0
  168. package/src/web/ui/popover.tsx +89 -0
  169. package/src/web/ui/progress.stories.tsx +239 -0
  170. package/src/web/ui/progress.tsx +128 -0
  171. package/src/web/ui/radio-group.stories.tsx +315 -0
  172. package/src/web/ui/radio-group.tsx +38 -0
  173. package/src/web/ui/resizable.stories.tsx +304 -0
  174. package/src/web/ui/resizable.tsx +53 -0
  175. package/src/web/ui/scroll-area.stories.tsx +276 -0
  176. package/src/web/ui/scroll-area.tsx +53 -0
  177. package/src/web/ui/select.stories.tsx +314 -0
  178. package/src/web/ui/select.tsx +312 -0
  179. package/src/web/ui/separator.stories.tsx +246 -0
  180. package/src/web/ui/separator.tsx +36 -0
  181. package/src/web/ui/sheet.stories.tsx +417 -0
  182. package/src/web/ui/sheet.tsx +133 -0
  183. package/src/web/ui/sidebar.stories.tsx +402 -0
  184. package/src/web/ui/sidebar.tsx +723 -0
  185. package/src/web/ui/skeleton.stories.tsx +235 -0
  186. package/src/web/ui/skeleton.tsx +26 -0
  187. package/src/web/ui/slider.stories.tsx +294 -0
  188. package/src/web/ui/slider.tsx +75 -0
  189. package/src/web/ui/sonner.stories.tsx +279 -0
  190. package/src/web/ui/sonner.tsx +46 -0
  191. package/src/web/ui/spinner.stories.tsx +204 -0
  192. package/src/web/ui/spinner.tsx +28 -0
  193. package/src/web/ui/switch.stories.tsx +285 -0
  194. package/src/web/ui/switch.tsx +43 -0
  195. package/src/web/ui/table.stories.tsx +362 -0
  196. package/src/web/ui/table.tsx +115 -0
  197. package/src/web/ui/tabs.stories.tsx +401 -0
  198. package/src/web/ui/tabs.tsx +136 -0
  199. package/src/web/ui/textarea.stories.tsx +272 -0
  200. package/src/web/ui/textarea.tsx +28 -0
  201. package/src/web/ui/toggle-group.stories.tsx +334 -0
  202. package/src/web/ui/toggle-group.tsx +88 -0
  203. package/src/web/ui/toggle.stories.tsx +264 -0
  204. package/src/web/ui/toggle.tsx +57 -0
  205. package/src/web/ui/tooltip.stories.tsx +342 -0
  206. package/src/web/ui/tooltip.tsx +116 -0
@@ -0,0 +1,271 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { IconHome, IconSlash } from "@tabler/icons-react";
3
+ import { Link } from "react-router";
4
+ import {
5
+ Breadcrumb,
6
+ BreadcrumbEllipsis,
7
+ BreadcrumbItem,
8
+ BreadcrumbLink,
9
+ BreadcrumbList,
10
+ BreadcrumbPage,
11
+ BreadcrumbSeparator,
12
+ } from "#src/web/ui/breadcrumb.tsx";
13
+ import {
14
+ DropdownMenu,
15
+ DropdownMenuContent,
16
+ DropdownMenuItem,
17
+ DropdownMenuTrigger,
18
+ } from "#src/web/ui/dropdown-menu.tsx";
19
+
20
+ const meta = {
21
+ title: "Base/Breadcrumb",
22
+ component: Breadcrumb,
23
+ tags: ["autodocs"],
24
+ parameters: {
25
+ layout: "centered",
26
+ docs: {
27
+ description: {
28
+ component:
29
+ "Displays the path to the current resource using a hierarchy of links. Helps users understand their location within the application and navigate back to parent pages.",
30
+ },
31
+ },
32
+ },
33
+ } satisfies Meta<typeof Breadcrumb>;
34
+
35
+ export default meta;
36
+ type Story = StoryObj<typeof meta>;
37
+
38
+ export const Default: Story = {
39
+ render: () => (
40
+ <Breadcrumb>
41
+ <BreadcrumbList>
42
+ <BreadcrumbItem>
43
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
44
+ </BreadcrumbItem>
45
+ <BreadcrumbSeparator />
46
+ <BreadcrumbItem>
47
+ <BreadcrumbLink href="/products">Products</BreadcrumbLink>
48
+ </BreadcrumbItem>
49
+ <BreadcrumbSeparator />
50
+ <BreadcrumbItem>
51
+ <BreadcrumbPage>Electronics</BreadcrumbPage>
52
+ </BreadcrumbItem>
53
+ </BreadcrumbList>
54
+ </Breadcrumb>
55
+ ),
56
+ parameters: {
57
+ docs: {
58
+ description: {
59
+ story:
60
+ "Default breadcrumb navigation showing a hierarchy of pages. The current page uses BreadcrumbPage for styling.",
61
+ },
62
+ },
63
+ },
64
+ };
65
+
66
+ export const WithHomeIcon: Story = {
67
+ render: () => (
68
+ <Breadcrumb>
69
+ <BreadcrumbList>
70
+ <BreadcrumbItem>
71
+ <BreadcrumbLink href="/">
72
+ <IconHome className="size-4" />
73
+ </BreadcrumbLink>
74
+ </BreadcrumbItem>
75
+ <BreadcrumbSeparator />
76
+ <BreadcrumbItem>
77
+ <BreadcrumbLink href="/dashboard">Dashboard</BreadcrumbLink>
78
+ </BreadcrumbItem>
79
+ <BreadcrumbSeparator />
80
+ <BreadcrumbItem>
81
+ <BreadcrumbPage>Settings</BreadcrumbPage>
82
+ </BreadcrumbItem>
83
+ </BreadcrumbList>
84
+ </Breadcrumb>
85
+ ),
86
+ parameters: {
87
+ docs: {
88
+ description: {
89
+ story:
90
+ "Breadcrumb with a home icon instead of text for the root level.",
91
+ },
92
+ },
93
+ },
94
+ };
95
+
96
+ export const WithEllipsis: Story = {
97
+ render: () => (
98
+ <Breadcrumb>
99
+ <BreadcrumbList>
100
+ <BreadcrumbItem>
101
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
102
+ </BreadcrumbItem>
103
+ <BreadcrumbSeparator />
104
+ <BreadcrumbItem>
105
+ <BreadcrumbEllipsis />
106
+ </BreadcrumbItem>
107
+ <BreadcrumbSeparator />
108
+ <BreadcrumbItem>
109
+ <BreadcrumbLink href="/products/electronics">
110
+ Electronics
111
+ </BreadcrumbLink>
112
+ </BreadcrumbItem>
113
+ <BreadcrumbSeparator />
114
+ <BreadcrumbItem>
115
+ <BreadcrumbPage>Smartphones</BreadcrumbPage>
116
+ </BreadcrumbItem>
117
+ </BreadcrumbList>
118
+ </Breadcrumb>
119
+ ),
120
+ parameters: {
121
+ docs: {
122
+ description: {
123
+ story:
124
+ "Breadcrumb with ellipsis to truncate long paths. Use when the hierarchy is too deep to display fully.",
125
+ },
126
+ },
127
+ },
128
+ };
129
+
130
+ export const WithDropdown: Story = {
131
+ render: () => (
132
+ <Breadcrumb>
133
+ <BreadcrumbList>
134
+ <BreadcrumbItem>
135
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
136
+ </BreadcrumbItem>
137
+ <BreadcrumbSeparator />
138
+ <BreadcrumbItem>
139
+ <DropdownMenu>
140
+ <DropdownMenuTrigger className="flex items-center gap-1">
141
+ <BreadcrumbEllipsis />
142
+ </DropdownMenuTrigger>
143
+ <DropdownMenuContent align="start">
144
+ <DropdownMenuItem>Products</DropdownMenuItem>
145
+ <DropdownMenuItem>Categories</DropdownMenuItem>
146
+ <DropdownMenuItem>Electronics</DropdownMenuItem>
147
+ </DropdownMenuContent>
148
+ </DropdownMenu>
149
+ </BreadcrumbItem>
150
+ <BreadcrumbSeparator />
151
+ <BreadcrumbItem>
152
+ <BreadcrumbLink href="/products/electronics/phones">
153
+ Phones
154
+ </BreadcrumbLink>
155
+ </BreadcrumbItem>
156
+ <BreadcrumbSeparator />
157
+ <BreadcrumbItem>
158
+ <BreadcrumbPage>iPhone 15</BreadcrumbPage>
159
+ </BreadcrumbItem>
160
+ </BreadcrumbList>
161
+ </Breadcrumb>
162
+ ),
163
+ parameters: {
164
+ docs: {
165
+ description: {
166
+ story:
167
+ "Breadcrumb with a dropdown menu for collapsed items. Allows users to navigate to hidden intermediate pages.",
168
+ },
169
+ },
170
+ },
171
+ };
172
+
173
+ export const CustomSeparator: Story = {
174
+ render: () => (
175
+ <Breadcrumb>
176
+ <BreadcrumbList>
177
+ <BreadcrumbItem>
178
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
179
+ </BreadcrumbItem>
180
+ <BreadcrumbSeparator>
181
+ <IconSlash className="size-3.5" />
182
+ </BreadcrumbSeparator>
183
+ <BreadcrumbItem>
184
+ <BreadcrumbLink href="/docs">Docs</BreadcrumbLink>
185
+ </BreadcrumbItem>
186
+ <BreadcrumbSeparator>
187
+ <IconSlash className="size-3.5" />
188
+ </BreadcrumbSeparator>
189
+ <BreadcrumbItem>
190
+ <BreadcrumbPage>Components</BreadcrumbPage>
191
+ </BreadcrumbItem>
192
+ </BreadcrumbList>
193
+ </Breadcrumb>
194
+ ),
195
+ parameters: {
196
+ docs: {
197
+ description: {
198
+ story:
199
+ "Breadcrumb with a custom separator icon. Pass a child to BreadcrumbSeparator to override the default chevron.",
200
+ },
201
+ },
202
+ },
203
+ };
204
+
205
+ export const WithRouterLink: Story = {
206
+ render: () => (
207
+ <Breadcrumb>
208
+ <BreadcrumbList>
209
+ <BreadcrumbItem>
210
+ <BreadcrumbLink render={<Link to="/" />}>Home</BreadcrumbLink>
211
+ </BreadcrumbItem>
212
+ <BreadcrumbSeparator />
213
+ <BreadcrumbItem>
214
+ <BreadcrumbLink render={<Link to="/settings" />}>
215
+ Settings
216
+ </BreadcrumbLink>
217
+ </BreadcrumbItem>
218
+ <BreadcrumbSeparator />
219
+ <BreadcrumbItem>
220
+ <BreadcrumbPage>Profile</BreadcrumbPage>
221
+ </BreadcrumbItem>
222
+ </BreadcrumbList>
223
+ </Breadcrumb>
224
+ ),
225
+ parameters: {
226
+ docs: {
227
+ description: {
228
+ story:
229
+ "Breadcrumb with React Router Link components using the render prop for client-side navigation.",
230
+ },
231
+ },
232
+ },
233
+ };
234
+
235
+ export const LongPath: Story = {
236
+ render: () => (
237
+ <Breadcrumb>
238
+ <BreadcrumbList>
239
+ <BreadcrumbItem>
240
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
241
+ </BreadcrumbItem>
242
+ <BreadcrumbSeparator />
243
+ <BreadcrumbItem>
244
+ <BreadcrumbLink href="/organization">Organization</BreadcrumbLink>
245
+ </BreadcrumbItem>
246
+ <BreadcrumbSeparator />
247
+ <BreadcrumbItem>
248
+ <BreadcrumbLink href="/organization/teams">Teams</BreadcrumbLink>
249
+ </BreadcrumbItem>
250
+ <BreadcrumbSeparator />
251
+ <BreadcrumbItem>
252
+ <BreadcrumbLink href="/organization/teams/engineering">
253
+ Engineering
254
+ </BreadcrumbLink>
255
+ </BreadcrumbItem>
256
+ <BreadcrumbSeparator />
257
+ <BreadcrumbItem>
258
+ <BreadcrumbPage>Members</BreadcrumbPage>
259
+ </BreadcrumbItem>
260
+ </BreadcrumbList>
261
+ </Breadcrumb>
262
+ ),
263
+ parameters: {
264
+ docs: {
265
+ description: {
266
+ story:
267
+ "Full breadcrumb path without truncation. Consider using ellipsis for very deep hierarchies.",
268
+ },
269
+ },
270
+ },
271
+ };
@@ -0,0 +1,214 @@
1
+ import { mergeProps } from "@base-ui/react/merge-props";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react";
4
+ import type * as React from "react";
5
+ import { cn } from "#src/web/lib/utils.ts";
6
+
7
+ /**
8
+ * A navigation component that shows the user's current location in a hierarchy.
9
+ *
10
+ * Helps users understand their position within a site structure and navigate
11
+ * back to parent pages. Includes proper accessibility attributes.
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * <Breadcrumb>
16
+ * <BreadcrumbList>
17
+ * <BreadcrumbItem>
18
+ * <BreadcrumbLink href="/">Home</BreadcrumbLink>
19
+ * </BreadcrumbItem>
20
+ * <BreadcrumbSeparator />
21
+ * <BreadcrumbItem>
22
+ * <BreadcrumbPage>Current Page</BreadcrumbPage>
23
+ * </BreadcrumbItem>
24
+ * </BreadcrumbList>
25
+ * </Breadcrumb>
26
+ * ```
27
+ */
28
+ function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) {
29
+ return (
30
+ <nav
31
+ aria-label="breadcrumb"
32
+ data-slot="breadcrumb"
33
+ className={cn(className)}
34
+ {...props}
35
+ />
36
+ );
37
+ }
38
+
39
+ /**
40
+ * The ordered list container for breadcrumb items.
41
+ *
42
+ * Wraps BreadcrumbItem components and handles flex layout with proper spacing.
43
+ *
44
+ * @example
45
+ * ```tsx
46
+ * <BreadcrumbList>
47
+ * <BreadcrumbItem>...</BreadcrumbItem>
48
+ * </BreadcrumbList>
49
+ * ```
50
+ */
51
+ function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
52
+ return (
53
+ <ol
54
+ data-slot="breadcrumb-list"
55
+ className={cn(
56
+ "text-muted-foreground gap-1.5 text-sm sm:gap-2.5 flex flex-wrap items-center wrap-break-word",
57
+ className,
58
+ )}
59
+ {...props}
60
+ />
61
+ );
62
+ }
63
+
64
+ /**
65
+ * A single item in the breadcrumb navigation.
66
+ *
67
+ * Contains either a BreadcrumbLink for navigable items or BreadcrumbPage
68
+ * for the current page indicator.
69
+ *
70
+ * @example
71
+ * ```tsx
72
+ * <BreadcrumbItem>
73
+ * <BreadcrumbLink href="/products">Products</BreadcrumbLink>
74
+ * </BreadcrumbItem>
75
+ * ```
76
+ */
77
+ function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
78
+ return (
79
+ <li
80
+ data-slot="breadcrumb-item"
81
+ className={cn("gap-1.5 inline-flex items-center", className)}
82
+ {...props}
83
+ />
84
+ );
85
+ }
86
+
87
+ /**
88
+ * A navigable link within a breadcrumb item.
89
+ *
90
+ * Use for all breadcrumb levels except the current page. Supports custom
91
+ * rendering via the `render` prop for integration with routing libraries.
92
+ *
93
+ * @example
94
+ * ```tsx
95
+ * <BreadcrumbLink href="/dashboard">Dashboard</BreadcrumbLink>
96
+ * ```
97
+ */
98
+ function BreadcrumbLink({
99
+ className,
100
+ render,
101
+ ...props
102
+ }: useRender.ComponentProps<"a">) {
103
+ return useRender({
104
+ defaultTagName: "a",
105
+ props: mergeProps<"a">(
106
+ {
107
+ className: cn("hover:text-foreground transition-colors", className),
108
+ },
109
+ props,
110
+ ),
111
+ render,
112
+ state: {
113
+ slot: "breadcrumb-link",
114
+ },
115
+ });
116
+ }
117
+
118
+ /**
119
+ * The current page indicator in a breadcrumb trail.
120
+ *
121
+ * Non-interactive element that represents the user's current location.
122
+ * Includes proper ARIA attributes for accessibility.
123
+ *
124
+ * @example
125
+ * ```tsx
126
+ * <BreadcrumbPage>Settings</BreadcrumbPage>
127
+ * ```
128
+ */
129
+ function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
130
+ return (
131
+ <span
132
+ data-slot="breadcrumb-page"
133
+ role="link"
134
+ aria-disabled="true"
135
+ aria-current="page"
136
+ className={cn("text-foreground font-normal", className)}
137
+ {...props}
138
+ />
139
+ );
140
+ }
141
+
142
+ /**
143
+ * A visual separator between breadcrumb items.
144
+ *
145
+ * Displays a chevron icon by default but accepts custom children.
146
+ * Hidden from screen readers as it's purely decorative.
147
+ *
148
+ * @example
149
+ * ```tsx
150
+ * <BreadcrumbSeparator />
151
+ * <BreadcrumbSeparator>/</BreadcrumbSeparator>
152
+ * ```
153
+ */
154
+ function BreadcrumbSeparator({
155
+ children,
156
+ className,
157
+ ...props
158
+ }: React.ComponentProps<"li">) {
159
+ return (
160
+ <li
161
+ data-slot="breadcrumb-separator"
162
+ role="presentation"
163
+ aria-hidden="true"
164
+ className={cn("[&>svg]:size-3.5", className)}
165
+ {...props}
166
+ >
167
+ {children ?? <ChevronRightIcon />}
168
+ </li>
169
+ );
170
+ }
171
+
172
+ /**
173
+ * An ellipsis indicator for truncated breadcrumb trails.
174
+ *
175
+ * Use when there are too many levels to display. Often combined with a
176
+ * dropdown menu to show hidden items.
177
+ *
178
+ * @example
179
+ * ```tsx
180
+ * <BreadcrumbItem>
181
+ * <BreadcrumbEllipsis />
182
+ * </BreadcrumbItem>
183
+ * ```
184
+ */
185
+ function BreadcrumbEllipsis({
186
+ className,
187
+ ...props
188
+ }: React.ComponentProps<"span">) {
189
+ return (
190
+ <span
191
+ data-slot="breadcrumb-ellipsis"
192
+ role="presentation"
193
+ aria-hidden="true"
194
+ className={cn(
195
+ "size-5 [&>svg]:size-4 flex items-center justify-center",
196
+ className,
197
+ )}
198
+ {...props}
199
+ >
200
+ <MoreHorizontalIcon />
201
+ <span className="sr-only">More</span>
202
+ </span>
203
+ );
204
+ }
205
+
206
+ export {
207
+ Breadcrumb,
208
+ BreadcrumbList,
209
+ BreadcrumbItem,
210
+ BreadcrumbLink,
211
+ BreadcrumbPage,
212
+ BreadcrumbSeparator,
213
+ BreadcrumbEllipsis,
214
+ };