@alpic-ai/ui 1.160.0 → 1.162.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 (58) hide show
  1. package/dist/components/accordion-card.d.mts +1 -5
  2. package/dist/components/accordion-card.mjs +1 -5
  3. package/dist/components/accordion.d.mts +1 -5
  4. package/dist/components/accordion.mjs +1 -5
  5. package/dist/components/attachment-tile.d.mts +0 -5
  6. package/dist/components/chart-legend.d.mts +4 -1
  7. package/dist/components/chart-legend.mjs +21 -7
  8. package/dist/components/chart-primitives.d.mts +3 -8
  9. package/dist/components/chart-primitives.mjs +3 -8
  10. package/dist/components/combobox.d.mts +0 -1
  11. package/dist/components/line-chart.d.mts +3 -1
  12. package/dist/components/line-chart.mjs +7 -4
  13. package/dist/components/select-trigger-variants.d.mts +1 -5
  14. package/dist/components/select-trigger-variants.mjs +1 -5
  15. package/dist/components/table.d.mts +1 -5
  16. package/dist/components/task-progress.d.mts +1 -4
  17. package/dist/lib/chart-palette.d.mts +1 -20
  18. package/dist/lib/chart-palette.mjs +1 -20
  19. package/dist/lib/chart.d.mts +1 -4
  20. package/dist/lib/chart.mjs +2 -11
  21. package/package.json +5 -5
  22. package/src/components/accordion-card.tsx +1 -5
  23. package/src/components/accordion.tsx +1 -5
  24. package/src/components/attachment-tile.tsx +0 -5
  25. package/src/components/avatar.tsx +0 -2
  26. package/src/components/bar-chart.tsx +1 -2
  27. package/src/components/bar-list.tsx +1 -2
  28. package/src/components/chart-legend.tsx +47 -10
  29. package/src/components/chart-primitives.tsx +3 -9
  30. package/src/components/combobox.tsx +1 -29
  31. package/src/components/dropdown-menu.tsx +0 -12
  32. package/src/components/form.tsx +0 -4
  33. package/src/components/heatmap-chart.tsx +4 -10
  34. package/src/components/line-chart.tsx +16 -3
  35. package/src/components/select-trigger-variants.ts +1 -5
  36. package/src/components/select.tsx +0 -10
  37. package/src/components/sidebar.tsx +0 -2
  38. package/src/components/table.tsx +1 -5
  39. package/src/components/tabs.tsx +1 -18
  40. package/src/components/tag.tsx +0 -6
  41. package/src/components/task-progress.tsx +2 -14
  42. package/src/components/wizard.tsx +0 -6
  43. package/src/lib/chart-palette.ts +3 -22
  44. package/src/lib/chart.ts +3 -15
  45. package/src/stories/button.stories.tsx +1 -15
  46. package/src/stories/combobox.stories.tsx +0 -12
  47. package/src/stories/dropdown-menu.stories.tsx +0 -4
  48. package/src/stories/form.stories.tsx +0 -6
  49. package/src/stories/heatmap-chart.stories.tsx +0 -1
  50. package/src/stories/input-group.stories.tsx +0 -4
  51. package/src/stories/input.stories.tsx +0 -8
  52. package/src/stories/line-chart.stories.tsx +120 -80
  53. package/src/stories/sidebar.stories.tsx +1 -4
  54. package/src/stories/skeleton.stories.tsx +0 -2
  55. package/src/stories/table.stories.tsx +0 -5
  56. package/src/stories/tabs.stories.tsx +0 -11
  57. package/src/stories/toggle-group.stories.tsx +0 -5
  58. package/src/stories/wizard.stories.tsx +0 -4
@@ -9,11 +9,7 @@ declare function AccordionCard({ defaultOpen, open, onOpenChange, disabled, clas
9
9
  } & Omit<React$1.ComponentProps<typeof AccordionPrimitive.Root>, "type" | "collapsible" | "defaultValue" | "value" | "onValueChange" | "disabled">): React$1.JSX.Element;
10
10
  declare function AccordionCardHeader({ className, children, ...props }: React$1.ComponentProps<typeof AccordionPrimitive.Trigger>): React$1.JSX.Element;
11
11
  declare function AccordionCardTitle({ className, children, ...props }: React$1.HTMLAttributes<HTMLHeadingElement>): React$1.JSX.Element;
12
- /**
13
- * `className` is forwarded to the inner padding wrapper, not the Radix Content root.
14
- * The root always applies overflow-hidden and the accordion animations.
15
- * To override overflow or animation behavior, wrap this component in an additional element.
16
- */
12
+ /** `className` styles the inner padding wrapper, not the Radix Content root, which keeps overflow-hidden and the accordion animations. */
17
13
  declare function AccordionCardContent({ className, children, ...props }: React$1.ComponentProps<typeof AccordionPrimitive.Content>): React$1.JSX.Element;
18
14
  //#endregion
19
15
  export { AccordionCard, AccordionCardContent, AccordionCardHeader, AccordionCardTitle };
@@ -41,11 +41,7 @@ function AccordionCardTitle({ className, children, ...props }) {
41
41
  children
42
42
  });
43
43
  }
44
- /**
45
- * `className` is forwarded to the inner padding wrapper, not the Radix Content root.
46
- * The root always applies overflow-hidden and the accordion animations.
47
- * To override overflow or animation behavior, wrap this component in an additional element.
48
- */
44
+ /** `className` styles the inner padding wrapper, not the Radix Content root, which keeps overflow-hidden and the accordion animations. */
49
45
  function AccordionCardContent({ className, children, ...props }) {
50
46
  return /* @__PURE__ */ jsx(AccordionPrimitive.Content, {
51
47
  "data-slot": "accordion-card-content",
@@ -4,11 +4,7 @@ import * as React$1 from "react";
4
4
  declare function Accordion({ ...props }: React$1.ComponentProps<typeof AccordionPrimitive.Root>): React$1.JSX.Element;
5
5
  declare function AccordionItem({ className, ...props }: React$1.ComponentProps<typeof AccordionPrimitive.Item>): React$1.JSX.Element;
6
6
  declare function AccordionTrigger({ className, children, ...props }: React$1.ComponentProps<typeof AccordionPrimitive.Trigger>): React$1.JSX.Element;
7
- /**
8
- * `className` is forwarded to the inner padding wrapper, not the Radix Content root.
9
- * The root always applies overflow-hidden and the accordion animations.
10
- * To override overflow or animation behavior, wrap this component in an additional element.
11
- */
7
+ /** `className` styles the inner padding wrapper, not the Radix Content root, which keeps overflow-hidden and the accordion animations. */
12
8
  declare function AccordionContent({ className, children, ...props }: React$1.ComponentProps<typeof AccordionPrimitive.Content>): React$1.JSX.Element;
13
9
  //#endregion
14
10
  export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
@@ -28,11 +28,7 @@ function AccordionTrigger({ className, children, ...props }) {
28
28
  })
29
29
  });
30
30
  }
31
- /**
32
- * `className` is forwarded to the inner padding wrapper, not the Radix Content root.
33
- * The root always applies overflow-hidden and the accordion animations.
34
- * To override overflow or animation behavior, wrap this component in an additional element.
35
- */
31
+ /** `className` styles the inner padding wrapper, not the Radix Content root, which keeps overflow-hidden and the accordion animations. */
36
32
  function AccordionContent({ className, children, ...props }) {
37
33
  return /* @__PURE__ */ jsx(AccordionPrimitive.Content, {
38
34
  "data-slot": "accordion-content",
@@ -1,14 +1,9 @@
1
1
  //#region src/components/attachment-tile.d.ts
2
2
  interface AttachmentTileProps {
3
- /** Source URL for the attachment thumbnail */
4
3
  src?: string;
5
- /** Whether the attachment is an image */
6
4
  isImage?: boolean;
7
- /** Accessible label describing the attachment */
8
5
  label?: string;
9
- /** Called when the remove button is clicked */
10
6
  onRemove?: () => void;
11
- /** Called when the tile is clicked (e.g. to open a preview) */
12
7
  onClick?: () => void;
13
8
  className?: string;
14
9
  }
@@ -1,5 +1,6 @@
1
1
  //#region src/components/chart-legend.d.ts
2
2
  interface ChartLegendItem {
3
+ key: string;
3
4
  name: string;
4
5
  color: string;
5
6
  dashed?: boolean;
@@ -8,7 +9,9 @@ interface ChartLegendProps extends React.HTMLAttributes<HTMLDivElement> {
8
9
  items: ChartLegendItem[];
9
10
  align?: "left" | "center" | "right";
10
11
  insetLeft?: number;
12
+ hiddenKeys?: ReadonlySet<string>;
13
+ onItemClick?: (key: string) => void;
11
14
  }
12
- declare function ChartLegend({ items, align, insetLeft, className, style, ...props }: ChartLegendProps): import("react").JSX.Element;
15
+ declare function ChartLegend({ items, align, insetLeft, hiddenKeys, onItemClick, className, style, ...props }: ChartLegendProps): import("react").JSX.Element;
13
16
  //#endregion
14
17
  export { ChartLegend, ChartLegendItem, ChartLegendProps };
@@ -1,12 +1,14 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.mjs";
3
- import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
4
  //#region src/components/chart-legend.tsx
5
5
  const ALIGN_CLASS = {
6
6
  left: "justify-start",
7
7
  center: "justify-center",
8
8
  right: "justify-end"
9
9
  };
10
+ const ITEM_CLASS = "inline-flex items-center gap-1.5 font-mono text-[10px] text-muted-foreground uppercase tracking-[0.12em]";
11
+ const INTERACTIVE_CLASS = "rounded-sm outline-none transition-opacity focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card [@media(hover:hover)]:hover:text-foreground";
10
12
  function Swatch({ color, dashed }) {
11
13
  return /* @__PURE__ */ jsx("span", {
12
14
  "aria-hidden": true,
@@ -14,7 +16,7 @@ function Swatch({ color, dashed }) {
14
16
  style: dashed ? { border: `1.5px solid ${color}` } : { background: color }
15
17
  });
16
18
  }
17
- function ChartLegend({ items, align = "left", insetLeft, className, style, ...props }) {
19
+ function ChartLegend({ items, align = "left", insetLeft, hiddenKeys, onItemClick, className, style, ...props }) {
18
20
  return /* @__PURE__ */ jsx("div", {
19
21
  className: cn("flex flex-wrap gap-x-4 gap-y-1.5", ALIGN_CLASS[align], className),
20
22
  style: {
@@ -22,13 +24,25 @@ function ChartLegend({ items, align = "left", insetLeft, className, style, ...pr
22
24
  ...style
23
25
  },
24
26
  ...props,
25
- children: items.map((item) => /* @__PURE__ */ jsxs("span", {
26
- className: "inline-flex items-center gap-1.5 font-mono text-[10px] text-muted-foreground uppercase tracking-[0.12em]",
27
- children: [/* @__PURE__ */ jsx(Swatch, {
27
+ children: items.map((item) => {
28
+ const swatchAndName = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Swatch, {
28
29
  color: item.color,
29
30
  dashed: item.dashed
30
- }), item.name]
31
- }, item.name))
31
+ }), item.name] });
32
+ if (!onItemClick) return /* @__PURE__ */ jsx("span", {
33
+ className: ITEM_CLASS,
34
+ children: swatchAndName
35
+ }, item.key);
36
+ const hidden = hiddenKeys?.has(item.key) ?? false;
37
+ return /* @__PURE__ */ jsx("button", {
38
+ type: "button",
39
+ "aria-label": `${item.name} series`,
40
+ "aria-pressed": !hidden,
41
+ onClick: () => onItemClick(item.key),
42
+ className: cn(ITEM_CLASS, INTERACTIVE_CLASS, hidden && "opacity-40"),
43
+ children: swatchAndName
44
+ }, item.key);
45
+ })
32
46
  });
33
47
  }
34
48
  //#endregion
@@ -22,14 +22,12 @@ declare function makeChartAxis(theme: ChartTheme): {
22
22
  };
23
23
  };
24
24
  declare function makeLegendItems(resolved: ResolvedSeries[]): {
25
+ key: string;
25
26
  name: string;
26
27
  color: string;
27
28
  dashed: boolean | undefined;
28
29
  }[];
29
- /**
30
- * Stacked series must reach the stack height (sum per x-point), not the tallest
31
- * single series, or reference bands and explicit Y domains clip a tall stack short.
32
- */
30
+ /** Stacked series must reach the stack height (sum per x-point), or reference bands and explicit Y domains clip a tall stack short. */
33
31
  declare function computeNumericMax(data: ChartData, series: ChartSeries[], stacked: boolean): number;
34
32
  declare function makeActiveDot(entry: ResolvedSeries, { valueFlags, theme, valueFormatter }: {
35
33
  valueFlags: boolean;
@@ -55,10 +53,7 @@ declare function makeLastValueLabel(color: string, { dataLength, theme, valueFor
55
53
  value?: string | number | boolean | Array<string | number | boolean> | null;
56
54
  index?: number;
57
55
  }) => import("react").JSX.Element | null;
58
- /**
59
- * Returns recharts elements (not a wrapper component) so recharts still detects
60
- * them as direct children when spread into a chart via `{renderReferenceLine(...)}`.
61
- */
56
+ /** Returns recharts elements (not a wrapper component) so recharts still detects them as direct chart children. */
62
57
  declare function renderReferenceLine({ referenceLine, numericMax, theme }: {
63
58
  referenceLine: ReferenceLineConfig | undefined;
64
59
  numericMax: number;
@@ -19,15 +19,13 @@ function makeChartAxis(theme) {
19
19
  }
20
20
  function makeLegendItems(resolved) {
21
21
  return resolved.map((entry) => ({
22
+ key: entry.key,
22
23
  name: entry.name,
23
24
  color: entry.color,
24
25
  dashed: entry.dashed
25
26
  }));
26
27
  }
27
- /**
28
- * Stacked series must reach the stack height (sum per x-point), not the tallest
29
- * single series, or reference bands and explicit Y domains clip a tall stack short.
30
- */
28
+ /** Stacked series must reach the stack height (sum per x-point), or reference bands and explicit Y domains clip a tall stack short. */
31
29
  function computeNumericMax(data, series, stacked) {
32
30
  let max = 0;
33
31
  for (const row of data) {
@@ -87,10 +85,7 @@ function makeLastValueLabel(color, { dataLength, theme, valueFormatter }) {
87
85
  });
88
86
  };
89
87
  }
90
- /**
91
- * Returns recharts elements (not a wrapper component) so recharts still detects
92
- * them as direct children when spread into a chart via `{renderReferenceLine(...)}`.
93
- */
88
+ /** Returns recharts elements (not a wrapper component) so recharts still detects them as direct chart children. */
94
89
  function renderReferenceLine({ referenceLine, numericMax, theme }) {
95
90
  if (!referenceLine) return null;
96
91
  return [referenceLine.band ? /* @__PURE__ */ jsx(ReferenceArea, {
@@ -42,7 +42,6 @@ declare function ComboboxEmpty({ className, ...props }: React.ComponentProps<typ
42
42
  declare function ComboboxGroup({ className, ...props }: React.ComponentProps<typeof Command.Group>): import("react").JSX.Element;
43
43
  declare function ComboboxSeparator({ className, ...props }: React.ComponentProps<typeof Command.Separator>): import("react").JSX.Element;
44
44
  interface ComboboxItemProps extends Omit<React.ComponentProps<typeof Command.Item>, "onSelect"> {
45
- /** The value stored when this item is selected */
46
45
  itemValue: string;
47
46
  }
48
47
  declare function ComboboxItem({ className, children, itemValue, ...props }: ComboboxItemProps): import("react").JSX.Element;
@@ -28,10 +28,12 @@ interface LineChartProps {
28
28
  markers?: ChartMarker[];
29
29
  lastValueLabel?: boolean;
30
30
  loading?: boolean;
31
+ hiddenSeries?: ReadonlySet<string>;
32
+ onLegendItemClick?: (key: string) => void;
31
33
  valueFormatter?: (value: number) => string;
32
34
  labelFormatter?: (label: string | number) => string;
33
35
  className?: string;
34
36
  }
35
- declare function LineChart({ data, index, series, curve, legend, legendAlign, valueFlags, dots, height, yAxisWidth, palette, referenceLine, markers, lastValueLabel, loading, valueFormatter, labelFormatter, className }: LineChartProps): React$1.JSX.Element;
37
+ declare function LineChart({ data, index, series, curve, legend, legendAlign, valueFlags, dots, height, yAxisWidth, palette, referenceLine, markers, lastValueLabel, loading, hiddenSeries, onLegendItemClick, valueFormatter, labelFormatter, className }: LineChartProps): React$1.JSX.Element;
36
38
  //#endregion
37
39
  export { LineChart, LineChartProps };
@@ -15,10 +15,11 @@ const CURVE_TYPE = {
15
15
  linear: "linear",
16
16
  step: "stepAfter"
17
17
  };
18
- function LineChart({ data, index, series, curve = "monotone", legend = false, legendAlign = "left", valueFlags = false, dots = false, height = 200, yAxisWidth = 48, palette, referenceLine, markers, lastValueLabel = false, loading = false, valueFormatter = (value) => value.toLocaleString("en-US"), labelFormatter, className }) {
18
+ function LineChart({ data, index, series, curve = "monotone", legend = false, legendAlign = "left", valueFlags = false, dots = false, height = 200, yAxisWidth = 48, palette, referenceLine, markers, lastValueLabel = false, loading = false, hiddenSeries, onLegendItemClick, valueFormatter = (value) => value.toLocaleString("en-US"), labelFormatter, className }) {
19
19
  const { palette: paletteColors, theme } = useChartContext(palette);
20
20
  const resolved = resolveSeries(series, paletteColors, theme);
21
- const numericMax = React$1.useMemo(() => computeNumericMax(data, series, false), [data, series]);
21
+ const visible = resolved.filter((entry) => !hiddenSeries?.has(entry.key));
22
+ const numericMax = React$1.useMemo(() => computeNumericMax(data, visible, false), [data, visible]);
22
23
  const curveType = CURVE_TYPE[curve];
23
24
  const margin = {
24
25
  top: markers?.length ? 18 : 8,
@@ -88,7 +89,7 @@ function LineChart({ data, index, series, curve = "monotone", legend = false, le
88
89
  numericMax,
89
90
  theme
90
91
  }),
91
- resolved.map((entry) => /* @__PURE__ */ jsx(Line, {
92
+ visible.map((entry) => /* @__PURE__ */ jsx(Line, {
92
93
  type: curveType,
93
94
  dataKey: entry.key,
94
95
  name: entry.name,
@@ -124,7 +125,9 @@ function LineChart({ data, index, series, curve = "monotone", legend = false, le
124
125
  }), legend && !isEmpty && /* @__PURE__ */ jsx(ChartLegend, {
125
126
  items: legendItems,
126
127
  align: legendAlign,
127
- insetLeft: yAxisWidth
128
+ insetLeft: yAxisWidth,
129
+ hiddenKeys: hiddenSeries,
130
+ onItemClick: onLegendItemClick
128
131
  })]
129
132
  });
130
133
  }
@@ -1,9 +1,5 @@
1
1
  //#region src/components/select-trigger-variants.d.ts
2
- /**
3
- * Shared trigger styles for Select and Combobox.
4
- * Both components use the same visual treatment for their trigger buttons.
5
- * Edit here to keep them in sync.
6
- */
2
+ /** Shared by Select and Combobox so their trigger buttons stay visually in sync. */
7
3
  declare const selectTriggerVariants: (props?: ({
8
4
  size?: "sm" | "md" | null | undefined;
9
5
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
@@ -1,10 +1,6 @@
1
1
  import { cva } from "class-variance-authority";
2
2
  //#region src/components/select-trigger-variants.ts
3
- /**
4
- * Shared trigger styles for Select and Combobox.
5
- * Both components use the same visual treatment for their trigger buttons.
6
- * Edit here to keep them in sync.
7
- */
3
+ /** Shared by Select and Combobox so their trigger buttons stay visually in sync. */
8
4
  const selectTriggerVariants = cva([
9
5
  "flex w-full items-center gap-2 rounded-md border bg-background text-foreground shadow-xs outline-hidden",
10
6
  "transition-colors",
@@ -10,11 +10,7 @@ declare function TableFooter({ className, ...props }: React$1.ComponentProps<"tf
10
10
  declare function TableRow({ className, ...props }: React$1.ComponentProps<"tr">): React$1.JSX.Element;
11
11
  declare function TableHead({ className, ...props }: React$1.ComponentProps<"th">): React$1.JSX.Element;
12
12
  interface TableCellProps extends React$1.ComponentProps<"td"> {
13
- /**
14
- * When true, the cell renders edge-to-edge so the child can act as the
15
- * interactive surface (e.g. a button or popover trigger filling the cell).
16
- * Defaults to false (standard padded cell).
17
- */
13
+ /** Renders the cell edge-to-edge so the child (e.g. a button or popover trigger) can fill it as the interactive surface. */
18
14
  interactive?: boolean;
19
15
  }
20
16
  declare function TableCell({ className, interactive, ...props }: TableCellProps): React$1.JSX.Element;
@@ -8,10 +8,7 @@ interface TaskProgressStep {
8
8
  interface TaskProgressProps extends Omit<React.ComponentProps<"div">, "children"> {
9
9
  steps: readonly TaskProgressStep[];
10
10
  trailingLabel?: string;
11
- /**
12
- * Optional mount-time stagger: each row fades + slides in with `animation-delay = index × stepRevealDelayMs`.
13
- * Pure CSS, runs once on mount. Omit for no animation.
14
- */
11
+ /** Mount-time stagger: each row fades in after `index × stepRevealDelayMs`; omit for no animation. */
15
12
  stepRevealDelayMs?: number;
16
13
  }
17
14
  declare function TaskProgress({ steps, trailingLabel, stepRevealDelayMs, className, ...props }: TaskProgressProps): import("react").JSX.Element;
@@ -1,19 +1,4 @@
1
1
  //#region src/lib/chart-palette.d.ts
2
- /**
3
- * Chart palettes — the locked "paired system" from the analytics-v2 design.
4
- *
5
- * These are charting-API color values (consumed by Recharts at draw time, which
6
- * cannot read CSS custom properties), so per the design-system rules they live
7
- * as documented hex constants rather than `--color-*` tokens. They are
8
- * theme-independent: the same series colors read on light and dark canvases.
9
- * Only the chrome (grid, axis text, tooltip surface, semantic colors) is
10
- * theme-aware — see `useChartTheme`.
11
- *
12
- * Rules baked in:
13
- * - Pink leads (index 0) — never buried, fixing the V1 "pink last" bug.
14
- * - Adjacent dashboard cards alternate lead palette (magenta / cyan) — the
15
- * page decides which to pass; the component just receives one.
16
- */
17
2
  declare const MAGENTA_PALETTE: readonly ["#da1b6a", "#ec82b0", "#9a67d7", "#668fdf", "#47bde0", "#75ddd8", "#cd8c4d", "#3eb0a1"];
18
3
  declare const CYAN_PALETTE: readonly ["#2eb2c5", "#50d0c0", "#4f90e0", "#8d74e0", "#bc73e0", "#ec82b0", "#da1b6a", "#c08dd3"];
19
4
  type ChartPaletteName = "magenta" | "cyan";
@@ -28,11 +13,7 @@ declare const heatRamp: (palette: ChartPaletteName, empty: string, isDark?: bool
28
13
  declare const luminance: (hex: string) => number;
29
14
  declare const paletteColor: (palette: readonly string[], index: number) => string;
30
15
  declare const rampColor: (palette: ChartPaletteName, fraction: number) => string;
31
- /**
32
- * Interpolate continuously across a multi-stop heat ramp (e.g. `heatRampMagenta`),
33
- * so a normalized 0..1 value reads as a smooth single-hue gradient rather than
34
- * the five discrete bands.
35
- */
16
+ /** Interpolates continuously across the ramp so a 0..1 value reads as a smooth gradient rather than five discrete bands. */
36
17
  declare const heatColor: (stops: readonly string[], fraction: number) => string;
37
18
  //#endregion
38
19
  export { CHART_PALETTES, CYAN_PALETTE, ChartPaletteName, HEAT_EMPTY, MAGENTA_PALETTE, heatColor, heatRamp, heatRampMagenta, heatRampMint, luminance, paletteColor, rampColor };
@@ -1,19 +1,4 @@
1
1
  //#region src/lib/chart-palette.ts
2
- /**
3
- * Chart palettes — the locked "paired system" from the analytics-v2 design.
4
- *
5
- * These are charting-API color values (consumed by Recharts at draw time, which
6
- * cannot read CSS custom properties), so per the design-system rules they live
7
- * as documented hex constants rather than `--color-*` tokens. They are
8
- * theme-independent: the same series colors read on light and dark canvases.
9
- * Only the chrome (grid, axis text, tooltip surface, semantic colors) is
10
- * theme-aware — see `useChartTheme`.
11
- *
12
- * Rules baked in:
13
- * - Pink leads (index 0) — never buried, fixing the V1 "pink last" bug.
14
- * - Adjacent dashboard cards alternate lead palette (magenta / cyan) — the
15
- * page decides which to pass; the component just receives one.
16
- */
17
2
  const MAGENTA_PALETTE = [
18
3
  "#da1b6a",
19
4
  "#ec82b0",
@@ -101,11 +86,7 @@ const rampColor = (palette, fraction) => {
101
86
  const [from, to] = RAMP_ENDS[palette];
102
87
  return mixHex(from, to, fraction);
103
88
  };
104
- /**
105
- * Interpolate continuously across a multi-stop heat ramp (e.g. `heatRampMagenta`),
106
- * so a normalized 0..1 value reads as a smooth single-hue gradient rather than
107
- * the five discrete bands.
108
- */
89
+ /** Interpolates continuously across the ramp so a 0..1 value reads as a smooth gradient rather than five discrete bands. */
109
90
  const heatColor = (stops, fraction) => {
110
91
  const clamped = Math.min(1, Math.max(0, fraction));
111
92
  const segment = (stops.length - 1) * clamped;
@@ -1,9 +1,6 @@
1
1
  import "react";
2
2
  //#region src/lib/chart.d.ts
3
- /**
4
- * Declarative description of one plotted series. The same shape drives area,
5
- * line and bar charts — what differs is how each chart renders it.
6
- */
3
+ /** One plotted series; the same shape drives area, line and bar charts. */
7
4
  interface ChartSeries {
8
5
  key: string;
9
6
  name?: string;
@@ -7,22 +7,13 @@ const semanticColor = (theme, semantic) => {
7
7
  if (semantic === "warning") return theme.warning;
8
8
  return theme.success;
9
9
  };
10
- /**
11
- * Resolve each series to a concrete color and name. Color precedence:
12
- * explicit `color` → `semantic` token → palette slot by declared index (so the
13
- * lead series keeps the lead color even after the bands are reordered).
14
- */
10
+ /** Palette fallback uses the declared index so the lead series keeps the lead color even after reordering. */
15
11
  const resolveSeries = (series, palette, theme) => series.map((entry, index) => ({
16
12
  ...entry,
17
13
  name: entry.name ?? entry.key,
18
14
  color: entry.color ?? (entry.semantic ? semanticColor(theme, entry.semantic) : paletteColor(palette, index))
19
15
  }));
20
- /**
21
- * Stacked bands read cleanest as a vertical gradient: darkest at the baseline,
22
- * lightest at the top edge. Sorting by luminance enforces that for any palette
23
- * (this is what fixed the "muddy cyan" stack in the lab). Render order maps to
24
- * stack order in Recharts — first entry sits at the bottom.
25
- */
16
+ /** Stacked bands read cleanest darkest-at-baseline to lightest-on-top; sorting by luminance enforces that for any palette. */
26
17
  const orderByLuminance = (series) => [...series].sort((lower, upper) => luminance(lower.color) - luminance(upper.color));
27
18
  const makeXAxisTick = (theme) => ({ x, y, payload, index, visibleTicksCount }) => {
28
19
  const isFirst = index === 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alpic-ai/ui",
3
- "version": "1.160.0",
3
+ "version": "1.162.0",
4
4
  "description": "Alpic design system — shared UI components",
5
5
  "type": "module",
6
6
  "exports": {
@@ -62,10 +62,10 @@
62
62
  "devDependencies": {
63
63
  "@ladle/react": "^5.1.1",
64
64
  "@tailwindcss/postcss": "^4.3.3",
65
- "@types/react": "19.2.17",
66
- "@types/react-dom": "19.2.3",
67
- "lucide-react": "^1.27.0",
68
- "react-hook-form": "^7.83.0",
65
+ "@types/react": "19.2.18",
66
+ "@types/react-dom": "19.2.4",
67
+ "lucide-react": "^1.28.0",
68
+ "react-hook-form": "^7.84.0",
69
69
  "shx": "^0.4.0",
70
70
  "sonner": "^2.0.7",
71
71
  "tailwindcss": "^4.3.3",
@@ -79,11 +79,7 @@ function AccordionCardTitle({ className, children, ...props }: React.HTMLAttribu
79
79
  );
80
80
  }
81
81
 
82
- /**
83
- * `className` is forwarded to the inner padding wrapper, not the Radix Content root.
84
- * The root always applies overflow-hidden and the accordion animations.
85
- * To override overflow or animation behavior, wrap this component in an additional element.
86
- */
82
+ /** `className` styles the inner padding wrapper, not the Radix Content root, which keeps overflow-hidden and the accordion animations. */
87
83
  function AccordionCardContent({
88
84
  className,
89
85
  children,
@@ -43,11 +43,7 @@ function AccordionTrigger({ className, children, ...props }: React.ComponentProp
43
43
  );
44
44
  }
45
45
 
46
- /**
47
- * `className` is forwarded to the inner padding wrapper, not the Radix Content root.
48
- * The root always applies overflow-hidden and the accordion animations.
49
- * To override overflow or animation behavior, wrap this component in an additional element.
50
- */
46
+ /** `className` styles the inner padding wrapper, not the Radix Content root, which keeps overflow-hidden and the accordion animations. */
51
47
  function AccordionContent({ className, children, ...props }: React.ComponentProps<typeof AccordionPrimitive.Content>) {
52
48
  return (
53
49
  <AccordionPrimitive.Content
@@ -7,15 +7,10 @@ import { cn } from "../lib/cn";
7
7
  import { TooltipIconButton } from "./tooltip-icon-button";
8
8
 
9
9
  interface AttachmentTileProps {
10
- /** Source URL for the attachment thumbnail */
11
10
  src?: string;
12
- /** Whether the attachment is an image */
13
11
  isImage?: boolean;
14
- /** Accessible label describing the attachment */
15
12
  label?: string;
16
- /** Called when the remove button is clicked */
17
13
  onRemove?: () => void;
18
- /** Called when the tile is clicked (e.g. to open a preview) */
19
14
  onClick?: () => void;
20
15
  className?: string;
21
16
  }
@@ -84,8 +84,6 @@ function AvatarFallback({ className, ...props }: React.ComponentProps<typeof Ava
84
84
  );
85
85
  }
86
86
 
87
- // ─── AvatarLabelGroup ─────────────────────────────────────────────────────────
88
-
89
87
  interface AvatarLabelGroupProps extends React.ComponentProps<"div"> {
90
88
  size?: "sm" | "md";
91
89
  src?: string;
@@ -122,8 +122,7 @@ function BarChart({
122
122
  if (texture && lead && entry.key === lead.key) {
123
123
  return `url(#bar-hatch-${reactId})`;
124
124
  }
125
- // Stacked segments read cleanest as flat solids — a per-segment gradient
126
- // banding looks like a drop shadow between bands. Grouped bars keep the fade.
125
+ // Stacked segments stay flat solids — per-segment gradients read as drop shadows between bands; grouped bars keep the fade.
127
126
  if (stacked) {
128
127
  return entry.color;
129
128
  }
@@ -27,8 +27,7 @@ const SEMANTIC_KEY = { error: "destructive", warning: "warning", success: "succe
27
27
  const PLACEHOLDER_HEIGHT = 168;
28
28
  // Cap the ramp off its palest end so low-rank bars stay legible on a light card.
29
29
  const RAMP_CEILING = 0.8;
30
- // Semantic bars keep a single hue: the lightest bar still holds this much colour
31
- // (mixed toward white) so a long error list never fades to near-invisible.
30
+ // The lightest semantic bar keeps this much hue (mixed toward white) so a long list never fades to near-invisible.
32
31
  const SEMANTIC_FLOOR = 0.62;
33
32
  const IN_FILL_SHADOW = "0 1px 2px rgb(0 0 0 / 0.28)";
34
33
 
@@ -3,6 +3,7 @@
3
3
  import { cn } from "../lib/cn";
4
4
 
5
5
  export interface ChartLegendItem {
6
+ key: string;
6
7
  name: string;
7
8
  color: string;
8
9
  dashed?: boolean;
@@ -12,10 +13,18 @@ export interface ChartLegendProps extends React.HTMLAttributes<HTMLDivElement> {
12
13
  items: ChartLegendItem[];
13
14
  align?: "left" | "center" | "right";
14
15
  insetLeft?: number;
16
+ hiddenKeys?: ReadonlySet<string>;
17
+ onItemClick?: (key: string) => void;
15
18
  }
16
19
 
17
20
  const ALIGN_CLASS = { left: "justify-start", center: "justify-center", right: "justify-end" } as const;
18
21
 
22
+ const ITEM_CLASS =
23
+ "inline-flex items-center gap-1.5 font-mono text-[10px] text-muted-foreground uppercase tracking-[0.12em]";
24
+
25
+ const INTERACTIVE_CLASS =
26
+ "rounded-sm outline-none transition-opacity focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card [@media(hover:hover)]:hover:text-foreground";
27
+
19
28
  function Swatch({ color, dashed }: { color: string; dashed?: boolean }) {
20
29
  return (
21
30
  <span
@@ -26,22 +35,50 @@ function Swatch({ color, dashed }: { color: string; dashed?: boolean }) {
26
35
  );
27
36
  }
28
37
 
29
- function ChartLegend({ items, align = "left", insetLeft, className, style, ...props }: ChartLegendProps) {
38
+ function ChartLegend({
39
+ items,
40
+ align = "left",
41
+ insetLeft,
42
+ hiddenKeys,
43
+ onItemClick,
44
+ className,
45
+ style,
46
+ ...props
47
+ }: ChartLegendProps) {
30
48
  return (
31
49
  <div
32
50
  className={cn("flex flex-wrap gap-x-4 gap-y-1.5", ALIGN_CLASS[align], className)}
33
51
  style={{ paddingLeft: align === "left" ? insetLeft : undefined, ...style }}
34
52
  {...props}
35
53
  >
36
- {items.map((item) => (
37
- <span
38
- key={item.name}
39
- className="inline-flex items-center gap-1.5 font-mono text-[10px] text-muted-foreground uppercase tracking-[0.12em]"
40
- >
41
- <Swatch color={item.color} dashed={item.dashed} />
42
- {item.name}
43
- </span>
44
- ))}
54
+ {items.map((item) => {
55
+ const swatchAndName = (
56
+ <>
57
+ <Swatch color={item.color} dashed={item.dashed} />
58
+ {item.name}
59
+ </>
60
+ );
61
+ if (!onItemClick) {
62
+ return (
63
+ <span key={item.key} className={ITEM_CLASS}>
64
+ {swatchAndName}
65
+ </span>
66
+ );
67
+ }
68
+ const hidden = hiddenKeys?.has(item.key) ?? false;
69
+ return (
70
+ <button
71
+ key={item.key}
72
+ type="button"
73
+ aria-label={`${item.name} series`}
74
+ aria-pressed={!hidden}
75
+ onClick={() => onItemClick(item.key)}
76
+ className={cn(ITEM_CLASS, INTERACTIVE_CLASS, hidden && "opacity-40")}
77
+ >
78
+ {swatchAndName}
79
+ </button>
80
+ );
81
+ })}
45
82
  </div>
46
83
  );
47
84
  }
@@ -19,13 +19,10 @@ export function makeChartAxis(theme: ChartTheme) {
19
19
  }
20
20
 
21
21
  export function makeLegendItems(resolved: ResolvedSeries[]) {
22
- return resolved.map((entry) => ({ name: entry.name, color: entry.color, dashed: entry.dashed }));
22
+ return resolved.map((entry) => ({ key: entry.key, name: entry.name, color: entry.color, dashed: entry.dashed }));
23
23
  }
24
24
 
25
- /**
26
- * Stacked series must reach the stack height (sum per x-point), not the tallest
27
- * single series, or reference bands and explicit Y domains clip a tall stack short.
28
- */
25
+ /** Stacked series must reach the stack height (sum per x-point), or reference bands and explicit Y domains clip a tall stack short. */
29
26
  export function computeNumericMax(data: ChartData, series: ChartSeries[], stacked: boolean) {
30
27
  let max = 0;
31
28
  for (const row of data) {
@@ -114,10 +111,7 @@ export function makeLastValueLabel(
114
111
  };
115
112
  }
116
113
 
117
- /**
118
- * Returns recharts elements (not a wrapper component) so recharts still detects
119
- * them as direct children when spread into a chart via `{renderReferenceLine(...)}`.
120
- */
114
+ /** Returns recharts elements (not a wrapper component) so recharts still detects them as direct chart children. */
121
115
  export function renderReferenceLine({
122
116
  referenceLine,
123
117
  numericMax,