@alpic-ai/ui 1.144.0 → 1.145.1

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 (44) hide show
  1. package/dist/components/accordion-card.d.mts +1 -1
  2. package/dist/components/accordion.d.mts +1 -1
  3. package/dist/components/alert.d.mts +1 -1
  4. package/dist/components/area-chart.mjs +5 -7
  5. package/dist/components/attachment-tile.mjs +1 -1
  6. package/dist/components/avatar.d.mts +1 -1
  7. package/dist/components/bar-chart.mjs +6 -12
  8. package/dist/components/bar-list.mjs +1 -1
  9. package/dist/components/button.d.mts +1 -1
  10. package/dist/components/chart-container.mjs +2 -2
  11. package/dist/components/chart-tooltip.mjs +52 -27
  12. package/dist/components/combobox.d.mts +1 -1
  13. package/dist/components/combobox.mjs +1 -1
  14. package/dist/components/copyable.mjs +1 -1
  15. package/dist/components/dialog.d.mts +1 -1
  16. package/dist/components/donut-chart.mjs +1 -1
  17. package/dist/components/dropdown-menu.d.mts +1 -1
  18. package/dist/components/form.mjs +1 -1
  19. package/dist/components/heatmap-chart.d.mts +6 -0
  20. package/dist/components/heatmap-chart.mjs +147 -117
  21. package/dist/components/input-group.d.mts +1 -1
  22. package/dist/components/input.mjs +1 -1
  23. package/dist/components/line-chart.mjs +5 -7
  24. package/dist/components/select.d.mts +1 -1
  25. package/dist/components/sidebar.d.mts +1 -1
  26. package/dist/components/sidebar.mjs +3 -3
  27. package/dist/components/skeleton.mjs +1 -1
  28. package/dist/components/stat.mjs +5 -5
  29. package/dist/components/tabs.d.mts +1 -1
  30. package/dist/components/tabs.mjs +1 -1
  31. package/dist/components/textarea.mjs +1 -1
  32. package/dist/components/toggle-group.d.mts +1 -1
  33. package/dist/components/toggle-group.mjs +1 -1
  34. package/dist/components/tooltip-icon-button.mjs +1 -1
  35. package/dist/lib/chart-palette.mjs +4 -1
  36. package/package.json +2 -2
  37. package/src/components/area-chart.tsx +11 -6
  38. package/src/components/bar-chart.tsx +12 -7
  39. package/src/components/chart-tooltip.tsx +17 -1
  40. package/src/components/heatmap-chart.tsx +49 -5
  41. package/src/components/line-chart.tsx +11 -6
  42. package/src/components/skeleton.tsx +1 -1
  43. package/src/components/stat.tsx +4 -4
  44. package/src/lib/chart-palette.ts +4 -1
@@ -2,8 +2,8 @@
2
2
  import { cn } from "../lib/cn.mjs";
3
3
  import { HEAT_EMPTY, heatColor, heatRamp } from "../lib/chart-palette.mjs";
4
4
  import { useChartContext } from "./chart-container.mjs";
5
- import { jsx, jsxs } from "react/jsx-runtime";
6
5
  import * as React$1 from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { createPortal } from "react-dom";
8
8
  //#region src/components/heatmap-chart.tsx
9
9
  const PLACEHOLDER_HEIGHT = 168;
@@ -31,7 +31,7 @@ const uniqueInOrder = (values) => {
31
31
  }
32
32
  return ordered;
33
33
  };
34
- function HeatmapChart({ data, xKey, yKey, dataKey = "value", variant = "square", palette, xLabels, yLabels, showAllXLabels = false, highlightPeak = true, loading = false, valueFormatter = (value) => value.toLocaleString("en-US"), xTickFormatter, yTickFormatter, tooltipMetrics, ariaLabel = "Activity heatmap", className }) {
34
+ function HeatmapChart({ data, xKey, yKey, dataKey = "value", variant = "square", palette, xLabels, yLabels, showAllXLabels = false, highlightPeak = true, loading = false, valueFormatter = (value) => value.toLocaleString("en-US"), xTickFormatter, yTickFormatter, tooltipMetrics, tooltipTitleKey, colorScale = "linear", showLegend = false, ariaLabel = "Activity heatmap", className }) {
35
35
  const { paletteName, theme } = useChartContext(palette);
36
36
  const [hovered, setHovered] = React$1.useState(null);
37
37
  const [mounted, setMounted] = React$1.useState(false);
@@ -81,6 +81,19 @@ function HeatmapChart({ data, xKey, yKey, dataKey = "value", variant = "square",
81
81
  yLabels
82
82
  ]);
83
83
  const isEmpty = columns.length === 0 || rows.length === 0 || maxValue <= 0;
84
+ const colorFractionOf = React$1.useMemo(() => {
85
+ if (colorScale === "rank") {
86
+ const sorted = [...new Set(cells.map((cell) => cell.value).filter((value) => value > 0))].sort((lower, upper) => lower - upper);
87
+ const RANK_FLOOR = .18;
88
+ const fractionByValue = new Map(sorted.map((value, index) => [value, sorted.length > 1 ? RANK_FLOOR + (1 - RANK_FLOOR) * (index / (sorted.length - 1)) : 1]));
89
+ return (value) => value > 0 ? fractionByValue.get(value) ?? 0 : 0;
90
+ }
91
+ return (value) => maxValue > 0 ? value / maxValue : 0;
92
+ }, [
93
+ cells,
94
+ colorScale,
95
+ maxValue
96
+ ]);
84
97
  if (loading) return /* @__PURE__ */ jsxs("div", {
85
98
  className: cn("flex items-center justify-center gap-2.5 font-mono text-quaternary-foreground text-text-xs", className),
86
99
  style: { minHeight: PLACEHOLDER_HEIGHT },
@@ -91,7 +104,7 @@ function HeatmapChart({ data, xKey, yKey, dataKey = "value", variant = "square",
91
104
  style: { minHeight: PLACEHOLDER_HEIGHT },
92
105
  children: "no data in range"
93
106
  });
94
- const ramp = heatRamp(paletteName, theme.isDark ? HEAT_EMPTY.dark : HEAT_EMPTY.light);
107
+ const ramp = heatRamp(paletteName, theme.isDark ? HEAT_EMPTY.dark : HEAT_EMPTY.light, theme.isDark);
95
108
  const totalWidth = PAD.left + columns.length * CELL + (columns.length - 1) * GAP + PAD.right;
96
109
  const totalHeight = PAD.top + rows.length * CELL + (rows.length - 1) * GAP + PAD.bottom;
97
110
  const xStride = showAllXLabels ? 1 : Math.ceil(columns.length / MAX_X_TICKS);
@@ -104,125 +117,142 @@ function HeatmapChart({ data, xKey, yKey, dataKey = "value", variant = "square",
104
117
  return /* @__PURE__ */ jsxs("div", {
105
118
  "data-slot": "heatmap-chart",
106
119
  className: cn("w-full", className),
107
- children: [/* @__PURE__ */ jsx("div", {
108
- className: "overflow-x-auto",
109
- children: /* @__PURE__ */ jsxs("svg", {
110
- viewBox: `0 0 ${totalWidth} ${totalHeight}`,
111
- className: "block min-w-[480px]",
112
- style: {
113
- width: "100%",
114
- height: "auto"
115
- },
116
- role: "img",
117
- "aria-label": ariaLabel,
118
- onMouseLeave: () => setHovered(null),
119
- children: [
120
- columns.map((label, col) => col % xStride === 0 ? /* @__PURE__ */ jsx("text", {
121
- x: cellX(col) + CELL / 2,
122
- y: PAD.top - 7,
123
- textAnchor: "middle",
124
- className: "fill-quaternary-foreground font-mono text-[8.5px]",
125
- children: formatX(label)
126
- }, `x-${label}`) : null),
127
- rows.map((label, row) => /* @__PURE__ */ jsx("text", {
128
- x: PAD.left - 8,
129
- y: cellY(row) + CELL / 2 + 3,
130
- textAnchor: "end",
131
- className: "fill-quaternary-foreground font-mono text-[8.5px]",
132
- children: formatY(label)
133
- }, `y-${label}`)),
134
- cells.map((cell) => {
135
- const fraction = cell.value / maxValue;
136
- const fill = heatColor(ramp, fraction);
137
- const key = pairKey(cell.rowLabel, cell.colLabel);
138
- const isPeak = highlightPeak && key === peakKey;
139
- if (variant === "dot") return /* @__PURE__ */ jsx("circle", {
140
- cx: cellX(cell.colIndex) + CELL / 2,
141
- cy: cellY(cell.rowIndex) + CELL / 2,
142
- r: CELL / 2 * (DOT_MIN + DOT_RANGE * fraction),
143
- fill,
144
- stroke: isPeak ? theme.foreground : void 0,
145
- strokeWidth: isPeak ? 1.4 : void 0
146
- }, key);
147
- return /* @__PURE__ */ jsx("rect", {
120
+ children: [
121
+ /* @__PURE__ */ jsx("div", {
122
+ className: "overflow-x-auto",
123
+ children: /* @__PURE__ */ jsxs("svg", {
124
+ viewBox: `0 0 ${totalWidth} ${totalHeight}`,
125
+ className: "block min-w-[480px]",
126
+ style: {
127
+ width: "100%",
128
+ height: "auto"
129
+ },
130
+ role: "img",
131
+ "aria-label": ariaLabel,
132
+ onMouseLeave: () => setHovered(null),
133
+ children: [
134
+ columns.map((label, col) => col % xStride === 0 ? /* @__PURE__ */ jsx("text", {
135
+ x: cellX(col) + CELL / 2,
136
+ y: PAD.top - 7,
137
+ textAnchor: "middle",
138
+ className: "fill-quaternary-foreground font-mono text-[8.5px]",
139
+ children: formatX(label)
140
+ }, `x-${label}`) : null),
141
+ rows.map((label, row) => /* @__PURE__ */ jsx("text", {
142
+ x: PAD.left - 8,
143
+ y: cellY(row) + CELL / 2 + 3,
144
+ textAnchor: "end",
145
+ className: "fill-quaternary-foreground font-mono text-[8.5px]",
146
+ children: formatY(label)
147
+ }, `y-${label}`)),
148
+ cells.map((cell) => {
149
+ const fraction = colorFractionOf(cell.value);
150
+ const fill = heatColor(ramp, fraction);
151
+ const key = pairKey(cell.rowLabel, cell.colLabel);
152
+ const isPeak = highlightPeak && key === peakKey;
153
+ if (variant === "dot") return /* @__PURE__ */ jsx("circle", {
154
+ cx: cellX(cell.colIndex) + CELL / 2,
155
+ cy: cellY(cell.rowIndex) + CELL / 2,
156
+ r: CELL / 2 * (DOT_MIN + DOT_RANGE * fraction),
157
+ fill,
158
+ stroke: isPeak ? theme.foreground : void 0,
159
+ strokeWidth: isPeak ? 1.4 : void 0
160
+ }, key);
161
+ return /* @__PURE__ */ jsx("rect", {
162
+ x: cellX(cell.colIndex),
163
+ y: cellY(cell.rowIndex),
164
+ width: CELL,
165
+ height: CELL,
166
+ rx: 2.5,
167
+ fill,
168
+ stroke: isPeak ? theme.foreground : void 0,
169
+ strokeWidth: isPeak ? 1.4 : void 0
170
+ }, key);
171
+ }),
172
+ cells.map((cell) => /* @__PURE__ */ jsx("rect", {
148
173
  x: cellX(cell.colIndex),
149
174
  y: cellY(cell.rowIndex),
150
- width: CELL,
151
- height: CELL,
152
- rx: 2.5,
153
- fill,
154
- stroke: isPeak ? theme.foreground : void 0,
155
- strokeWidth: isPeak ? 1.4 : void 0
156
- }, key);
157
- }),
158
- cells.map((cell) => /* @__PURE__ */ jsx("rect", {
159
- x: cellX(cell.colIndex),
160
- y: cellY(cell.rowIndex),
161
- width: 25,
162
- height: 25,
163
- fill: "transparent",
164
- onMouseMove: (event) => setHovered({
165
- x: event.clientX,
166
- y: event.clientY,
167
- rowLabel: cell.rowLabel,
168
- colLabel: cell.colLabel,
169
- value: cell.value,
170
- record: cell.record
171
- })
172
- }, `hit-${pairKey(cell.rowLabel, cell.colLabel)}`))
173
- ]
174
- })
175
- }), mounted && hovered && createPortal(/* @__PURE__ */ jsxs("div", {
176
- className: "pointer-events-none fixed z-50 min-w-[130px] rounded-lg border border-border bg-popover px-3 py-2.5 text-popover-foreground shadow-lg",
177
- style: {
178
- left: tooltipLeft,
179
- top: tooltipTop
180
- },
181
- children: [/* @__PURE__ */ jsxs("p", {
182
- className: "mb-1.5 font-mono text-[10px] text-quaternary-foreground uppercase tracking-wider",
183
- children: [
184
- formatY(hovered.rowLabel),
185
- " · ",
186
- formatX(hovered.colLabel)
187
- ]
188
- }), tooltipMetrics && tooltipMetrics.length > 0 ? /* @__PURE__ */ jsx("div", {
189
- className: "flex flex-col gap-1",
190
- children: tooltipMetrics.map((metric) => {
191
- const raw = hovered.record ? Number(hovered.record[metric.key]) || 0 : 0;
192
- const isActive = metric.key === dataKey;
193
- return /* @__PURE__ */ jsxs("div", {
194
- className: "flex items-center justify-between gap-4 text-text-xs",
195
- children: [/* @__PURE__ */ jsxs("span", {
196
- className: "inline-flex items-center gap-2 text-muted-foreground",
197
- children: [/* @__PURE__ */ jsx("span", {
198
- "aria-hidden": true,
199
- className: "size-2 shrink-0 rounded-[2px]",
200
- style: {
201
- background: isActive ? heatColor(ramp, hovered.value / maxValue) : theme.mutedForeground,
202
- opacity: isActive ? 1 : .35
203
- }
204
- }), metric.label]
205
- }), /* @__PURE__ */ jsx("span", {
206
- className: cn("font-mono tabular-nums", isActive ? "font-semibold text-foreground" : "text-muted-foreground"),
207
- children: (metric.format ?? valueFormatter)(raw)
208
- })]
209
- }, metric.key);
175
+ width: 25,
176
+ height: 25,
177
+ fill: "transparent",
178
+ onMouseMove: (event) => setHovered({
179
+ x: event.clientX,
180
+ y: event.clientY,
181
+ rowLabel: cell.rowLabel,
182
+ colLabel: cell.colLabel,
183
+ value: cell.value,
184
+ record: cell.record
185
+ })
186
+ }, `hit-${pairKey(cell.rowLabel, cell.colLabel)}`))
187
+ ]
210
188
  })
211
- }) : /* @__PURE__ */ jsxs("div", {
212
- className: "flex items-center justify-between gap-4 text-text-xs",
213
- children: [/* @__PURE__ */ jsxs("span", {
214
- className: "inline-flex items-center gap-2 text-muted-foreground",
215
- children: [/* @__PURE__ */ jsx("span", {
189
+ }),
190
+ showLegend && /* @__PURE__ */ jsxs("div", {
191
+ className: "mt-3 flex items-center justify-end gap-2",
192
+ children: [
193
+ /* @__PURE__ */ jsx("span", {
194
+ className: "font-mono text-[9px] text-quaternary-foreground uppercase tracking-[0.14em]",
195
+ children: "Less"
196
+ }),
197
+ /* @__PURE__ */ jsx("span", {
216
198
  "aria-hidden": true,
217
- className: "size-2 shrink-0 rounded-[2px]",
218
- style: { background: heatColor(ramp, hovered.value / maxValue) }
219
- }), "activity"]
220
- }), /* @__PURE__ */ jsx("span", {
221
- className: "font-mono font-semibold tabular-nums text-foreground",
222
- children: valueFormatter(hovered.value)
199
+ className: "h-2 w-24 rounded-full border border-border",
200
+ style: { background: `linear-gradient(90deg, ${ramp.join(", ")})` }
201
+ }),
202
+ /* @__PURE__ */ jsx("span", {
203
+ className: "font-mono text-[9px] text-quaternary-foreground uppercase tracking-[0.14em]",
204
+ children: "More"
205
+ })
206
+ ]
207
+ }),
208
+ mounted && hovered && createPortal(/* @__PURE__ */ jsxs("div", {
209
+ className: "pointer-events-none fixed z-50 min-w-[130px] rounded-lg border border-border bg-popover px-3 py-2.5 text-popover-foreground shadow-lg",
210
+ style: {
211
+ left: tooltipLeft,
212
+ top: tooltipTop
213
+ },
214
+ children: [/* @__PURE__ */ jsx("p", {
215
+ className: "mb-1.5 font-mono text-[10px] text-quaternary-foreground uppercase tracking-wider",
216
+ children: tooltipTitleKey && typeof hovered.record?.[tooltipTitleKey] === "string" ? hovered.record[tooltipTitleKey] : `${formatY(hovered.rowLabel)} · ${formatX(hovered.colLabel)}`
217
+ }), tooltipMetrics && tooltipMetrics.length > 0 ? /* @__PURE__ */ jsx("div", {
218
+ className: "flex flex-col gap-1",
219
+ children: tooltipMetrics.map((metric) => {
220
+ const raw = hovered.record ? Number(hovered.record[metric.key]) || 0 : 0;
221
+ const isActive = metric.key === dataKey;
222
+ return /* @__PURE__ */ jsxs("div", {
223
+ className: "flex items-center justify-between gap-4 text-text-xs",
224
+ children: [/* @__PURE__ */ jsxs("span", {
225
+ className: "inline-flex items-center gap-2 text-muted-foreground",
226
+ children: [/* @__PURE__ */ jsx("span", {
227
+ "aria-hidden": true,
228
+ className: "size-2 shrink-0 rounded-[2px]",
229
+ style: {
230
+ background: isActive ? heatColor(ramp, colorFractionOf(hovered.value)) : theme.mutedForeground,
231
+ opacity: isActive ? 1 : .35
232
+ }
233
+ }), metric.label]
234
+ }), /* @__PURE__ */ jsx("span", {
235
+ className: cn("font-mono tabular-nums", isActive ? "font-semibold text-foreground" : "text-muted-foreground"),
236
+ children: (metric.format ?? valueFormatter)(raw)
237
+ })]
238
+ }, metric.key);
239
+ })
240
+ }) : /* @__PURE__ */ jsxs("div", {
241
+ className: "flex items-center justify-between gap-4 text-text-xs",
242
+ children: [/* @__PURE__ */ jsxs("span", {
243
+ className: "inline-flex items-center gap-2 text-muted-foreground",
244
+ children: [/* @__PURE__ */ jsx("span", {
245
+ "aria-hidden": true,
246
+ className: "size-2 shrink-0 rounded-[2px]",
247
+ style: { background: heatColor(ramp, colorFractionOf(hovered.value)) }
248
+ }), "activity"]
249
+ }), /* @__PURE__ */ jsx("span", {
250
+ className: "font-mono font-semibold tabular-nums text-foreground",
251
+ children: valueFormatter(hovered.value)
252
+ })]
223
253
  })]
224
- })]
225
- }), document.body)]
254
+ }), document.body)
255
+ ]
226
256
  });
227
257
  }
228
258
  //#endregion
@@ -1,5 +1,5 @@
1
- import { VariantProps } from "class-variance-authority";
2
1
  import * as React$1 from "react";
2
+ import { VariantProps } from "class-variance-authority";
3
3
 
4
4
  //#region src/components/input-group.d.ts
5
5
  declare function InputGroup({
@@ -2,9 +2,9 @@
2
2
  import { cn } from "../lib/cn.mjs";
3
3
  import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.mjs";
4
4
  import { Label } from "./label.mjs";
5
+ import * as React$1 from "react";
5
6
  import { Info } from "lucide-react";
6
7
  import { jsx, jsxs } from "react/jsx-runtime";
7
- import * as React$1 from "react";
8
8
  //#region src/components/input.tsx
9
9
  const inputSizeStyles = {
10
10
  sm: {
@@ -4,8 +4,9 @@ import { makeXAxisTick, resolveSeries } from "../lib/chart.mjs";
4
4
  import { useChartContext } from "./chart-container.mjs";
5
5
  import { ChartLegend } from "./chart-legend.mjs";
6
6
  import { ChartTooltipContent } from "./chart-tooltip.mjs";
7
- import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { Skeleton } from "./skeleton.mjs";
8
8
  import * as React$1 from "react";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
9
10
  import { CartesianGrid, LabelList, Line, LineChart as LineChart$1, ReferenceArea, ReferenceDot, ReferenceLine, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
10
11
  //#region src/components/line-chart.tsx
11
12
  const CURVE_TYPE = {
@@ -91,14 +92,11 @@ function LineChart({ data, index, series, curve = "monotone", legend = false, le
91
92
  const isEmpty = data.length === 0 || resolved.length === 0;
92
93
  return /* @__PURE__ */ jsxs("div", {
93
94
  "data-slot": "line-chart",
94
- className: cn("flex w-full flex-col gap-3", className),
95
+ className: cn("flex w-full flex-col gap-3", "[&_.recharts-surface]:outline-none [&_.recharts-wrapper]:outline-none", className),
95
96
  children: [/* @__PURE__ */ jsx("div", {
96
97
  className: "w-full",
97
98
  style: { height },
98
- children: loading ? /* @__PURE__ */ jsxs("div", {
99
- className: "flex h-full items-center justify-center gap-2.5 font-mono text-quaternary-foreground text-text-xs",
100
- children: [/* @__PURE__ */ jsx("span", { className: "size-4 animate-spin rounded-full border-2 border-border border-t-foreground" }), "loading…"]
101
- }) : isEmpty ? /* @__PURE__ */ jsx("div", {
99
+ children: loading ? /* @__PURE__ */ jsx(Skeleton, { className: "h-full w-full rounded-lg" }) : isEmpty ? /* @__PURE__ */ jsx("div", {
102
100
  className: "flex h-full items-center justify-center rounded-lg border border-border border-dashed font-mono text-quaternary-foreground text-text-xs",
103
101
  children: "no data in range"
104
102
  }) : /* @__PURE__ */ jsx(ResponsiveContainer, {
@@ -122,7 +120,7 @@ function LineChart({ data, index, series, curve = "monotone", legend = false, le
122
120
  ...axis,
123
121
  tick: makeXAxisTick(theme),
124
122
  interval: "preserveStartEnd",
125
- minTickGap: 44
123
+ minTickGap: 56
126
124
  }),
127
125
  /* @__PURE__ */ jsx(YAxis, {
128
126
  ...axis,
@@ -1,6 +1,6 @@
1
1
  import { selectTriggerVariants } from "./select-trigger-variants.mjs";
2
- import { VariantProps } from "class-variance-authority";
3
2
  import * as React$1 from "react";
3
+ import { VariantProps } from "class-variance-authority";
4
4
  import * as SelectPrimitive from "@radix-ui/react-select";
5
5
 
6
6
  //#region src/components/select.d.ts
@@ -1,7 +1,7 @@
1
1
  import { Button } from "./button.mjs";
2
2
  import { TooltipContent } from "./tooltip.mjs";
3
- import { VariantProps } from "class-variance-authority";
4
3
  import * as React$1 from "react";
4
+ import { VariantProps } from "class-variance-authority";
5
5
 
6
6
  //#region src/components/sidebar.d.ts
7
7
  type SidebarContextProps = {
@@ -1,14 +1,14 @@
1
1
  "use client";
2
+ import { useIsMobile } from "../hooks/use-mobile.mjs";
2
3
  import { cn } from "../lib/cn.mjs";
4
+ import { Skeleton } from "./skeleton.mjs";
3
5
  import { Button } from "./button.mjs";
4
6
  import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.mjs";
5
7
  import { Separator } from "./separator.mjs";
6
8
  import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "./sheet.mjs";
7
- import { useIsMobile } from "../hooks/use-mobile.mjs";
8
- import { Skeleton } from "./skeleton.mjs";
9
+ import * as React$1 from "react";
9
10
  import { jsx, jsxs } from "react/jsx-runtime";
10
11
  import { cva } from "class-variance-authority";
11
- import * as React$1 from "react";
12
12
  import { Slot } from "@radix-ui/react-slot";
13
13
  //#region src/components/sidebar.tsx
14
14
  const SIDEBAR_COOKIE_NAME = "sidebar_state";
@@ -3,7 +3,7 @@ import { cn } from "../lib/cn.mjs";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  import { cva } from "class-variance-authority";
5
5
  //#region src/components/skeleton.tsx
6
- const skeletonVariants = cva("bg-accent motion-safe:animate-pulse", {
6
+ const skeletonVariants = cva("bg-foreground/10 motion-safe:animate-pulse", {
7
7
  variants: { shape: {
8
8
  rectangle: "rounded-md",
9
9
  circle: "rounded-full"
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.mjs";
3
3
  import { useChartContext } from "./chart-container.mjs";
4
+ import * as React$1 from "react";
4
5
  import { ArrowDown, ArrowUp } from "lucide-react";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  import { cva } from "class-variance-authority";
7
- import * as React$1 from "react";
8
8
  import { Area, AreaChart, ResponsiveContainer } from "recharts";
9
9
  //#region src/components/stat.tsx
10
10
  const statDeltaVariants = cva("inline-flex items-center gap-0.5 rounded-md px-1.5 py-0.5 font-mono text-[11px] font-medium leading-none", {
@@ -35,13 +35,13 @@ function Stat({ value, unit, delta, sparkline, semantic, className, ...props })
35
35
  const sentiment = delta && (delta.invert ? delta.direction === "down" : delta.direction === "up") ? "positive" : "negative";
36
36
  return /* @__PURE__ */ jsxs("div", {
37
37
  "data-slot": "stat",
38
- className: cn("flex flex-col gap-2.5", className),
38
+ className: cn("flex min-w-0 flex-col gap-2.5", className),
39
39
  ...props,
40
40
  children: [/* @__PURE__ */ jsxs("div", {
41
- className: "flex items-baseline gap-3",
41
+ className: "flex min-w-0 items-baseline gap-x-2.5",
42
42
  children: [
43
43
  /* @__PURE__ */ jsx("span", {
44
- className: "type-display-sm font-bold leading-none tracking-tight tabular-nums text-foreground",
44
+ className: "type-display-sm min-w-0 truncate font-bold leading-none tracking-tight tabular-nums text-foreground",
45
45
  children: value
46
46
  }),
47
47
  unit && /* @__PURE__ */ jsx("span", {
@@ -55,7 +55,7 @@ function Stat({ value, unit, delta, sparkline, semantic, className, ...props })
55
55
  })
56
56
  ]
57
57
  }), hasSpark && /* @__PURE__ */ jsx("div", {
58
- className: "h-9 w-full",
58
+ className: "pointer-events-none h-9 w-full",
59
59
  children: /* @__PURE__ */ jsx(ResponsiveContainer, {
60
60
  width: "100%",
61
61
  height: "100%",
@@ -1,5 +1,5 @@
1
- import { VariantProps } from "class-variance-authority";
2
1
  import * as React$1 from "react";
2
+ import { VariantProps } from "class-variance-authority";
3
3
  import * as TabsPrimitive from "@radix-ui/react-tabs";
4
4
 
5
5
  //#region src/components/tabs.d.ts
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.mjs";
3
+ import { createContext, use } from "react";
3
4
  import { jsx } from "react/jsx-runtime";
4
5
  import { cva } from "class-variance-authority";
5
- import { createContext, use } from "react";
6
6
  import { Slot } from "@radix-ui/react-slot";
7
7
  import * as TabsPrimitive from "@radix-ui/react-tabs";
8
8
  //#region src/components/tabs.tsx
@@ -2,9 +2,9 @@
2
2
  import { cn } from "../lib/cn.mjs";
3
3
  import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.mjs";
4
4
  import { Label } from "./label.mjs";
5
+ import * as React$1 from "react";
5
6
  import { Info } from "lucide-react";
6
7
  import { jsx, jsxs } from "react/jsx-runtime";
7
- import * as React$1 from "react";
8
8
  //#region src/components/textarea.tsx
9
9
  function Textarea({ className, id, label, required, hint, error, tooltip, ...props }) {
10
10
  const generatedId = React$1.useId();
@@ -1,5 +1,5 @@
1
- import { VariantProps } from "class-variance-authority";
2
1
  import * as React$1 from "react";
2
+ import { VariantProps } from "class-variance-authority";
3
3
  import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
4
4
 
5
5
  //#region src/components/toggle-group.d.ts
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.mjs";
3
+ import * as React$1 from "react";
3
4
  import { jsx } from "react/jsx-runtime";
4
5
  import { cva } from "class-variance-authority";
5
- import * as React$1 from "react";
6
6
  import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
7
7
  //#region src/components/toggle-group.tsx
8
8
  const toggleGroupItemVariants = cva([
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { Button } from "./button.mjs";
3
3
  import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.mjs";
4
- import { jsx, jsxs } from "react/jsx-runtime";
5
4
  import { forwardRef } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { Slottable } from "@radix-ui/react-slot";
7
7
  //#region src/components/tooltip-icon-button.tsx
8
8
  const TooltipIconButton = forwardRef(({ children, tooltip, side = "bottom", ...rest }, ref) => {
@@ -42,7 +42,10 @@ const HEAT_RAMPS = {
42
42
  magenta: heatRampMagenta,
43
43
  cyan: heatRampMint
44
44
  };
45
- const heatRamp = (palette, empty) => HEAT_RAMPS[palette](empty);
45
+ const heatRamp = (palette, empty, isDark = true) => {
46
+ const [, ...colored] = HEAT_RAMPS[palette](empty);
47
+ return [empty, ...isDark ? colored : colored.reverse()];
48
+ };
46
49
  const hexToRgb = (hex) => {
47
50
  const value = Number.parseInt(hex.slice(1), 16);
48
51
  return [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alpic-ai/ui",
3
- "version": "1.144.0",
3
+ "version": "1.145.1",
4
4
  "description": "Alpic design system — shared UI components",
5
5
  "type": "module",
6
6
  "exports": {
@@ -52,7 +52,7 @@
52
52
  "class-variance-authority": "^0.7.1",
53
53
  "clsx": "^2.1.1",
54
54
  "cmdk": "^1.1.1",
55
- "recharts": "^3.8.1",
55
+ "recharts": "^3.9.0",
56
56
  "tailwind-merge": "^3.6.0"
57
57
  },
58
58
  "devDependencies": {
@@ -21,6 +21,7 @@ import { cn } from "../lib/cn";
21
21
  import { useChartContext } from "./chart-container";
22
22
  import { ChartLegend } from "./chart-legend";
23
23
  import { ChartTooltipContent } from "./chart-tooltip";
24
+ import { Skeleton } from "./skeleton";
24
25
 
25
26
  const CURVE_TYPE = { monotone: "monotone", linear: "linear", step: "stepAfter" } as const;
26
27
 
@@ -192,13 +193,17 @@ function AreaChart({
192
193
  const isEmpty = data.length === 0 || rendered.length === 0;
193
194
 
194
195
  return (
195
- <div data-slot="area-chart" className={cn("flex w-full flex-col gap-3", className)}>
196
+ <div
197
+ data-slot="area-chart"
198
+ className={cn(
199
+ "flex w-full flex-col gap-3",
200
+ "[&_.recharts-surface]:outline-none [&_.recharts-wrapper]:outline-none",
201
+ className,
202
+ )}
203
+ >
196
204
  <div className="w-full" style={{ height }}>
197
205
  {loading ? (
198
- <div className="flex h-full items-center justify-center gap-2.5 font-mono text-quaternary-foreground text-text-xs">
199
- <span className="size-4 animate-spin rounded-full border-2 border-border border-t-foreground" />
200
- loading…
201
- </div>
206
+ <Skeleton className="h-full w-full rounded-lg" />
202
207
  ) : isEmpty ? (
203
208
  <div className="flex h-full items-center justify-center rounded-lg border border-border border-dashed font-mono text-quaternary-foreground text-text-xs">
204
209
  no data in range
@@ -238,7 +243,7 @@ function AreaChart({
238
243
  {...axis}
239
244
  tick={makeXAxisTick(theme)}
240
245
  interval="preserveStartEnd"
241
- minTickGap={44}
246
+ minTickGap={56}
242
247
  />
243
248
  <YAxis
244
249
  {...axis}
@@ -22,6 +22,7 @@ import type { ChartMarker } from "./area-chart";
22
22
  import { useChartContext } from "./chart-container";
23
23
  import { ChartLegend } from "./chart-legend";
24
24
  import { ChartTooltipContent } from "./chart-tooltip";
25
+ import { Skeleton } from "./skeleton";
25
26
 
26
27
  const BAR_RADIUS = 4;
27
28
  const MAX_BAR_SIZE = 48;
@@ -155,13 +156,17 @@ function BarChart({
155
156
  const isEmpty = data.length === 0 || rendered.length === 0;
156
157
 
157
158
  return (
158
- <div data-slot="bar-chart" className={cn("flex w-full flex-col gap-3", className)}>
159
+ <div
160
+ data-slot="bar-chart"
161
+ className={cn(
162
+ "flex w-full flex-col gap-3",
163
+ "[&_.recharts-surface]:outline-none [&_.recharts-wrapper]:outline-none",
164
+ className,
165
+ )}
166
+ >
159
167
  <div className="w-full" style={{ height }}>
160
168
  {loading ? (
161
- <div className="flex h-full items-center justify-center gap-2.5 font-mono text-quaternary-foreground text-text-xs">
162
- <span className="size-4 animate-spin rounded-full border-2 border-border border-t-foreground" />
163
- loading…
164
- </div>
169
+ <Skeleton className="h-full w-full rounded-lg" />
165
170
  ) : isEmpty ? (
166
171
  <div className="flex h-full items-center justify-center rounded-lg border border-border border-dashed font-mono text-quaternary-foreground text-text-xs">
167
172
  no data in range
@@ -202,7 +207,7 @@ function BarChart({
202
207
  {...axis}
203
208
  tick={makeXAxisTick(theme)}
204
209
  interval="preserveStartEnd"
205
- minTickGap={44}
210
+ minTickGap={56}
206
211
  />
207
212
  <YAxis
208
213
  {...axis}
@@ -268,7 +273,7 @@ function BarChart({
268
273
  strokeWidth={0}
269
274
  radius={radiusFor(slot)}
270
275
  maxBarSize={MAX_BAR_SIZE}
271
- activeBar={{ fillOpacity: 1, stroke: theme.card, strokeWidth: 1 }}
276
+ activeBar={false}
272
277
  isAnimationActive={false}
273
278
  animationDuration={650}
274
279
  animationEasing="ease-out"