@olympusoss/canvas 2.20.2 → 3.2.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 (214) hide show
  1. package/README.md +73 -35
  2. package/package.json +46 -177
  3. package/src/cn.ts +3 -0
  4. package/src/index.ts +12 -603
  5. package/src/theme.ts +62 -0
  6. package/src/tokens.ts +11 -0
  7. package/styles/atoms/avatar.css +22 -0
  8. package/styles/atoms/badge.css +83 -0
  9. package/styles/atoms/breadcrumb.css +35 -0
  10. package/styles/atoms/button-group.css +23 -0
  11. package/styles/atoms/button.css +107 -0
  12. package/styles/atoms/checkbox.css +55 -0
  13. package/styles/atoms/combobox.css +75 -0
  14. package/styles/atoms/dropdown.css +54 -0
  15. package/styles/atoms/icon.css +8 -0
  16. package/styles/atoms/input-group.css +45 -0
  17. package/styles/atoms/input.css +56 -0
  18. package/styles/atoms/kbd.css +15 -0
  19. package/styles/atoms/pagination.css +48 -0
  20. package/styles/atoms/popover.css +14 -0
  21. package/styles/atoms/radio.css +28 -0
  22. package/styles/atoms/select.css +57 -0
  23. package/styles/atoms/separator.css +32 -0
  24. package/styles/atoms/skeleton.css +32 -0
  25. package/styles/atoms/spinner.css +26 -0
  26. package/styles/atoms/switch.css +45 -0
  27. package/styles/atoms/textarea.css +31 -0
  28. package/styles/atoms/tooltip.css +53 -0
  29. package/styles/atoms/typography.css +105 -0
  30. package/styles/base.css +17 -0
  31. package/styles/canvas.css +77 -52
  32. package/styles/molecules/alert.css +66 -0
  33. package/styles/molecules/card.css +58 -0
  34. package/styles/molecules/code-block.css +18 -0
  35. package/styles/molecules/empty-state.css +17 -0
  36. package/styles/molecules/field.css +27 -0
  37. package/styles/molecules/form.css +27 -0
  38. package/styles/molecules/page-header.css +52 -0
  39. package/styles/molecules/section-card.css +49 -0
  40. package/styles/molecules/stat-card.css +71 -0
  41. package/styles/molecules/toast.css +95 -0
  42. package/styles/organisms/app-shell.css +46 -0
  43. package/styles/organisms/calendar.css +73 -0
  44. package/styles/organisms/command.css +94 -0
  45. package/styles/organisms/data-table.css +142 -0
  46. package/styles/organisms/dialog.css +72 -0
  47. package/styles/organisms/filter-panel.css +58 -0
  48. package/styles/organisms/row-menu.css +69 -0
  49. package/styles/organisms/sheet.css +70 -0
  50. package/styles/organisms/sidebar.css +146 -0
  51. package/styles/organisms/stepper.css +63 -0
  52. package/styles/organisms/tabs.css +40 -0
  53. package/styles/organisms/topbar.css +24 -0
  54. package/styles/patterns/backdrops.css +35 -0
  55. package/styles/patterns/density.css +66 -0
  56. package/styles/patterns/focus.css +22 -0
  57. package/styles/patterns/glass.css +85 -0
  58. package/styles/patterns/high-contrast.css +70 -0
  59. package/styles/patterns/reduced-motion.css +12 -0
  60. package/styles/patterns/scrollbar.css +10 -0
  61. package/styles/reset.css +89 -0
  62. package/styles/tokens/colors.css +106 -0
  63. package/styles/tokens/motion.css +33 -0
  64. package/styles/tokens/radius.css +10 -0
  65. package/styles/tokens/shadows.css +35 -0
  66. package/styles/tokens/spacing.css +19 -0
  67. package/styles/tokens/typography.css +6 -0
  68. package/styles/tokens/z-index.css +12 -0
  69. package/styles/utilities/display.css +66 -0
  70. package/styles/utilities/flexbox.css +240 -0
  71. package/styles/utilities/gap.css +288 -0
  72. package/styles/utilities/grid.css +138 -0
  73. package/styles/utilities/position.css +78 -0
  74. package/styles/utilities/sizing.css +138 -0
  75. package/tsconfig.json +20 -21
  76. package/src/components/atoms/README.md +0 -11
  77. package/src/components/atoms/aspect-ratio.tsx +0 -32
  78. package/src/components/atoms/avatar.tsx +0 -98
  79. package/src/components/atoms/badge.tsx +0 -44
  80. package/src/components/atoms/brand-mark.tsx +0 -74
  81. package/src/components/atoms/button.tsx +0 -105
  82. package/src/components/atoms/checkbox.tsx +0 -63
  83. package/src/components/atoms/flex-box.tsx +0 -105
  84. package/src/components/atoms/icon.tsx +0 -34
  85. package/src/components/atoms/input.tsx +0 -92
  86. package/src/components/atoms/label.tsx +0 -41
  87. package/src/components/atoms/logo.tsx +0 -89
  88. package/src/components/atoms/progress.tsx +0 -55
  89. package/src/components/atoms/radio-group.tsx +0 -122
  90. package/src/components/atoms/scroll-area.tsx +0 -106
  91. package/src/components/atoms/section.tsx +0 -48
  92. package/src/components/atoms/separator.tsx +0 -45
  93. package/src/components/atoms/skeleton.tsx +0 -17
  94. package/src/components/atoms/slider.tsx +0 -93
  95. package/src/components/atoms/spinner.tsx +0 -47
  96. package/src/components/atoms/switch.tsx +0 -60
  97. package/src/components/atoms/textarea.tsx +0 -78
  98. package/src/components/atoms/toggle.tsx +0 -80
  99. package/src/components/charts/activity-heatmap.tsx +0 -186
  100. package/src/components/charts/axes.tsx +0 -21
  101. package/src/components/charts/chart-container.tsx +0 -254
  102. package/src/components/charts/chart-legend.tsx +0 -67
  103. package/src/components/charts/chart-tooltip.tsx +0 -161
  104. package/src/components/charts/chart-types.tsx +0 -49
  105. package/src/components/charts/containers.tsx +0 -11
  106. package/src/components/charts/data.tsx +0 -16
  107. package/src/components/charts/details.tsx +0 -25
  108. package/src/components/charts/dot-pulse.tsx +0 -61
  109. package/src/components/charts/gauge.tsx +0 -106
  110. package/src/components/charts/grids.tsx +0 -8
  111. package/src/components/charts/index.ts +0 -62
  112. package/src/components/charts/labeled-bar-list.tsx +0 -85
  113. package/src/components/charts/metric-breakdown.tsx +0 -316
  114. package/src/components/charts/references.tsx +0 -8
  115. package/src/components/charts/service-health-list.tsx +0 -85
  116. package/src/components/charts/sparkline-area.tsx +0 -80
  117. package/src/components/charts/sparkline.tsx +0 -52
  118. package/src/components/charts/stacked-bar.tsx +0 -104
  119. package/src/components/charts/text.tsx +0 -10
  120. package/src/components/charts/world-heat-map-inner.tsx +0 -317
  121. package/src/components/charts/world-heat-map.tsx +0 -184
  122. package/src/components/molecules/README.md +0 -12
  123. package/src/components/molecules/action-bar.tsx +0 -73
  124. package/src/components/molecules/activity-item.tsx +0 -74
  125. package/src/components/molecules/alert.tsx +0 -86
  126. package/src/components/molecules/animated-background.tsx +0 -92
  127. package/src/components/molecules/auth-shell.tsx +0 -95
  128. package/src/components/molecules/brand-lockup.tsx +0 -48
  129. package/src/components/molecules/breadcrumb.tsx +0 -157
  130. package/src/components/molecules/button-group.tsx +0 -104
  131. package/src/components/molecules/calendar.tsx +0 -217
  132. package/src/components/molecules/card.tsx +0 -102
  133. package/src/components/molecules/client-brand.tsx +0 -95
  134. package/src/components/molecules/code-block.tsx +0 -86
  135. package/src/components/molecules/countdown-button.tsx +0 -92
  136. package/src/components/molecules/empty-state.tsx +0 -56
  137. package/src/components/molecules/error-state.tsx +0 -42
  138. package/src/components/molecules/field-display.tsx +0 -35
  139. package/src/components/molecules/input-otp.tsx +0 -74
  140. package/src/components/molecules/launcher-card.tsx +0 -152
  141. package/src/components/molecules/loading-state.tsx +0 -36
  142. package/src/components/molecules/notification-item.tsx +0 -67
  143. package/src/components/molecules/notification-list.tsx +0 -45
  144. package/src/components/molecules/number-badge.tsx +0 -53
  145. package/src/components/molecules/or-separator.tsx +0 -38
  146. package/src/components/molecules/page-header.tsx +0 -88
  147. package/src/components/molecules/page-tabs.tsx +0 -94
  148. package/src/components/molecules/pagination.tsx +0 -150
  149. package/src/components/molecules/password-input.tsx +0 -83
  150. package/src/components/molecules/password-strength-meter.tsx +0 -104
  151. package/src/components/molecules/phone-input.tsx +0 -200
  152. package/src/components/molecules/search-bar.tsx +0 -64
  153. package/src/components/molecules/secret-field.tsx +0 -158
  154. package/src/components/molecules/section-card.tsx +0 -91
  155. package/src/components/molecules/social-buttons.tsx +0 -165
  156. package/src/components/molecules/stat-card.tsx +0 -100
  157. package/src/components/molecules/status-badge.tsx +0 -42
  158. package/src/components/molecules/stepper.tsx +0 -96
  159. package/src/components/molecules/table.tsx +0 -157
  160. package/src/components/molecules/terminal.tsx +0 -74
  161. package/src/components/molecules/toggle-group.tsx +0 -145
  162. package/src/components/molecules/tooltip.tsx +0 -155
  163. package/src/components/molecules/user-avatar-chip.tsx +0 -71
  164. package/src/components/organisms/README.md +0 -14
  165. package/src/components/organisms/accordion.tsx +0 -154
  166. package/src/components/organisms/alert-dialog.tsx +0 -277
  167. package/src/components/organisms/carousel.tsx +0 -244
  168. package/src/components/organisms/collapsible.tsx +0 -69
  169. package/src/components/organisms/command.tsx +0 -144
  170. package/src/components/organisms/context-menu.tsx +0 -339
  171. package/src/components/organisms/dashboard-grid.tsx +0 -369
  172. package/src/components/organisms/data-table.tsx +0 -330
  173. package/src/components/organisms/dialog.tsx +0 -312
  174. package/src/components/organisms/drawer.tsx +0 -123
  175. package/src/components/organisms/dropdown-menu.tsx +0 -440
  176. package/src/components/organisms/editors/code-editor.tsx +0 -144
  177. package/src/components/organisms/editors/index.ts +0 -4
  178. package/src/components/organisms/editors/markdown-editor.tsx +0 -153
  179. package/src/components/organisms/editors/markdown-renderer.ts +0 -27
  180. package/src/components/organisms/editors/prose-canvas-classes.ts +0 -45
  181. package/src/components/organisms/editors/rich-text-editor.tsx +0 -126
  182. package/src/components/organisms/editors/toolbar/md-toolbar.tsx +0 -129
  183. package/src/components/organisms/editors/toolbar/rte-toolbar.tsx +0 -211
  184. package/src/components/organisms/editors/toolbar/toolbar-shell.tsx +0 -45
  185. package/src/components/organisms/editors/use-codemirror-theme.ts +0 -61
  186. package/src/components/organisms/error-boundary.tsx +0 -61
  187. package/src/components/organisms/form.tsx +0 -174
  188. package/src/components/organisms/hover-card.tsx +0 -115
  189. package/src/components/organisms/menubar.tsx +0 -498
  190. package/src/components/organisms/navbar.tsx +0 -104
  191. package/src/components/organisms/navigation-menu.tsx +0 -235
  192. package/src/components/organisms/popover.tsx +0 -149
  193. package/src/components/organisms/resizable.tsx +0 -58
  194. package/src/components/organisms/schema-form.tsx +0 -232
  195. package/src/components/organisms/select.tsx +0 -309
  196. package/src/components/organisms/sheet.tsx +0 -265
  197. package/src/components/organisms/sidebar.tsx +0 -1040
  198. package/src/components/organisms/sonner.tsx +0 -96
  199. package/src/components/organisms/tabs.tsx +0 -133
  200. package/src/components/organisms/theme-provider.tsx +0 -101
  201. package/src/hooks/use-mobile.tsx +0 -19
  202. package/src/lib/portal-container.tsx +0 -35
  203. package/src/lib/utils.ts +0 -6
  204. package/src/native.ts +0 -23
  205. package/src/tokens/colors.ts +0 -91
  206. package/src/tokens/index.ts +0 -3
  207. package/src/tokens/spacing.ts +0 -55
  208. package/src/tokens/typography.ts +0 -27
  209. package/styles/dashboard-grid.css +0 -47
  210. package/styles/fonts/Roboto-VariableFont_wdth_wght.ttf +0 -0
  211. package/styles/glass.css +0 -175
  212. package/styles/leaflet.css +0 -13
  213. package/styles/tokens.css +0 -317
  214. package/tailwind.config.ts +0 -70
@@ -1,45 +0,0 @@
1
- "use client";
2
-
3
- import * as SeparatorPrimitive from "@radix-ui/react-separator";
4
- import * as React from "react";
5
-
6
- import { cn } from "../../lib/utils";
7
-
8
- export interface SeparatorProps
9
- extends React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root> {
10
- /**
11
- * Layout direction. `horizontal` is a 1px row spanning width;
12
- * `vertical` is a 1px column spanning height.
13
- * @default "horizontal"
14
- */
15
- orientation?: "horizontal" | "vertical";
16
- /**
17
- * When true (default), the separator is hidden from screen readers. Set
18
- * to false for separators that have semantic meaning.
19
- * @default true
20
- */
21
- decorative?: boolean;
22
- asChild?: boolean;
23
- className?: string;
24
- }
25
-
26
- /** Thin divider line — horizontal (default) or vertical. */
27
- const Separator = React.forwardRef<
28
- React.ElementRef<typeof SeparatorPrimitive.Root>,
29
- SeparatorProps
30
- >(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => (
31
- <SeparatorPrimitive.Root
32
- ref={ref}
33
- decorative={decorative}
34
- orientation={orientation}
35
- className={cn(
36
- "shrink-0 bg-border",
37
- orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
38
- className,
39
- )}
40
- {...props}
41
- />
42
- ));
43
- Separator.displayName = SeparatorPrimitive.Root.displayName;
44
-
45
- export { Separator };
@@ -1,17 +0,0 @@
1
- import type * as React from "react";
2
-
3
- import { cn } from "../../lib/utils";
4
-
5
- export interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {
6
- className?: string;
7
- }
8
-
9
- /**
10
- * Animated placeholder for content that's loading. Set width/height via
11
- * className; Skeleton fills with a pulsing tinted block.
12
- */
13
- function Skeleton({ className, ...props }: SkeletonProps) {
14
- return <div className={cn("animate-pulse rounded-md bg-primary/10", className)} {...props} />;
15
- }
16
-
17
- export { Skeleton };
@@ -1,93 +0,0 @@
1
- "use client";
2
-
3
- import * as SliderPrimitive from "@radix-ui/react-slider";
4
- import * as React from "react";
5
-
6
- import { cn } from "../../lib/utils";
7
-
8
- export interface SliderProps extends React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> {
9
- /**
10
- * Controlled value. Pass an array — single-thumb sliders use a length-1
11
- * tuple (`[40]`), range sliders use length-2 (`[20, 80]`). Pair with
12
- * `onValueChange`.
13
- */
14
- value?: number[];
15
- /**
16
- * Initial value for uncontrolled usage. Same array shape as `value`.
17
- * @default [0]
18
- */
19
- defaultValue?: number[];
20
- /** Fires on every move. Use this for live previews. */
21
- onValueChange?: (value: number[]) => void;
22
- /** Fires when the user releases the thumb (commit handler). */
23
- onValueCommit?: (value: number[]) => void;
24
- /**
25
- * Minimum value the slider can reach.
26
- * @default 0
27
- */
28
- min?: number;
29
- /**
30
- * Maximum value the slider can reach.
31
- * @default 100
32
- */
33
- max?: number;
34
- /**
35
- * Quantum the slider snaps to. Set to `1` for integer-only values.
36
- * @default 1
37
- */
38
- step?: number;
39
- /**
40
- * Minimum gap between two thumbs in a range slider. Ignored for
41
- * single-thumb sliders.
42
- * @default 0
43
- */
44
- minStepsBetweenThumbs?: number;
45
- /**
46
- * Layout direction.
47
- * @default "horizontal"
48
- */
49
- orientation?: "horizontal" | "vertical";
50
- /**
51
- * Reading direction. Affects which end is "min" on the visual axis.
52
- * @default "ltr"
53
- */
54
- dir?: "ltr" | "rtl";
55
- /**
56
- * Whether the slider is inverted — flips which end is "min".
57
- * @default false
58
- */
59
- inverted?: boolean;
60
- /**
61
- * Disable the slider.
62
- * @default false
63
- */
64
- disabled?: boolean;
65
- /** Form field name. Required when relying on uncontrolled native form submission. */
66
- name?: string;
67
- /**
68
- * Render as a Radix Slot — forwards props onto the immediate child
69
- * element instead of rendering a wrapper `<span>`.
70
- * @default false
71
- */
72
- asChild?: boolean;
73
- /** Tailwind / CSS classes merged onto the slider via `cn()`. */
74
- className?: string;
75
- }
76
-
77
- const Slider = React.forwardRef<React.ElementRef<typeof SliderPrimitive.Root>, SliderProps>(
78
- ({ className, ...props }, ref) => (
79
- <SliderPrimitive.Root
80
- ref={ref}
81
- className={cn("relative flex w-full touch-none select-none items-center", className)}
82
- {...props}
83
- >
84
- <SliderPrimitive.Track className="relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20">
85
- <SliderPrimitive.Range className="absolute h-full bg-primary" />
86
- </SliderPrimitive.Track>
87
- <SliderPrimitive.Thumb className="block h-4 w-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
88
- </SliderPrimitive.Root>
89
- ),
90
- );
91
- Slider.displayName = SliderPrimitive.Root.displayName;
92
-
93
- export { Slider };
@@ -1,47 +0,0 @@
1
- "use client";
2
-
3
- import { Loader2 } from "lucide-react";
4
- import * as React from "react";
5
-
6
- import { cn } from "../../lib/utils";
7
-
8
- export interface SpinnerProps extends React.SVGAttributes<SVGSVGElement> {
9
- /**
10
- * Pixel size of the rendered SVG.
11
- * @default 16
12
- */
13
- size?: number;
14
- /** Tailwind / CSS classes merged via `cn()`. */
15
- className?: string;
16
- /**
17
- * Accessible label announced by screen readers. Defaults to `"Loading"`.
18
- * Pass an empty string to mark as purely decorative when the surrounding
19
- * label already announces the loading state.
20
- */
21
- label?: string;
22
- }
23
-
24
- /**
25
- * Inline loading indicator. Wraps `Loader2` from lucide-react with the
26
- * canvas `animate-spin` keyframe and an accessible label.
27
- *
28
- * Use inside buttons (`{loading ? <Spinner/> : 'Submit'}`), next to inline
29
- * labels, or anywhere a small spinning indicator is appropriate. For a
30
- * full-section loader with a message, use `LoadingState` (molecule).
31
- */
32
- const Spinner = React.forwardRef<SVGSVGElement, SpinnerProps>(
33
- ({ size = 16, className, label = "Loading", ...props }, ref) => (
34
- <Loader2
35
- ref={ref}
36
- size={size}
37
- className={cn("animate-spin shrink-0", className)}
38
- role={label ? "status" : undefined}
39
- aria-label={label || undefined}
40
- aria-hidden={label ? undefined : true}
41
- {...props}
42
- />
43
- ),
44
- );
45
- Spinner.displayName = "Spinner";
46
-
47
- export { Spinner };
@@ -1,60 +0,0 @@
1
- "use client";
2
-
3
- import * as SwitchPrimitives from "@radix-ui/react-switch";
4
- import * as React from "react";
5
-
6
- import { cn } from "../../lib/utils";
7
-
8
- export interface SwitchProps extends React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root> {
9
- /** Controlled state. */
10
- checked?: boolean;
11
- /**
12
- * Initial state for uncontrolled usage.
13
- * @default false
14
- */
15
- defaultChecked?: boolean;
16
- /** Fires when the user flips the switch. */
17
- onCheckedChange?: (checked: boolean) => void;
18
- /**
19
- * Dims and blocks input.
20
- * @default false
21
- */
22
- disabled?: boolean;
23
- /**
24
- * Block native form submit unless the switch is on.
25
- * @default false
26
- */
27
- required?: boolean;
28
- /** Form field name for native form submission. */
29
- name?: string;
30
- /** Form field value when submitted. */
31
- value?: string;
32
- asChild?: boolean;
33
- className?: string;
34
- }
35
-
36
- /**
37
- * Wraps Radix's `Switch.Root` — a binary on/off toggle. Pair with `<Label>`
38
- * for accessibility.
39
- */
40
- const Switch = React.forwardRef<React.ElementRef<typeof SwitchPrimitives.Root>, SwitchProps>(
41
- ({ className, ...props }, ref) => (
42
- <SwitchPrimitives.Root
43
- className={cn(
44
- "peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
45
- className,
46
- )}
47
- {...props}
48
- ref={ref}
49
- >
50
- <SwitchPrimitives.Thumb
51
- className={cn(
52
- "pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0",
53
- )}
54
- />
55
- </SwitchPrimitives.Root>
56
- ),
57
- );
58
- Switch.displayName = SwitchPrimitives.Root.displayName;
59
-
60
- export { Switch };
@@ -1,78 +0,0 @@
1
- import * as React from "react";
2
-
3
- import { cn } from "../../lib/utils";
4
-
5
- export interface TextareaProps extends React.ComponentProps<"textarea"> {
6
- /** Controlled value. Pair with `onChange`. */
7
- value?: string | number | readonly string[];
8
- /** Uncontrolled initial value. */
9
- defaultValue?: string | number | readonly string[];
10
- /** Hint text shown when empty. */
11
- placeholder?: string;
12
- /**
13
- * Visible row count. Canvas's default min-height is 60px regardless;
14
- * `rows` overrides.
15
- */
16
- rows?: number;
17
- /** Visible column count (width). Canvas overrides this with `w-full`. */
18
- cols?: number;
19
- /**
20
- * Dim and block input.
21
- * @default false
22
- */
23
- disabled?: boolean;
24
- /**
25
- * Selectable but not editable.
26
- * @default false
27
- */
28
- readOnly?: boolean;
29
- /**
30
- * Block native form submit unless the textarea has a value.
31
- * @default false
32
- */
33
- required?: boolean;
34
- /** Form field name for native form submission. */
35
- name?: string;
36
- /** DOM id for `<Label htmlFor>` association. */
37
- id?: string;
38
- /** Browser autofill hint. */
39
- autoComplete?: string;
40
- /**
41
- * Focus on mount.
42
- * @default false
43
- */
44
- autoFocus?: boolean;
45
- /** Character count upper limit. */
46
- maxLength?: number;
47
- /** Character count lower limit. */
48
- minLength?: number;
49
- /** Fires on every keystroke. */
50
- onChange?: React.ChangeEventHandler<HTMLTextAreaElement>;
51
- /** Fires on focus. */
52
- onFocus?: React.FocusEventHandler<HTMLTextAreaElement>;
53
- /** Fires on blur. */
54
- onBlur?: React.FocusEventHandler<HTMLTextAreaElement>;
55
- className?: string;
56
- }
57
-
58
- /**
59
- * Styled wrapper around the native `<textarea>`. 60px min-height, rounded-md,
60
- * 1px border, transparent background.
61
- */
62
- const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
63
- ({ className, ...props }, ref) => {
64
- return (
65
- <textarea
66
- className={cn(
67
- "flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
68
- className,
69
- )}
70
- ref={ref}
71
- {...props}
72
- />
73
- );
74
- },
75
- );
76
- Textarea.displayName = "Textarea";
77
-
78
- export { Textarea };
@@ -1,80 +0,0 @@
1
- "use client";
2
-
3
- import * as TogglePrimitive from "@radix-ui/react-toggle";
4
- import { cva, type VariantProps } from "class-variance-authority";
5
- import * as React from "react";
6
-
7
- import { cn } from "../../lib/utils";
8
-
9
- const toggleVariants = cva(
10
- "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-brand data-[state=on]:text-brand-foreground data-[state=on]:hover:bg-brand/90 data-[state=on]:hover:text-brand-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
11
- {
12
- variants: {
13
- variant: {
14
- default: "bg-transparent",
15
- outline:
16
- "border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
17
- },
18
- size: {
19
- default: "h-9 px-2 min-w-9",
20
- sm: "h-8 px-1.5 min-w-8",
21
- lg: "h-10 px-2.5 min-w-10",
22
- },
23
- },
24
- defaultVariants: {
25
- variant: "default",
26
- size: "default",
27
- },
28
- },
29
- );
30
-
31
- export interface ToggleProps
32
- extends React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root>,
33
- VariantProps<typeof toggleVariants> {
34
- /**
35
- * `default` (filled when on) or `outline` (bordered).
36
- * @default "default"
37
- */
38
- variant?: "default" | "outline";
39
- /**
40
- * Square size — `sm` (32px), `default` (36px), or `lg` (40px).
41
- * @default "default"
42
- */
43
- size?: "default" | "sm" | "lg";
44
- /** Controlled pressed state. Pair with `onPressedChange`. */
45
- pressed?: boolean;
46
- /**
47
- * Initial pressed state for uncontrolled usage.
48
- * @default false
49
- */
50
- defaultPressed?: boolean;
51
- /** Fires when the user toggles the pressed state. */
52
- onPressedChange?: (pressed: boolean) => void;
53
- /**
54
- * Disable the toggle.
55
- * @default false
56
- */
57
- disabled?: boolean;
58
- /**
59
- * Render as a Radix Slot.
60
- * @default false
61
- */
62
- asChild?: boolean;
63
- /** Toggle content (typically an icon or short label). */
64
- children?: React.ReactNode;
65
- className?: string;
66
- }
67
-
68
- const Toggle = React.forwardRef<React.ElementRef<typeof TogglePrimitive.Root>, ToggleProps>(
69
- ({ className, variant, size, ...props }, ref) => (
70
- <TogglePrimitive.Root
71
- ref={ref}
72
- className={cn(toggleVariants({ variant, size, className }))}
73
- {...props}
74
- />
75
- ),
76
- );
77
-
78
- Toggle.displayName = TogglePrimitive.Root.displayName;
79
-
80
- export { Toggle, toggleVariants };
@@ -1,186 +0,0 @@
1
- import * as React from "react";
2
-
3
- import { cn } from "../../lib/utils";
4
-
5
- const DEFAULT_WEEKDAY_LABELS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] as const;
6
-
7
- export interface ActivityHeatmapProps extends React.HTMLAttributes<HTMLDivElement> {
8
- /**
9
- * Cell values in row-major order. Each entry is a number in `[0, 1]`
10
- * where `0` paints the lowest tint and `1` paints the highest. Values are
11
- * clamped on render. The grid dimensions come from `data.length` and
12
- * `data[0].length`; pass jagged arrays only if you accept short rows.
13
- */
14
- data: number[][];
15
- /**
16
- * CSS variable name (without leading `--`) used for the cell hue. Default
17
- * `chart-1`. Cells render as `hsl(var(--{colorVar}) / opacity)`.
18
- */
19
- colorVar?: string;
20
- /** Pixel height of each cell row. Default `14`. */
21
- cellHeight?: number;
22
- /** Pixel gap between cells. Default `2`. */
23
- gap?: number;
24
- /** Pixel border-radius on each cell. Default `3`. */
25
- cellRadius?: number;
26
- /**
27
- * Render the cell `title` attribute (browser tooltip on hover) for each
28
- * coordinate. Receives `(rowIndex, colIndex, value)` and should return a
29
- * string. Returns nothing → no title set.
30
- */
31
- cellTitle?: (row: number, col: number, value: number) => string | undefined;
32
- /**
33
- * Optional left-side row labels (Y-axis). When provided, must align with
34
- * `data.length`. Empty / nullish entries render as blank cells so the
35
- * label column stays aligned with the grid.
36
- */
37
- rowLabels?: React.ReactNode[];
38
- /**
39
- * Optional bottom-side column labels (X-axis). When provided, must align
40
- * with `data[0].length`. Pass empty strings (or `null`) for indices you
41
- * want to leave blank — useful for sparse hour ticks (e.g. only label
42
- * 0/6/12/18/23 across a 24-column matrix).
43
- */
44
- colLabels?: React.ReactNode[];
45
- /**
46
- * Show a "Fewer ↔ More" gradient legend below the grid. Pass `true` for
47
- * the default labels, or an object to override one or both ends. The
48
- * gradient mirrors the cell-opacity ramp (`0.08` → `0.93`).
49
- * @default false
50
- */
51
- legend?: boolean | { fromLabel?: React.ReactNode; toLabel?: React.ReactNode };
52
- }
53
-
54
- /**
55
- * CSS-grid heatmap of opacity-tinted cells. Useful for time-of-day × day-of-week
56
- * matrices (token issuance, sign-in concentration, queue depth) where a full
57
- * chart would be overkill. Rendering is a flat `display: grid` — no canvas, no
58
- * SVG, fully interactive via hover titles.
59
- *
60
- * Optionally renders row labels on the left, sparse column labels below, and a
61
- * `Fewer ↔ More` gradient legend — toggle each with `rowLabels` / `colLabels` /
62
- * `legend` props.
63
- */
64
- export const ActivityHeatmap = React.forwardRef<HTMLDivElement, ActivityHeatmapProps>(
65
- (
66
- {
67
- data,
68
- colorVar = "chart-1",
69
- cellHeight = 14,
70
- gap = 2,
71
- cellRadius = 3,
72
- cellTitle,
73
- rowLabels,
74
- colLabels,
75
- legend = false,
76
- className,
77
- ...props
78
- },
79
- ref,
80
- ) => {
81
- const cols = data[0]?.length ?? 0;
82
- const legendObj = typeof legend === "object" ? legend : null;
83
- const fromLabel = legendObj?.fromLabel ?? "Fewer";
84
- const toLabel = legendObj?.toLabel ?? "More";
85
- const showLegend = legend !== false;
86
- // 7-row grids default to weekday labels (Mon–Sun) — covers the common
87
- // GitHub-style yearly contribution pattern without each consumer
88
- // re-declaring the array.
89
- const resolvedRowLabels =
90
- rowLabels ?? (data.length === 7 ? DEFAULT_WEEKDAY_LABELS.slice() : undefined);
91
-
92
- return (
93
- <div ref={ref} className={cn("w-full", className)} {...props}>
94
- <div className="flex gap-2">
95
- {resolvedRowLabels && resolvedRowLabels.length > 0 && (
96
- <div
97
- className="grid text-[10px] tabular-nums text-muted-foreground"
98
- style={{
99
- gridTemplateRows: `repeat(${data.length}, ${cellHeight}px)`,
100
- rowGap: gap,
101
- }}
102
- aria-hidden
103
- >
104
- {Array.from({ length: data.length }, (_, i) => (
105
- <span key={`row-label-${i}`} className="flex items-center leading-none">
106
- {resolvedRowLabels[i] ?? ""}
107
- </span>
108
- ))}
109
- </div>
110
- )}
111
- <div className="flex-1">
112
- <div
113
- style={{
114
- display: "grid",
115
- gridTemplateRows: `repeat(${data.length}, ${cellHeight}px)`,
116
- gap,
117
- }}
118
- >
119
- {data.map((row, r) => (
120
- <div
121
- key={`r-${r}`}
122
- style={{
123
- display: "grid",
124
- gridTemplateColumns: `repeat(${cols}, 1fr)`,
125
- gap,
126
- }}
127
- >
128
- {row.map((raw, c) => {
129
- const v = Math.max(0, Math.min(1, raw));
130
- const opacity = 0.08 + v * 0.85;
131
- const title = cellTitle?.(r, c, v);
132
- return (
133
- <div
134
- key={`c-${r}-${c}`}
135
- data-cell=""
136
- title={title}
137
- aria-hidden
138
- style={{
139
- borderRadius: cellRadius,
140
- background: `hsl(var(--${colorVar}) / ${opacity})`,
141
- }}
142
- />
143
- );
144
- })}
145
- </div>
146
- ))}
147
- </div>
148
- {colLabels && colLabels.length > 0 && (
149
- <div
150
- className="mt-2 grid text-[10px] tabular-nums text-muted-foreground"
151
- style={{
152
- gridTemplateColumns: `repeat(${cols}, 1fr)`,
153
- columnGap: gap,
154
- }}
155
- >
156
- {Array.from({ length: cols }, (_, i) => {
157
- const label = colLabels[i];
158
- const empty = label === undefined || label === null || label === "";
159
- return (
160
- <span key={`col-label-${i}`} className="text-center" aria-hidden={empty}>
161
- {empty ? "" : label}
162
- </span>
163
- );
164
- })}
165
- </div>
166
- )}
167
- </div>
168
- </div>
169
- {showLegend && (
170
- <div className="mt-3 flex items-center gap-2 text-xs text-muted-foreground">
171
- <span>{fromLabel}</span>
172
- <div
173
- className="h-2 flex-1 rounded-full"
174
- style={{
175
- background: `linear-gradient(90deg, hsl(var(--${colorVar}) / 0.08) 0%, hsl(var(--${colorVar}) / 0.93) 100%)`,
176
- }}
177
- aria-hidden
178
- />
179
- <span>{toLabel}</span>
180
- </div>
181
- )}
182
- </div>
183
- );
184
- },
185
- );
186
- ActivityHeatmap.displayName = "ActivityHeatmap";
@@ -1,21 +0,0 @@
1
- "use client";
2
-
3
- /**
4
- * Axis re-exports — pure pass-throughs of the Recharts primitives. Wrapping
5
- * them in function components breaks Recharts' `findAllByType` introspection
6
- * (chart types like LineChart look for `child.type === XAxis` to detect axes;
7
- * our wrapper would have a different type, so the chart can't find them and
8
- * crashes with "xAxisId requires a corresponding xAxisId on the targeted
9
- * graphical component" errors).
10
- *
11
- * Theming is applied via CSS selectors on the `<ChartContainer>` wrapping div
12
- * (`[&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground`, etc.).
13
- */
14
- export {
15
- CartesianAxis,
16
- PolarAngleAxis,
17
- PolarRadiusAxis,
18
- XAxis,
19
- YAxis,
20
- ZAxis,
21
- } from "recharts";