@olympusoss/canvas 2.20.2 → 4.0.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 (208) hide show
  1. package/package.json +41 -177
  2. package/src/cn.ts +3 -0
  3. package/src/index.ts +12 -603
  4. package/src/theme.ts +41 -0
  5. package/src/tokens.ts +11 -0
  6. package/styles/base.css +17 -0
  7. package/styles/canvas.css +69 -52
  8. package/styles/components/alert.css +66 -0
  9. package/styles/components/app-shell.css +46 -0
  10. package/styles/components/avatar.css +15 -0
  11. package/styles/components/badge.css +83 -0
  12. package/styles/components/breadcrumb.css +35 -0
  13. package/styles/components/button-group.css +23 -0
  14. package/styles/components/button.css +107 -0
  15. package/styles/components/calendar.css +73 -0
  16. package/styles/components/card.css +58 -0
  17. package/styles/components/checkbox.css +55 -0
  18. package/styles/components/code-block.css +18 -0
  19. package/styles/components/combobox.css +75 -0
  20. package/styles/components/command.css +94 -0
  21. package/styles/components/data-table.css +142 -0
  22. package/styles/components/dialog.css +72 -0
  23. package/styles/components/dropdown.css +54 -0
  24. package/styles/components/empty-state.css +17 -0
  25. package/styles/components/field.css +27 -0
  26. package/styles/components/filter-panel.css +58 -0
  27. package/styles/components/form.css +27 -0
  28. package/styles/components/icon.css +8 -0
  29. package/styles/components/input-group.css +45 -0
  30. package/styles/components/input.css +56 -0
  31. package/styles/components/kbd.css +15 -0
  32. package/styles/components/page-header.css +52 -0
  33. package/styles/components/pagination.css +48 -0
  34. package/styles/components/popover.css +14 -0
  35. package/styles/components/radio.css +28 -0
  36. package/styles/components/row-menu.css +69 -0
  37. package/styles/components/section-card.css +49 -0
  38. package/styles/components/select.css +57 -0
  39. package/styles/components/separator.css +32 -0
  40. package/styles/components/sheet.css +70 -0
  41. package/styles/components/sidebar.css +146 -0
  42. package/styles/components/skeleton.css +32 -0
  43. package/styles/components/spinner.css +26 -0
  44. package/styles/components/stat-card.css +71 -0
  45. package/styles/components/stepper.css +63 -0
  46. package/styles/components/switch.css +45 -0
  47. package/styles/components/tabs.css +40 -0
  48. package/styles/components/textarea.css +31 -0
  49. package/styles/components/toast.css +95 -0
  50. package/styles/components/tooltip.css +53 -0
  51. package/styles/components/topbar.css +24 -0
  52. package/styles/components/typography.css +105 -0
  53. package/styles/patterns/backdrops.css +35 -0
  54. package/styles/patterns/density.css +66 -0
  55. package/styles/patterns/focus.css +38 -0
  56. package/styles/patterns/glass.css +85 -0
  57. package/styles/patterns/high-contrast.css +70 -0
  58. package/styles/patterns/reduced-motion.css +12 -0
  59. package/styles/patterns/scrollbar.css +10 -0
  60. package/styles/reset.css +89 -0
  61. package/styles/tokens/colors.css +106 -0
  62. package/styles/tokens/motion.css +33 -0
  63. package/styles/tokens/radius.css +10 -0
  64. package/styles/tokens/shadows.css +35 -0
  65. package/styles/tokens/spacing.css +19 -0
  66. package/styles/tokens/typography.css +6 -0
  67. package/styles/tokens/z-index.css +12 -0
  68. package/tsconfig.json +20 -21
  69. package/README.md +0 -60
  70. package/src/components/atoms/README.md +0 -11
  71. package/src/components/atoms/aspect-ratio.tsx +0 -32
  72. package/src/components/atoms/avatar.tsx +0 -98
  73. package/src/components/atoms/badge.tsx +0 -44
  74. package/src/components/atoms/brand-mark.tsx +0 -74
  75. package/src/components/atoms/button.tsx +0 -105
  76. package/src/components/atoms/checkbox.tsx +0 -63
  77. package/src/components/atoms/flex-box.tsx +0 -105
  78. package/src/components/atoms/icon.tsx +0 -34
  79. package/src/components/atoms/input.tsx +0 -92
  80. package/src/components/atoms/label.tsx +0 -41
  81. package/src/components/atoms/logo.tsx +0 -89
  82. package/src/components/atoms/progress.tsx +0 -55
  83. package/src/components/atoms/radio-group.tsx +0 -122
  84. package/src/components/atoms/scroll-area.tsx +0 -106
  85. package/src/components/atoms/section.tsx +0 -48
  86. package/src/components/atoms/separator.tsx +0 -45
  87. package/src/components/atoms/skeleton.tsx +0 -17
  88. package/src/components/atoms/slider.tsx +0 -93
  89. package/src/components/atoms/spinner.tsx +0 -47
  90. package/src/components/atoms/switch.tsx +0 -60
  91. package/src/components/atoms/textarea.tsx +0 -78
  92. package/src/components/atoms/toggle.tsx +0 -80
  93. package/src/components/charts/activity-heatmap.tsx +0 -186
  94. package/src/components/charts/axes.tsx +0 -21
  95. package/src/components/charts/chart-container.tsx +0 -254
  96. package/src/components/charts/chart-legend.tsx +0 -67
  97. package/src/components/charts/chart-tooltip.tsx +0 -161
  98. package/src/components/charts/chart-types.tsx +0 -49
  99. package/src/components/charts/containers.tsx +0 -11
  100. package/src/components/charts/data.tsx +0 -16
  101. package/src/components/charts/details.tsx +0 -25
  102. package/src/components/charts/dot-pulse.tsx +0 -61
  103. package/src/components/charts/gauge.tsx +0 -106
  104. package/src/components/charts/grids.tsx +0 -8
  105. package/src/components/charts/index.ts +0 -62
  106. package/src/components/charts/labeled-bar-list.tsx +0 -85
  107. package/src/components/charts/metric-breakdown.tsx +0 -316
  108. package/src/components/charts/references.tsx +0 -8
  109. package/src/components/charts/service-health-list.tsx +0 -85
  110. package/src/components/charts/sparkline-area.tsx +0 -80
  111. package/src/components/charts/sparkline.tsx +0 -52
  112. package/src/components/charts/stacked-bar.tsx +0 -104
  113. package/src/components/charts/text.tsx +0 -10
  114. package/src/components/charts/world-heat-map-inner.tsx +0 -317
  115. package/src/components/charts/world-heat-map.tsx +0 -184
  116. package/src/components/molecules/README.md +0 -12
  117. package/src/components/molecules/action-bar.tsx +0 -73
  118. package/src/components/molecules/activity-item.tsx +0 -74
  119. package/src/components/molecules/alert.tsx +0 -86
  120. package/src/components/molecules/animated-background.tsx +0 -92
  121. package/src/components/molecules/auth-shell.tsx +0 -95
  122. package/src/components/molecules/brand-lockup.tsx +0 -48
  123. package/src/components/molecules/breadcrumb.tsx +0 -157
  124. package/src/components/molecules/button-group.tsx +0 -104
  125. package/src/components/molecules/calendar.tsx +0 -217
  126. package/src/components/molecules/card.tsx +0 -102
  127. package/src/components/molecules/client-brand.tsx +0 -95
  128. package/src/components/molecules/code-block.tsx +0 -86
  129. package/src/components/molecules/countdown-button.tsx +0 -92
  130. package/src/components/molecules/empty-state.tsx +0 -56
  131. package/src/components/molecules/error-state.tsx +0 -42
  132. package/src/components/molecules/field-display.tsx +0 -35
  133. package/src/components/molecules/input-otp.tsx +0 -74
  134. package/src/components/molecules/launcher-card.tsx +0 -152
  135. package/src/components/molecules/loading-state.tsx +0 -36
  136. package/src/components/molecules/notification-item.tsx +0 -67
  137. package/src/components/molecules/notification-list.tsx +0 -45
  138. package/src/components/molecules/number-badge.tsx +0 -53
  139. package/src/components/molecules/or-separator.tsx +0 -38
  140. package/src/components/molecules/page-header.tsx +0 -88
  141. package/src/components/molecules/page-tabs.tsx +0 -94
  142. package/src/components/molecules/pagination.tsx +0 -150
  143. package/src/components/molecules/password-input.tsx +0 -83
  144. package/src/components/molecules/password-strength-meter.tsx +0 -104
  145. package/src/components/molecules/phone-input.tsx +0 -200
  146. package/src/components/molecules/search-bar.tsx +0 -64
  147. package/src/components/molecules/secret-field.tsx +0 -158
  148. package/src/components/molecules/section-card.tsx +0 -91
  149. package/src/components/molecules/social-buttons.tsx +0 -165
  150. package/src/components/molecules/stat-card.tsx +0 -100
  151. package/src/components/molecules/status-badge.tsx +0 -42
  152. package/src/components/molecules/stepper.tsx +0 -96
  153. package/src/components/molecules/table.tsx +0 -157
  154. package/src/components/molecules/terminal.tsx +0 -74
  155. package/src/components/molecules/toggle-group.tsx +0 -145
  156. package/src/components/molecules/tooltip.tsx +0 -155
  157. package/src/components/molecules/user-avatar-chip.tsx +0 -71
  158. package/src/components/organisms/README.md +0 -14
  159. package/src/components/organisms/accordion.tsx +0 -154
  160. package/src/components/organisms/alert-dialog.tsx +0 -277
  161. package/src/components/organisms/carousel.tsx +0 -244
  162. package/src/components/organisms/collapsible.tsx +0 -69
  163. package/src/components/organisms/command.tsx +0 -144
  164. package/src/components/organisms/context-menu.tsx +0 -339
  165. package/src/components/organisms/dashboard-grid.tsx +0 -369
  166. package/src/components/organisms/data-table.tsx +0 -330
  167. package/src/components/organisms/dialog.tsx +0 -312
  168. package/src/components/organisms/drawer.tsx +0 -123
  169. package/src/components/organisms/dropdown-menu.tsx +0 -440
  170. package/src/components/organisms/editors/code-editor.tsx +0 -144
  171. package/src/components/organisms/editors/index.ts +0 -4
  172. package/src/components/organisms/editors/markdown-editor.tsx +0 -153
  173. package/src/components/organisms/editors/markdown-renderer.ts +0 -27
  174. package/src/components/organisms/editors/prose-canvas-classes.ts +0 -45
  175. package/src/components/organisms/editors/rich-text-editor.tsx +0 -126
  176. package/src/components/organisms/editors/toolbar/md-toolbar.tsx +0 -129
  177. package/src/components/organisms/editors/toolbar/rte-toolbar.tsx +0 -211
  178. package/src/components/organisms/editors/toolbar/toolbar-shell.tsx +0 -45
  179. package/src/components/organisms/editors/use-codemirror-theme.ts +0 -61
  180. package/src/components/organisms/error-boundary.tsx +0 -61
  181. package/src/components/organisms/form.tsx +0 -174
  182. package/src/components/organisms/hover-card.tsx +0 -115
  183. package/src/components/organisms/menubar.tsx +0 -498
  184. package/src/components/organisms/navbar.tsx +0 -104
  185. package/src/components/organisms/navigation-menu.tsx +0 -235
  186. package/src/components/organisms/popover.tsx +0 -149
  187. package/src/components/organisms/resizable.tsx +0 -58
  188. package/src/components/organisms/schema-form.tsx +0 -232
  189. package/src/components/organisms/select.tsx +0 -309
  190. package/src/components/organisms/sheet.tsx +0 -265
  191. package/src/components/organisms/sidebar.tsx +0 -1040
  192. package/src/components/organisms/sonner.tsx +0 -96
  193. package/src/components/organisms/tabs.tsx +0 -133
  194. package/src/components/organisms/theme-provider.tsx +0 -101
  195. package/src/hooks/use-mobile.tsx +0 -19
  196. package/src/lib/portal-container.tsx +0 -35
  197. package/src/lib/utils.ts +0 -6
  198. package/src/native.ts +0 -23
  199. package/src/tokens/colors.ts +0 -91
  200. package/src/tokens/index.ts +0 -3
  201. package/src/tokens/spacing.ts +0 -55
  202. package/src/tokens/typography.ts +0 -27
  203. package/styles/dashboard-grid.css +0 -47
  204. package/styles/fonts/Roboto-VariableFont_wdth_wght.ttf +0 -0
  205. package/styles/glass.css +0 -175
  206. package/styles/leaflet.css +0 -13
  207. package/styles/tokens.css +0 -317
  208. package/tailwind.config.ts +0 -70
@@ -1,86 +0,0 @@
1
- import { cva, type VariantProps } from "class-variance-authority";
2
- import * as React from "react";
3
-
4
- import { cn } from "../../lib/utils";
5
-
6
- const alertVariants = cva(
7
- "relative w-full rounded-lg border border-border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
8
- {
9
- variants: {
10
- variant: {
11
- default: "bg-background text-foreground",
12
- destructive:
13
- "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
14
- },
15
- },
16
- defaultVariants: {
17
- variant: "default",
18
- },
19
- },
20
- );
21
-
22
- export interface AlertProps
23
- extends React.HTMLAttributes<HTMLDivElement>,
24
- VariantProps<typeof alertVariants> {
25
- /**
26
- * Visual emphasis preset. `default` is informational, `destructive`
27
- * uses the danger palette for errors and warnings.
28
- * @default "default"
29
- */
30
- variant?: "default" | "destructive";
31
- /**
32
- * Optional leading icon (lucide-react), `<AlertTitle>`, and
33
- * `<AlertDescription>`. The icon — when present as a direct child —
34
- * is auto-positioned in the top-left.
35
- */
36
- children?: React.ReactNode;
37
- /** Tailwind / CSS classes merged onto the alert via `cn()`. */
38
- className?: string;
39
- }
40
-
41
- const Alert = React.forwardRef<HTMLDivElement, AlertProps>(
42
- ({ className, variant, ...props }, ref) => (
43
- <div
44
- ref={ref}
45
- role="alert"
46
- data-slot="alert"
47
- className={cn(alertVariants({ variant }), className)}
48
- {...props}
49
- />
50
- ),
51
- );
52
- Alert.displayName = "Alert";
53
-
54
- export interface AlertTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {
55
- /** The alert headline. Renders as an `<h5>`. */
56
- children?: React.ReactNode;
57
- /** Tailwind / CSS classes merged onto the title via `cn()`. */
58
- className?: string;
59
- }
60
-
61
- const AlertTitle = React.forwardRef<HTMLParagraphElement, AlertTitleProps>(
62
- ({ className, ...props }, ref) => (
63
- <h5
64
- ref={ref}
65
- className={cn("mb-1 font-medium leading-none tracking-tight", className)}
66
- {...props}
67
- />
68
- ),
69
- );
70
- AlertTitle.displayName = "AlertTitle";
71
-
72
- export interface AlertDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {
73
- /** Body copy of the alert. Renders as a `<div>` so it can hold paragraphs and lists. */
74
- children?: React.ReactNode;
75
- /** Tailwind / CSS classes merged onto the description via `cn()`. */
76
- className?: string;
77
- }
78
-
79
- const AlertDescription = React.forwardRef<HTMLParagraphElement, AlertDescriptionProps>(
80
- ({ className, ...props }, ref) => (
81
- <div ref={ref} className={cn("text-sm [&_p]:leading-relaxed", className)} {...props} />
82
- ),
83
- );
84
- AlertDescription.displayName = "AlertDescription";
85
-
86
- export { Alert, AlertDescription, AlertTitle };
@@ -1,92 +0,0 @@
1
- import { cn } from "../../lib/utils";
2
-
3
- export interface AnimatedBackgroundOrb {
4
- /** CSS color for the radial gradient (hex / rgb / hsl / token). */
5
- color: string;
6
- /**
7
- * Diameter in pixels.
8
- * @default 500
9
- */
10
- size?: number;
11
- /**
12
- * Opacity 0–1. Lower values let more of the page bg bleed through.
13
- * @default 0.2
14
- */
15
- opacity?: number;
16
- /**
17
- * Gaussian blur radius in pixels. Larger values produce softer orbs.
18
- * @default 100
19
- */
20
- blur?: number;
21
- /** Tailwind position classes, e.g. `"-top-32 -right-32"` or `"left-1/2 top-1/3"`. */
22
- position?: string;
23
- /**
24
- * CSS `animation` shorthand. Pair with the `orb-float-1` / `orb-float-2`
25
- * keyframes shipped in canvas's tokens, or your own.
26
- */
27
- animation?: string;
28
- }
29
-
30
- export interface AnimatedBackgroundProps {
31
- /**
32
- * Orbs to render. Defaults to a 3-orb indigo/purple/cyan composition
33
- * that mirrors the auth-screen backdrop. Pass an empty array `[]` to
34
- * render no orbs (useful for testing).
35
- */
36
- orbs?: AnimatedBackgroundOrb[];
37
- /**
38
- * Tailwind / CSS classes merged onto the root container via `cn()`.
39
- * Defaults to `pointer-events-none fixed inset-0 overflow-hidden`.
40
- */
41
- className?: string;
42
- }
43
-
44
- const DEFAULT_ORBS: AnimatedBackgroundOrb[] = [
45
- {
46
- color: "#6366f1",
47
- size: 500,
48
- opacity: 0.2,
49
- blur: 120,
50
- position: "-top-32 -right-32",
51
- animation: "orb-float-1 8s ease-in-out infinite",
52
- },
53
- {
54
- color: "#8b5cf6",
55
- size: 400,
56
- opacity: 0.15,
57
- blur: 100,
58
- position: "-bottom-32 -left-32",
59
- animation: "orb-float-2 10s ease-in-out infinite",
60
- },
61
- {
62
- color: "#06b6d4",
63
- size: 300,
64
- opacity: 0.1,
65
- blur: 80,
66
- position: "left-1/2 top-1/3 -translate-x-1/2",
67
- animation: "orb-float-1 12s ease-in-out 2s infinite",
68
- },
69
- ];
70
-
71
- export function AnimatedBackground({ orbs = DEFAULT_ORBS, className }: AnimatedBackgroundProps) {
72
- return (
73
- <div className={cn("pointer-events-none fixed inset-0 overflow-hidden", className)}>
74
- {orbs.map((orb, i) => (
75
- <div
76
- key={i}
77
- className={cn("absolute rounded-full", orb.position)}
78
- style={{
79
- width: orb.size ?? 500,
80
- height: orb.size ?? 500,
81
- opacity: orb.opacity ?? 0.2,
82
- filter: `blur(${orb.blur ?? 100}px)`,
83
- background: `radial-gradient(circle, ${orb.color} 0%, transparent 70%)`,
84
- animation: orb.animation,
85
- }}
86
- />
87
- ))}
88
- </div>
89
- );
90
- }
91
-
92
- AnimatedBackground.displayName = "AnimatedBackground";
@@ -1,95 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
-
5
- import { cn } from "../../lib/utils";
6
- import { Card, CardContent, CardHeader } from "./card";
7
-
8
- export interface AuthShellProps {
9
- /**
10
- * Brand lockup rendered above the card. Compose a `ClientBrand` (or
11
- * your own component) and pass it in. Slot is left empty to keep this
12
- * shell unaware of OAuth2 / Hydra specifics.
13
- */
14
- brand?: React.ReactNode;
15
- /** Card title. Pairs with `subtitle`. */
16
- title?: React.ReactNode;
17
- /** Optional one-line subtitle shown beneath `title`. */
18
- subtitle?: React.ReactNode;
19
- /** Card body content. */
20
- children?: React.ReactNode;
21
- /**
22
- * Optional footer line beneath the card (legal / privacy / support).
23
- */
24
- footer?: React.ReactNode;
25
- /**
26
- * Card width preset. `default` = 408px (single-column flows like login,
27
- * recovery), `wide` = 460px (multi-step or denser flows like consent).
28
- * @default "default"
29
- */
30
- width?: "default" | "wide";
31
- /**
32
- * Allow children to break the card frame (useful for full-bleed flow
33
- * pickers or media). When `false` the card content gets the standard
34
- * `p-6` padding.
35
- * @default false
36
- */
37
- flush?: boolean;
38
- /** Tailwind / CSS classes merged onto the outer wrapper via `cn()`. */
39
- className?: string;
40
- }
41
-
42
- /**
43
- * Centered single-card layout for auth flows.
44
- *
45
- * Renders, top to bottom:
46
- * 1. Brand slot (`brand`) above the card
47
- * 2. Card with optional centred title + subtitle, then `children`
48
- * 3. Optional footer line beneath the card
49
- *
50
- * Layout is intentionally narrow and prescriptive: this is the
51
- * agreed-upon shape for every Olympus auth screen (login, register,
52
- * recovery, reset, verify, OTP, consent, logout, status). For app shells
53
- * with sidebars or multi-pane layouts, compose your own flex shell
54
- * directly (see `Sidebar` + `SidebarInset`).
55
- */
56
- const AuthShell = React.forwardRef<HTMLDivElement, AuthShellProps>(
57
- (
58
- { brand, title, subtitle, children, footer, width = "default", flush = false, className },
59
- ref,
60
- ) => (
61
- <div
62
- ref={ref}
63
- className={cn(
64
- "relative z-10 flex min-h-screen flex-col items-center justify-center px-6 py-12",
65
- className,
66
- )}
67
- >
68
- {brand && <div className="mb-7">{brand}</div>}
69
-
70
- <Card
71
- className={cn(
72
- "w-full shadow-lg shadow-black/5 dark:shadow-black/30",
73
- width === "wide" ? "max-w-[460px]" : "max-w-[408px]",
74
- )}
75
- >
76
- {title && (
77
- <CardHeader className={cn("text-center", subtitle ? "pb-3" : "pb-4")}>
78
- <h1 className="text-xl font-semibold tracking-tight">{title}</h1>
79
- {subtitle && <p className="mt-1.5 text-sm text-muted-foreground">{subtitle}</p>}
80
- </CardHeader>
81
- )}
82
- <CardContent className={cn(flush ? "p-0" : "pt-0", !title && !flush && "pt-6")}>
83
- {children}
84
- </CardContent>
85
- </Card>
86
-
87
- {footer && (
88
- <div className="mt-6 max-w-[460px] text-center text-xs text-muted-foreground">{footer}</div>
89
- )}
90
- </div>
91
- ),
92
- );
93
- AuthShell.displayName = "AuthShell";
94
-
95
- export { AuthShell };
@@ -1,48 +0,0 @@
1
- import * as React from "react";
2
-
3
- import { cn } from "../../lib/utils";
4
-
5
- export interface BrandLockupProps extends React.HTMLAttributes<HTMLDivElement> {
6
- /**
7
- * Logo node rendered to the left of the wordmark — typically `<Logo />`
8
- * for the canvas Olympus ring, or any other brand mark of the consumer's
9
- * choosing. Required so canvas stays brand-agnostic.
10
- */
11
- logo: React.ReactNode;
12
- /** Wordmark next to the logo (e.g. "Athena", "Hera"). */
13
- productName: string;
14
- /** Optional secondary line under the wordmark. */
15
- subtitle?: string;
16
- /** Visual size — sm = sidebar collapsed, md = sidebar expanded, lg = hero. */
17
- size?: "sm" | "md" | "lg";
18
- /** When true, renders only the logo without the wordmark or subtitle. */
19
- collapsed?: boolean;
20
- }
21
-
22
- const SIZE: Record<NonNullable<BrandLockupProps["size"]>, { name: string; sub: string }> = {
23
- sm: { name: "text-[13px]", sub: "text-[10px]" },
24
- md: { name: "text-sm", sub: "text-[11px]" },
25
- lg: { name: "text-2xl", sub: "text-xs" },
26
- };
27
-
28
- export const BrandLockup = React.forwardRef<HTMLDivElement, BrandLockupProps>(
29
- ({ logo, productName, subtitle, size = "md", collapsed = false, className, ...props }, ref) => {
30
- const sz = SIZE[size];
31
- return (
32
- <div ref={ref} className={cn("flex items-center gap-2.5", className)} {...props}>
33
- <span className="shrink-0">{logo}</span>
34
- {!collapsed && (
35
- <div className="flex flex-col leading-tight">
36
- <span className={cn(sz.name, "font-semibold tracking-tight text-foreground")}>
37
- {productName}
38
- </span>
39
- {subtitle && (
40
- <span className={cn(sz.sub, "font-mono text-muted-foreground")}>{subtitle}</span>
41
- )}
42
- </div>
43
- )}
44
- </div>
45
- );
46
- },
47
- );
48
- BrandLockup.displayName = "BrandLockup";
@@ -1,157 +0,0 @@
1
- import { Slot } from "@radix-ui/react-slot";
2
- import { ChevronRight, MoreHorizontal } from "lucide-react";
3
- import * as React from "react";
4
-
5
- import { cn } from "../../lib/utils";
6
-
7
- export interface BreadcrumbProps extends React.ComponentPropsWithoutRef<"nav"> {
8
- /**
9
- * Custom separator element used between items. Defaults to a chevron
10
- * via `<BreadcrumbSeparator>`.
11
- */
12
- separator?: React.ReactNode;
13
- /** A `<BreadcrumbList>` containing items. */
14
- children?: React.ReactNode;
15
- /** Tailwind / CSS classes merged onto the `<nav>` via `cn()`. */
16
- className?: string;
17
- }
18
-
19
- const Breadcrumb = React.forwardRef<HTMLElement, BreadcrumbProps>(({ ...props }, ref) => (
20
- <nav ref={ref} aria-label="breadcrumb" {...props} />
21
- ));
22
- Breadcrumb.displayName = "Breadcrumb";
23
-
24
- export interface BreadcrumbListProps extends React.ComponentPropsWithoutRef<"ol"> {
25
- /** A flat list of `<BreadcrumbItem>`s, separated by `<BreadcrumbSeparator>`. */
26
- children?: React.ReactNode;
27
- /** Tailwind / CSS classes merged onto the `<ol>` via `cn()`. */
28
- className?: string;
29
- }
30
-
31
- const BreadcrumbList = React.forwardRef<HTMLOListElement, BreadcrumbListProps>(
32
- ({ className, ...props }, ref) => (
33
- <ol
34
- ref={ref}
35
- className={cn(
36
- "flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
37
- className,
38
- )}
39
- {...props}
40
- />
41
- ),
42
- );
43
- BreadcrumbList.displayName = "BreadcrumbList";
44
-
45
- export interface BreadcrumbItemProps extends React.ComponentPropsWithoutRef<"li"> {
46
- /** Typically a `<BreadcrumbLink>` or `<BreadcrumbPage>`. */
47
- children?: React.ReactNode;
48
- /** Tailwind / CSS classes merged onto the `<li>` via `cn()`. */
49
- className?: string;
50
- }
51
-
52
- const BreadcrumbItem = React.forwardRef<HTMLLIElement, BreadcrumbItemProps>(
53
- ({ className, ...props }, ref) => (
54
- <li ref={ref} className={cn("inline-flex items-center gap-1.5", className)} {...props} />
55
- ),
56
- );
57
- BreadcrumbItem.displayName = "BreadcrumbItem";
58
-
59
- export interface BreadcrumbLinkProps extends React.ComponentPropsWithoutRef<"a"> {
60
- /**
61
- * Render as a Radix Slot — useful for wrapping a router `<Link>` so
62
- * it inherits breadcrumb styling.
63
- * @default false
64
- */
65
- asChild?: boolean;
66
- /** Anchor target. Used when not in `asChild` mode. */
67
- href?: string;
68
- /** Link label. */
69
- children?: React.ReactNode;
70
- /** Tailwind / CSS classes merged onto the link via `cn()`. */
71
- className?: string;
72
- }
73
-
74
- const BreadcrumbLink = React.forwardRef<HTMLAnchorElement, BreadcrumbLinkProps>(
75
- ({ asChild, className, ...props }, ref) => {
76
- const Comp = asChild ? Slot : "a";
77
-
78
- return (
79
- <Comp ref={ref} className={cn("transition-colors hover:text-brand", className)} {...props} />
80
- );
81
- },
82
- );
83
- BreadcrumbLink.displayName = "BreadcrumbLink";
84
-
85
- export interface BreadcrumbPageProps extends React.ComponentPropsWithoutRef<"span"> {
86
- /**
87
- * Label of the current page. This is the last breadcrumb item and is
88
- * non-clickable; sets `aria-current="page"` for assistive tech.
89
- */
90
- children?: React.ReactNode;
91
- /** Tailwind / CSS classes merged onto the page span via `cn()`. */
92
- className?: string;
93
- }
94
-
95
- const BreadcrumbPage = React.forwardRef<HTMLSpanElement, BreadcrumbPageProps>(
96
- ({ className, ...props }, ref) => (
97
- <span
98
- ref={ref}
99
- role="link"
100
- aria-disabled="true"
101
- aria-current="page"
102
- className={cn("font-normal text-foreground", className)}
103
- {...props}
104
- />
105
- ),
106
- );
107
- BreadcrumbPage.displayName = "BreadcrumbPage";
108
-
109
- export interface BreadcrumbSeparatorProps extends React.ComponentProps<"li"> {
110
- /**
111
- * Override the default chevron with a custom node (e.g. a slash, an
112
- * arrow icon).
113
- */
114
- children?: React.ReactNode;
115
- /** Tailwind / CSS classes merged onto the separator via `cn()`. */
116
- className?: string;
117
- }
118
-
119
- const BreadcrumbSeparator = ({ children, className, ...props }: BreadcrumbSeparatorProps) => (
120
- <li
121
- role="presentation"
122
- aria-hidden="true"
123
- className={cn("[&>svg]:w-3.5 [&>svg]:h-3.5", className)}
124
- {...props}
125
- >
126
- {children ?? <ChevronRight />}
127
- </li>
128
- );
129
- BreadcrumbSeparator.displayName = "BreadcrumbSeparator";
130
-
131
- export interface BreadcrumbEllipsisProps extends React.ComponentProps<"span"> {
132
- /** Tailwind / CSS classes merged onto the ellipsis via `cn()`. */
133
- className?: string;
134
- }
135
-
136
- const BreadcrumbEllipsis = ({ className, ...props }: BreadcrumbEllipsisProps) => (
137
- <span
138
- role="presentation"
139
- aria-hidden="true"
140
- className={cn("flex h-9 w-9 items-center justify-center", className)}
141
- {...props}
142
- >
143
- <MoreHorizontal className="h-4 w-4" />
144
- <span className="sr-only">More</span>
145
- </span>
146
- );
147
- BreadcrumbEllipsis.displayName = "BreadcrumbElipssis";
148
-
149
- export {
150
- Breadcrumb,
151
- BreadcrumbEllipsis,
152
- BreadcrumbItem,
153
- BreadcrumbLink,
154
- BreadcrumbList,
155
- BreadcrumbPage,
156
- BreadcrumbSeparator,
157
- };
@@ -1,104 +0,0 @@
1
- import { Slot } from "@radix-ui/react-slot";
2
- import { cva, type VariantProps } from "class-variance-authority";
3
- import type * as React from "react";
4
-
5
- import { cn } from "../../lib/utils";
6
- import { Separator } from "../atoms/separator";
7
-
8
- const buttonGroupVariants = cva(
9
- "flex w-fit items-stretch has-[>[data-slot=button-group]]:gap-2 [&>*]:focus-visible:relative [&>*]:focus-visible:z-10 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
10
- {
11
- variants: {
12
- orientation: {
13
- horizontal:
14
- "[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
15
- vertical:
16
- "flex-col [&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none",
17
- },
18
- },
19
- defaultVariants: {
20
- orientation: "horizontal",
21
- },
22
- },
23
- );
24
-
25
- export interface ButtonGroupProps
26
- extends React.ComponentProps<"div">,
27
- VariantProps<typeof buttonGroupVariants> {
28
- /**
29
- * `horizontal` (default) lays buttons left-to-right with shared borders;
30
- * `vertical` stacks them with shared horizontal borders.
31
- * @default "horizontal"
32
- */
33
- orientation?: "horizontal" | "vertical";
34
- /** A row/column of `<Button>`s, `<ButtonGroupText>`s, or separators. */
35
- children?: React.ReactNode;
36
- className?: string;
37
- }
38
-
39
- function ButtonGroup({ className, orientation, ...props }: ButtonGroupProps) {
40
- return (
41
- <div
42
- role="group"
43
- data-slot="button-group"
44
- data-orientation={orientation}
45
- className={cn(buttonGroupVariants({ orientation }), className)}
46
- {...props}
47
- />
48
- );
49
- }
50
-
51
- export interface ButtonGroupTextProps extends React.ComponentProps<"div"> {
52
- /**
53
- * Render as a Radix Slot — useful for wrapping a label or icon as the
54
- * group's text element.
55
- * @default false
56
- */
57
- asChild?: boolean;
58
- /** Text or icon content. */
59
- children?: React.ReactNode;
60
- className?: string;
61
- }
62
-
63
- function ButtonGroupText({ className, asChild = false, ...props }: ButtonGroupTextProps) {
64
- const Comp = asChild ? Slot : "div";
65
-
66
- return (
67
- <Comp
68
- className={cn(
69
- "bg-muted shadow-xs flex items-center gap-2 rounded-md border border-border px-4 text-sm font-medium [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none",
70
- className,
71
- )}
72
- {...props}
73
- />
74
- );
75
- }
76
-
77
- export interface ButtonGroupSeparatorProps extends React.ComponentProps<typeof Separator> {
78
- /**
79
- * Layout direction.
80
- * @default "vertical"
81
- */
82
- orientation?: "horizontal" | "vertical";
83
- className?: string;
84
- }
85
-
86
- function ButtonGroupSeparator({
87
- className,
88
- orientation = "vertical",
89
- ...props
90
- }: ButtonGroupSeparatorProps) {
91
- return (
92
- <Separator
93
- data-slot="button-group-separator"
94
- orientation={orientation}
95
- className={cn(
96
- "bg-input relative !m-0 self-stretch data-[orientation=vertical]:h-auto",
97
- className,
98
- )}
99
- {...props}
100
- />
101
- );
102
- }
103
-
104
- export { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants };