@olympusoss/canvas 2.6.19

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 (128) hide show
  1. package/package.json +179 -0
  2. package/src/components/atoms/README.md +11 -0
  3. package/src/components/atoms/aspect-ratio.tsx +32 -0
  4. package/src/components/atoms/avatar.tsx +98 -0
  5. package/src/components/atoms/badge.tsx +44 -0
  6. package/src/components/atoms/brand-mark.tsx +74 -0
  7. package/src/components/atoms/button.tsx +104 -0
  8. package/src/components/atoms/checkbox.tsx +63 -0
  9. package/src/components/atoms/flex-box.tsx +105 -0
  10. package/src/components/atoms/icon.tsx +34 -0
  11. package/src/components/atoms/input.tsx +91 -0
  12. package/src/components/atoms/label.tsx +41 -0
  13. package/src/components/atoms/logo.tsx +89 -0
  14. package/src/components/atoms/progress.tsx +55 -0
  15. package/src/components/atoms/radio-group.tsx +122 -0
  16. package/src/components/atoms/scroll-area.tsx +106 -0
  17. package/src/components/atoms/section.tsx +48 -0
  18. package/src/components/atoms/separator.tsx +45 -0
  19. package/src/components/atoms/skeleton.tsx +17 -0
  20. package/src/components/atoms/slider.tsx +93 -0
  21. package/src/components/atoms/switch.tsx +60 -0
  22. package/src/components/atoms/textarea.tsx +78 -0
  23. package/src/components/atoms/toggle.tsx +80 -0
  24. package/src/components/charts/activity-heatmap.tsx +96 -0
  25. package/src/components/charts/axes.tsx +21 -0
  26. package/src/components/charts/chart-container.tsx +195 -0
  27. package/src/components/charts/chart-legend.tsx +67 -0
  28. package/src/components/charts/chart-tooltip.tsx +161 -0
  29. package/src/components/charts/chart-types.tsx +49 -0
  30. package/src/components/charts/containers.tsx +11 -0
  31. package/src/components/charts/data.tsx +16 -0
  32. package/src/components/charts/details.tsx +25 -0
  33. package/src/components/charts/gauge.tsx +106 -0
  34. package/src/components/charts/grids.tsx +8 -0
  35. package/src/components/charts/index.ts +62 -0
  36. package/src/components/charts/labeled-bar-list.tsx +85 -0
  37. package/src/components/charts/references.tsx +8 -0
  38. package/src/components/charts/service-health-list.tsx +73 -0
  39. package/src/components/charts/sparkline.tsx +52 -0
  40. package/src/components/charts/stacked-bar.tsx +104 -0
  41. package/src/components/charts/text.tsx +10 -0
  42. package/src/components/charts/world-heat-map-inner.tsx +317 -0
  43. package/src/components/charts/world-heat-map.tsx +184 -0
  44. package/src/components/molecules/README.md +12 -0
  45. package/src/components/molecules/action-bar.tsx +73 -0
  46. package/src/components/molecules/activity-item.tsx +74 -0
  47. package/src/components/molecules/alert.tsx +80 -0
  48. package/src/components/molecules/animated-background.tsx +92 -0
  49. package/src/components/molecules/brand-lockup.tsx +48 -0
  50. package/src/components/molecules/breadcrumb.tsx +161 -0
  51. package/src/components/molecules/button-group.tsx +104 -0
  52. package/src/components/molecules/calendar.tsx +216 -0
  53. package/src/components/molecules/card.tsx +101 -0
  54. package/src/components/molecules/code-block.tsx +48 -0
  55. package/src/components/molecules/empty-state.tsx +55 -0
  56. package/src/components/molecules/error-state.tsx +42 -0
  57. package/src/components/molecules/field-display.tsx +35 -0
  58. package/src/components/molecules/input-otp.tsx +74 -0
  59. package/src/components/molecules/loading-state.tsx +36 -0
  60. package/src/components/molecules/notification-item.tsx +67 -0
  61. package/src/components/molecules/notification-list.tsx +45 -0
  62. package/src/components/molecules/number-badge.tsx +53 -0
  63. package/src/components/molecules/page-header.tsx +88 -0
  64. package/src/components/molecules/page-tabs.tsx +94 -0
  65. package/src/components/molecules/pagination.tsx +150 -0
  66. package/src/components/molecules/phone-input.tsx +200 -0
  67. package/src/components/molecules/search-bar.tsx +64 -0
  68. package/src/components/molecules/secret-field.tsx +158 -0
  69. package/src/components/molecules/section-card.tsx +91 -0
  70. package/src/components/molecules/stat-card.tsx +96 -0
  71. package/src/components/molecules/status-badge.tsx +42 -0
  72. package/src/components/molecules/stepper.tsx +96 -0
  73. package/src/components/molecules/table.tsx +157 -0
  74. package/src/components/molecules/toggle-group.tsx +145 -0
  75. package/src/components/molecules/tooltip.tsx +150 -0
  76. package/src/components/molecules/user-avatar-chip.tsx +71 -0
  77. package/src/components/organisms/README.md +14 -0
  78. package/src/components/organisms/accordion.tsx +149 -0
  79. package/src/components/organisms/alert-dialog.tsx +269 -0
  80. package/src/components/organisms/carousel.tsx +244 -0
  81. package/src/components/organisms/collapsible.tsx +69 -0
  82. package/src/components/organisms/command.tsx +143 -0
  83. package/src/components/organisms/context-menu.tsx +333 -0
  84. package/src/components/organisms/dashboard-grid.tsx +360 -0
  85. package/src/components/organisms/data-table.tsx +330 -0
  86. package/src/components/organisms/dialog.tsx +304 -0
  87. package/src/components/organisms/drawer.tsx +100 -0
  88. package/src/components/organisms/dropdown-menu.tsx +434 -0
  89. package/src/components/organisms/editors/code-editor.tsx +144 -0
  90. package/src/components/organisms/editors/index.ts +4 -0
  91. package/src/components/organisms/editors/markdown-editor.tsx +153 -0
  92. package/src/components/organisms/editors/markdown-renderer.ts +27 -0
  93. package/src/components/organisms/editors/prose-canvas-classes.ts +45 -0
  94. package/src/components/organisms/editors/rich-text-editor.tsx +126 -0
  95. package/src/components/organisms/editors/toolbar/md-toolbar.tsx +129 -0
  96. package/src/components/organisms/editors/toolbar/rte-toolbar.tsx +211 -0
  97. package/src/components/organisms/editors/toolbar/toolbar-shell.tsx +45 -0
  98. package/src/components/organisms/editors/use-codemirror-theme.ts +61 -0
  99. package/src/components/organisms/error-boundary.tsx +61 -0
  100. package/src/components/organisms/form.tsx +174 -0
  101. package/src/components/organisms/hover-card.tsx +114 -0
  102. package/src/components/organisms/menubar.tsx +491 -0
  103. package/src/components/organisms/navbar.tsx +101 -0
  104. package/src/components/organisms/navigation-menu.tsx +234 -0
  105. package/src/components/organisms/popover.tsx +144 -0
  106. package/src/components/organisms/resizable.tsx +39 -0
  107. package/src/components/organisms/schema-form.tsx +232 -0
  108. package/src/components/organisms/select.tsx +303 -0
  109. package/src/components/organisms/sheet.tsx +256 -0
  110. package/src/components/organisms/sidebar.tsx +1037 -0
  111. package/src/components/organisms/sonner.tsx +96 -0
  112. package/src/components/organisms/tabs.tsx +132 -0
  113. package/src/components/organisms/theme-provider.tsx +101 -0
  114. package/src/hooks/use-mobile.tsx +19 -0
  115. package/src/index.ts +547 -0
  116. package/src/lib/portal-container.tsx +35 -0
  117. package/src/lib/utils.ts +6 -0
  118. package/src/native.ts +23 -0
  119. package/src/tokens/colors.ts +91 -0
  120. package/src/tokens/index.ts +3 -0
  121. package/src/tokens/spacing.ts +55 -0
  122. package/src/tokens/typography.ts +27 -0
  123. package/styles/canvas.css +55 -0
  124. package/styles/dashboard-grid.css +47 -0
  125. package/styles/leaflet.css +13 -0
  126. package/styles/tokens.css +234 -0
  127. package/tailwind.config.ts +70 -0
  128. package/tsconfig.json +23 -0
@@ -0,0 +1,96 @@
1
+ "use client";
2
+
3
+ import { useTheme } from "next-themes";
4
+ import { Toaster as Sonner, toast } from "sonner";
5
+
6
+ type ToasterPropsBase = React.ComponentProps<typeof Sonner>;
7
+
8
+ export interface ToasterProps extends ToasterPropsBase {
9
+ /**
10
+ * Where toasts stack.
11
+ * @default "bottom-right"
12
+ */
13
+ position?:
14
+ | "top-left"
15
+ | "top-center"
16
+ | "top-right"
17
+ | "bottom-left"
18
+ | "bottom-center"
19
+ | "bottom-right";
20
+ /**
21
+ * Toast colour scheme. Defaults to inheriting from `next-themes`.
22
+ * @default "system"
23
+ */
24
+ theme?: "light" | "dark" | "system";
25
+ /**
26
+ * Make toasts rich-coloured by default — success/error/warning tints.
27
+ * @default false
28
+ */
29
+ richColors?: boolean;
30
+ /**
31
+ * Show a close button on every toast.
32
+ * @default false
33
+ */
34
+ closeButton?: boolean;
35
+ /**
36
+ * How long toasts stay visible (ms).
37
+ * @default 4000
38
+ */
39
+ duration?: number;
40
+ /**
41
+ * Visual gap between stacked toasts (px).
42
+ * @default 14
43
+ */
44
+ gap?: number;
45
+ /**
46
+ * Maximum number of toasts visible at once.
47
+ * @default 3
48
+ */
49
+ visibleToasts?: number;
50
+ /**
51
+ * Hide the toaster's offset region — useful when you want toasts to
52
+ * butt against the viewport edge.
53
+ * @default 32
54
+ */
55
+ offset?: string | number;
56
+ /**
57
+ * Pause toast timers when the user hovers any toast.
58
+ * @default true
59
+ */
60
+ pauseWhenPageIsHidden?: boolean;
61
+ /**
62
+ * Reading direction.
63
+ * @default "ltr"
64
+ */
65
+ dir?: "ltr" | "rtl" | "auto";
66
+ /** Tailwind / CSS classes merged onto the toaster region. */
67
+ className?: string;
68
+ /**
69
+ * Default toast options applied to every toast (className,
70
+ * descriptionClassName, etc.). See sonner docs for the full list.
71
+ */
72
+ toastOptions?: ToasterPropsBase["toastOptions"];
73
+ }
74
+
75
+ const Toaster = ({ ...props }: ToasterProps) => {
76
+ const { theme = "system" } = useTheme();
77
+
78
+ return (
79
+ <Sonner
80
+ theme={theme as ToasterProps["theme"]}
81
+ className="toaster group"
82
+ toastOptions={{
83
+ classNames: {
84
+ toast:
85
+ "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
86
+ description: "group-[.toast]:text-muted-foreground",
87
+ actionButton: "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
88
+ cancelButton: "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
89
+ },
90
+ }}
91
+ {...props}
92
+ />
93
+ );
94
+ };
95
+
96
+ export { Toaster, toast };
@@ -0,0 +1,132 @@
1
+ "use client";
2
+
3
+ import * as TabsPrimitive from "@radix-ui/react-tabs";
4
+ import * as React from "react";
5
+
6
+ import { cn } from "../../lib/utils";
7
+
8
+ export interface TabsProps extends React.ComponentProps<typeof TabsPrimitive.Root> {
9
+ /** Controlled active tab value. Pair with `onValueChange`. */
10
+ value?: string;
11
+ /** Initial active tab for uncontrolled usage. */
12
+ defaultValue?: string;
13
+ /** Fires when the user switches tabs. */
14
+ onValueChange?: (value: string) => void;
15
+ /**
16
+ * Tab orientation. Affects keyboard arrow navigation.
17
+ * @default "horizontal"
18
+ */
19
+ orientation?: "horizontal" | "vertical";
20
+ /**
21
+ * Reading direction.
22
+ * @default "ltr"
23
+ */
24
+ dir?: "ltr" | "rtl";
25
+ /**
26
+ * When and how content is activated.
27
+ * - `automatic` activates on focus (best for tabs that load fast)
28
+ * - `manual` requires Enter/Space (best for tabs that fetch data)
29
+ * @default "automatic"
30
+ */
31
+ activationMode?: "automatic" | "manual";
32
+ /** TabsList + TabsContent siblings. */
33
+ children?: React.ReactNode;
34
+ className?: string;
35
+ }
36
+
37
+ const Tabs = TabsPrimitive.Root as React.FC<TabsProps>;
38
+
39
+ export interface TabsListProps extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> {
40
+ /** When true, hold-to-skip-disabled-tabs is on. */
41
+ loop?: boolean;
42
+ /**
43
+ * Render as a Radix Slot.
44
+ * @default false
45
+ */
46
+ asChild?: boolean;
47
+ /** A flat list of `<TabsTrigger>`s. */
48
+ children?: React.ReactNode;
49
+ className?: string;
50
+ }
51
+
52
+ const TabsList = React.forwardRef<React.ElementRef<typeof TabsPrimitive.List>, TabsListProps>(
53
+ ({ className, ...props }, ref) => (
54
+ <TabsPrimitive.List
55
+ ref={ref}
56
+ className={cn(
57
+ "inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
58
+ className,
59
+ )}
60
+ {...props}
61
+ />
62
+ ),
63
+ );
64
+ TabsList.displayName = TabsPrimitive.List.displayName;
65
+
66
+ export interface TabsTriggerProps
67
+ extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger> {
68
+ /** Required — value of the tab this trigger activates. Match with `<TabsContent value>`. */
69
+ value: string;
70
+ /** Disable this tab. */
71
+ disabled?: boolean;
72
+ /**
73
+ * Render as a Radix Slot.
74
+ * @default false
75
+ */
76
+ asChild?: boolean;
77
+ /** Tab label. */
78
+ children?: React.ReactNode;
79
+ className?: string;
80
+ }
81
+
82
+ const TabsTrigger = React.forwardRef<
83
+ React.ElementRef<typeof TabsPrimitive.Trigger>,
84
+ TabsTriggerProps
85
+ >(({ className, ...props }, ref) => (
86
+ <TabsPrimitive.Trigger
87
+ ref={ref}
88
+ className={cn(
89
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
90
+ className,
91
+ )}
92
+ {...props}
93
+ />
94
+ ));
95
+ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
96
+
97
+ export interface TabsContentProps
98
+ extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content> {
99
+ /** Required — matches the `value` of a `<TabsTrigger>`. */
100
+ value: string;
101
+ /**
102
+ * Force the content to mount even when not active. Useful for
103
+ * preserving form state across tab switches.
104
+ * @default false
105
+ */
106
+ forceMount?: true;
107
+ /**
108
+ * Render as a Radix Slot.
109
+ * @default false
110
+ */
111
+ asChild?: boolean;
112
+ /** Tab pane body. */
113
+ children?: React.ReactNode;
114
+ className?: string;
115
+ }
116
+
117
+ const TabsContent = React.forwardRef<
118
+ React.ElementRef<typeof TabsPrimitive.Content>,
119
+ TabsContentProps
120
+ >(({ className, ...props }, ref) => (
121
+ <TabsPrimitive.Content
122
+ ref={ref}
123
+ className={cn(
124
+ "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
125
+ className,
126
+ )}
127
+ {...props}
128
+ />
129
+ ));
130
+ TabsContent.displayName = TabsPrimitive.Content.displayName;
131
+
132
+ export { Tabs, TabsContent, TabsList, TabsTrigger };
@@ -0,0 +1,101 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+
5
+ export type Theme = "light" | "dark" | "system";
6
+ export type ResolvedTheme = "light" | "dark";
7
+
8
+ interface ThemeContextValue {
9
+ theme: Theme;
10
+ resolvedTheme: ResolvedTheme;
11
+ setTheme: (theme: Theme) => void;
12
+ toggleTheme: () => void;
13
+ }
14
+
15
+ const ThemeContext = React.createContext<ThemeContextValue | null>(null);
16
+
17
+ export interface ThemeProviderProps {
18
+ defaultTheme?: Theme;
19
+ /** localStorage key. Default: `"olympus-theme"`. */
20
+ storageKey?: string;
21
+ /** Skip DOM/storage side effects (useful for SSR/tests). */
22
+ disableTransitionOnChange?: boolean;
23
+ children: React.ReactNode;
24
+ }
25
+
26
+ function systemTheme(): ResolvedTheme {
27
+ /* c8 ignore next -- SSR guard: window is always defined in jsdom tests */
28
+ if (typeof window === "undefined") return "light";
29
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
30
+ }
31
+
32
+ function resolve(theme: Theme): ResolvedTheme {
33
+ return theme === "system" ? systemTheme() : theme;
34
+ }
35
+
36
+ export function ThemeProvider({
37
+ defaultTheme = "system",
38
+ storageKey = "olympus-theme",
39
+ children,
40
+ }: ThemeProviderProps) {
41
+ const [theme, setThemeState] = React.useState<Theme>(defaultTheme);
42
+ const [resolvedTheme, setResolvedTheme] = React.useState<ResolvedTheme>(() =>
43
+ resolve(defaultTheme),
44
+ );
45
+
46
+ // On mount: read storage and apply.
47
+ React.useEffect(() => {
48
+ /* c8 ignore next -- SSR guard: window is always defined in jsdom tests */
49
+ if (typeof window === "undefined") return;
50
+ const stored = window.localStorage.getItem(storageKey) as Theme | null;
51
+ const initial = stored ?? defaultTheme;
52
+ setThemeState(initial);
53
+ setResolvedTheme(resolve(initial));
54
+ }, [defaultTheme, storageKey]);
55
+
56
+ // Apply the resolved theme to <html> and persist.
57
+ React.useEffect(() => {
58
+ /* c8 ignore next -- SSR guard: document is always defined in jsdom tests */
59
+ if (typeof document === "undefined") return;
60
+ const root = document.documentElement;
61
+ if (resolvedTheme === "dark") root.classList.add("dark");
62
+ else root.classList.remove("dark");
63
+ /* c8 ignore next -- SSR guard: window is always defined in jsdom tests */
64
+ if (typeof window !== "undefined") {
65
+ window.localStorage.setItem(storageKey, theme);
66
+ }
67
+ }, [theme, resolvedTheme, storageKey]);
68
+
69
+ // Respond to system preference changes when theme === "system".
70
+ React.useEffect(() => {
71
+ if (theme !== "system" || typeof window === "undefined") return;
72
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
73
+ const listener = () => setResolvedTheme(mq.matches ? "dark" : "light");
74
+ mq.addEventListener("change", listener);
75
+ return () => mq.removeEventListener("change", listener);
76
+ }, [theme]);
77
+
78
+ const setTheme = React.useCallback((t: Theme) => {
79
+ setThemeState(t);
80
+ setResolvedTheme(resolve(t));
81
+ }, []);
82
+
83
+ const toggleTheme = React.useCallback(() => {
84
+ setTheme(resolvedTheme === "dark" ? "light" : "dark");
85
+ }, [resolvedTheme, setTheme]);
86
+
87
+ const value = React.useMemo<ThemeContextValue>(
88
+ () => ({ theme, resolvedTheme, setTheme, toggleTheme }),
89
+ [theme, resolvedTheme, setTheme, toggleTheme],
90
+ );
91
+
92
+ return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
93
+ }
94
+
95
+ export function useTheme(): ThemeContextValue {
96
+ const ctx = React.useContext(ThemeContext);
97
+ if (!ctx) throw new Error("useTheme must be used within a <ThemeProvider>");
98
+ return ctx;
99
+ }
100
+
101
+ ThemeProvider.displayName = "ThemeProvider";
@@ -0,0 +1,19 @@
1
+ import * as React from "react";
2
+
3
+ const MOBILE_BREAKPOINT = 768;
4
+
5
+ export function useIsMobile() {
6
+ const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);
7
+
8
+ React.useEffect(() => {
9
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
10
+ const onChange = () => {
11
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
12
+ };
13
+ mql.addEventListener("change", onChange);
14
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
15
+ return () => mql.removeEventListener("change", onChange);
16
+ }, []);
17
+
18
+ return !!isMobile;
19
+ }