@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.
- package/dist/components/accordion-card.d.mts +1 -5
- package/dist/components/accordion-card.mjs +1 -5
- package/dist/components/accordion.d.mts +1 -5
- package/dist/components/accordion.mjs +1 -5
- package/dist/components/attachment-tile.d.mts +0 -5
- package/dist/components/chart-legend.d.mts +4 -1
- package/dist/components/chart-legend.mjs +21 -7
- package/dist/components/chart-primitives.d.mts +3 -8
- package/dist/components/chart-primitives.mjs +3 -8
- package/dist/components/combobox.d.mts +0 -1
- package/dist/components/line-chart.d.mts +3 -1
- package/dist/components/line-chart.mjs +7 -4
- package/dist/components/select-trigger-variants.d.mts +1 -5
- package/dist/components/select-trigger-variants.mjs +1 -5
- package/dist/components/table.d.mts +1 -5
- package/dist/components/task-progress.d.mts +1 -4
- package/dist/lib/chart-palette.d.mts +1 -20
- package/dist/lib/chart-palette.mjs +1 -20
- package/dist/lib/chart.d.mts +1 -4
- package/dist/lib/chart.mjs +2 -11
- package/package.json +5 -5
- package/src/components/accordion-card.tsx +1 -5
- package/src/components/accordion.tsx +1 -5
- package/src/components/attachment-tile.tsx +0 -5
- package/src/components/avatar.tsx +0 -2
- package/src/components/bar-chart.tsx +1 -2
- package/src/components/bar-list.tsx +1 -2
- package/src/components/chart-legend.tsx +47 -10
- package/src/components/chart-primitives.tsx +3 -9
- package/src/components/combobox.tsx +1 -29
- package/src/components/dropdown-menu.tsx +0 -12
- package/src/components/form.tsx +0 -4
- package/src/components/heatmap-chart.tsx +4 -10
- package/src/components/line-chart.tsx +16 -3
- package/src/components/select-trigger-variants.ts +1 -5
- package/src/components/select.tsx +0 -10
- package/src/components/sidebar.tsx +0 -2
- package/src/components/table.tsx +1 -5
- package/src/components/tabs.tsx +1 -18
- package/src/components/tag.tsx +0 -6
- package/src/components/task-progress.tsx +2 -14
- package/src/components/wizard.tsx +0 -6
- package/src/lib/chart-palette.ts +3 -22
- package/src/lib/chart.ts +3 -15
- package/src/stories/button.stories.tsx +1 -15
- package/src/stories/combobox.stories.tsx +0 -12
- package/src/stories/dropdown-menu.stories.tsx +0 -4
- package/src/stories/form.stories.tsx +0 -6
- package/src/stories/heatmap-chart.stories.tsx +0 -1
- package/src/stories/input-group.stories.tsx +0 -4
- package/src/stories/input.stories.tsx +0 -8
- package/src/stories/line-chart.stories.tsx +120 -80
- package/src/stories/sidebar.stories.tsx +1 -4
- package/src/stories/skeleton.stories.tsx +0 -2
- package/src/stories/table.stories.tsx +0 -5
- package/src/stories/tabs.stories.tsx +0 -11
- package/src/stories/toggle-group.stories.tsx +0 -5
- package/src/stories/wizard.stories.tsx +0 -4
|
@@ -10,8 +10,6 @@ import { Popover, PopoverContent, PopoverTrigger } from "./popover";
|
|
|
10
10
|
import { selectTriggerVariants } from "./select-trigger-variants";
|
|
11
11
|
import { TagDismissible } from "./tag";
|
|
12
12
|
|
|
13
|
-
/* ── Context ──────────────────────────────────────────────────────────────── */
|
|
14
|
-
|
|
15
13
|
interface ComboboxContextValue {
|
|
16
14
|
multiple: boolean;
|
|
17
15
|
value: string | null;
|
|
@@ -35,8 +33,6 @@ function useComboboxContext() {
|
|
|
35
33
|
return context;
|
|
36
34
|
}
|
|
37
35
|
|
|
38
|
-
/* ── Root ─────────────────────────────────────────────────────────────────── */
|
|
39
|
-
|
|
40
36
|
interface ComboboxBaseProps {
|
|
41
37
|
children: ReactNode;
|
|
42
38
|
open?: boolean;
|
|
@@ -72,12 +68,10 @@ function Combobox(props: ComboboxProps) {
|
|
|
72
68
|
getOptionLabel,
|
|
73
69
|
} = props;
|
|
74
70
|
|
|
75
|
-
// Single mode state
|
|
76
71
|
const [uncontrolledSingleValue, setUncontrolledSingleValue] = useState<string | null>(
|
|
77
72
|
!multiple ? ((props as ComboboxSingleProps).defaultValue ?? null) : null,
|
|
78
73
|
);
|
|
79
74
|
|
|
80
|
-
// Multi mode state
|
|
81
75
|
const [uncontrolledMultiValue, setUncontrolledMultiValue] = useState<string[]>(
|
|
82
76
|
multiple ? ((props as ComboboxMultipleProps).defaultValue ?? []) : [],
|
|
83
77
|
);
|
|
@@ -97,7 +91,6 @@ function Combobox(props: ComboboxProps) {
|
|
|
97
91
|
[isOpenControlled, controlledOnOpenChange],
|
|
98
92
|
);
|
|
99
93
|
|
|
100
|
-
// Resolve current values
|
|
101
94
|
const singleValue = multiple
|
|
102
95
|
? null
|
|
103
96
|
: (((props as ComboboxSingleProps).value !== undefined
|
|
@@ -136,7 +129,7 @@ function Combobox(props: ComboboxProps) {
|
|
|
136
129
|
setUncontrolledMultiValue(next);
|
|
137
130
|
}
|
|
138
131
|
onValueChangeMulti?.(next);
|
|
139
|
-
//
|
|
132
|
+
// Intentionally stays open in multi mode so several items can be picked.
|
|
140
133
|
} else {
|
|
141
134
|
if (!isControlledSingle) {
|
|
142
135
|
setUncontrolledSingleValue(itemValue);
|
|
@@ -194,8 +187,6 @@ function Combobox(props: ComboboxProps) {
|
|
|
194
187
|
);
|
|
195
188
|
}
|
|
196
189
|
|
|
197
|
-
/* ── Trigger ──────────────────────────────────────────────────────────────── */
|
|
198
|
-
|
|
199
190
|
interface ComboboxTriggerProps
|
|
200
191
|
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "size">,
|
|
201
192
|
VariantProps<typeof selectTriggerVariants> {
|
|
@@ -232,8 +223,6 @@ function ComboboxTrigger({ className, size, placeholder, children, ...props }: C
|
|
|
232
223
|
);
|
|
233
224
|
}
|
|
234
225
|
|
|
235
|
-
/* ── Tags (internal, for multi-select trigger) ────────────────────────────── */
|
|
236
|
-
|
|
237
226
|
function ComboboxTags({ values, onDeselect }: { values: string[]; onDeselect: (value: string) => void }) {
|
|
238
227
|
const { getOptionLabel } = useComboboxContext();
|
|
239
228
|
return (
|
|
@@ -251,8 +240,6 @@ function ComboboxTags({ values, onDeselect }: { values: string[]; onDeselect: (v
|
|
|
251
240
|
);
|
|
252
241
|
}
|
|
253
242
|
|
|
254
|
-
/* ── Content ──────────────────────────────────────────────────────────────── */
|
|
255
|
-
|
|
256
243
|
interface ComboboxContentProps extends React.ComponentProps<typeof PopoverContent> {
|
|
257
244
|
className?: string;
|
|
258
245
|
children?: ReactNode;
|
|
@@ -280,8 +267,6 @@ function ComboboxContent({ className, children, filter, ...props }: ComboboxCont
|
|
|
280
267
|
);
|
|
281
268
|
}
|
|
282
269
|
|
|
283
|
-
/* ── Search ───────────────────────────────────────────────────────────────── */
|
|
284
|
-
|
|
285
270
|
function ComboboxSearch({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Input>) {
|
|
286
271
|
return (
|
|
287
272
|
<div data-slot="combobox-search" className="flex items-center gap-2 border-b border-border-secondary px-3 py-2.5">
|
|
@@ -300,8 +285,6 @@ function ComboboxSearch({ className, ...props }: React.ComponentProps<typeof Com
|
|
|
300
285
|
);
|
|
301
286
|
}
|
|
302
287
|
|
|
303
|
-
/* ── List ─────────────────────────────────────────────────────────────────── */
|
|
304
|
-
|
|
305
288
|
function ComboboxList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>) {
|
|
306
289
|
return (
|
|
307
290
|
<CommandPrimitive.List
|
|
@@ -312,8 +295,6 @@ function ComboboxList({ className, ...props }: React.ComponentProps<typeof Comma
|
|
|
312
295
|
);
|
|
313
296
|
}
|
|
314
297
|
|
|
315
|
-
/* ── Empty ────────────────────────────────────────────────────────────────── */
|
|
316
|
-
|
|
317
298
|
function ComboboxEmpty({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Empty>) {
|
|
318
299
|
return (
|
|
319
300
|
<CommandPrimitive.Empty
|
|
@@ -324,8 +305,6 @@ function ComboboxEmpty({ className, ...props }: React.ComponentProps<typeof Comm
|
|
|
324
305
|
);
|
|
325
306
|
}
|
|
326
307
|
|
|
327
|
-
/* ── Group ────────────────────────────────────────────────────────────────── */
|
|
328
|
-
|
|
329
308
|
function ComboboxGroup({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Group>) {
|
|
330
309
|
return (
|
|
331
310
|
<CommandPrimitive.Group
|
|
@@ -339,8 +318,6 @@ function ComboboxGroup({ className, ...props }: React.ComponentProps<typeof Comm
|
|
|
339
318
|
);
|
|
340
319
|
}
|
|
341
320
|
|
|
342
|
-
/* ── Separator ────────────────────────────────────────────────────────────── */
|
|
343
|
-
|
|
344
321
|
function ComboboxSeparator({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Separator>) {
|
|
345
322
|
return (
|
|
346
323
|
<CommandPrimitive.Separator
|
|
@@ -351,10 +328,7 @@ function ComboboxSeparator({ className, ...props }: React.ComponentProps<typeof
|
|
|
351
328
|
);
|
|
352
329
|
}
|
|
353
330
|
|
|
354
|
-
/* ── Item ─────────────────────────────────────────────────────────────────── */
|
|
355
|
-
|
|
356
331
|
interface ComboboxItemProps extends Omit<React.ComponentProps<typeof CommandPrimitive.Item>, "onSelect"> {
|
|
357
|
-
/** The value stored when this item is selected */
|
|
358
332
|
itemValue: string;
|
|
359
333
|
}
|
|
360
334
|
|
|
@@ -384,8 +358,6 @@ function ComboboxItem({ className, children, itemValue, ...props }: ComboboxItem
|
|
|
384
358
|
);
|
|
385
359
|
}
|
|
386
360
|
|
|
387
|
-
/* ── Item supporting text ─────────────────────────────────────────────────── */
|
|
388
|
-
|
|
389
361
|
function ComboboxItemText({ className, children, ...props }: React.HTMLAttributes<HTMLSpanElement>) {
|
|
390
362
|
return (
|
|
391
363
|
<span
|
|
@@ -51,8 +51,6 @@ function DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMen
|
|
|
51
51
|
return <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
/* ── Item ─────────────────────────────────────────────────────────────────── */
|
|
55
|
-
|
|
56
54
|
const dropdownMenuItemVariants = cva(
|
|
57
55
|
[
|
|
58
56
|
"relative flex cursor-default items-center gap-2 rounded-sm px-2.5 py-2 outline-hidden select-none",
|
|
@@ -103,8 +101,6 @@ function DropdownMenuItem({
|
|
|
103
101
|
);
|
|
104
102
|
}
|
|
105
103
|
|
|
106
|
-
/* ── Label ────────────────────────────────────────────────────────────────── */
|
|
107
|
-
|
|
108
104
|
function DropdownMenuLabel({
|
|
109
105
|
className,
|
|
110
106
|
inset,
|
|
@@ -121,8 +117,6 @@ function DropdownMenuLabel({
|
|
|
121
117
|
);
|
|
122
118
|
}
|
|
123
119
|
|
|
124
|
-
/* ── Header (avatar group) ────────────────────────────────────────────────── */
|
|
125
|
-
|
|
126
120
|
function DropdownMenuHeader({ className, children, ...props }: React.HTMLAttributes<HTMLDivElement>) {
|
|
127
121
|
return (
|
|
128
122
|
<div
|
|
@@ -135,8 +129,6 @@ function DropdownMenuHeader({ className, children, ...props }: React.HTMLAttribu
|
|
|
135
129
|
);
|
|
136
130
|
}
|
|
137
131
|
|
|
138
|
-
/* ── Separator ────────────────────────────────────────────────────────────── */
|
|
139
|
-
|
|
140
132
|
function DropdownMenuSeparator({ className, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
|
141
133
|
return (
|
|
142
134
|
<DropdownMenuPrimitive.Separator
|
|
@@ -147,8 +139,6 @@ function DropdownMenuSeparator({ className, ...props }: React.ComponentProps<typ
|
|
|
147
139
|
);
|
|
148
140
|
}
|
|
149
141
|
|
|
150
|
-
/* ── Shortcut ─────────────────────────────────────────────────────────────── */
|
|
151
|
-
|
|
152
142
|
function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">) {
|
|
153
143
|
return (
|
|
154
144
|
<span
|
|
@@ -162,8 +152,6 @@ function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"spa
|
|
|
162
152
|
);
|
|
163
153
|
}
|
|
164
154
|
|
|
165
|
-
/* ── Sub menu ─────────────────────────────────────────────────────────────── */
|
|
166
|
-
|
|
167
155
|
function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
|
168
156
|
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
|
|
169
157
|
}
|
package/src/components/form.tsx
CHANGED
|
@@ -166,8 +166,6 @@ function FormMessage({ className, ...props }: React.ComponentProps<"p">) {
|
|
|
166
166
|
);
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
/* ── Layout components ───────────────────────────────────────────────────── */
|
|
170
|
-
|
|
171
169
|
interface FormHeaderProps extends React.ComponentProps<"div"> {
|
|
172
170
|
title: string;
|
|
173
171
|
description?: string;
|
|
@@ -186,8 +184,6 @@ function FormFields({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
186
184
|
return <div className={cn("flex flex-col gap-6", className)} {...props} />;
|
|
187
185
|
}
|
|
188
186
|
|
|
189
|
-
/* ── Convenience field wrappers ─────────────────────────────────────────── */
|
|
190
|
-
|
|
191
187
|
interface FormFieldBaseProps<TFieldValues extends FieldValues, TName extends FieldPath<TFieldValues>> {
|
|
192
188
|
control: ControllerProps<TFieldValues, TName>["control"];
|
|
193
189
|
name: TName;
|
|
@@ -129,16 +129,13 @@ function HeatmapChart({
|
|
|
129
129
|
const { columns, rows, cells, maxValue, peakKey } = layout;
|
|
130
130
|
const isEmpty = columns.length === 0 || rows.length === 0 || maxValue <= 0;
|
|
131
131
|
|
|
132
|
-
// "rank"
|
|
133
|
-
// by its position among the distinct non-zero values rather than its raw ratio
|
|
134
|
-
// to the max — the right read for skewed activity counts (à la GitHub).
|
|
132
|
+
// "rank" colours each cell by its position among distinct non-zero values, spreading skewed activity counts across the whole ramp (à la GitHub).
|
|
135
133
|
const colorFractionOf = React.useMemo(() => {
|
|
136
134
|
if (colorScale === "rank") {
|
|
137
135
|
const sorted = [...new Set(cells.map((cell) => cell.value).filter((value) => value > 0))].sort(
|
|
138
136
|
(lower, upper) => lower - upper,
|
|
139
137
|
);
|
|
140
|
-
// Floor non-zero ranks above the empty colour so the quietest active day
|
|
141
|
-
// still reads as coloured, never mistaken for no data.
|
|
138
|
+
// Floor non-zero ranks above the empty colour so the quietest active day is never mistaken for no data.
|
|
142
139
|
const RANK_FLOOR = 0.18;
|
|
143
140
|
const fractionByValue = new Map(
|
|
144
141
|
sorted.map((value, index) => [
|
|
@@ -189,9 +186,7 @@ function HeatmapChart({
|
|
|
189
186
|
const formatX = (label: string) => (xTickFormatter ? xTickFormatter(label) : label);
|
|
190
187
|
const formatY = (label: string) => (yTickFormatter ? yTickFormatter(label) : label);
|
|
191
188
|
|
|
192
|
-
// The tooltip
|
|
193
|
-
// clipped ancestor (e.g. the card's mount animation + overflow-hidden) can't
|
|
194
|
-
// shift or trim it. Flip near the viewport edges.
|
|
189
|
+
// The tooltip renders through a portal so a transformed/clipped ancestor (e.g. the card's mount animation + overflow-hidden) can't shift or trim it.
|
|
195
190
|
const tooltipLeft =
|
|
196
191
|
hovered && hovered.x + TOOLTIP_OFFSET + TOOLTIP_WIDTH > window.innerWidth
|
|
197
192
|
? hovered.x - TOOLTIP_OFFSET - TOOLTIP_WIDTH
|
|
@@ -268,8 +263,7 @@ function HeatmapChart({
|
|
|
268
263
|
/>
|
|
269
264
|
);
|
|
270
265
|
})}
|
|
271
|
-
{/* Transparent hit layer over the full pitch so
|
|
272
|
-
between dots — registers hover uniformly. */}
|
|
266
|
+
{/* Transparent hit layer over the full pitch so cells and the gaps between dots register hover uniformly. */}
|
|
273
267
|
{cells.map((cell) => (
|
|
274
268
|
// biome-ignore lint/a11y/noStaticElementInteractions: decorative hover tooltip; all values are visible on the cells
|
|
275
269
|
<rect
|
|
@@ -48,6 +48,8 @@ export interface LineChartProps {
|
|
|
48
48
|
markers?: ChartMarker[];
|
|
49
49
|
lastValueLabel?: boolean;
|
|
50
50
|
loading?: boolean;
|
|
51
|
+
hiddenSeries?: ReadonlySet<string>;
|
|
52
|
+
onLegendItemClick?: (key: string) => void;
|
|
51
53
|
valueFormatter?: (value: number) => string;
|
|
52
54
|
labelFormatter?: (label: string | number) => string;
|
|
53
55
|
className?: string;
|
|
@@ -69,6 +71,8 @@ function LineChart({
|
|
|
69
71
|
markers,
|
|
70
72
|
lastValueLabel = false,
|
|
71
73
|
loading = false,
|
|
74
|
+
hiddenSeries,
|
|
75
|
+
onLegendItemClick,
|
|
72
76
|
valueFormatter = (value) => value.toLocaleString("en-US"),
|
|
73
77
|
labelFormatter,
|
|
74
78
|
className,
|
|
@@ -76,8 +80,9 @@ function LineChart({
|
|
|
76
80
|
const { palette: paletteColors, theme } = useChartContext(palette);
|
|
77
81
|
|
|
78
82
|
const resolved = resolveSeries(series, paletteColors, theme);
|
|
83
|
+
const visible = resolved.filter((entry) => !hiddenSeries?.has(entry.key));
|
|
79
84
|
|
|
80
|
-
const numericMax = React.useMemo(() => computeNumericMax(data,
|
|
85
|
+
const numericMax = React.useMemo(() => computeNumericMax(data, visible, false), [data, visible]);
|
|
81
86
|
|
|
82
87
|
const curveType = CURVE_TYPE[curve];
|
|
83
88
|
const margin = { top: markers?.length ? 18 : 8, right: lastValueLabel ? 56 : 8, bottom: 2, left: 0 };
|
|
@@ -129,7 +134,7 @@ function LineChart({
|
|
|
129
134
|
/>
|
|
130
135
|
{renderReferenceLine({ referenceLine, numericMax, theme })}
|
|
131
136
|
|
|
132
|
-
{
|
|
137
|
+
{visible.map((entry) => (
|
|
133
138
|
<Line
|
|
134
139
|
key={entry.key}
|
|
135
140
|
type={curveType}
|
|
@@ -159,7 +164,15 @@ function LineChart({
|
|
|
159
164
|
)}
|
|
160
165
|
</div>
|
|
161
166
|
|
|
162
|
-
{legend && !isEmpty &&
|
|
167
|
+
{legend && !isEmpty && (
|
|
168
|
+
<ChartLegend
|
|
169
|
+
items={legendItems}
|
|
170
|
+
align={legendAlign}
|
|
171
|
+
insetLeft={yAxisWidth}
|
|
172
|
+
hiddenKeys={hiddenSeries}
|
|
173
|
+
onItemClick={onLegendItemClick}
|
|
174
|
+
/>
|
|
175
|
+
)}
|
|
163
176
|
</div>
|
|
164
177
|
);
|
|
165
178
|
}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { cva } from "class-variance-authority";
|
|
2
2
|
|
|
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
|
export const selectTriggerVariants = cva(
|
|
9
5
|
[
|
|
10
6
|
"flex w-full items-center gap-2 rounded-md border bg-background text-foreground shadow-xs outline-hidden",
|
|
@@ -20,8 +20,6 @@ function SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.V
|
|
|
20
20
|
return <SelectPrimitive.Value data-slot="select-value" {...props} />;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
/* ── Trigger ──────────────────────────────────────────────────────────────── */
|
|
24
|
-
|
|
25
23
|
function SelectTrigger({
|
|
26
24
|
className,
|
|
27
25
|
size = "md",
|
|
@@ -47,8 +45,6 @@ function SelectTrigger({
|
|
|
47
45
|
);
|
|
48
46
|
}
|
|
49
47
|
|
|
50
|
-
/* ── Content ──────────────────────────────────────────────────────────────── */
|
|
51
|
-
|
|
52
48
|
function SelectContent({
|
|
53
49
|
className,
|
|
54
50
|
children,
|
|
@@ -89,8 +85,6 @@ function SelectContent({
|
|
|
89
85
|
);
|
|
90
86
|
}
|
|
91
87
|
|
|
92
|
-
/* ── Label ────────────────────────────────────────────────────────────────── */
|
|
93
|
-
|
|
94
88
|
function SelectLabel({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
|
95
89
|
return (
|
|
96
90
|
<SelectPrimitive.Label
|
|
@@ -101,8 +95,6 @@ function SelectLabel({ className, ...props }: React.ComponentProps<typeof Select
|
|
|
101
95
|
);
|
|
102
96
|
}
|
|
103
97
|
|
|
104
|
-
/* ── Item ─────────────────────────────────────────────────────────────────── */
|
|
105
|
-
|
|
106
98
|
function SelectItem({ className, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
|
107
99
|
return (
|
|
108
100
|
<SelectPrimitive.Item
|
|
@@ -128,8 +120,6 @@ function SelectItem({ className, children, ...props }: React.ComponentProps<type
|
|
|
128
120
|
);
|
|
129
121
|
}
|
|
130
122
|
|
|
131
|
-
/* ── Separator ────────────────────────────────────────────────────────────── */
|
|
132
|
-
|
|
133
123
|
function SelectSeparator({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
|
134
124
|
return (
|
|
135
125
|
<SelectPrimitive.Separator
|
|
@@ -88,7 +88,6 @@ function SidebarProvider({
|
|
|
88
88
|
[setOpenProp, open],
|
|
89
89
|
);
|
|
90
90
|
|
|
91
|
-
// Helper to toggle the sidebar.
|
|
92
91
|
const toggleSidebar = React.useCallback(() => {
|
|
93
92
|
return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
|
|
94
93
|
}, [isMobile, setOpen]);
|
|
@@ -240,7 +239,6 @@ function Sidebar({
|
|
|
240
239
|
side === "left"
|
|
241
240
|
? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
|
|
242
241
|
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
|
|
243
|
-
// Adjust the padding for floating and inset variants.
|
|
244
242
|
variant === "floating" || variant === "inset"
|
|
245
243
|
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
|
|
246
244
|
: "border-sidebar-border group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
|
package/src/components/table.tsx
CHANGED
|
@@ -75,11 +75,7 @@ function TableHead({ className, ...props }: React.ComponentProps<"th">) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
interface TableCellProps extends React.ComponentProps<"td"> {
|
|
78
|
-
/**
|
|
79
|
-
* When true, the cell renders edge-to-edge so the child can act as the
|
|
80
|
-
* interactive surface (e.g. a button or popover trigger filling the cell).
|
|
81
|
-
* Defaults to false (standard padded cell).
|
|
82
|
-
*/
|
|
78
|
+
/** Renders the cell edge-to-edge so the child (e.g. a button or popover trigger) can fill it as the interactive surface. */
|
|
83
79
|
interactive?: boolean;
|
|
84
80
|
}
|
|
85
81
|
|
package/src/components/tabs.tsx
CHANGED
|
@@ -1,17 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
/*
|
|
4
|
-
* Two tab families, one visual system:
|
|
5
|
-
*
|
|
6
|
-
* - Tabs / TabsList / TabsTrigger / TabsContent — state-managed.
|
|
7
|
-
* Use when tab content lives in the same page (e.g. "Code" vs "Preview").
|
|
8
|
-
*
|
|
9
|
-
* - TabsNav / TabsNavList / TabsNavTrigger — semantic <nav>/<ul>/<a>, URL-based.
|
|
10
|
-
* Use when each tab is a route (e.g. settings pages). Pair with <Link> via asChild.
|
|
11
|
-
*
|
|
12
|
-
* Both share `tabsTriggerVariants` for visual styles (colors, spacing, active state).
|
|
13
|
-
* Layout concerns (flex-1, orientation group selectors) stay component-specific.
|
|
14
|
-
*/
|
|
3
|
+
/* Two families sharing `tabsTriggerVariants`: Tabs for in-page state-switched content, TabsNav (semantic <nav>/<ul>/<a>) for URL-routed tabs. */
|
|
15
4
|
|
|
16
5
|
import { Slot } from "@radix-ui/react-slot";
|
|
17
6
|
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
|
@@ -21,8 +10,6 @@ import { createContext, use } from "react";
|
|
|
21
10
|
|
|
22
11
|
import { cn } from "../lib/cn";
|
|
23
12
|
|
|
24
|
-
/* ─── Shared trigger styles ──────────────────────────────────────────────── */
|
|
25
|
-
|
|
26
13
|
const tabsTriggerVariants = cva(
|
|
27
14
|
[
|
|
28
15
|
"type-text-sm items-center gap-1.5 font-medium",
|
|
@@ -57,8 +44,6 @@ const tabsTriggerVariants = cva(
|
|
|
57
44
|
},
|
|
58
45
|
);
|
|
59
46
|
|
|
60
|
-
/* ─── Tabs (state-based, in-page content switching) ────────────────── */
|
|
61
|
-
|
|
62
47
|
function Tabs({ className, orientation = "horizontal", ...props }: React.ComponentProps<typeof TabsPrimitive.Root>) {
|
|
63
48
|
return (
|
|
64
49
|
<TabsPrimitive.Root
|
|
@@ -134,8 +119,6 @@ function TabsContent({ className, ...props }: React.ComponentProps<typeof TabsPr
|
|
|
134
119
|
return <TabsPrimitive.Content data-slot="tabs-content" className={cn("flex-1 outline-none", className)} {...props} />;
|
|
135
120
|
}
|
|
136
121
|
|
|
137
|
-
/* ─── Navigation tabs (semantic <nav>/<ul>/<a>, for URL-based routing) ──── */
|
|
138
|
-
|
|
139
122
|
type TabsNavVariant = "line" | "pill";
|
|
140
123
|
type TabsNavOrientation = "horizontal" | "vertical";
|
|
141
124
|
|
package/src/components/tag.tsx
CHANGED
|
@@ -9,8 +9,6 @@ interface TagBaseProps {
|
|
|
9
9
|
icon?: React.ReactNode;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
/* ── Tag (text only) ──────────────────────────────────────────── */
|
|
13
|
-
|
|
14
12
|
interface TagProps extends React.ComponentProps<"span">, TagBaseProps {}
|
|
15
13
|
|
|
16
14
|
function Tag({ className, icon, children, ...props }: TagProps) {
|
|
@@ -22,8 +20,6 @@ function Tag({ className, icon, children, ...props }: TagProps) {
|
|
|
22
20
|
);
|
|
23
21
|
}
|
|
24
22
|
|
|
25
|
-
/* ── TagDismissible (with × button) ───────────────────────────── */
|
|
26
|
-
|
|
27
23
|
interface TagDismissibleProps extends React.ComponentProps<"span">, TagBaseProps {
|
|
28
24
|
onDismiss?: () => void;
|
|
29
25
|
}
|
|
@@ -61,8 +57,6 @@ function TagDismissible({ className, icon, children, onDismiss, ...props }: TagD
|
|
|
61
57
|
);
|
|
62
58
|
}
|
|
63
59
|
|
|
64
|
-
/* ── TagCount (with count badge) ──────────────────────────────── */
|
|
65
|
-
|
|
66
60
|
interface TagCountProps extends React.ComponentProps<"span">, TagBaseProps {
|
|
67
61
|
count: number;
|
|
68
62
|
}
|
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
/*
|
|
4
|
-
* TaskProgress — multi-step async progress primitive.
|
|
5
|
-
*
|
|
6
|
-
* Dumb component: the consumer owns orchestration (timer, websocket, polling) and
|
|
7
|
-
* passes `steps` with each step's status. Renders a percentage bar at the top
|
|
8
|
-
* and one row per step with done/running/pending state badges.
|
|
9
|
-
*
|
|
10
|
-
* `trailingLabel` is for "still working on something not in the step list" —
|
|
11
|
-
* shows after the last step as a running row that isn't counted in the percent.
|
|
12
|
-
*/
|
|
3
|
+
/* Dumb component: the consumer owns orchestration (timer, websocket, polling) and passes each step's status. */
|
|
13
4
|
|
|
14
5
|
import { CheckIcon } from "lucide-react";
|
|
15
6
|
|
|
@@ -27,10 +18,7 @@ interface TaskProgressStep {
|
|
|
27
18
|
interface TaskProgressProps extends Omit<React.ComponentProps<"div">, "children"> {
|
|
28
19
|
steps: readonly TaskProgressStep[];
|
|
29
20
|
trailingLabel?: string;
|
|
30
|
-
/**
|
|
31
|
-
* Optional mount-time stagger: each row fades + slides in with `animation-delay = index × stepRevealDelayMs`.
|
|
32
|
-
* Pure CSS, runs once on mount. Omit for no animation.
|
|
33
|
-
*/
|
|
21
|
+
/** Mount-time stagger: each row fades in after `index × stepRevealDelayMs`; omit for no animation. */
|
|
34
22
|
stepRevealDelayMs?: number;
|
|
35
23
|
}
|
|
36
24
|
|
package/src/lib/chart-palette.ts
CHANGED
|
@@ -1,18 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Chart palettes — the locked "paired system" from the analytics-v2 design.
|
|
3
|
-
*
|
|
4
|
-
* These are charting-API color values (consumed by Recharts at draw time, which
|
|
5
|
-
* cannot read CSS custom properties), so per the design-system rules they live
|
|
6
|
-
* as documented hex constants rather than `--color-*` tokens. They are
|
|
7
|
-
* theme-independent: the same series colors read on light and dark canvases.
|
|
8
|
-
* Only the chrome (grid, axis text, tooltip surface, semantic colors) is
|
|
9
|
-
* theme-aware — see `useChartTheme`.
|
|
10
|
-
*
|
|
11
|
-
* Rules baked in:
|
|
12
|
-
* - Pink leads (index 0) — never buried, fixing the V1 "pink last" bug.
|
|
13
|
-
* - Adjacent dashboard cards alternate lead palette (magenta / cyan) — the
|
|
14
|
-
* page decides which to pass; the component just receives one.
|
|
15
|
-
*/
|
|
1
|
+
// Theme-independent hex constants (Recharts can't read CSS custom properties); pink leads at index 0 and adjacent cards alternate magenta/cyan lead palettes.
|
|
16
2
|
|
|
17
3
|
export const MAGENTA_PALETTE = [
|
|
18
4
|
"#da1b6a",
|
|
@@ -46,8 +32,7 @@ export const CHART_PALETTES: Record<ChartPaletteName, readonly string[]> = {
|
|
|
46
32
|
export const heatRampMagenta = (empty: string) => [empty, "#5b0a31", "#a3034a", "#e90060", "#ff7eb6"];
|
|
47
33
|
export const heatRampMint = (empty: string) => [empty, "#0c4a52", "#17b8cf", "#41ddc9", "#6eece7"];
|
|
48
34
|
|
|
49
|
-
//
|
|
50
|
-
// light/dark pair rather than a `--color-*` token (heatmaps draw to SVG fills).
|
|
35
|
+
// The only theme-dependent charting value; a light/dark pair rather than a `--color-*` token because heatmaps draw to SVG fills.
|
|
51
36
|
export const HEAT_EMPTY = { light: "#eef3f3", dark: "#102222" } as const;
|
|
52
37
|
|
|
53
38
|
const HEAT_RAMPS: Record<ChartPaletteName, (empty: string) => string[]> = {
|
|
@@ -99,11 +84,7 @@ export const rampColor = (palette: ChartPaletteName, fraction: number) => {
|
|
|
99
84
|
return mixHex(from, to, fraction);
|
|
100
85
|
};
|
|
101
86
|
|
|
102
|
-
/**
|
|
103
|
-
* Interpolate continuously across a multi-stop heat ramp (e.g. `heatRampMagenta`),
|
|
104
|
-
* so a normalized 0..1 value reads as a smooth single-hue gradient rather than
|
|
105
|
-
* the five discrete bands.
|
|
106
|
-
*/
|
|
87
|
+
/** Interpolates continuously across the ramp so a 0..1 value reads as a smooth gradient rather than five discrete bands. */
|
|
107
88
|
export const heatColor = (stops: readonly string[], fraction: number) => {
|
|
108
89
|
const clamped = Math.min(1, Math.max(0, fraction));
|
|
109
90
|
const segment = (stops.length - 1) * clamped;
|
package/src/lib/chart.ts
CHANGED
|
@@ -2,10 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import type { ChartTheme } from "../hooks/use-chart-theme";
|
|
3
3
|
import { luminance, paletteColor } from "./chart-palette";
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Declarative description of one plotted series. The same shape drives area,
|
|
7
|
-
* line and bar charts — what differs is how each chart renders it.
|
|
8
|
-
*/
|
|
5
|
+
/** One plotted series; the same shape drives area, line and bar charts. */
|
|
9
6
|
export interface ChartSeries {
|
|
10
7
|
key: string;
|
|
11
8
|
name?: string;
|
|
@@ -31,11 +28,7 @@ const semanticColor = (theme: ChartTheme, semantic: NonNullable<ChartSeries["sem
|
|
|
31
28
|
return theme.success;
|
|
32
29
|
};
|
|
33
30
|
|
|
34
|
-
/**
|
|
35
|
-
* Resolve each series to a concrete color and name. Color precedence:
|
|
36
|
-
* explicit `color` → `semantic` token → palette slot by declared index (so the
|
|
37
|
-
* lead series keeps the lead color even after the bands are reordered).
|
|
38
|
-
*/
|
|
31
|
+
/** Palette fallback uses the declared index so the lead series keeps the lead color even after reordering. */
|
|
39
32
|
export const resolveSeries = (
|
|
40
33
|
series: readonly ChartSeries[],
|
|
41
34
|
palette: readonly string[],
|
|
@@ -47,12 +40,7 @@ export const resolveSeries = (
|
|
|
47
40
|
color: entry.color ?? (entry.semantic ? semanticColor(theme, entry.semantic) : paletteColor(palette, index)),
|
|
48
41
|
}));
|
|
49
42
|
|
|
50
|
-
/**
|
|
51
|
-
* Stacked bands read cleanest as a vertical gradient: darkest at the baseline,
|
|
52
|
-
* lightest at the top edge. Sorting by luminance enforces that for any palette
|
|
53
|
-
* (this is what fixed the "muddy cyan" stack in the lab). Render order maps to
|
|
54
|
-
* stack order in Recharts — first entry sits at the bottom.
|
|
55
|
-
*/
|
|
43
|
+
/** Stacked bands read cleanest darkest-at-baseline to lightest-on-top; sorting by luminance enforces that for any palette. */
|
|
56
44
|
export const orderByLuminance = (series: ResolvedSeries[]) =>
|
|
57
45
|
[...series].sort((lower, upper) => luminance(lower.color) - luminance(upper.color));
|
|
58
46
|
|