@matthieumordrel/chart-studio 0.2.2 → 0.2.4

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.
@@ -4,7 +4,7 @@ import { ChartDropdownPanel } from "./chart-dropdown.mjs";
4
4
  import { ChartMetricPanel } from "./chart-metric-panel.mjs";
5
5
  import { useRef, useState } from "react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
- import { ChevronDown, TrendingUpDown } from "lucide-react";
7
+ import { ChevronDown, MoveVertical } from "lucide-react";
8
8
  //#region src/ui/chart-metric-selector.tsx
9
9
  /**
10
10
  * Metric selector — trigger button + popover wrapping ChartMetricPanel.
@@ -28,7 +28,7 @@ function ChartMetricSelector({ className }) {
28
28
  className: `inline-flex h-7 items-center gap-1.5 rounded-lg border px-2.5 text-xs font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/20 ${isActive ? "border-primary/30 bg-primary/5 text-primary shadow-sm shadow-primary/5 hover:bg-primary/8" : "border-border/50 bg-background text-muted-foreground shadow-sm hover:border-border hover:bg-muted/30 hover:shadow hover:text-foreground"}`,
29
29
  "aria-label": "Metric",
30
30
  children: [
31
- /* @__PURE__ */ jsx(TrendingUpDown, { className: "h-3 w-3" }),
31
+ /* @__PURE__ */ jsx(MoveVertical, { className: "h-3 w-3" }),
32
32
  /* @__PURE__ */ jsx("span", { children: label }),
33
33
  isActive && !includeZeros && /* @__PURE__ */ jsx("span", {
34
34
  className: "rounded bg-muted px-1 py-px text-[9px] font-normal text-muted-foreground",
@@ -4,11 +4,6 @@ import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { ChevronDown } from "lucide-react";
5
5
  //#region src/ui/chart-select.tsx
6
6
  /**
7
- * Custom select dropdown — premium replacement for native <select> elements.
8
- * Uses fixed positioning so the options list works correctly even inside
9
- * overflow-hidden containers (e.g. the toolbar overflow panel).
10
- */
11
- /**
12
7
  * Premium styled select dropdown with highlight-only selection styling.
13
8
  *
14
9
  * @property value - Currently selected value
@@ -17,7 +12,7 @@ import { ChevronDown } from "lucide-react";
17
12
  * @property ariaLabel - Accessible label for the trigger
18
13
  * @property className - Additional CSS classes
19
14
  */
20
- function ChartSelect({ value, options, onChange, ariaLabel, className }) {
15
+ function ChartSelect({ value, options, onChange, ariaLabel, icon: Icon, hideIcon, className }) {
21
16
  const [isOpen, setIsOpen] = useState(false);
22
17
  const triggerRef = useRef(null);
23
18
  const selected = options.find((o) => o.value === value);
@@ -37,10 +32,14 @@ function ChartSelect({ value, options, onChange, ariaLabel, className }) {
37
32
  onClick: handleToggle,
38
33
  className: "inline-flex h-7 items-center gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 text-xs font-medium text-foreground shadow-sm transition-all hover:border-border hover:bg-muted/30 hover:shadow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/20",
39
34
  "aria-label": ariaLabel,
40
- children: [/* @__PURE__ */ jsx("span", {
41
- className: "truncate",
42
- children: selected?.label ?? value
43
- }), /* @__PURE__ */ jsx(ChevronDown, { className: `h-3 w-3 shrink-0 text-muted-foreground/60 transition-transform ${isOpen ? "rotate-180" : ""}` })]
35
+ children: [
36
+ Icon && !hideIcon && /* @__PURE__ */ jsx(Icon, { className: "h-3 w-3 shrink-0 text-muted-foreground" }),
37
+ /* @__PURE__ */ jsx("span", {
38
+ className: "truncate",
39
+ children: selected?.label ?? value
40
+ }),
41
+ /* @__PURE__ */ jsx(ChevronDown, { className: `h-3 w-3 shrink-0 text-muted-foreground/60 transition-transform ${isOpen ? "rotate-180" : ""}` })
42
+ ]
44
43
  }), /* @__PURE__ */ jsx(ChartDropdownPanel, {
45
44
  isOpen,
46
45
  onClose: () => setIsOpen(false),
@@ -14,9 +14,11 @@ import * as react_jsx_runtime0 from "react/jsx-runtime";
14
14
  * - Multi source → dropdown to switch between sources
15
15
  */
16
16
  declare function ChartSourceSwitcher({
17
- className
17
+ className,
18
+ hideIcon
18
19
  }: {
19
20
  className?: string;
21
+ hideIcon?: boolean;
20
22
  }): react_jsx_runtime0.JSX.Element;
21
23
  //#endregion
22
24
  export { ChartSourceSwitcher };
@@ -19,14 +19,14 @@ function formatCount(n) {
19
19
  * - Single source → read-only badge: "[icon] Jobs · 1,247 records"
20
20
  * - Multi source → dropdown to switch between sources
21
21
  */
22
- function ChartSourceSwitcher({ className }) {
22
+ function ChartSourceSwitcher({ className, hideIcon }) {
23
23
  const { hasMultipleSources, sources, activeSourceId, setActiveSource, recordCount } = useChartContext();
24
24
  if (!hasMultipleSources) {
25
25
  const label = sources[0]?.label ?? "Unnamed Source";
26
26
  return /* @__PURE__ */ jsxs("div", {
27
27
  className: `inline-flex items-center gap-1.5 whitespace-nowrap text-xs text-muted-foreground ${className ?? ""}`,
28
28
  children: [
29
- /* @__PURE__ */ jsx(Database, { className: "h-3 w-3 shrink-0" }),
29
+ !hideIcon && /* @__PURE__ */ jsx(Database, { className: "h-3 w-3 shrink-0" }),
30
30
  /* @__PURE__ */ jsx("span", {
31
31
  className: "font-medium text-foreground",
32
32
  children: label
@@ -47,6 +47,8 @@ function ChartSourceSwitcher({ className }) {
47
47
  })),
48
48
  onChange: (v) => setActiveSource(v),
49
49
  ariaLabel: "Data source",
50
+ icon: Database,
51
+ hideIcon,
50
52
  className
51
53
  });
52
54
  }
@@ -7,9 +7,11 @@ import * as react_jsx_runtime0 from "react/jsx-runtime";
7
7
  */
8
8
  /** Custom dropdown to select time granularity. */
9
9
  declare function ChartTimeBucketSelector({
10
- className
10
+ className,
11
+ hideIcon
11
12
  }: {
12
13
  className?: string;
14
+ hideIcon?: boolean;
13
15
  }): react_jsx_runtime0.JSX.Element | null;
14
16
  //#endregion
15
17
  export { ChartTimeBucketSelector };
@@ -2,6 +2,7 @@ import { CHART_TYPE_CONFIG } from "../core/chart-capabilities.mjs";
2
2
  import { useChartContext } from "./chart-context.mjs";
3
3
  import { ChartSelect } from "./chart-select.mjs";
4
4
  import { jsx } from "react/jsx-runtime";
5
+ import { Clock } from "lucide-react";
5
6
  //#region src/ui/chart-time-bucket-selector.tsx
6
7
  /**
7
8
  * Time bucket selector — premium custom dropdown.
@@ -16,7 +17,7 @@ const BUCKET_LABELS = {
16
17
  year: "Year"
17
18
  };
18
19
  /** Custom dropdown to select time granularity. */
19
- function ChartTimeBucketSelector({ className }) {
20
+ function ChartTimeBucketSelector({ className, hideIcon }) {
20
21
  const { chartType, isTimeSeries, timeBucket, setTimeBucket, availableTimeBuckets } = useChartContext();
21
22
  if (!isTimeSeries || !CHART_TYPE_CONFIG[chartType].supportsTimeBucketing || availableTimeBuckets.length === 0) return null;
22
23
  return /* @__PURE__ */ jsx(ChartSelect, {
@@ -27,6 +28,8 @@ function ChartTimeBucketSelector({ className }) {
27
28
  })),
28
29
  onChange: setTimeBucket,
29
30
  ariaLabel: "Time granularity",
31
+ icon: Clock,
32
+ hideIcon,
30
33
  className
31
34
  });
32
35
  }
@@ -7,22 +7,25 @@ import { ChartMetricPanel } from "./chart-metric-panel.mjs";
7
7
  import { CONTROL_IDS, CONTROL_REGISTRY, SECTIONS } from "./toolbar-types.mjs";
8
8
  import { useRef, useState } from "react";
9
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
- import { ArrowLeft, ChevronRight, Ellipsis, Eraser } from "lucide-react";
10
+ import { ArrowLeft, BarChart3, Calendar, ChevronRight, Clock, Database, Ellipsis, Eraser, Filter, Layers, MoveHorizontal, MoveVertical } from "lucide-react";
11
11
  //#region src/ui/chart-toolbar-overflow.tsx
12
- /**
13
- * Overflow menu for toolbar controls — Notion-inspired configuration panel.
14
- *
15
- * Renders an ellipsis button that opens a panel with all non-pinned controls.
16
- * Simple controls (selects, toggle buttons) render inline in rows.
17
- * Complex controls (metric, filters, date range) show as clickable rows that
18
- * navigate to a full-page detail view within the panel (Notion-style drill-down).
19
- */
20
12
  /** Controls that drill-down into a detail page instead of rendering inline. */
21
13
  const COMPLEX_CONTROLS = new Set([
22
14
  "metric",
23
15
  "filters",
24
16
  "dateRange"
25
17
  ]);
18
+ /** Icon for each control in the overflow menu. */
19
+ const CONTROL_ICONS = {
20
+ source: Database,
21
+ xAxis: MoveHorizontal,
22
+ chartType: BarChart3,
23
+ groupBy: Layers,
24
+ timeBucket: Clock,
25
+ metric: MoveVertical,
26
+ filters: Filter,
27
+ dateRange: Calendar
28
+ };
26
29
  /**
27
30
  * Ellipsis overflow menu with Notion-style drill-down navigation.
28
31
  * Main view shows all controls. Clicking a complex control replaces
@@ -157,16 +160,13 @@ function DetailPage({ controlId, onBack }) {
157
160
  * Used for selects and toggle buttons that work inline without popovers.
158
161
  */
159
162
  function SimpleControlRow({ controlId }) {
160
- const entry = CONTROL_REGISTRY[controlId];
161
- const Component = entry.component;
163
+ const Component = CONTROL_REGISTRY[controlId].component;
164
+ const Icon = CONTROL_ICONS[controlId];
162
165
  return /* @__PURE__ */ jsxs("div", {
163
- className: "flex items-center gap-3 rounded-lg px-1 py-1.5",
164
- children: [/* @__PURE__ */ jsx("div", {
165
- className: "shrink-0 text-xs text-muted-foreground",
166
- children: entry.label
167
- }), /* @__PURE__ */ jsx("div", {
168
- className: "ml-auto flex min-w-0 items-center",
169
- children: /* @__PURE__ */ jsx(Component, {})
166
+ className: "flex items-center gap-3 rounded-lg px-2 py-1.5",
167
+ children: [Icon && /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }), /* @__PURE__ */ jsx("div", {
168
+ className: "flex min-w-0 items-center",
169
+ children: /* @__PURE__ */ jsx(Component, { hideIcon: true })
170
170
  })]
171
171
  });
172
172
  }
@@ -175,17 +175,14 @@ function SimpleControlRow({ controlId }) {
175
175
  * Shows the control label, current value summary, and a chevron.
176
176
  */
177
177
  function ComplexControlRow({ controlId, onNavigate }) {
178
- const entry = CONTROL_REGISTRY[controlId];
178
+ const Icon = CONTROL_ICONS[controlId];
179
179
  return /* @__PURE__ */ jsxs("button", {
180
180
  onClick: onNavigate,
181
181
  className: "flex w-full items-center gap-3 rounded-lg px-2 py-2 text-left transition-colors hover:bg-muted/50",
182
182
  children: [
183
+ Icon && /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
183
184
  /* @__PURE__ */ jsx("div", {
184
- className: "shrink-0 text-xs text-muted-foreground",
185
- children: entry.label
186
- }),
187
- /* @__PURE__ */ jsx("div", {
188
- className: "ml-auto truncate text-xs text-foreground",
185
+ className: "truncate text-xs text-foreground",
189
186
  children: /* @__PURE__ */ jsx(ControlSummary, { controlId })
190
187
  }),
191
188
  /* @__PURE__ */ jsx(ChevronRight, { className: "h-3 w-3 shrink-0 text-muted-foreground" })
@@ -194,14 +191,39 @@ function ComplexControlRow({ controlId, onNavigate }) {
194
191
  }
195
192
  /** Summary text for a complex control in the main menu. */
196
193
  function ControlSummary({ controlId }) {
197
- const { metric, columns, filters, dateRangeFilter } = useChartContext();
194
+ const { metric, columns, filters, dateRange, dateRangePreset } = useChartContext();
198
195
  switch (controlId) {
199
196
  case "metric": return /* @__PURE__ */ jsx("span", { children: getMetricLabel(metric, columns) });
200
197
  case "filters": {
201
198
  const count = [...filters.values()].reduce((sum, set) => sum + set.size, 0);
202
199
  return /* @__PURE__ */ jsx("span", { children: count > 0 ? `${count} active` : "None" });
203
200
  }
204
- case "dateRange": return /* @__PURE__ */ jsx("span", { children: resolvePresetLabel(dateRangeFilter) });
201
+ case "dateRange": {
202
+ const label = resolvePresetLabel(dateRangePreset);
203
+ if (dateRange?.min && dateRange?.max) {
204
+ const fmt = (d) => d.toLocaleDateString("en-US", {
205
+ month: "short",
206
+ day: "numeric",
207
+ year: "2-digit"
208
+ });
209
+ return /* @__PURE__ */ jsxs("span", { children: [
210
+ label,
211
+ /* @__PURE__ */ jsx("span", {
212
+ className: "text-muted-foreground/40",
213
+ children: " · "
214
+ }),
215
+ /* @__PURE__ */ jsxs("span", {
216
+ className: "font-normal",
217
+ children: [
218
+ fmt(dateRange.min),
219
+ " – ",
220
+ fmt(dateRange.max)
221
+ ]
222
+ })
223
+ ] });
224
+ }
225
+ return /* @__PURE__ */ jsx("span", { children: label });
226
+ }
205
227
  default: return null;
206
228
  }
207
229
  }
@@ -2,9 +2,14 @@ import * as react_jsx_runtime0 from "react/jsx-runtime";
2
2
 
3
3
  //#region src/ui/chart-type-selector.d.ts
4
4
  /**
5
- * Chart type selector — inline toggle buttons for bar/line/area/pie/donut.
5
+ * Chart type selector — inline toggle buttons with variant dropdown.
6
+ *
7
+ * Primary types: Bar, Line, Area, Pie, Donut.
8
+ * Types with variants show a small chevron that opens a dropdown:
9
+ * Bar → Stacked, Grouped, 100%
10
+ * Area → Stacked, 100%
6
11
  */
7
- /** Inline toggle buttons to select the chart type. */
12
+ /** Inline toggle buttons with variant dropdown for chart type selection. */
8
13
  declare function ChartTypeSelector({
9
14
  className
10
15
  }: {
@@ -1,32 +1,167 @@
1
1
  import { useChartContext } from "./chart-context.mjs";
2
- import { jsx } from "react/jsx-runtime";
2
+ import { ChartDropdownPanel } from "./chart-dropdown.mjs";
3
+ import { useMemo, useRef, useState } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { ChevronDown } from "lucide-react";
3
6
  //#region src/ui/chart-type-selector.tsx
4
- /** Labels for each chart type. */
5
- const CHART_TYPE_LABELS = {
6
- bar: "Bar",
7
- line: "Line",
8
- area: "Area",
9
- pie: "Pie",
10
- donut: "Donut"
11
- };
12
- /** Inline toggle buttons to select the chart type. */
7
+ /**
8
+ * Chart type selector — inline toggle buttons with variant dropdown.
9
+ *
10
+ * Primary types: Bar, Line, Area, Pie, Donut.
11
+ * Types with variants show a small chevron that opens a dropdown:
12
+ * Bar → Stacked, Grouped, 100%
13
+ * Area → Stacked, 100%
14
+ */
15
+ const CHART_TYPE_GROUPS = [
16
+ {
17
+ primary: "bar",
18
+ label: "Bar",
19
+ variants: [
20
+ {
21
+ type: "bar",
22
+ label: "Stacked"
23
+ },
24
+ {
25
+ type: "grouped-bar",
26
+ label: "Grouped"
27
+ },
28
+ {
29
+ type: "percent-bar",
30
+ label: "100%"
31
+ }
32
+ ]
33
+ },
34
+ {
35
+ primary: "line",
36
+ label: "Line",
37
+ variants: []
38
+ },
39
+ {
40
+ primary: "area",
41
+ label: "Area",
42
+ variants: [{
43
+ type: "area",
44
+ label: "Stacked"
45
+ }, {
46
+ type: "percent-area",
47
+ label: "100%"
48
+ }]
49
+ },
50
+ {
51
+ primary: "pie",
52
+ label: "Pie",
53
+ variants: []
54
+ },
55
+ {
56
+ primary: "donut",
57
+ label: "Donut",
58
+ variants: []
59
+ }
60
+ ];
61
+ function buildVisibleGroups(availableChartTypes) {
62
+ const available = new Set(availableChartTypes);
63
+ const result = [];
64
+ for (const group of CHART_TYPE_GROUPS) if (group.variants.length === 0) {
65
+ if (available.has(group.primary)) result.push({
66
+ ...group,
67
+ visibleVariants: []
68
+ });
69
+ } else {
70
+ const visibleVariants = group.variants.filter((v) => available.has(v.type));
71
+ if (visibleVariants.length > 0) result.push({
72
+ ...group,
73
+ visibleVariants
74
+ });
75
+ }
76
+ return result;
77
+ }
78
+ function findGroupForType(chartType) {
79
+ return CHART_TYPE_GROUPS.find((g) => g.primary === chartType || g.variants.some((v) => v.type === chartType));
80
+ }
81
+ /** Inline toggle buttons with variant dropdown for chart type selection. */
13
82
  function ChartTypeSelector({ className }) {
14
83
  const { chartType, setChartType, availableChartTypes } = useChartContext();
15
- if (availableChartTypes.length <= 1) return null;
84
+ const [openGroup, setOpenGroup] = useState(null);
85
+ const visibleGroups = useMemo(() => buildVisibleGroups(availableChartTypes), [availableChartTypes]);
86
+ const activeGroup = useMemo(() => {
87
+ const staticGroup = findGroupForType(chartType);
88
+ if (!staticGroup) return void 0;
89
+ return visibleGroups.find((g) => g.primary === staticGroup.primary);
90
+ }, [chartType, visibleGroups]);
91
+ if (visibleGroups.length <= 1 && (activeGroup?.visibleVariants.length ?? 0) <= 1) return null;
16
92
  return /* @__PURE__ */ jsx("div", {
17
- className: `inline-flex items-center rounded-lg border border-border/50 bg-muted/50 p-0.5 shadow-sm ${className ?? ""}`,
93
+ className: `inline-flex items-center rounded-lg border border-border/50 bg-background p-0.5 shadow-sm ${className ?? ""}`,
18
94
  role: "tablist",
19
95
  "aria-label": "Chart type",
20
- children: availableChartTypes.map((type) => {
21
- const isActive = type === chartType;
22
- return /* @__PURE__ */ jsx("button", {
96
+ children: visibleGroups.map((group) => {
97
+ const isActive = activeGroup?.primary === group.primary;
98
+ return /* @__PURE__ */ jsx(ChartTypeButton, {
99
+ group,
100
+ isActive,
101
+ hasVariants: group.visibleVariants.length > 1,
102
+ isDropdownOpen: openGroup === group.primary,
103
+ chartType,
104
+ onSelect: () => {
105
+ if (isActive) return;
106
+ if (availableChartTypes.includes(group.primary)) setChartType(group.primary);
107
+ else if (group.visibleVariants.length > 0) setChartType(group.visibleVariants[0].type);
108
+ },
109
+ onToggleDropdown: () => setOpenGroup(openGroup === group.primary ? null : group.primary),
110
+ onSelectVariant: (type) => {
111
+ setChartType(type);
112
+ setOpenGroup(null);
113
+ },
114
+ onCloseDropdown: () => setOpenGroup(null)
115
+ }, group.primary);
116
+ })
117
+ });
118
+ }
119
+ function ChartTypeButton({ group, isActive, hasVariants, isDropdownOpen, chartType, onSelect, onToggleDropdown, onSelectVariant, onCloseDropdown }) {
120
+ const triggerRef = useRef(null);
121
+ if (!hasVariants) return /* @__PURE__ */ jsx("button", {
122
+ role: "tab",
123
+ "aria-selected": isActive,
124
+ onClick: onSelect,
125
+ className: `rounded-md px-2.5 py-1 text-xs font-medium transition-all ${isActive ? "bg-primary/10 text-primary" : "text-muted-foreground hover:bg-muted/40 hover:text-foreground"}`,
126
+ children: group.label
127
+ });
128
+ return /* @__PURE__ */ jsxs("div", {
129
+ ref: triggerRef,
130
+ className: `relative flex items-center rounded-md transition-all ${isActive ? "bg-primary/10" : "hover:bg-muted/40"}`,
131
+ children: [
132
+ /* @__PURE__ */ jsx("button", {
23
133
  role: "tab",
24
134
  "aria-selected": isActive,
25
- onClick: () => setChartType(type),
26
- className: `rounded-md px-2.5 py-1 text-xs font-medium transition-all ${isActive ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:bg-background/50 hover:text-foreground"}`,
27
- children: CHART_TYPE_LABELS[type]
28
- }, type);
29
- })
135
+ onClick: () => {
136
+ if (isActive) onToggleDropdown();
137
+ else onSelect();
138
+ },
139
+ className: `py-1 pl-2.5 pr-1 text-xs font-medium transition-colors ${isActive ? "text-primary" : "text-muted-foreground hover:text-foreground"}`,
140
+ children: group.label
141
+ }),
142
+ /* @__PURE__ */ jsx("button", {
143
+ "aria-label": `${group.label} options`,
144
+ onClick: (e) => {
145
+ e.stopPropagation();
146
+ if (!isActive) onSelect();
147
+ onToggleDropdown();
148
+ },
149
+ className: `py-1 pr-2 pl-0.5 transition-colors ${isActive ? "text-primary/60 hover:text-primary" : "text-muted-foreground/40 hover:text-muted-foreground"}`,
150
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: `h-2.5 w-2.5 transition-transform ${isDropdownOpen ? "rotate-180" : ""}` })
151
+ }),
152
+ /* @__PURE__ */ jsx(ChartDropdownPanel, {
153
+ isOpen: isDropdownOpen,
154
+ onClose: onCloseDropdown,
155
+ triggerRef,
156
+ minWidth: "trigger",
157
+ className: "p-1",
158
+ children: group.visibleVariants.map((variant) => /* @__PURE__ */ jsx("button", {
159
+ onClick: () => onSelectVariant(variant.type),
160
+ className: `flex w-full items-center rounded-md px-2.5 py-1.5 text-xs transition-colors ${variant.type === chartType ? "bg-primary/8 font-medium text-primary" : "text-foreground hover:bg-muted/60"}`,
161
+ children: variant.label
162
+ }, variant.type))
163
+ })
164
+ ]
30
165
  });
31
166
  }
32
167
  //#endregion
@@ -6,9 +6,11 @@ import * as react_jsx_runtime0 from "react/jsx-runtime";
6
6
  */
7
7
  /** Custom dropdown to select the X-axis column. */
8
8
  declare function ChartXAxisSelector({
9
- className
9
+ className,
10
+ hideIcon
10
11
  }: {
11
12
  className?: string;
13
+ hideIcon?: boolean;
12
14
  }): react_jsx_runtime0.JSX.Element | null;
13
15
  //#endregion
14
16
  export { ChartXAxisSelector };
@@ -1,12 +1,13 @@
1
1
  import { useChartContext } from "./chart-context.mjs";
2
2
  import { ChartSelect } from "./chart-select.mjs";
3
3
  import { jsx } from "react/jsx-runtime";
4
+ import { MoveHorizontal } from "lucide-react";
4
5
  //#region src/ui/chart-x-axis-selector.tsx
5
6
  /**
6
7
  * X-axis selector — premium custom dropdown for choosing which column drives the X-axis.
7
8
  */
8
9
  /** Custom dropdown to select the X-axis column. */
9
- function ChartXAxisSelector({ className }) {
10
+ function ChartXAxisSelector({ className, hideIcon }) {
10
11
  const { xAxisId, setXAxis, availableXAxes } = useChartContext();
11
12
  if (availableXAxes.length <= 1) return null;
12
13
  const options = availableXAxes.map((col) => ({
@@ -18,6 +19,8 @@ function ChartXAxisSelector({ className }) {
18
19
  options,
19
20
  onChange: (v) => setXAxis(v),
20
21
  ariaLabel: "X-axis",
22
+ icon: MoveHorizontal,
23
+ hideIcon,
21
24
  className
22
25
  });
23
26
  }
package/dist/ui/theme.css CHANGED
@@ -1,62 +1,67 @@
1
1
  @source "./";
2
2
 
3
3
  @theme inline {
4
- --color-background: hsl(var(--cs-background));
5
- --color-foreground: hsl(var(--cs-foreground));
6
- --color-card: hsl(var(--cs-card));
7
- --color-card-foreground: hsl(var(--cs-card-foreground));
8
- --color-popover: hsl(var(--cs-popover));
9
- --color-popover-foreground: hsl(var(--cs-popover-foreground));
10
- --color-primary: hsl(var(--cs-primary));
11
- --color-primary-foreground: hsl(var(--cs-primary-foreground));
12
- --color-muted: hsl(var(--cs-muted));
13
- --color-muted-foreground: hsl(var(--cs-muted-foreground));
14
- --color-border: hsl(var(--cs-border));
15
- --color-input: hsl(var(--cs-input));
16
- --color-ring: hsl(var(--cs-ring));
4
+ --color-background: var(--cs-background);
5
+ --color-foreground: var(--cs-foreground);
6
+ --color-card: var(--cs-card);
7
+ --color-card-foreground: var(--cs-card-foreground);
8
+ --color-popover: var(--cs-popover);
9
+ --color-popover-foreground: var(--cs-popover-foreground);
10
+ --color-primary: var(--cs-primary);
11
+ --color-primary-foreground: var(--cs-primary-foreground);
12
+ --color-muted: var(--cs-muted);
13
+ --color-muted-foreground: var(--cs-muted-foreground);
14
+ --color-border: var(--cs-border);
15
+ --color-input: var(--cs-input);
16
+ --color-ring: var(--cs-ring);
17
+ --radius-sm: calc(var(--cs-radius) - 4px);
18
+ --radius-md: calc(var(--cs-radius) - 2px);
19
+ --radius-lg: var(--cs-radius);
20
+ --radius-xl: calc(var(--cs-radius) + 4px);
17
21
  }
18
22
 
19
23
  :root {
20
24
  color-scheme: light;
21
- --cs-background: var(--background, 220 16% 97.5%);
22
- --cs-foreground: var(--foreground, 224 71% 4%);
23
- --cs-card: var(--card, 0 0% 100%);
24
- --cs-card-foreground: var(--card-foreground, 224 71% 4%);
25
- --cs-popover: var(--popover, 0 0% 100%);
26
- --cs-popover-foreground: var(--popover-foreground, 224 71% 4%);
27
- --cs-primary: var(--primary, 245 72% 57%);
28
- --cs-primary-foreground: var(--primary-foreground, 0 0% 100%);
29
- --cs-muted: var(--muted, 220 14% 93.5%);
30
- --cs-muted-foreground: var(--muted-foreground, 220 9% 46%);
31
- --cs-border: var(--border, 220 13% 90%);
32
- --cs-input: var(--input, 220 13% 90%);
33
- --cs-ring: var(--ring, 245 72% 57%);
34
- --cs-chart-1: 245 72% 57%;
35
- --cs-chart-2: 271 72% 55%;
36
- --cs-chart-3: 330 68% 54%;
37
- --cs-chart-4: 170 65% 38%;
38
- --cs-chart-5: 30 90% 54%;
25
+ --cs-radius: var(--radius, 0.25rem);
26
+ --cs-background: var(--background, oklch(0.980 0.002 264.545));
27
+ --cs-foreground: var(--foreground, oklch(0.128 0.027 261.594));
28
+ --cs-card: var(--card, oklch(1.000 0 0));
29
+ --cs-card-foreground: var(--card-foreground, oklch(0.128 0.027 261.594));
30
+ --cs-popover: var(--popover, oklch(1.000 0 0));
31
+ --cs-popover-foreground: var(--popover-foreground, oklch(0.128 0.027 261.594));
32
+ --cs-primary: var(--primary, oklch(0.501 0.228 277.992));
33
+ --cs-primary-foreground: var(--primary-foreground, oklch(1.000 0 0));
34
+ --cs-muted: var(--muted, oklch(0.948 0.004 264.536));
35
+ --cs-muted-foreground: var(--muted-foreground, oklch(0.550 0.023 264.362));
36
+ --cs-border: var(--border, oklch(0.920 0.006 264.529));
37
+ --cs-input: var(--input, oklch(0.920 0.006 264.529));
38
+ --cs-ring: var(--ring, oklch(0.501 0.228 277.992));
39
+ --cs-chart-1: oklch(0.501 0.228 277.992);
40
+ --cs-chart-2: oklch(0.550 0.235 302.715);
41
+ --cs-chart-3: oklch(0.609 0.206 354.673);
42
+ --cs-chart-4: oklch(0.635 0.109 178.228);
43
+ --cs-chart-5: oklch(0.732 0.166 58.213);
39
44
  }
40
45
 
41
46
  :root[data-theme='dark'],
42
47
  .dark {
43
48
  color-scheme: dark;
44
- --cs-background: var(--background, 228 25% 7%);
45
- --cs-foreground: var(--foreground, 220 15% 93%);
46
- --cs-card: var(--card, 228 22% 10%);
47
- --cs-card-foreground: var(--card-foreground, 220 15% 93%);
48
- --cs-popover: var(--popover, 228 20% 12%);
49
- --cs-popover-foreground: var(--popover-foreground, 220 15% 93%);
50
- --cs-primary: var(--primary, 245 80% 67%);
51
- --cs-primary-foreground: var(--primary-foreground, 0 0% 100%);
52
- --cs-muted: var(--muted, 228 16% 14%);
53
- --cs-muted-foreground: var(--muted-foreground, 220 10% 54%);
54
- --cs-border: var(--border, 228 14% 15%);
55
- --cs-input: var(--input, 228 14% 18%);
56
- --cs-ring: var(--ring, 245 80% 67%);
57
- --cs-chart-1: 245 85% 70%;
58
- --cs-chart-2: 271 82% 68%;
59
- --cs-chart-3: 190 85% 55%;
60
- --cs-chart-4: 155 72% 50%;
61
- --cs-chart-5: 38 90% 62%;
49
+ --cs-background: var(--background, oklch(0.171 0.015 273.761));
50
+ --cs-foreground: var(--foreground, oklch(0.944 0.005 264.534));
51
+ --cs-card: var(--card, oklch(0.203 0.018 273.739));
52
+ --cs-card-foreground: var(--card-foreground, oklch(0.944 0.005 264.534));
53
+ --cs-popover: var(--popover, oklch(0.224 0.019 273.793));
54
+ --cs-popover-foreground: var(--popover-foreground, oklch(0.944 0.005 264.534));
55
+ --cs-primary: var(--primary, oklch(0.597 0.196 282.474));
56
+ --cs-primary-foreground: var(--primary-foreground, oklch(1.000 0 0));
57
+ --cs-muted: var(--muted, oklch(0.246 0.018 274.033));
58
+ --cs-muted-foreground: var(--muted-foreground, oklch(0.618 0.025 264.372));
59
+ --cs-border: var(--border, oklch(0.258 0.016 274.161));
60
+ --cs-input: var(--input, oklch(0.287 0.019 274.112));
61
+ --cs-ring: var(--ring, oklch(0.597 0.196 282.474));
62
+ --cs-chart-1: oklch(0.625 0.188 283.272);
63
+ --cs-chart-2: oklch(0.660 0.198 305.491);
64
+ --cs-chart-3: oklch(0.785 0.132 215.571);
65
+ --cs-chart-4: oklch(0.789 0.176 158.514);
66
+ --cs-chart-5: oklch(0.815 0.143 77.593);
62
67
  }