@matthieumordrel/chart-studio 0.2.0 → 0.2.2
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/README.md +1 -1
- package/dist/core/chart-capabilities.d.mts +48 -0
- package/dist/core/chart-capabilities.mjs +55 -0
- package/dist/core/{colors.d.ts → colors.d.mts} +5 -3
- package/dist/core/colors.mjs +55 -0
- package/dist/core/config-utils.mjs +79 -0
- package/dist/core/date-utils.mjs +49 -0
- package/dist/core/define-chart-schema.d.mts +106 -0
- package/dist/core/define-chart-schema.mjs +47 -0
- package/dist/core/formatting.mjs +349 -0
- package/dist/core/infer-columns.d.mts +9 -0
- package/dist/core/infer-columns.mjs +481 -0
- package/dist/core/metric-utils.d.mts +13 -0
- package/dist/core/metric-utils.mjs +121 -0
- package/dist/core/pipeline-data-points.mjs +212 -0
- package/dist/core/pipeline-helpers.mjs +85 -0
- package/dist/core/{pipeline.d.ts → pipeline.d.mts} +21 -24
- package/dist/core/pipeline.mjs +153 -0
- package/dist/core/types.d.mts +957 -0
- package/dist/core/use-chart-options.d.mts +64 -0
- package/dist/core/use-chart-options.mjs +7 -0
- package/dist/core/use-chart-resolvers.mjs +34 -0
- package/dist/core/{use-chart.d.ts → use-chart.d.mts} +12 -9
- package/dist/core/use-chart.mjs +299 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.mjs +8 -0
- package/dist/ui/chart-axis-ticks.mjs +65 -0
- package/dist/ui/{chart-canvas.d.ts → chart-canvas.d.mts} +13 -6
- package/dist/ui/chart-canvas.mjs +461 -0
- package/dist/ui/chart-context.d.mts +92 -0
- package/dist/ui/chart-context.mjs +112 -0
- package/dist/ui/{chart-date-range-badge.d.ts → chart-date-range-badge.d.mts} +10 -4
- package/dist/ui/chart-date-range-badge.mjs +49 -0
- package/dist/ui/chart-date-range-panel.d.mts +18 -0
- package/dist/ui/chart-date-range-panel.mjs +208 -0
- package/dist/ui/{chart-date-range.d.ts → chart-date-range.d.mts} +10 -4
- package/dist/ui/chart-date-range.mjs +67 -0
- package/dist/ui/chart-debug.d.mts +17 -0
- package/dist/ui/chart-debug.mjs +169 -0
- package/dist/ui/chart-dropdown.mjs +92 -0
- package/dist/ui/{chart-filters-panel.d.ts → chart-filters-panel.d.mts} +12 -5
- package/dist/ui/chart-filters-panel.mjs +132 -0
- package/dist/ui/{chart-filters.d.ts → chart-filters.d.mts} +10 -4
- package/dist/ui/chart-filters.mjs +48 -0
- package/dist/ui/chart-group-by-selector.d.mts +14 -0
- package/dist/ui/chart-group-by-selector.mjs +29 -0
- package/dist/ui/{chart-metric-panel.d.ts → chart-metric-panel.d.mts} +12 -5
- package/dist/ui/chart-metric-panel.mjs +172 -0
- package/dist/ui/chart-metric-selector.d.mts +16 -0
- package/dist/ui/chart-metric-selector.mjs +50 -0
- package/dist/ui/chart-select.mjs +62 -0
- package/dist/ui/{chart-source-switcher.d.ts → chart-source-switcher.d.mts} +10 -4
- package/dist/ui/chart-source-switcher.mjs +54 -0
- package/dist/ui/chart-time-bucket-selector.d.mts +15 -0
- package/dist/ui/chart-time-bucket-selector.mjs +34 -0
- package/dist/ui/chart-toolbar-overflow.d.mts +28 -0
- package/dist/ui/chart-toolbar-overflow.mjs +209 -0
- package/dist/ui/chart-toolbar.d.mts +29 -0
- package/dist/ui/chart-toolbar.mjs +56 -0
- package/dist/ui/chart-type-selector.d.mts +14 -0
- package/dist/ui/chart-type-selector.mjs +33 -0
- package/dist/ui/chart-x-axis-selector.d.mts +14 -0
- package/dist/ui/chart-x-axis-selector.mjs +25 -0
- package/dist/ui/index.d.mts +19 -0
- package/dist/ui/index.mjs +18 -0
- package/dist/ui/toolbar-types.d.mts +7 -0
- package/dist/ui/toolbar-types.mjs +83 -0
- package/package.json +11 -10
- package/dist/core/chart-capabilities.d.ts +0 -60
- package/dist/core/chart-capabilities.d.ts.map +0 -1
- package/dist/core/chart-capabilities.js +0 -54
- package/dist/core/colors.d.ts.map +0 -1
- package/dist/core/colors.js +0 -54
- package/dist/core/config-utils.d.ts +0 -43
- package/dist/core/config-utils.d.ts.map +0 -1
- package/dist/core/config-utils.js +0 -80
- package/dist/core/date-utils.d.ts +0 -29
- package/dist/core/date-utils.d.ts.map +0 -1
- package/dist/core/date-utils.js +0 -58
- package/dist/core/define-chart-schema.d.ts +0 -105
- package/dist/core/define-chart-schema.d.ts.map +0 -1
- package/dist/core/define-chart-schema.js +0 -44
- package/dist/core/formatting.d.ts +0 -47
- package/dist/core/formatting.d.ts.map +0 -1
- package/dist/core/formatting.js +0 -396
- package/dist/core/index.d.ts +0 -17
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -12
- package/dist/core/infer-columns.d.ts +0 -6
- package/dist/core/infer-columns.d.ts.map +0 -1
- package/dist/core/infer-columns.js +0 -512
- package/dist/core/metric-utils.d.ts +0 -43
- package/dist/core/metric-utils.d.ts.map +0 -1
- package/dist/core/metric-utils.js +0 -141
- package/dist/core/pipeline-data-points.d.ts +0 -23
- package/dist/core/pipeline-data-points.d.ts.map +0 -1
- package/dist/core/pipeline-data-points.js +0 -235
- package/dist/core/pipeline-helpers.d.ts +0 -38
- package/dist/core/pipeline-helpers.d.ts.map +0 -1
- package/dist/core/pipeline-helpers.js +0 -97
- package/dist/core/pipeline.d.ts.map +0 -1
- package/dist/core/pipeline.js +0 -156
- package/dist/core/types.d.ts +0 -1109
- package/dist/core/types.d.ts.map +0 -1
- package/dist/core/types.js +0 -14
- package/dist/core/use-chart-options.d.ts +0 -66
- package/dist/core/use-chart-options.d.ts.map +0 -1
- package/dist/core/use-chart-options.js +0 -4
- package/dist/core/use-chart-resolvers.d.ts +0 -14
- package/dist/core/use-chart-resolvers.d.ts.map +0 -1
- package/dist/core/use-chart-resolvers.js +0 -41
- package/dist/core/use-chart.d.ts.map +0 -1
- package/dist/core/use-chart.js +0 -265
- package/dist/index.d.ts +0 -36
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -35
- package/dist/ui/chart-axis-ticks.d.ts +0 -35
- package/dist/ui/chart-axis-ticks.d.ts.map +0 -1
- package/dist/ui/chart-axis-ticks.js +0 -79
- package/dist/ui/chart-canvas.d.ts.map +0 -1
- package/dist/ui/chart-canvas.js +0 -337
- package/dist/ui/chart-context.d.ts +0 -89
- package/dist/ui/chart-context.d.ts.map +0 -1
- package/dist/ui/chart-context.js +0 -128
- package/dist/ui/chart-date-range-badge.d.ts.map +0 -1
- package/dist/ui/chart-date-range-badge.js +0 -30
- package/dist/ui/chart-date-range-panel.d.ts +0 -25
- package/dist/ui/chart-date-range-panel.d.ts.map +0 -1
- package/dist/ui/chart-date-range-panel.js +0 -125
- package/dist/ui/chart-date-range.d.ts.map +0 -1
- package/dist/ui/chart-date-range.js +0 -37
- package/dist/ui/chart-debug.d.ts +0 -10
- package/dist/ui/chart-debug.d.ts.map +0 -1
- package/dist/ui/chart-debug.js +0 -126
- package/dist/ui/chart-dropdown.d.ts +0 -35
- package/dist/ui/chart-dropdown.d.ts.map +0 -1
- package/dist/ui/chart-dropdown.js +0 -76
- package/dist/ui/chart-filters-panel.d.ts.map +0 -1
- package/dist/ui/chart-filters-panel.js +0 -46
- package/dist/ui/chart-filters.d.ts.map +0 -1
- package/dist/ui/chart-filters.js +0 -26
- package/dist/ui/chart-group-by-selector.d.ts +0 -8
- package/dist/ui/chart-group-by-selector.d.ts.map +0 -1
- package/dist/ui/chart-group-by-selector.js +0 -19
- package/dist/ui/chart-metric-panel.d.ts.map +0 -1
- package/dist/ui/chart-metric-panel.js +0 -118
- package/dist/ui/chart-metric-selector.d.ts +0 -10
- package/dist/ui/chart-metric-selector.d.ts.map +0 -1
- package/dist/ui/chart-metric-selector.js +0 -27
- package/dist/ui/chart-select.d.ts +0 -25
- package/dist/ui/chart-select.d.ts.map +0 -1
- package/dist/ui/chart-select.js +0 -35
- package/dist/ui/chart-source-switcher.d.ts.map +0 -1
- package/dist/ui/chart-source-switcher.js +0 -31
- package/dist/ui/chart-time-bucket-selector.d.ts +0 -9
- package/dist/ui/chart-time-bucket-selector.d.ts.map +0 -1
- package/dist/ui/chart-time-bucket-selector.js +0 -25
- package/dist/ui/chart-toolbar-overflow.d.ts +0 -29
- package/dist/ui/chart-toolbar-overflow.d.ts.map +0 -1
- package/dist/ui/chart-toolbar-overflow.js +0 -109
- package/dist/ui/chart-toolbar.d.ts +0 -45
- package/dist/ui/chart-toolbar.d.ts.map +0 -1
- package/dist/ui/chart-toolbar.js +0 -44
- package/dist/ui/chart-type-selector.d.ts +0 -8
- package/dist/ui/chart-type-selector.d.ts.map +0 -1
- package/dist/ui/chart-type-selector.js +0 -22
- package/dist/ui/chart-x-axis-selector.d.ts +0 -8
- package/dist/ui/chart-x-axis-selector.d.ts.map +0 -1
- package/dist/ui/chart-x-axis-selector.js +0 -14
- package/dist/ui/index.d.ts +0 -25
- package/dist/ui/index.d.ts.map +0 -1
- package/dist/ui/index.js +0 -23
- package/dist/ui/toolbar-types.d.ts +0 -43
- package/dist/ui/toolbar-types.d.ts.map +0 -1
- package/dist/ui/toolbar-types.js +0 -50
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo } from 'react';
|
|
3
|
-
import { ArrowDownToLine, ArrowUpToLine, Divide, Hash, Sigma } from 'lucide-react';
|
|
4
|
-
import { DEFAULT_METRIC, isAggregateMetric } from '../core/metric-utils.js';
|
|
5
|
-
import { useChartContext } from './chart-context.js';
|
|
6
|
-
const AGGREGATE_OPTIONS = [
|
|
7
|
-
{ fn: 'sum', label: 'Sum', shortLabel: 'Sum', icon: _jsx(Sigma, { className: "h-3.5 w-3.5 shrink-0" }) },
|
|
8
|
-
{
|
|
9
|
-
fn: 'avg',
|
|
10
|
-
label: 'Average',
|
|
11
|
-
shortLabel: 'Avg',
|
|
12
|
-
icon: _jsx(Divide, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
fn: 'min',
|
|
16
|
-
label: 'Minimum',
|
|
17
|
-
shortLabel: 'Min',
|
|
18
|
-
icon: _jsx(ArrowDownToLine, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
fn: 'max',
|
|
22
|
-
label: 'Maximum',
|
|
23
|
-
shortLabel: 'Max',
|
|
24
|
-
icon: _jsx(ArrowUpToLine, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
25
|
-
},
|
|
26
|
-
];
|
|
27
|
-
/** Aggregates where the "Exclude zeros" toggle is relevant */
|
|
28
|
-
const ZERO_TOGGLE_AGGREGATES = new Set(['avg', 'min', 'max']);
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
// Helpers
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
/**
|
|
33
|
-
* Extract number columns from the chart column list.
|
|
34
|
-
*/
|
|
35
|
-
function getNumberColumns(columns) {
|
|
36
|
-
return columns.filter((column) => column.type === 'number');
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Group the allowed aggregate metrics by number column while preserving column order.
|
|
40
|
-
*/
|
|
41
|
-
function getMetricColumnGroups(availableMetrics, columns) {
|
|
42
|
-
const aggregateMap = new Map();
|
|
43
|
-
for (const metric of availableMetrics) {
|
|
44
|
-
if (metric.kind !== 'aggregate') {
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
const aggregates = aggregateMap.get(metric.columnId) ?? new Set();
|
|
48
|
-
aggregates.add(metric.aggregate);
|
|
49
|
-
aggregateMap.set(metric.columnId, aggregates);
|
|
50
|
-
}
|
|
51
|
-
return getNumberColumns(columns)
|
|
52
|
-
.filter(column => aggregateMap.has(column.id))
|
|
53
|
-
.map(column => ({
|
|
54
|
-
columnId: column.id,
|
|
55
|
-
label: column.label,
|
|
56
|
-
aggregates: [...(aggregateMap.get(column.id) ?? new Set())],
|
|
57
|
-
}));
|
|
58
|
-
}
|
|
59
|
-
// ---------------------------------------------------------------------------
|
|
60
|
-
// Sub-components
|
|
61
|
-
// ---------------------------------------------------------------------------
|
|
62
|
-
/** A single number column section with aggregate buttons + optional zero toggle. */
|
|
63
|
-
function MetricColumnGroup({ group, isActiveColumn, activeAggregate, includeZeros, onSelectAggregate, onToggleZeros, }) {
|
|
64
|
-
const isZeroToggleEnabled = isActiveColumn && activeAggregate !== null && ZERO_TOGGLE_AGGREGATES.has(activeAggregate);
|
|
65
|
-
const isZeroToggleDisabled = isActiveColumn && activeAggregate === 'sum';
|
|
66
|
-
return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: group.label }), isActiveColumn && (_jsxs("button", { onClick: isZeroToggleDisabled ? undefined : onToggleZeros, className: `flex items-center gap-1.5 text-[10px] transition-colors ${isZeroToggleDisabled
|
|
67
|
-
? 'cursor-not-allowed text-muted-foreground/30'
|
|
68
|
-
: 'text-muted-foreground hover:text-foreground'}`, disabled: isZeroToggleDisabled, title: isZeroToggleDisabled
|
|
69
|
-
? 'Not applicable for Sum'
|
|
70
|
-
: 'Exclude zero values from calculation', children: [_jsx("div", { className: `flex h-3 w-3 shrink-0 items-center justify-center rounded-sm border transition-colors ${isZeroToggleEnabled && !includeZeros
|
|
71
|
-
? 'border-primary bg-primary'
|
|
72
|
-
: isZeroToggleDisabled
|
|
73
|
-
? 'border-muted-foreground/20'
|
|
74
|
-
: 'border-muted-foreground/30'}`, children: isZeroToggleEnabled && !includeZeros && (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "8", height: "8", viewBox: "0 0 24 24", fill: "none", stroke: "white", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("polyline", { points: "20 6 9 17 4 12" }) })) }), "Excl. zeros"] }))] }), _jsx("div", { className: "grid grid-cols-2 gap-1.5", children: AGGREGATE_OPTIONS.filter(opt => group.aggregates.includes(opt.fn)).map((opt) => {
|
|
75
|
-
const isActive = isActiveColumn && activeAggregate === opt.fn;
|
|
76
|
-
return (_jsxs("button", { onClick: () => onSelectAggregate(opt.fn), className: `inline-flex h-8 items-center justify-center gap-2 rounded-md border text-xs transition-colors ${isActive
|
|
77
|
-
? 'border-primary/50 bg-primary/10 font-medium text-primary'
|
|
78
|
-
: 'border-transparent bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground'}`, title: opt.label, children: [opt.icon, opt.shortLabel] }, opt.fn));
|
|
79
|
-
}) })] }));
|
|
80
|
-
}
|
|
81
|
-
// ---------------------------------------------------------------------------
|
|
82
|
-
// Main component
|
|
83
|
-
// ---------------------------------------------------------------------------
|
|
84
|
-
/**
|
|
85
|
-
* Metric panel content (no popover wrapper).
|
|
86
|
-
*
|
|
87
|
-
* @property onClose - Optional callback when user makes a definitive selection (e.g. "Count")
|
|
88
|
-
* @property className - Additional CSS classes
|
|
89
|
-
*/
|
|
90
|
-
export function ChartMetricPanel({ onClose, className }) {
|
|
91
|
-
const { metric, setMetric, columns, availableMetrics } = useChartContext();
|
|
92
|
-
const countMetricEnabled = useMemo(() => availableMetrics.some(candidate => candidate.kind === 'count'), [availableMetrics]);
|
|
93
|
-
const metricColumnGroups = useMemo(() => getMetricColumnGroups(availableMetrics, columns), [availableMetrics, columns]);
|
|
94
|
-
const isCount = metric.kind === 'count';
|
|
95
|
-
const includeZeros = isAggregateMetric(metric) ? (metric.includeZeros ?? true) : true;
|
|
96
|
-
const handleSelectCount = () => {
|
|
97
|
-
if (!countMetricEnabled) {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
setMetric(DEFAULT_METRIC);
|
|
101
|
-
onClose?.();
|
|
102
|
-
};
|
|
103
|
-
const handleSelectAggregate = (columnId, fn) => {
|
|
104
|
-
setMetric({
|
|
105
|
-
kind: 'aggregate',
|
|
106
|
-
columnId,
|
|
107
|
-
aggregate: fn,
|
|
108
|
-
includeZeros: isAggregateMetric(metric) && metric.columnId === columnId ? includeZeros : true,
|
|
109
|
-
});
|
|
110
|
-
};
|
|
111
|
-
const handleToggleZeros = () => {
|
|
112
|
-
if (!isAggregateMetric(metric)) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
setMetric({ ...metric, includeZeros: !includeZeros });
|
|
116
|
-
};
|
|
117
|
-
return (_jsxs("div", { className: className, children: [countMetricEnabled && (_jsxs("button", { onClick: handleSelectCount, className: `flex w-full items-center gap-2.5 rounded-lg px-2.5 py-2 text-left text-xs transition-colors ${isCount ? 'bg-primary/10 font-medium text-primary' : 'text-foreground hover:bg-muted'}`, children: [_jsx("div", { className: `flex h-6 w-6 items-center justify-center rounded-md ${isCount ? 'bg-primary/15 text-primary' : 'bg-muted text-muted-foreground'}`, children: _jsx(Hash, { className: "h-3.5 w-3.5" }) }), _jsxs("div", { children: [_jsx("div", { className: "font-medium", children: "Count" }), _jsx("div", { className: "text-[10px] text-muted-foreground", children: "Number of items" })] })] })), countMetricEnabled && metricColumnGroups.length > 0 && _jsx("div", { className: "my-4 border-t border-border" }), _jsx("div", { className: "space-y-4", children: metricColumnGroups.map((group) => (_jsx(MetricColumnGroup, { group: group, isActiveColumn: isAggregateMetric(metric) && metric.columnId === group.columnId, activeAggregate: isAggregateMetric(metric) && metric.columnId === group.columnId ? metric.aggregate : null, includeZeros: includeZeros, onSelectAggregate: (fn) => handleSelectAggregate(group.columnId, fn), onToggleZeros: handleToggleZeros }, group.columnId))) })] }));
|
|
118
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Metric selector — trigger button + popover wrapping ChartMetricPanel.
|
|
3
|
-
*
|
|
4
|
-
* Follows the same dropdown pattern as ChartFilters / ChartDateRange.
|
|
5
|
-
*/
|
|
6
|
-
/** Styled popover to select the Y-axis metric with grouped aggregate buttons. */
|
|
7
|
-
export declare function ChartMetricSelector({ className }: {
|
|
8
|
-
className?: string;
|
|
9
|
-
}): import("react/jsx-runtime").JSX.Element | null;
|
|
10
|
-
//# sourceMappingURL=chart-metric-selector.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chart-metric-selector.d.ts","sourceRoot":"","sources":["../../src/ui/chart-metric-selector.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,iFAAiF;AACjF,wBAAgB,mBAAmB,CAAC,EAAC,SAAS,EAAC,EAAE;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAC,kDAiDpE"}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* Metric selector — trigger button + popover wrapping ChartMetricPanel.
|
|
4
|
-
*
|
|
5
|
-
* Follows the same dropdown pattern as ChartFilters / ChartDateRange.
|
|
6
|
-
*/
|
|
7
|
-
import { useRef, useState } from 'react';
|
|
8
|
-
import { ChevronDown, TrendingUpDown } from 'lucide-react';
|
|
9
|
-
import { getMetricLabel, isAggregateMetric } from '../core/metric-utils.js';
|
|
10
|
-
import { useChartContext } from './chart-context.js';
|
|
11
|
-
import { ChartDropdownPanel } from './chart-dropdown.js';
|
|
12
|
-
import { ChartMetricPanel } from './chart-metric-panel.js';
|
|
13
|
-
/** Styled popover to select the Y-axis metric with grouped aggregate buttons. */
|
|
14
|
-
export function ChartMetricSelector({ className }) {
|
|
15
|
-
const { metric, availableMetrics, columns } = useChartContext();
|
|
16
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
17
|
-
const triggerRef = useRef(null);
|
|
18
|
-
if (availableMetrics.length <= 1)
|
|
19
|
-
return null;
|
|
20
|
-
const isCount = metric.kind === 'count';
|
|
21
|
-
const isActive = !isCount;
|
|
22
|
-
const includeZeros = isAggregateMetric(metric) ? (metric.includeZeros ?? true) : true;
|
|
23
|
-
const label = getMetricLabel(metric, columns);
|
|
24
|
-
return (_jsxs("div", { className: className, children: [_jsxs("button", { ref: triggerRef, onClick: () => setIsOpen(!isOpen), 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
|
|
25
|
-
? 'border-primary/30 bg-primary/5 text-primary shadow-sm shadow-primary/5 hover:bg-primary/8'
|
|
26
|
-
: 'border-border/50 bg-background text-muted-foreground shadow-sm hover:border-border hover:bg-muted/30 hover:shadow hover:text-foreground'}`, "aria-label": "Metric", children: [_jsx(TrendingUpDown, { className: "h-3 w-3" }), _jsx("span", { children: label }), isActive && !includeZeros && (_jsx("span", { className: "rounded bg-muted px-1 py-px text-[9px] font-normal text-muted-foreground", children: "excl. 0" })), _jsx(ChevronDown, { className: `h-3 w-3 text-muted-foreground/50 transition-transform ${isOpen ? 'rotate-180' : ''}` })] }), _jsx(ChartDropdownPanel, { isOpen: isOpen, onClose: () => setIsOpen(false), triggerRef: triggerRef, width: 288, className: "p-4", children: _jsx(ChartMetricPanel, { onClose: () => setIsOpen(false) }) })] }));
|
|
27
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Custom select dropdown — premium replacement for native <select> elements.
|
|
3
|
-
* Uses fixed positioning so the options list works correctly even inside
|
|
4
|
-
* overflow-hidden containers (e.g. the toolbar overflow panel).
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Premium styled select dropdown with highlight-only selection styling.
|
|
8
|
-
*
|
|
9
|
-
* @property value - Currently selected value
|
|
10
|
-
* @property options - Array of { value, label } options
|
|
11
|
-
* @property onChange - Callback when selection changes
|
|
12
|
-
* @property ariaLabel - Accessible label for the trigger
|
|
13
|
-
* @property className - Additional CSS classes
|
|
14
|
-
*/
|
|
15
|
-
export declare function ChartSelect<T extends string>({ value, options, onChange, ariaLabel, className, }: {
|
|
16
|
-
value: T;
|
|
17
|
-
options: ReadonlyArray<{
|
|
18
|
-
value: T;
|
|
19
|
-
label: string;
|
|
20
|
-
}>;
|
|
21
|
-
onChange: (value: T) => void;
|
|
22
|
-
ariaLabel?: string;
|
|
23
|
-
className?: string;
|
|
24
|
-
}): import("react/jsx-runtime").JSX.Element;
|
|
25
|
-
//# sourceMappingURL=chart-select.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chart-select.d.ts","sourceRoot":"","sources":["../../src/ui/chart-select.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,EAC5C,KAAK,EACL,OAAO,EACP,QAAQ,EACR,SAAS,EACT,SAAS,GACV,EAAE;IACD,KAAK,EAAE,CAAC,CAAA;IACR,OAAO,EAAE,aAAa,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC,CAAA;IACjD,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,2CAuDA"}
|
package/dist/ui/chart-select.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* Custom select dropdown — premium replacement for native <select> elements.
|
|
4
|
-
* Uses fixed positioning so the options list works correctly even inside
|
|
5
|
-
* overflow-hidden containers (e.g. the toolbar overflow panel).
|
|
6
|
-
*/
|
|
7
|
-
import { useRef, useState } from 'react';
|
|
8
|
-
import { ChevronDown } from 'lucide-react';
|
|
9
|
-
import { ChartDropdownPanel } from './chart-dropdown.js';
|
|
10
|
-
/**
|
|
11
|
-
* Premium styled select dropdown with highlight-only selection styling.
|
|
12
|
-
*
|
|
13
|
-
* @property value - Currently selected value
|
|
14
|
-
* @property options - Array of { value, label } options
|
|
15
|
-
* @property onChange - Callback when selection changes
|
|
16
|
-
* @property ariaLabel - Accessible label for the trigger
|
|
17
|
-
* @property className - Additional CSS classes
|
|
18
|
-
*/
|
|
19
|
-
export function ChartSelect({ value, options, onChange, ariaLabel, className, }) {
|
|
20
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
21
|
-
const triggerRef = useRef(null);
|
|
22
|
-
const selected = options.find((o) => o.value === value);
|
|
23
|
-
/** Toggle the dropdown. */
|
|
24
|
-
const handleToggle = () => {
|
|
25
|
-
setIsOpen((current) => !current);
|
|
26
|
-
};
|
|
27
|
-
/** Select an option and close the dropdown. */
|
|
28
|
-
const handleSelect = (optionValue) => {
|
|
29
|
-
onChange(optionValue);
|
|
30
|
-
setIsOpen(false);
|
|
31
|
-
};
|
|
32
|
-
return (_jsxs("div", { className: className, children: [_jsxs("button", { ref: triggerRef, onClick: handleToggle, 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", "aria-label": ariaLabel, children: [_jsx("span", { className: "truncate", children: selected?.label ?? value }), _jsx(ChevronDown, { className: `h-3 w-3 shrink-0 text-muted-foreground/60 transition-transform ${isOpen ? 'rotate-180' : ''}` })] }), _jsx(ChartDropdownPanel, { isOpen: isOpen, onClose: () => setIsOpen(false), triggerRef: triggerRef, minWidth: "trigger", className: "p-1", children: options.map((option) => (_jsx("button", { onClick: () => handleSelect(option.value), className: `flex w-full items-center gap-2 rounded-lg px-2.5 py-1.5 text-xs transition-colors ${option.value === value
|
|
33
|
-
? 'bg-primary/8 font-medium text-primary'
|
|
34
|
-
: 'text-foreground hover:bg-muted/60'}`, children: _jsx("span", { className: "truncate", children: option.label }) }, option.value))) })] }));
|
|
35
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chart-source-switcher.d.ts","sourceRoot":"","sources":["../../src/ui/chart-source-switcher.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,EAAC,SAAS,EAAC,EAAE;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAC,2CA+BpE"}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* Data source control — adapts based on single vs multi-source.
|
|
4
|
-
*
|
|
5
|
-
* Single source: read-only badge showing source label + record count.
|
|
6
|
-
* Multi source: dropdown to switch between data sources.
|
|
7
|
-
*/
|
|
8
|
-
import { Database } from 'lucide-react';
|
|
9
|
-
import { useChartContext } from './chart-context.js';
|
|
10
|
-
import { ChartSelect } from './chart-select.js';
|
|
11
|
-
/** Format a number with locale-aware separators (e.g. 1,247). */
|
|
12
|
-
function formatCount(n) {
|
|
13
|
-
return n.toLocaleString('en-US');
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Data source display/switcher.
|
|
17
|
-
*
|
|
18
|
-
* - Single source → read-only badge: "[icon] Jobs · 1,247 records"
|
|
19
|
-
* - Multi source → dropdown to switch between sources
|
|
20
|
-
*/
|
|
21
|
-
export function ChartSourceSwitcher({ className }) {
|
|
22
|
-
const { hasMultipleSources, sources, activeSourceId, setActiveSource, recordCount } = useChartContext();
|
|
23
|
-
// Single source — read-only info badge
|
|
24
|
-
if (!hasMultipleSources) {
|
|
25
|
-
const label = sources[0]?.label ?? 'Unnamed Source';
|
|
26
|
-
return (_jsxs("div", { className: `inline-flex items-center gap-1.5 whitespace-nowrap text-xs text-muted-foreground ${className ?? ''}`, children: [_jsx(Database, { className: "h-3 w-3 shrink-0" }), _jsx("span", { className: "font-medium text-foreground", children: label }), _jsx("span", { className: "text-muted-foreground/40", children: "\u00B7" }), _jsxs("span", { children: [formatCount(recordCount), " records"] })] }));
|
|
27
|
-
}
|
|
28
|
-
// Multi source — dropdown select
|
|
29
|
-
const options = sources.map((source) => ({ value: source.id, label: `Source: ${source.label}` }));
|
|
30
|
-
return (_jsx(ChartSelect, { value: activeSourceId, options: options, onChange: (v) => setActiveSource(v), ariaLabel: "Data source", className: className }));
|
|
31
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Time bucket selector — premium custom dropdown.
|
|
3
|
-
* Only renders when the X-axis is a date column.
|
|
4
|
-
*/
|
|
5
|
-
/** Custom dropdown to select time granularity. */
|
|
6
|
-
export declare function ChartTimeBucketSelector({ className }: {
|
|
7
|
-
className?: string;
|
|
8
|
-
}): import("react/jsx-runtime").JSX.Element | null;
|
|
9
|
-
//# sourceMappingURL=chart-time-bucket-selector.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chart-time-bucket-selector.d.ts","sourceRoot":"","sources":["../../src/ui/chart-time-bucket-selector.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH,kDAAkD;AAClD,wBAAgB,uBAAuB,CAAC,EAAC,SAAS,EAAC,EAAE;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAC,kDAkBxE"}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* Time bucket selector — premium custom dropdown.
|
|
4
|
-
* Only renders when the X-axis is a date column.
|
|
5
|
-
*/
|
|
6
|
-
import { CHART_TYPE_CONFIG } from '../core/chart-capabilities.js';
|
|
7
|
-
import { useChartContext } from './chart-context.js';
|
|
8
|
-
import { ChartSelect } from './chart-select.js';
|
|
9
|
-
/** Labels for each time bucket. */
|
|
10
|
-
const BUCKET_LABELS = {
|
|
11
|
-
day: 'Day',
|
|
12
|
-
week: 'Week',
|
|
13
|
-
month: 'Month',
|
|
14
|
-
quarter: 'Quarter',
|
|
15
|
-
year: 'Year',
|
|
16
|
-
};
|
|
17
|
-
/** Custom dropdown to select time granularity. */
|
|
18
|
-
export function ChartTimeBucketSelector({ className }) {
|
|
19
|
-
const { chartType, isTimeSeries, timeBucket, setTimeBucket, availableTimeBuckets } = useChartContext();
|
|
20
|
-
if (!isTimeSeries || !CHART_TYPE_CONFIG[chartType].supportsTimeBucketing || availableTimeBuckets.length === 0) {
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
const options = availableTimeBuckets.map((bucket) => ({ value: bucket, label: BUCKET_LABELS[bucket] }));
|
|
24
|
-
return (_jsx(ChartSelect, { value: timeBucket, options: options, onChange: setTimeBucket, ariaLabel: "Time granularity", className: className }));
|
|
25
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Overflow menu for toolbar controls — Notion-inspired configuration panel.
|
|
3
|
-
*
|
|
4
|
-
* Renders an ellipsis button that opens a panel with all non-pinned controls.
|
|
5
|
-
* Simple controls (selects, toggle buttons) render inline in rows.
|
|
6
|
-
* Complex controls (metric, filters, date range) show as clickable rows that
|
|
7
|
-
* navigate to a full-page detail view within the panel (Notion-style drill-down).
|
|
8
|
-
*/
|
|
9
|
-
import type { ControlId } from './toolbar-types.js';
|
|
10
|
-
/**
|
|
11
|
-
* Props for ChartToolbarOverflow.
|
|
12
|
-
*
|
|
13
|
-
* @property pinned - Controls shown outside the overflow (excluded from menu)
|
|
14
|
-
* @property hidden - Controls completely hidden everywhere
|
|
15
|
-
* @property className - Additional CSS classes
|
|
16
|
-
*/
|
|
17
|
-
type ChartToolbarOverflowProps = {
|
|
18
|
-
pinned: ReadonlySet<ControlId>;
|
|
19
|
-
hidden: ReadonlySet<ControlId>;
|
|
20
|
-
className?: string;
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* Ellipsis overflow menu with Notion-style drill-down navigation.
|
|
24
|
-
* Main view shows all controls. Clicking a complex control replaces
|
|
25
|
-
* the panel content with that control's detail page + back button.
|
|
26
|
-
*/
|
|
27
|
-
export declare function ChartToolbarOverflow({ pinned, hidden, className }: ChartToolbarOverflowProps): import("react/jsx-runtime").JSX.Element | null;
|
|
28
|
-
export {};
|
|
29
|
-
//# sourceMappingURL=chart-toolbar-overflow.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chart-toolbar-overflow.d.ts","sourceRoot":"","sources":["../../src/ui/chart-toolbar-overflow.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,OAAO,KAAK,EAAC,SAAS,EAAiB,MAAM,oBAAoB,CAAA;AAMjE;;;;;;GAMG;AACH,KAAK,yBAAyB,GAAG;IAC/B,MAAM,EAAE,WAAW,CAAC,SAAS,CAAC,CAAA;IAC9B,MAAM,EAAE,WAAW,CAAC,SAAS,CAAC,CAAA;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,EAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAC,EAAE,yBAAyB,kDAgE1F"}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* Overflow menu for toolbar controls — Notion-inspired configuration panel.
|
|
4
|
-
*
|
|
5
|
-
* Renders an ellipsis button that opens a panel with all non-pinned controls.
|
|
6
|
-
* Simple controls (selects, toggle buttons) render inline in rows.
|
|
7
|
-
* Complex controls (metric, filters, date range) show as clickable rows that
|
|
8
|
-
* navigate to a full-page detail view within the panel (Notion-style drill-down).
|
|
9
|
-
*/
|
|
10
|
-
import { useRef, useState } from 'react';
|
|
11
|
-
import { ArrowLeft, ChevronRight, Ellipsis, Eraser } from 'lucide-react';
|
|
12
|
-
import { getMetricLabel } from '../core/metric-utils.js';
|
|
13
|
-
import { useChartContext } from './chart-context.js';
|
|
14
|
-
import { ChartDropdownPanel } from './chart-dropdown.js';
|
|
15
|
-
import { ChartDateRangePanel, resolvePresetLabel } from './chart-date-range-panel.js';
|
|
16
|
-
import { ChartFiltersPanel } from './chart-filters-panel.js';
|
|
17
|
-
import { ChartMetricPanel } from './chart-metric-panel.js';
|
|
18
|
-
import { CONTROL_IDS, CONTROL_REGISTRY, SECTIONS } from './toolbar-types.js';
|
|
19
|
-
/** Controls that drill-down into a detail page instead of rendering inline. */
|
|
20
|
-
const COMPLEX_CONTROLS = new Set(['metric', 'filters', 'dateRange']);
|
|
21
|
-
/**
|
|
22
|
-
* Ellipsis overflow menu with Notion-style drill-down navigation.
|
|
23
|
-
* Main view shows all controls. Clicking a complex control replaces
|
|
24
|
-
* the panel content with that control's detail page + back button.
|
|
25
|
-
*/
|
|
26
|
-
export function ChartToolbarOverflow({ pinned, hidden, className }) {
|
|
27
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
28
|
-
/** null = main menu, ControlId = detail page for that control */
|
|
29
|
-
const [activePage, setActivePage] = useState(null);
|
|
30
|
-
const triggerRef = useRef(null);
|
|
31
|
-
// Collect overflow controls (not pinned, not hidden) grouped by section
|
|
32
|
-
const sectionGroups = SECTIONS.map((section) => {
|
|
33
|
-
const controls = CONTROL_IDS.filter((id) => {
|
|
34
|
-
if (pinned.has(id) || hidden.has(id))
|
|
35
|
-
return false;
|
|
36
|
-
return CONTROL_REGISTRY[id].section === section.id;
|
|
37
|
-
});
|
|
38
|
-
return { section, controls };
|
|
39
|
-
}).filter((g) => g.controls.length > 0);
|
|
40
|
-
if (sectionGroups.length === 0)
|
|
41
|
-
return null;
|
|
42
|
-
const handleClose = () => {
|
|
43
|
-
setIsOpen(false);
|
|
44
|
-
setActivePage(null);
|
|
45
|
-
};
|
|
46
|
-
const handleToggle = () => {
|
|
47
|
-
if (isOpen) {
|
|
48
|
-
handleClose();
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
setIsOpen(true);
|
|
52
|
-
};
|
|
53
|
-
return (_jsxs("div", { className: className, children: [_jsx("button", { ref: triggerRef, onClick: handleToggle, className: `inline-flex h-7 w-7 items-center justify-center rounded-md border transition-colors ${isOpen
|
|
54
|
-
? 'border-primary/50 bg-primary/10 text-primary'
|
|
55
|
-
: 'border-border bg-background text-muted-foreground hover:bg-muted hover:text-foreground'}`, "aria-label": "Chart settings", children: _jsx(Ellipsis, { className: "h-4 w-4" }) }), _jsx(ChartDropdownPanel, { isOpen: isOpen, onClose: handleClose, triggerRef: triggerRef, align: "right", width: 320, repositionKey: activePage ?? 'main', className: "flex min-h-[280px] max-h-[min(480px,80vh)] flex-col", children: activePage === null ? (_jsx(MainMenu, { sectionGroups: sectionGroups, onNavigate: setActivePage })) : (_jsx(DetailPage, { controlId: activePage, onBack: () => setActivePage(null) })) })] }));
|
|
56
|
-
}
|
|
57
|
-
// ---------------------------------------------------------------------------
|
|
58
|
-
// Main menu view
|
|
59
|
-
// ---------------------------------------------------------------------------
|
|
60
|
-
/** Main menu showing all controls organized by section. */
|
|
61
|
-
function MainMenu({ sectionGroups, onNavigate, }) {
|
|
62
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "border-b border-border px-4 py-3", children: [_jsx("div", { className: "text-xs font-semibold text-foreground", children: "Chart configuration" }), _jsx("div", { className: "mt-0.5 text-[10px] text-muted-foreground", children: "Customize how your data is displayed" })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto overscroll-contain p-2", onWheel: (e) => e.stopPropagation(), children: sectionGroups.map(({ section, controls }, groupIdx) => (_jsxs("div", { children: [groupIdx > 0 && _jsx("div", { className: "mx-2 my-1.5 border-t border-border" }), _jsxs("div", { className: "px-2 pb-1 pt-2", children: [_jsx("div", { className: "mb-2 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: section.label }), _jsx("div", { className: "space-y-1", children: controls.map((id) => COMPLEX_CONTROLS.has(id) ? (_jsx(ComplexControlRow, { controlId: id, onNavigate: () => onNavigate(id) }, id)) : (_jsx(SimpleControlRow, { controlId: id }, id))) })] })] }, section.id))) })] }));
|
|
63
|
-
}
|
|
64
|
-
// ---------------------------------------------------------------------------
|
|
65
|
-
// Detail page view (drill-down)
|
|
66
|
-
// ---------------------------------------------------------------------------
|
|
67
|
-
/** Full-page detail view for a complex control, with back navigation. */
|
|
68
|
-
function DetailPage({ controlId, onBack }) {
|
|
69
|
-
const entry = CONTROL_REGISTRY[controlId];
|
|
70
|
-
const { filters, clearAllFilters } = useChartContext();
|
|
71
|
-
const filterActiveCount = controlId === 'filters' ? [...filters.values()].reduce((sum, set) => sum + set.size, 0) : 0;
|
|
72
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center gap-2 border-b border-border px-3 py-2.5", children: [_jsx("button", { onClick: onBack, className: "inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground", "aria-label": "Back", children: _jsx(ArrowLeft, { className: "h-3.5 w-3.5" }) }), controlId === 'filters' ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "min-w-0 flex-1 truncate text-xs font-semibold text-foreground", children: [filterActiveCount > 0 && (_jsxs("span", { className: "text-muted-foreground", children: [filterActiveCount, " filter", filterActiveCount !== 1 ? 's' : '', " active \u00B7", ' '] })), "Filters"] }), filterActiveCount > 0 && (_jsx("button", { onClick: () => clearAllFilters(), className: "shrink-0 rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground", "aria-label": "Clear all filters", children: _jsx(Eraser, { className: "h-3.5 w-3.5" }) }))] })) : (_jsx("div", { className: "text-xs font-semibold text-foreground", children: entry.label }))] }), _jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto overscroll-contain p-3", onWheel: (e) => e.stopPropagation(), children: [controlId === 'metric' && _jsx(ChartMetricPanel, {}), controlId === 'filters' && _jsx(ChartFiltersPanel, { showHeader: false }), controlId === 'dateRange' && _jsx(ChartDateRangePanel, {})] })] }));
|
|
73
|
-
}
|
|
74
|
-
// ---------------------------------------------------------------------------
|
|
75
|
-
// Control rows
|
|
76
|
-
// ---------------------------------------------------------------------------
|
|
77
|
-
/**
|
|
78
|
-
* A simple control row — label on the left, component on the right.
|
|
79
|
-
* Used for selects and toggle buttons that work inline without popovers.
|
|
80
|
-
*/
|
|
81
|
-
function SimpleControlRow({ controlId }) {
|
|
82
|
-
const entry = CONTROL_REGISTRY[controlId];
|
|
83
|
-
const Component = entry.component;
|
|
84
|
-
return (_jsxs("div", { className: "flex items-center gap-3 rounded-lg px-1 py-1.5", children: [_jsx("div", { className: "shrink-0 text-xs text-muted-foreground", children: entry.label }), _jsx("div", { className: "ml-auto flex min-w-0 items-center", children: _jsx(Component, {}) })] }));
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* A clickable row for complex controls — navigates to detail page on click.
|
|
88
|
-
* Shows the control label, current value summary, and a chevron.
|
|
89
|
-
*/
|
|
90
|
-
function ComplexControlRow({ controlId, onNavigate, }) {
|
|
91
|
-
const entry = CONTROL_REGISTRY[controlId];
|
|
92
|
-
return (_jsxs("button", { onClick: onNavigate, className: "flex w-full items-center gap-3 rounded-lg px-2 py-2 text-left transition-colors hover:bg-muted/50", children: [_jsx("div", { className: "shrink-0 text-xs text-muted-foreground", children: entry.label }), _jsx("div", { className: "ml-auto truncate text-xs text-foreground", children: _jsx(ControlSummary, { controlId: controlId }) }), _jsx(ChevronRight, { className: "h-3 w-3 shrink-0 text-muted-foreground" })] }));
|
|
93
|
-
}
|
|
94
|
-
/** Summary text for a complex control in the main menu. */
|
|
95
|
-
function ControlSummary({ controlId }) {
|
|
96
|
-
const { metric, columns, filters, dateRangeFilter } = useChartContext();
|
|
97
|
-
switch (controlId) {
|
|
98
|
-
case 'metric':
|
|
99
|
-
return _jsx("span", { children: getMetricLabel(metric, columns) });
|
|
100
|
-
case 'filters': {
|
|
101
|
-
const count = [...filters.values()].reduce((sum, set) => sum + set.size, 0);
|
|
102
|
-
return _jsx("span", { children: count > 0 ? `${count} active` : 'None' });
|
|
103
|
-
}
|
|
104
|
-
case 'dateRange':
|
|
105
|
-
return _jsx("span", { children: resolvePresetLabel(dateRangeFilter) });
|
|
106
|
-
default:
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Composable, configurable toolbar with pinned controls and an ellipsis
|
|
3
|
-
* overflow menu — inspired by Notion's clean database view toolbar.
|
|
4
|
-
*
|
|
5
|
-
* Default behavior: the date range stays pinned so the active time window is
|
|
6
|
-
* always visible, while the remaining controls live inside the overflow menu.
|
|
7
|
-
* Developers can pin additional controls to the toolbar row and hide others.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```tsx
|
|
11
|
-
* // Date range pinned by default, everything else in overflow
|
|
12
|
-
* <ChartToolbar />
|
|
13
|
-
*
|
|
14
|
-
* // Pin chart type and group-by to the toolbar row
|
|
15
|
-
* <ChartToolbar pinned={['chartType', 'groupBy']} />
|
|
16
|
-
*
|
|
17
|
-
* // Hide time bucket and x-axis entirely
|
|
18
|
-
* <ChartToolbar hidden={['timeBucket', 'xAxis']} />
|
|
19
|
-
*
|
|
20
|
-
* // Combine both
|
|
21
|
-
* <ChartToolbar pinned={['chartType', 'metric']} hidden={['source']} />
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
import type { ControlId } from './toolbar-types.js';
|
|
25
|
-
/**
|
|
26
|
-
* Props for ChartToolbar.
|
|
27
|
-
*
|
|
28
|
-
* @property className - Additional CSS classes for the toolbar container
|
|
29
|
-
* @property pinned - Control IDs to always show in the toolbar row (outside the overflow menu)
|
|
30
|
-
* @property hidden - Control IDs to completely hide (not in toolbar, not in overflow)
|
|
31
|
-
*/
|
|
32
|
-
type ChartToolbarProps = {
|
|
33
|
-
className?: string;
|
|
34
|
-
pinned?: readonly ControlId[];
|
|
35
|
-
hidden?: readonly ControlId[];
|
|
36
|
-
};
|
|
37
|
-
/**
|
|
38
|
-
* Composable toolbar with pinned controls and an ellipsis overflow menu.
|
|
39
|
-
*
|
|
40
|
-
* Controls are rendered in registry order. Each sub-component still
|
|
41
|
-
* auto-hides when not relevant (e.g. time bucket only shows for date X-axis).
|
|
42
|
-
*/
|
|
43
|
-
export declare function ChartToolbar({ className, pinned, hidden, }: ChartToolbarProps): import("react/jsx-runtime").JSX.Element;
|
|
44
|
-
export {};
|
|
45
|
-
//# sourceMappingURL=chart-toolbar.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chart-toolbar.d.ts","sourceRoot":"","sources":["../../src/ui/chart-toolbar.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAA;AAKjD;;;;;;GAMG;AACH,KAAK,iBAAiB,GAAG;IACvB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,SAAS,SAAS,EAAE,CAAA;IAC7B,MAAM,CAAC,EAAE,SAAS,SAAS,EAAE,CAAA;CAC9B,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAC3B,SAAS,EACT,MAAgC,EAChC,MAAW,GACZ,EAAE,iBAAiB,2CAoBnB"}
|
package/dist/ui/chart-toolbar.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* Composable, configurable toolbar with pinned controls and an ellipsis
|
|
4
|
-
* overflow menu — inspired by Notion's clean database view toolbar.
|
|
5
|
-
*
|
|
6
|
-
* Default behavior: the date range stays pinned so the active time window is
|
|
7
|
-
* always visible, while the remaining controls live inside the overflow menu.
|
|
8
|
-
* Developers can pin additional controls to the toolbar row and hide others.
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```tsx
|
|
12
|
-
* // Date range pinned by default, everything else in overflow
|
|
13
|
-
* <ChartToolbar />
|
|
14
|
-
*
|
|
15
|
-
* // Pin chart type and group-by to the toolbar row
|
|
16
|
-
* <ChartToolbar pinned={['chartType', 'groupBy']} />
|
|
17
|
-
*
|
|
18
|
-
* // Hide time bucket and x-axis entirely
|
|
19
|
-
* <ChartToolbar hidden={['timeBucket', 'xAxis']} />
|
|
20
|
-
*
|
|
21
|
-
* // Combine both
|
|
22
|
-
* <ChartToolbar pinned={['chartType', 'metric']} hidden={['source']} />
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
25
|
-
import { useMemo } from 'react';
|
|
26
|
-
import { ChartToolbarOverflow } from './chart-toolbar-overflow.js';
|
|
27
|
-
import { CONTROL_IDS, CONTROL_REGISTRY } from './toolbar-types.js';
|
|
28
|
-
const DEFAULT_PINNED_CONTROLS = ['dateRange'];
|
|
29
|
-
/**
|
|
30
|
-
* Composable toolbar with pinned controls and an ellipsis overflow menu.
|
|
31
|
-
*
|
|
32
|
-
* Controls are rendered in registry order. Each sub-component still
|
|
33
|
-
* auto-hides when not relevant (e.g. time bucket only shows for date X-axis).
|
|
34
|
-
*/
|
|
35
|
-
export function ChartToolbar({ className, pinned = DEFAULT_PINNED_CONTROLS, hidden = [], }) {
|
|
36
|
-
const pinnedSet = useMemo(() => new Set(pinned), [pinned]);
|
|
37
|
-
const hiddenSet = useMemo(() => new Set(hidden), [hidden]);
|
|
38
|
-
// Pinned controls in registry order
|
|
39
|
-
const pinnedControls = CONTROL_IDS.filter((id) => pinnedSet.has(id) && !hiddenSet.has(id));
|
|
40
|
-
return (_jsxs("div", { className: `flex items-start justify-between gap-2 ${className ?? ''}`, children: [_jsx("div", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-2", children: pinnedControls.map((id) => {
|
|
41
|
-
const Component = CONTROL_REGISTRY[id].component;
|
|
42
|
-
return _jsx(Component, {}, id);
|
|
43
|
-
}) }), _jsx(ChartToolbarOverflow, { pinned: pinnedSet, hidden: hiddenSet, className: "shrink-0 self-start" })] }));
|
|
44
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Chart type selector — inline toggle buttons for bar/line/area/pie/donut.
|
|
3
|
-
*/
|
|
4
|
-
/** Inline toggle buttons to select the chart type. */
|
|
5
|
-
export declare function ChartTypeSelector({ className }: {
|
|
6
|
-
className?: string;
|
|
7
|
-
}): import("react/jsx-runtime").JSX.Element | null;
|
|
8
|
-
//# sourceMappingURL=chart-type-selector.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chart-type-selector.d.ts","sourceRoot":"","sources":["../../src/ui/chart-type-selector.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAcH,sDAAsD;AACtD,wBAAgB,iBAAiB,CAAC,EAAC,SAAS,EAAC,EAAE;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAC,kDA+BlE"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useChartContext } from './chart-context.js';
|
|
3
|
-
/** Labels for each chart type. */
|
|
4
|
-
const CHART_TYPE_LABELS = {
|
|
5
|
-
bar: 'Bar',
|
|
6
|
-
line: 'Line',
|
|
7
|
-
area: 'Area',
|
|
8
|
-
pie: 'Pie',
|
|
9
|
-
donut: 'Donut',
|
|
10
|
-
};
|
|
11
|
-
/** Inline toggle buttons to select the chart type. */
|
|
12
|
-
export function ChartTypeSelector({ className }) {
|
|
13
|
-
const { chartType, setChartType, availableChartTypes } = useChartContext();
|
|
14
|
-
if (availableChartTypes.length <= 1)
|
|
15
|
-
return null;
|
|
16
|
-
return (_jsx("div", { className: `inline-flex items-center rounded-lg border border-border/50 bg-muted/50 p-0.5 shadow-sm ${className ?? ''}`, role: "tablist", "aria-label": "Chart type", children: availableChartTypes.map((type) => {
|
|
17
|
-
const isActive = type === chartType;
|
|
18
|
-
return (_jsx("button", { role: "tab", "aria-selected": isActive, onClick: () => setChartType(type), className: `rounded-md px-2.5 py-1 text-xs font-medium transition-all ${isActive
|
|
19
|
-
? 'bg-background text-foreground shadow-sm'
|
|
20
|
-
: 'text-muted-foreground hover:bg-background/50 hover:text-foreground'}`, children: CHART_TYPE_LABELS[type] }, type));
|
|
21
|
-
}) }));
|
|
22
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* X-axis selector — premium custom dropdown for choosing which column drives the X-axis.
|
|
3
|
-
*/
|
|
4
|
-
/** Custom dropdown to select the X-axis column. */
|
|
5
|
-
export declare function ChartXAxisSelector({ className }: {
|
|
6
|
-
className?: string;
|
|
7
|
-
}): import("react/jsx-runtime").JSX.Element | null;
|
|
8
|
-
//# sourceMappingURL=chart-x-axis-selector.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chart-x-axis-selector.d.ts","sourceRoot":"","sources":["../../src/ui/chart-x-axis-selector.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAKH,mDAAmD;AACnD,wBAAgB,kBAAkB,CAAC,EAAC,SAAS,EAAC,EAAE;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAC,kDAgBnE"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* X-axis selector — premium custom dropdown for choosing which column drives the X-axis.
|
|
4
|
-
*/
|
|
5
|
-
import { useChartContext } from './chart-context.js';
|
|
6
|
-
import { ChartSelect } from './chart-select.js';
|
|
7
|
-
/** Custom dropdown to select the X-axis column. */
|
|
8
|
-
export function ChartXAxisSelector({ className }) {
|
|
9
|
-
const { xAxisId, setXAxis, availableXAxes } = useChartContext();
|
|
10
|
-
if (availableXAxes.length <= 1)
|
|
11
|
-
return null;
|
|
12
|
-
const options = availableXAxes.map((col) => ({ value: col.id, label: `X-axis: ${col.label}` }));
|
|
13
|
-
return (_jsx(ChartSelect, { value: xAxisId ?? '', options: options, onChange: (v) => setXAxis(v), ariaLabel: "X-axis", className: className }));
|
|
14
|
-
}
|