@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,67 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as RechartsPrimitive from "recharts";
5
+
6
+ import { cn } from "../../lib/utils";
7
+ import { getPayloadConfigFromPayload, useChart } from "./chart-container";
8
+
9
+ const ChartLegend = RechartsPrimitive.Legend;
10
+
11
+ const ChartLegendContent = React.forwardRef<
12
+ HTMLDivElement,
13
+ React.ComponentProps<"div"> &
14
+ Pick<RechartsPrimitive.LegendProps, "payload" | "verticalAlign"> & {
15
+ hideIcon?: boolean;
16
+ nameKey?: string;
17
+ }
18
+ >(({ className, hideIcon = false, payload, verticalAlign = "bottom", nameKey }, ref) => {
19
+ const { config } = useChart();
20
+
21
+ if (!payload?.length) {
22
+ return null;
23
+ }
24
+
25
+ return (
26
+ <div
27
+ ref={ref}
28
+ className={cn(
29
+ "flex items-center justify-center gap-4",
30
+ verticalAlign === "top" ? "pb-3" : "pt-3",
31
+ className,
32
+ )}
33
+ >
34
+ {payload
35
+ .filter((item) => item.type !== "none")
36
+ .map((item) => {
37
+ /* c8 ignore next -- prefers nameKey when provided; remaining fallbacks are recharts-internal edge cases */
38
+ const key = `${nameKey || item.dataKey || "value"}`;
39
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
40
+
41
+ return (
42
+ <div
43
+ key={item.value}
44
+ className={cn(
45
+ "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground",
46
+ )}
47
+ >
48
+ {itemConfig?.icon && !hideIcon ? (
49
+ <itemConfig.icon />
50
+ ) : (
51
+ <div
52
+ className="h-2 w-2 shrink-0 rounded-[2px]"
53
+ style={{
54
+ backgroundColor: item.color,
55
+ }}
56
+ />
57
+ )}
58
+ {itemConfig?.label}
59
+ </div>
60
+ );
61
+ })}
62
+ </div>
63
+ );
64
+ });
65
+ ChartLegendContent.displayName = "ChartLegend";
66
+
67
+ export { ChartLegend, ChartLegendContent };
@@ -0,0 +1,161 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as RechartsPrimitive from "recharts";
5
+
6
+ import { cn } from "../../lib/utils";
7
+ import { getPayloadConfigFromPayload, useChart } from "./chart-container";
8
+
9
+ const ChartTooltip = RechartsPrimitive.Tooltip;
10
+
11
+ const ChartTooltipContent = React.forwardRef<
12
+ HTMLDivElement,
13
+ React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
14
+ React.ComponentProps<"div"> & {
15
+ hideLabel?: boolean;
16
+ hideIndicator?: boolean;
17
+ indicator?: "line" | "dot" | "dashed";
18
+ nameKey?: string;
19
+ labelKey?: string;
20
+ }
21
+ >(
22
+ (
23
+ {
24
+ active,
25
+ payload,
26
+ className,
27
+ indicator = "dot",
28
+ hideLabel = false,
29
+ hideIndicator = false,
30
+ label,
31
+ labelFormatter,
32
+ labelClassName,
33
+ formatter,
34
+ color,
35
+ nameKey,
36
+ labelKey,
37
+ },
38
+ ref,
39
+ ) => {
40
+ const { config } = useChart();
41
+
42
+ const tooltipLabel = React.useMemo(() => {
43
+ if (hideLabel || !payload?.length) {
44
+ return null;
45
+ }
46
+
47
+ const [item] = payload;
48
+ /* c8 ignore next -- the || chain prefers labelKey when set; the remaining fallbacks are recharts-internal edge cases */
49
+ const key = `${labelKey || item?.dataKey || item?.name || "value"}`;
50
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
51
+ const value =
52
+ !labelKey && typeof label === "string"
53
+ ? config[label as keyof typeof config]?.label || label
54
+ : itemConfig?.label;
55
+
56
+ if (labelFormatter) {
57
+ return (
58
+ <div className={cn("font-medium", labelClassName)}>{labelFormatter(value, payload)}</div>
59
+ );
60
+ }
61
+
62
+ /* c8 ignore next 3 -- defensive fallback: value is always truthy when this branch is reached in practice */
63
+ if (!value) {
64
+ return null;
65
+ }
66
+
67
+ return <div className={cn("font-medium", labelClassName)}>{value}</div>;
68
+ }, [label, labelFormatter, payload, hideLabel, labelClassName, config, labelKey]);
69
+
70
+ if (!active || !payload?.length) {
71
+ return null;
72
+ }
73
+
74
+ const nestLabel = payload.length === 1 && indicator !== "dot";
75
+
76
+ return (
77
+ <div
78
+ ref={ref}
79
+ className={cn(
80
+ "grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl",
81
+ className,
82
+ )}
83
+ >
84
+ {!nestLabel ? tooltipLabel : null}
85
+ <div className="grid gap-1.5">
86
+ {payload
87
+ .filter((item) => item.type !== "none")
88
+ .map((item, index) => {
89
+ /* c8 ignore next -- prefers nameKey when provided; remaining fallbacks are recharts-internal edge cases */
90
+ const key = `${nameKey || item.name || item.dataKey || "value"}`;
91
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
92
+ /* c8 ignore next -- defers to explicit color prop; remaining fallbacks cover recharts-internal edge cases */
93
+ const indicatorColor = color || item.payload.fill || item.color;
94
+
95
+ return (
96
+ <div
97
+ key={item.dataKey}
98
+ className={cn(
99
+ "flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
100
+ indicator === "dot" && "items-center",
101
+ )}
102
+ >
103
+ {formatter && item?.value !== undefined && item.name ? (
104
+ formatter(item.value, item.name, item, index, item.payload)
105
+ ) : (
106
+ <>
107
+ {itemConfig?.icon ? (
108
+ <itemConfig.icon />
109
+ ) : (
110
+ !hideIndicator && (
111
+ <div
112
+ className={cn(
113
+ "shrink-0 rounded-[2px] border-[var(--color-border)] bg-[var(--color-bg)]",
114
+ {
115
+ "h-2.5 w-2.5": indicator === "dot",
116
+ "w-1": indicator === "line",
117
+ "w-0 border-[1.5px] border-dashed bg-transparent":
118
+ indicator === "dashed",
119
+ "my-0.5": nestLabel && indicator === "dashed",
120
+ },
121
+ )}
122
+ style={
123
+ {
124
+ "--color-bg": indicatorColor,
125
+ "--color-border": indicatorColor,
126
+ } as React.CSSProperties
127
+ }
128
+ />
129
+ )
130
+ )}
131
+ <div
132
+ className={cn(
133
+ "flex flex-1 justify-between leading-none",
134
+ nestLabel ? "items-end" : "items-center",
135
+ )}
136
+ >
137
+ <div className="grid gap-1.5">
138
+ {nestLabel ? tooltipLabel : null}
139
+ <span className="text-muted-foreground">
140
+ {itemConfig?.label || item.name}
141
+ </span>
142
+ </div>
143
+ {item.value && (
144
+ <span className="font-mono font-medium tabular-nums text-foreground">
145
+ {item.value.toLocaleString()}
146
+ </span>
147
+ )}
148
+ </div>
149
+ </>
150
+ )}
151
+ </div>
152
+ );
153
+ })}
154
+ </div>
155
+ </div>
156
+ );
157
+ },
158
+ );
159
+ ChartTooltipContent.displayName = "ChartTooltip";
160
+
161
+ export { ChartTooltip, ChartTooltipContent };
@@ -0,0 +1,49 @@
1
+ "use client";
2
+
3
+ import type * as React from "react";
4
+ import * as RechartsPrimitive from "recharts";
5
+
6
+ /**
7
+ * Chart-type wrappers. Each wraps a Recharts top-level chart component with
8
+ * sensible default `margin` so axis labels don't clip. Children pass through
9
+ * UNWRAPPED — Recharts uses `findAllByType` on its direct children to detect
10
+ * `<Line>` / `<XAxis>` / `<CartesianGrid>` etc., so any extra wrapper element
11
+ * (Context.Provider, fragment-only-on-render, etc.) breaks chart rendering.
12
+ *
13
+ * The auto-palette context is established by `<ChartContainer>` instead, so
14
+ * data primitives still cycle through `--chart-N` colours when no fill /
15
+ * stroke is supplied.
16
+ *
17
+ * Margin defaults are merged with any user-supplied margin (user wins on
18
+ * conflict). Everything else is straight pass-through.
19
+ */
20
+
21
+ const DEFAULT_MARGIN = { top: 12, right: 12, bottom: 4, left: 0 } as const;
22
+
23
+ function withDefaults<P extends { children?: React.ReactNode; margin?: object }>(
24
+ Comp: React.ComponentType<P>,
25
+ ): React.FC<P> {
26
+ const Wrapped = ({ children, margin, ...rest }: P) => {
27
+ const merged = { ...DEFAULT_MARGIN, ...(margin ?? {}) };
28
+ const props = { ...rest, margin: merged } as any;
29
+ return <Comp {...props}>{children}</Comp>;
30
+ };
31
+ /* c8 ignore next -- defensive: every recharts top-level chart component ships with a `displayName`; the `?? Comp.name ?? "Anonymous"` fallback chain only fires for hand-rolled non-recharts wrappers */
32
+ Wrapped.displayName = `Chart(${(Comp as { displayName?: string }).displayName ?? Comp.name ?? "Anonymous"})`;
33
+ return Wrapped;
34
+ }
35
+
36
+ export const LineChart = withDefaults(RechartsPrimitive.LineChart);
37
+ export const BarChart = withDefaults(RechartsPrimitive.BarChart);
38
+ export const AreaChart = withDefaults(RechartsPrimitive.AreaChart);
39
+ export const ComposedChart = withDefaults(RechartsPrimitive.ComposedChart);
40
+ export const PieChart = withDefaults(RechartsPrimitive.PieChart);
41
+ export const ScatterChart = withDefaults(RechartsPrimitive.ScatterChart);
42
+ export const RadarChart = withDefaults(RechartsPrimitive.RadarChart);
43
+ export const RadialBarChart = withDefaults(RechartsPrimitive.RadialBarChart);
44
+ export const FunnelChart = withDefaults(RechartsPrimitive.FunnelChart);
45
+ export const SunburstChart = withDefaults(RechartsPrimitive.SunburstChart);
46
+
47
+ // Treemap and Sankey have a different children shape — pure pass-throughs.
48
+ export const Treemap = RechartsPrimitive.Treemap;
49
+ export const Sankey = RechartsPrimitive.Sankey;
@@ -0,0 +1,11 @@
1
+ "use client";
2
+
3
+ /**
4
+ * Container-level Recharts primitives. Pure pass-throughs.
5
+ * `ResponsiveContainer` is also re-rendered internally by `<ChartContainer>`,
6
+ * but consumers might want to use it directly for non-canvas-themed charts.
7
+ *
8
+ * NOTE: re-exported via `export { … }` (not `export const = …`) so TypeScript
9
+ * doesn't have to name internal Recharts prop types in the d.ts emit.
10
+ */
11
+ export { Brush, Layer, ResponsiveContainer, Surface } from "recharts";
@@ -0,0 +1,16 @@
1
+ "use client";
2
+
3
+ /**
4
+ * Data-primitive re-exports. These are direct pass-throughs of the Recharts
5
+ * primitives — wrapping them in our own function components breaks Recharts'
6
+ * `findAllByType` introspection (it looks for `child.type === Bar` etc., and
7
+ * a wrapper's `type` is our function, not Bar). The earlier wrapped version
8
+ * crashed Recharts with "Cannot read properties of undefined (reading
9
+ * 'yAxisId')" because the chart-type couldn't find our axes / data.
10
+ *
11
+ * Auto-palette cycling happens inside `<ChartContainer>` via a deep
12
+ * `React.cloneElement` walk that injects `fill`/`stroke` defaults when the
13
+ * consumer didn't supply one. The wrapped types remain the real Recharts
14
+ * classes, so axis detection / chart-type child resolution keep working.
15
+ */
16
+ export { Area, Bar, Funnel, Line, Pie, Radar, RadialBar, Scatter } from "recharts";
@@ -0,0 +1,25 @@
1
+ "use client";
2
+
3
+ /**
4
+ * Detail-level Recharts primitives. Pure pass-throughs — no theming
5
+ * opportunity, but re-exported here so consumers can import the entire
6
+ * Recharts surface from canvas.
7
+ *
8
+ * `Cell` and `Customized` are aliased to `ChartCell` / `ChartCustomized` to
9
+ * avoid likely future collisions with canvas-domain primitives.
10
+ *
11
+ * Re-exported via `export { … }` (not `export const = …`) so TypeScript
12
+ * doesn't have to name internal Recharts prop types in the d.ts emit.
13
+ */
14
+ export {
15
+ Cell as ChartCell,
16
+ Cross,
17
+ Curve,
18
+ Customized as ChartCustomized,
19
+ Dot,
20
+ ErrorBar,
21
+ Polygon,
22
+ Rectangle,
23
+ Sector,
24
+ Trapezoid,
25
+ } from "recharts";
@@ -0,0 +1,106 @@
1
+ import * as React from "react";
2
+
3
+ import { cn } from "../../lib/utils";
4
+
5
+ export interface GaugeProps extends React.HTMLAttributes<HTMLDivElement> {
6
+ /** Percentage to fill (0–100). Values outside the range are clamped. */
7
+ value: number;
8
+ /** Pixel size (width = height). Default `160`. */
9
+ size?: number;
10
+ /** Pixel stroke width of the ring. Default `14`. */
11
+ strokeWidth?: number;
12
+ /**
13
+ * CSS variable name (without leading `--`) used for the filled arc. Default
14
+ * `chart-1`.
15
+ */
16
+ colorVar?: string;
17
+ /**
18
+ * Center value text. Defaults to `"{value}%"`. Pass a custom node to render
19
+ * something richer (e.g. a unit label).
20
+ */
21
+ valueLabel?: React.ReactNode;
22
+ /** Small label rendered below the centre value. Optional. */
23
+ caption?: React.ReactNode;
24
+ /** Accessible label describing the gauge. Default `"Gauge"`. */
25
+ "aria-label"?: string;
26
+ }
27
+
28
+ /**
29
+ * Single-arc circular gauge with a centered value. Useful for adoption
30
+ * percentages, health scores, completion ratios, and similar 0–100 metrics.
31
+ * Renders a complete background ring plus a filled arc; the arc is animated
32
+ * via `transition-[stroke-dashoffset]` so consumers get smooth updates when
33
+ * `value` changes.
34
+ */
35
+ export const Gauge = React.forwardRef<HTMLDivElement, GaugeProps>(
36
+ (
37
+ {
38
+ value,
39
+ size = 160,
40
+ strokeWidth = 14,
41
+ colorVar = "chart-1",
42
+ valueLabel,
43
+ caption,
44
+ className,
45
+ "aria-label": ariaLabel = "Gauge",
46
+ ...props
47
+ },
48
+ ref,
49
+ ) => {
50
+ const clamped = Math.max(0, Math.min(100, value));
51
+ const r = (size - strokeWidth) / 2;
52
+ const cx = size / 2;
53
+ const c = 2 * Math.PI * r;
54
+ const offset = c - (clamped / 100) * c;
55
+ const display = valueLabel ?? `${Math.round(clamped)}%`;
56
+ return (
57
+ <div
58
+ ref={ref}
59
+ role="meter"
60
+ aria-label={ariaLabel}
61
+ aria-valuenow={Math.round(clamped)}
62
+ aria-valuemin={0}
63
+ aria-valuemax={100}
64
+ className={cn("relative inline-flex flex-col items-center", className)}
65
+ style={{ width: size, height: caption ? "auto" : size }}
66
+ {...props}
67
+ >
68
+ <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} aria-hidden>
69
+ <circle
70
+ cx={cx}
71
+ cy={cx}
72
+ r={r}
73
+ fill="none"
74
+ stroke="hsl(var(--muted))"
75
+ strokeWidth={strokeWidth}
76
+ />
77
+ <circle
78
+ cx={cx}
79
+ cy={cx}
80
+ r={r}
81
+ fill="none"
82
+ stroke={`hsl(var(--${colorVar}))`}
83
+ strokeWidth={strokeWidth}
84
+ strokeDasharray={c}
85
+ strokeDashoffset={offset}
86
+ strokeLinecap="round"
87
+ transform={`rotate(-90 ${cx} ${cx})`}
88
+ className="transition-[stroke-dashoffset] duration-500"
89
+ />
90
+ </svg>
91
+ <div
92
+ className="pointer-events-none absolute inset-x-0 flex flex-col items-center justify-center"
93
+ style={{ top: 0, height: size }}
94
+ >
95
+ <span className="font-mono text-3xl font-bold tabular-nums">{display}</span>
96
+ {caption && (
97
+ <span className="mt-1 text-[11px] uppercase tracking-[0.04em] text-muted-foreground">
98
+ {caption}
99
+ </span>
100
+ )}
101
+ </div>
102
+ </div>
103
+ );
104
+ },
105
+ );
106
+ Gauge.displayName = "Gauge";
@@ -0,0 +1,8 @@
1
+ "use client";
2
+
3
+ /**
4
+ * Grid re-exports — pure pass-throughs. Theming via CSS in `<ChartContainer>`
5
+ * (`[&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50` etc.).
6
+ * Wrapping breaks Recharts' child-by-type detection.
7
+ */
8
+ export { CartesianGrid, PolarGrid } from "recharts";
@@ -0,0 +1,62 @@
1
+ // Container + style emitter (canvas-specific)
2
+
3
+ // Chrome — canvas-token defaults
4
+ export {
5
+ CartesianAxis,
6
+ PolarAngleAxis,
7
+ PolarRadiusAxis,
8
+ XAxis,
9
+ YAxis,
10
+ ZAxis,
11
+ } from "./axes";
12
+ export {
13
+ type ChartConfig,
14
+ ChartContainer,
15
+ ChartStyle,
16
+ useChart,
17
+ } from "./chart-container";
18
+ export { ChartLegend, ChartLegendContent } from "./chart-legend";
19
+ export { ChartTooltip, ChartTooltipContent } from "./chart-tooltip";
20
+ // Chart-type wrappers (`margin` defaults; auto-palette runs in ChartContainer)
21
+ export {
22
+ AreaChart,
23
+ BarChart,
24
+ ComposedChart,
25
+ FunnelChart,
26
+ LineChart,
27
+ PieChart,
28
+ RadarChart,
29
+ RadialBarChart,
30
+ Sankey,
31
+ ScatterChart,
32
+ SunburstChart,
33
+ Treemap,
34
+ } from "./chart-types";
35
+ // Container-level — pure pass-through
36
+ export { Brush, Layer, ResponsiveContainer, Surface } from "./containers";
37
+ // Data primitives (auto-cycle palette)
38
+ export { Area, Bar, Funnel, Line, Pie, Radar, RadialBar, Scatter } from "./data";
39
+ // Detail primitives — pure pass-through
40
+ export {
41
+ ChartCell,
42
+ ChartCustomized,
43
+ Cross,
44
+ Curve,
45
+ Dot,
46
+ ErrorBar,
47
+ Polygon,
48
+ Rectangle,
49
+ Sector,
50
+ Trapezoid,
51
+ } from "./details";
52
+ export { CartesianGrid, PolarGrid } from "./grids";
53
+ export { ReferenceArea, ReferenceDot, ReferenceLine } from "./references";
54
+ // Text + labels (Label aliased to avoid collision with canvas form Label)
55
+ export { ChartLabel, LabelList, Text } from "./text";
56
+
57
+ // Geographic — Leaflet-based heat-map (peer-optional `leaflet` + `react-leaflet`)
58
+ export {
59
+ WorldHeatMap,
60
+ type WorldHeatMapPoint,
61
+ type WorldHeatMapProps,
62
+ } from "./world-heat-map";
@@ -0,0 +1,85 @@
1
+ import * as React from "react";
2
+
3
+ import { cn } from "../../lib/utils";
4
+
5
+ export interface LabeledBarListItem {
6
+ /** Row label. Used as the React key. */
7
+ label: React.ReactNode;
8
+ /** Numeric value rendered in the right cap; bar fill scales against the max. */
9
+ value: number;
10
+ /** Optional leading element — e.g. a flag, avatar, or `<Icon />`. */
11
+ leading?: React.ReactNode;
12
+ }
13
+
14
+ export interface LabeledBarListProps extends React.HTMLAttributes<HTMLDivElement> {
15
+ /** Rows rendered top-to-bottom. */
16
+ items: LabeledBarListItem[];
17
+ /**
18
+ * CSS variable name (without leading `--`) used for the bar fill. Default
19
+ * `chart-1`.
20
+ */
21
+ colorVar?: string;
22
+ /** Format the value rendered to the right of each label. Default `toLocaleString`. */
23
+ valueFormatter?: (value: number) => string;
24
+ /** Pixel height of the row's bar track. Default `4`. */
25
+ barHeight?: number;
26
+ /** Caption rendered below the list. */
27
+ caption?: React.ReactNode;
28
+ }
29
+
30
+ /**
31
+ * Vertical list of labeled rows with a horizontal progress bar per row. Useful
32
+ * for "top regions", "schema usage", "provider connections" — anywhere a small
33
+ * set of named values needs proportional comparison without a full chart.
34
+ */
35
+ export const LabeledBarList = React.forwardRef<HTMLDivElement, LabeledBarListProps>(
36
+ (
37
+ {
38
+ items,
39
+ colorVar = "chart-1",
40
+ valueFormatter = (v) => v.toLocaleString(),
41
+ barHeight = 4,
42
+ caption,
43
+ className,
44
+ ...props
45
+ },
46
+ ref,
47
+ ) => {
48
+ const max = Math.max(1, ...items.map((it) => it.value));
49
+ return (
50
+ <div ref={ref} className={cn("w-full", className)} {...props}>
51
+ <ul className="flex flex-col gap-2.5">
52
+ {items.map((item, i) => {
53
+ const pct = Math.max(0, Math.min(100, (item.value / max) * 100));
54
+ return (
55
+ <li key={`${i}-${item.value}`} className="flex flex-col gap-1.5">
56
+ <div className="flex items-center gap-2 text-[13px]">
57
+ {item.leading && <span className="shrink-0">{item.leading}</span>}
58
+ <span className="flex-1 truncate">{item.label}</span>
59
+ <span className="font-mono text-xs text-muted-foreground tabular-nums">
60
+ {valueFormatter(item.value)}
61
+ </span>
62
+ </div>
63
+ <div
64
+ className="overflow-hidden rounded-full bg-muted"
65
+ style={{ height: barHeight }}
66
+ aria-hidden
67
+ >
68
+ <div
69
+ className="h-full rounded-full"
70
+ style={{
71
+ width: `${pct}%`,
72
+ background: `hsl(var(--${colorVar}))`,
73
+ }}
74
+ />
75
+ </div>
76
+ </li>
77
+ );
78
+ })}
79
+ </ul>
80
+ {caption && <p className="mt-3 text-xs text-muted-foreground">{caption}</p>}
81
+ </div>
82
+ );
83
+ },
84
+ );
85
+ LabeledBarList.displayName = "LabeledBarList";
@@ -0,0 +1,8 @@
1
+ "use client";
2
+
3
+ /**
4
+ * Reference primitives — pure pass-throughs. Theming via CSS in
5
+ * `<ChartContainer>` (`[&_.recharts-reference-line_[stroke='#ccc']]:stroke-border`).
6
+ * Wrapping breaks Recharts' child-by-type detection.
7
+ */
8
+ export { ReferenceArea, ReferenceDot, ReferenceLine } from "recharts";
@@ -0,0 +1,73 @@
1
+ import * as React from "react";
2
+
3
+ import { cn } from "../../lib/utils";
4
+
5
+ export type ServiceHealthStatus = "healthy" | "degraded" | "down";
6
+
7
+ export interface ServiceHealthItem {
8
+ /** Service name shown in the row. Used as the React key. */
9
+ name: string;
10
+ /** Status — drives the dot color. */
11
+ status: ServiceHealthStatus;
12
+ /**
13
+ * Right-aligned meta cells, monospace, muted-foreground. Pass an array of
14
+ * primitives or React nodes — each renders as its own cell.
15
+ */
16
+ meta?: React.ReactNode[];
17
+ }
18
+
19
+ export interface ServiceHealthListProps extends React.HTMLAttributes<HTMLDivElement> {
20
+ /** Service rows rendered top-to-bottom. */
21
+ items: ServiceHealthItem[];
22
+ /** Caption rendered below the list. */
23
+ caption?: React.ReactNode;
24
+ }
25
+
26
+ const DOT_TOKENS: Record<ServiceHealthStatus, string> = {
27
+ healthy: "143 70% 45%",
28
+ degraded: "38 92% 50%",
29
+ down: "0 80% 60%",
30
+ };
31
+
32
+ /**
33
+ * Vertical list of services with a colored status dot, name, and optional
34
+ * monospace meta cells (latency, uptime, region, …). The dot has a 3-px halo
35
+ * matching the status hue at 18% opacity to pull focus.
36
+ */
37
+ export const ServiceHealthList = React.forwardRef<HTMLDivElement, ServiceHealthListProps>(
38
+ ({ items, caption, className, ...props }, ref) => {
39
+ return (
40
+ <div ref={ref} className={cn("w-full", className)} {...props}>
41
+ <ul className="flex flex-col gap-2.5">
42
+ {items.map((item) => {
43
+ const hsl = DOT_TOKENS[item.status];
44
+ return (
45
+ <li key={item.name} className="flex items-center gap-2.5 text-[13px]">
46
+ <span
47
+ role="img"
48
+ className="size-2 shrink-0 rounded-full"
49
+ style={{
50
+ background: `hsl(${hsl})`,
51
+ boxShadow: `0 0 0 3px hsl(${hsl} / 0.18)`,
52
+ }}
53
+ aria-label={`Status: ${item.status}`}
54
+ />
55
+ <span className="flex-1 font-medium">{item.name}</span>
56
+ {item.meta?.map((cell, i) => (
57
+ <span
58
+ key={`${item.name}-meta-${i}`}
59
+ className="font-mono text-[11.5px] text-muted-foreground"
60
+ >
61
+ {cell}
62
+ </span>
63
+ ))}
64
+ </li>
65
+ );
66
+ })}
67
+ </ul>
68
+ {caption && <p className="mt-3 text-xs text-muted-foreground">{caption}</p>}
69
+ </div>
70
+ );
71
+ },
72
+ );
73
+ ServiceHealthList.displayName = "ServiceHealthList";