@matthieumordrel/chart-studio 0.1.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/LICENSE +21 -0
- package/README.md +371 -0
- package/dist/core/chart-capabilities.d.ts +60 -0
- package/dist/core/chart-capabilities.d.ts.map +1 -0
- package/dist/core/chart-capabilities.js +55 -0
- package/dist/core/chart-capabilities.js.map +1 -0
- package/dist/core/colors.d.ts +25 -0
- package/dist/core/colors.d.ts.map +1 -0
- package/dist/core/colors.js +55 -0
- package/dist/core/colors.js.map +1 -0
- package/dist/core/config-utils.d.ts +43 -0
- package/dist/core/config-utils.d.ts.map +1 -0
- package/dist/core/config-utils.js +81 -0
- package/dist/core/config-utils.js.map +1 -0
- package/dist/core/date-utils.d.ts +29 -0
- package/dist/core/date-utils.d.ts.map +1 -0
- package/dist/core/date-utils.js +59 -0
- package/dist/core/date-utils.js.map +1 -0
- package/dist/core/define-chart-schema.d.ts +105 -0
- package/dist/core/define-chart-schema.d.ts.map +1 -0
- package/dist/core/define-chart-schema.js +45 -0
- package/dist/core/define-chart-schema.js.map +1 -0
- package/dist/core/formatting.d.ts +47 -0
- package/dist/core/formatting.d.ts.map +1 -0
- package/dist/core/formatting.js +397 -0
- package/dist/core/formatting.js.map +1 -0
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +13 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/infer-columns.d.ts +6 -0
- package/dist/core/infer-columns.d.ts.map +1 -0
- package/dist/core/infer-columns.js +513 -0
- package/dist/core/infer-columns.js.map +1 -0
- package/dist/core/metric-utils.d.ts +43 -0
- package/dist/core/metric-utils.d.ts.map +1 -0
- package/dist/core/metric-utils.js +142 -0
- package/dist/core/metric-utils.js.map +1 -0
- package/dist/core/pipeline-data-points.d.ts +23 -0
- package/dist/core/pipeline-data-points.d.ts.map +1 -0
- package/dist/core/pipeline-data-points.js +236 -0
- package/dist/core/pipeline-data-points.js.map +1 -0
- package/dist/core/pipeline-helpers.d.ts +38 -0
- package/dist/core/pipeline-helpers.d.ts.map +1 -0
- package/dist/core/pipeline-helpers.js +98 -0
- package/dist/core/pipeline-helpers.js.map +1 -0
- package/dist/core/pipeline.d.ts +70 -0
- package/dist/core/pipeline.d.ts.map +1 -0
- package/dist/core/pipeline.js +157 -0
- package/dist/core/pipeline.js.map +1 -0
- package/dist/core/types.d.ts +1109 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +15 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/use-chart-options.d.ts +66 -0
- package/dist/core/use-chart-options.d.ts.map +1 -0
- package/dist/core/use-chart-options.js +5 -0
- package/dist/core/use-chart-options.js.map +1 -0
- package/dist/core/use-chart-resolvers.d.ts +14 -0
- package/dist/core/use-chart-resolvers.d.ts.map +1 -0
- package/dist/core/use-chart-resolvers.js +42 -0
- package/dist/core/use-chart-resolvers.js.map +1 -0
- package/dist/core/use-chart.d.ts +47 -0
- package/dist/core/use-chart.d.ts.map +1 -0
- package/dist/core/use-chart.js +266 -0
- package/dist/core/use-chart.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/ui/chart-axis-ticks.d.ts +35 -0
- package/dist/ui/chart-axis-ticks.d.ts.map +1 -0
- package/dist/ui/chart-axis-ticks.js +80 -0
- package/dist/ui/chart-axis-ticks.js.map +1 -0
- package/dist/ui/chart-canvas.d.ts +22 -0
- package/dist/ui/chart-canvas.d.ts.map +1 -0
- package/dist/ui/chart-canvas.js +338 -0
- package/dist/ui/chart-canvas.js.map +1 -0
- package/dist/ui/chart-context.d.ts +89 -0
- package/dist/ui/chart-context.d.ts.map +1 -0
- package/dist/ui/chart-context.js +129 -0
- package/dist/ui/chart-context.js.map +1 -0
- package/dist/ui/chart-date-range-badge.d.ts +14 -0
- package/dist/ui/chart-date-range-badge.d.ts.map +1 -0
- package/dist/ui/chart-date-range-badge.js +31 -0
- package/dist/ui/chart-date-range-badge.js.map +1 -0
- package/dist/ui/chart-date-range-panel.d.ts +25 -0
- package/dist/ui/chart-date-range-panel.d.ts.map +1 -0
- package/dist/ui/chart-date-range-panel.js +126 -0
- package/dist/ui/chart-date-range-panel.js.map +1 -0
- package/dist/ui/chart-date-range.d.ts +14 -0
- package/dist/ui/chart-date-range.d.ts.map +1 -0
- package/dist/ui/chart-date-range.js +38 -0
- package/dist/ui/chart-date-range.js.map +1 -0
- package/dist/ui/chart-debug.d.ts +10 -0
- package/dist/ui/chart-debug.d.ts.map +1 -0
- package/dist/ui/chart-debug.js +127 -0
- package/dist/ui/chart-debug.js.map +1 -0
- package/dist/ui/chart-dropdown.d.ts +35 -0
- package/dist/ui/chart-dropdown.d.ts.map +1 -0
- package/dist/ui/chart-dropdown.js +77 -0
- package/dist/ui/chart-dropdown.js.map +1 -0
- package/dist/ui/chart-filters-panel.d.ts +19 -0
- package/dist/ui/chart-filters-panel.d.ts.map +1 -0
- package/dist/ui/chart-filters-panel.js +47 -0
- package/dist/ui/chart-filters-panel.js.map +1 -0
- package/dist/ui/chart-filters.d.ts +12 -0
- package/dist/ui/chart-filters.d.ts.map +1 -0
- package/dist/ui/chart-filters.js +27 -0
- package/dist/ui/chart-filters.js.map +1 -0
- package/dist/ui/chart-group-by-selector.d.ts +8 -0
- package/dist/ui/chart-group-by-selector.d.ts.map +1 -0
- package/dist/ui/chart-group-by-selector.js +20 -0
- package/dist/ui/chart-group-by-selector.js.map +1 -0
- package/dist/ui/chart-metric-panel.d.ts +18 -0
- package/dist/ui/chart-metric-panel.d.ts.map +1 -0
- package/dist/ui/chart-metric-panel.js +119 -0
- package/dist/ui/chart-metric-panel.js.map +1 -0
- package/dist/ui/chart-metric-selector.d.ts +10 -0
- package/dist/ui/chart-metric-selector.d.ts.map +1 -0
- package/dist/ui/chart-metric-selector.js +28 -0
- package/dist/ui/chart-metric-selector.js.map +1 -0
- package/dist/ui/chart-select.d.ts +25 -0
- package/dist/ui/chart-select.d.ts.map +1 -0
- package/dist/ui/chart-select.js +36 -0
- package/dist/ui/chart-select.js.map +1 -0
- package/dist/ui/chart-source-switcher.d.ts +16 -0
- package/dist/ui/chart-source-switcher.d.ts.map +1 -0
- package/dist/ui/chart-source-switcher.js +32 -0
- package/dist/ui/chart-source-switcher.js.map +1 -0
- package/dist/ui/chart-time-bucket-selector.d.ts +9 -0
- package/dist/ui/chart-time-bucket-selector.d.ts.map +1 -0
- package/dist/ui/chart-time-bucket-selector.js +26 -0
- package/dist/ui/chart-time-bucket-selector.js.map +1 -0
- package/dist/ui/chart-toolbar-overflow.d.ts +29 -0
- package/dist/ui/chart-toolbar-overflow.d.ts.map +1 -0
- package/dist/ui/chart-toolbar-overflow.js +110 -0
- package/dist/ui/chart-toolbar-overflow.js.map +1 -0
- package/dist/ui/chart-toolbar.d.ts +45 -0
- package/dist/ui/chart-toolbar.d.ts.map +1 -0
- package/dist/ui/chart-toolbar.js +45 -0
- package/dist/ui/chart-toolbar.js.map +1 -0
- package/dist/ui/chart-type-selector.d.ts +8 -0
- package/dist/ui/chart-type-selector.d.ts.map +1 -0
- package/dist/ui/chart-type-selector.js +23 -0
- package/dist/ui/chart-type-selector.js.map +1 -0
- package/dist/ui/chart-x-axis-selector.d.ts +8 -0
- package/dist/ui/chart-x-axis-selector.d.ts.map +1 -0
- package/dist/ui/chart-x-axis-selector.js +15 -0
- package/dist/ui/chart-x-axis-selector.js.map +1 -0
- package/dist/ui/index.d.ts +25 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +24 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/theme.css +62 -0
- package/dist/ui/toolbar-types.d.ts +43 -0
- package/dist/ui/toolbar-types.d.ts.map +1 -0
- package/dist/ui/toolbar-types.js +51 -0
- package/dist/ui/toolbar-types.js.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Shared dropdown panel primitive for chart-studio popover controls.
|
|
4
|
+
* Provides a positioned floating panel with backdrop, premium layered
|
|
5
|
+
* shadows, and close-on-click-outside.
|
|
6
|
+
*/
|
|
7
|
+
import { useLayoutEffect, useRef, useState } from 'react';
|
|
8
|
+
import { createPortal } from 'react-dom';
|
|
9
|
+
/**
|
|
10
|
+
* Positioned dropdown panel with premium styling.
|
|
11
|
+
* Renders a transparent backdrop overlay and a fixed-position content panel
|
|
12
|
+
* anchored to a trigger element.
|
|
13
|
+
*
|
|
14
|
+
* @property isOpen - Whether the panel is visible
|
|
15
|
+
* @property onClose - Callback to close the panel
|
|
16
|
+
* @property triggerRef - Ref to the button or element that anchors the panel
|
|
17
|
+
* @property align - Horizontal alignment relative to trigger ('left' | 'right')
|
|
18
|
+
* @property width - Fixed panel width in pixels
|
|
19
|
+
* @property minWidth - Minimum panel width in pixels or equal to trigger width
|
|
20
|
+
* @property offset - Gap between trigger and panel
|
|
21
|
+
* @property repositionKey - Value that forces re-measurement when panel content changes
|
|
22
|
+
* @property className - Additional CSS classes for the content area
|
|
23
|
+
* @property children - Panel content
|
|
24
|
+
*/
|
|
25
|
+
export function ChartDropdownPanel({ isOpen, onClose, triggerRef, align = 'left', width, minWidth, offset = 6, repositionKey, className, children, }) {
|
|
26
|
+
const panelRef = useRef(null);
|
|
27
|
+
const [position, setPosition] = useState(null);
|
|
28
|
+
useLayoutEffect(() => {
|
|
29
|
+
if (!isOpen) {
|
|
30
|
+
setPosition(null);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Measure the trigger and panel, then place the panel in the best
|
|
35
|
+
* available viewport position.
|
|
36
|
+
*/
|
|
37
|
+
function updatePosition() {
|
|
38
|
+
const trigger = triggerRef.current;
|
|
39
|
+
const panel = panelRef.current;
|
|
40
|
+
if (!trigger || !panel) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
44
|
+
const measuredPanelWidth = width ?? panel.offsetWidth;
|
|
45
|
+
const resolvedMinWidth = minWidth === 'trigger' ? triggerRect.width : minWidth;
|
|
46
|
+
const panelWidth = Math.max(measuredPanelWidth, resolvedMinWidth ?? 0);
|
|
47
|
+
const panelHeight = panel.offsetHeight;
|
|
48
|
+
let left = align === 'right' ? triggerRect.right - panelWidth : triggerRect.left;
|
|
49
|
+
left = Math.min(Math.max(left, 8), window.innerWidth - panelWidth - 8);
|
|
50
|
+
const spaceBelow = window.innerHeight - triggerRect.bottom;
|
|
51
|
+
const openAbove = spaceBelow < panelHeight + offset && triggerRect.top >= panelHeight + offset;
|
|
52
|
+
let top = openAbove ? triggerRect.top - panelHeight - offset : triggerRect.bottom + offset;
|
|
53
|
+
top = Math.max(8, Math.min(top, window.innerHeight - panelHeight - 8));
|
|
54
|
+
setPosition({ top, left });
|
|
55
|
+
}
|
|
56
|
+
updatePosition();
|
|
57
|
+
window.addEventListener('resize', updatePosition);
|
|
58
|
+
window.addEventListener('scroll', updatePosition, true);
|
|
59
|
+
return () => {
|
|
60
|
+
window.removeEventListener('resize', updatePosition);
|
|
61
|
+
window.removeEventListener('scroll', updatePosition, true);
|
|
62
|
+
};
|
|
63
|
+
}, [align, isOpen, minWidth, offset, repositionKey, triggerRef, width]);
|
|
64
|
+
if (!isOpen)
|
|
65
|
+
return null;
|
|
66
|
+
if (typeof document === 'undefined') {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return createPortal(_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-40", onClick: onClose }), _jsx("div", { ref: panelRef, className: `fixed z-50 overflow-hidden rounded-xl border border-border/50 bg-popover text-popover-foreground shadow-[0_8px_30px_-6px_rgba(0,0,0,0.12),0_2px_8px_-2px_rgba(0,0,0,0.05)] ${className ?? ''}`, style: {
|
|
70
|
+
top: position?.top ?? 0,
|
|
71
|
+
left: position?.left ?? 0,
|
|
72
|
+
width,
|
|
73
|
+
minWidth: minWidth === 'trigger' ? triggerRef.current?.getBoundingClientRect().width : minWidth,
|
|
74
|
+
visibility: position ? 'visible' : 'hidden',
|
|
75
|
+
}, onWheel: (e) => e.stopPropagation(), children: children })] }), document.body);
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=chart-dropdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-dropdown.js","sourceRoot":"","sources":["../../src/ui/chart-dropdown.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filters panel content — reusable by both ChartFilters (inside a popover)
|
|
3
|
+
* and ChartToolbarOverflow (rendered inline).
|
|
4
|
+
*
|
|
5
|
+
* Shows filterable columns as collapsible sections with checkbox options.
|
|
6
|
+
* Each column section can be expanded/collapsed independently.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Filters panel content (no popover wrapper).
|
|
10
|
+
*
|
|
11
|
+
* @property className - Additional CSS classes
|
|
12
|
+
* @property showHeader - When true (default), shows "X filter(s) active · Filters" + clear icon.
|
|
13
|
+
* Set false when the header is rendered by the parent (e.g. overflow DetailPage).
|
|
14
|
+
*/
|
|
15
|
+
export declare function ChartFiltersPanel({ className, showHeader, }: {
|
|
16
|
+
className?: string;
|
|
17
|
+
showHeader?: boolean;
|
|
18
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
//# sourceMappingURL=chart-filters-panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-filters-panel.d.ts","sourceRoot":"","sources":["../../src/ui/chart-filters-panel.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,UAAiB,GAClB,EAAE;IACD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,2CAoDA"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Filters panel content — reusable by both ChartFilters (inside a popover)
|
|
4
|
+
* and ChartToolbarOverflow (rendered inline).
|
|
5
|
+
*
|
|
6
|
+
* Shows filterable columns as collapsible sections with checkbox options.
|
|
7
|
+
* Each column section can be expanded/collapsed independently.
|
|
8
|
+
*/
|
|
9
|
+
import { useState } from 'react';
|
|
10
|
+
import { ChevronDown, Eraser } from 'lucide-react';
|
|
11
|
+
import { useChartContext } from './chart-context.js';
|
|
12
|
+
/** Maximum number of options to show per column before collapsing. */
|
|
13
|
+
const MAX_VISIBLE_OPTIONS = 6;
|
|
14
|
+
/**
|
|
15
|
+
* Filters panel content (no popover wrapper).
|
|
16
|
+
*
|
|
17
|
+
* @property className - Additional CSS classes
|
|
18
|
+
* @property showHeader - When true (default), shows "X filter(s) active · Filters" + clear icon.
|
|
19
|
+
* Set false when the header is rendered by the parent (e.g. overflow DetailPage).
|
|
20
|
+
*/
|
|
21
|
+
export function ChartFiltersPanel({ className, showHeader = true, }) {
|
|
22
|
+
const { availableFilters, filters, toggleFilter, clearAllFilters } = useChartContext();
|
|
23
|
+
// Count total active filters
|
|
24
|
+
const activeCount = [...filters.values()].reduce((sum, set) => sum + set.size, 0);
|
|
25
|
+
if (availableFilters.length === 0) {
|
|
26
|
+
return (_jsx("div", { className: className, children: _jsx("div", { className: "py-6 text-center text-xs text-muted-foreground", children: "No filterable columns" }) }));
|
|
27
|
+
}
|
|
28
|
+
return (_jsxs("div", { className: className, children: [showHeader && (_jsxs("div", { className: "mb-3 flex items-center justify-between gap-2", children: [_jsxs("div", { className: "truncate text-xs font-semibold text-foreground", children: [activeCount > 0 && (_jsxs("span", { className: "text-muted-foreground", children: [activeCount, " filter", activeCount !== 1 ? 's' : '', " active \u00B7", ' '] })), "Filters"] }), activeCount > 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: "space-y-1", children: availableFilters.map((filter) => (_jsx(FilterSection, { filter: filter, activeValues: filters.get(filter.columnId), onToggle: (value) => toggleFilter(filter.columnId, value) }, filter.columnId))) })] }));
|
|
29
|
+
}
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Sub-components
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
/** A collapsible filter column section with checkable options. */
|
|
34
|
+
function FilterSection({ filter, activeValues, onToggle, }) {
|
|
35
|
+
const [isOpen, setIsOpen] = useState(true);
|
|
36
|
+
const [expanded, setExpanded] = useState(false);
|
|
37
|
+
const visibleOptions = expanded ? filter.options : filter.options.slice(0, MAX_VISIBLE_OPTIONS);
|
|
38
|
+
const hasMore = filter.options.length > MAX_VISIBLE_OPTIONS;
|
|
39
|
+
const activeCount = activeValues?.size ?? 0;
|
|
40
|
+
return (_jsxs("div", { className: "rounded-lg", children: [_jsxs("button", { onClick: () => setIsOpen(!isOpen), className: "flex w-full items-center gap-2 rounded-lg px-2 py-1.5 text-left transition-colors hover:bg-muted/50", children: [_jsx(ChevronDown, { className: `h-3 w-3 shrink-0 text-muted-foreground transition-transform ${isOpen ? '' : '-rotate-90'}` }), _jsx("span", { className: "text-[11px] font-semibold text-foreground", children: filter.label }), activeCount > 0 && (_jsx("span", { className: "ml-auto flex h-4 min-w-4 items-center justify-center rounded-full bg-primary/10 px-1.5 text-[9px] font-semibold text-primary", children: activeCount }))] }), isOpen && (_jsxs("div", { className: "pb-1 pl-2 pr-1 pt-0.5", children: [_jsx("div", { className: "space-y-px", children: visibleOptions.map((option) => {
|
|
41
|
+
const isActive = activeValues?.has(option.value) ?? false;
|
|
42
|
+
return (_jsxs("button", { onClick: () => onToggle(option.value), className: `flex w-full items-center gap-2.5 rounded-md px-2 py-1.5 text-left text-xs transition-colors ${isActive ? 'bg-primary/8 text-primary' : 'text-foreground hover:bg-muted/60'}`, children: [_jsx("div", { className: `flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors ${isActive
|
|
43
|
+
? 'border-primary bg-primary'
|
|
44
|
+
: 'border-muted-foreground/30 bg-background'}`, children: isActive && (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "10", height: "10", 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" }) })) }), _jsx("span", { className: "flex-1 truncate", children: option.label }), _jsx("span", { className: "shrink-0 tabular-nums text-[10px] text-muted-foreground/70", children: option.count })] }, option.value));
|
|
45
|
+
}) }), hasMore && (_jsx("button", { onClick: () => setExpanded(!expanded), className: "mt-1 w-full rounded-md px-2 py-1 text-left text-[10px] font-medium text-muted-foreground transition-colors hover:bg-muted/60 hover:text-foreground", children: expanded ? 'Show less' : `Show ${filter.options.length - MAX_VISIBLE_OPTIONS} more…` }))] }))] }));
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=chart-filters-panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-filters-panel.js","sourceRoot":"","sources":["../../src/ui/chart-filters-panel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chart filters — compact button that shows active filter count.
|
|
3
|
+
* Clicking reveals a popover wrapping ChartFiltersPanel.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Compact filter button + dropdown for all filterable columns.
|
|
7
|
+
* Shows a count badge when filters are active.
|
|
8
|
+
*/
|
|
9
|
+
export declare function ChartFilters({ className }: {
|
|
10
|
+
className?: string;
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
12
|
+
//# sourceMappingURL=chart-filters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-filters.d.ts","sourceRoot":"","sources":["../../src/ui/chart-filters.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAQH;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAC,SAAS,EAAC,EAAE;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAC,kDA2C7D"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Chart filters — compact button that shows active filter count.
|
|
4
|
+
* Clicking reveals a popover wrapping ChartFiltersPanel.
|
|
5
|
+
*/
|
|
6
|
+
import { useRef, useState } from 'react';
|
|
7
|
+
import { Filter } from 'lucide-react';
|
|
8
|
+
import { useChartContext } from './chart-context.js';
|
|
9
|
+
import { ChartDropdownPanel } from './chart-dropdown.js';
|
|
10
|
+
import { ChartFiltersPanel } from './chart-filters-panel.js';
|
|
11
|
+
/**
|
|
12
|
+
* Compact filter button + dropdown for all filterable columns.
|
|
13
|
+
* Shows a count badge when filters are active.
|
|
14
|
+
*/
|
|
15
|
+
export function ChartFilters({ className }) {
|
|
16
|
+
const { availableFilters, filters } = useChartContext();
|
|
17
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
18
|
+
const triggerRef = useRef(null);
|
|
19
|
+
if (availableFilters.length === 0)
|
|
20
|
+
return null;
|
|
21
|
+
const activeCount = [...filters.values()].reduce((sum, set) => sum + set.size, 0);
|
|
22
|
+
const isActive = activeCount > 0;
|
|
23
|
+
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
|
|
24
|
+
? 'border-primary/30 bg-primary/5 text-primary shadow-sm shadow-primary/5 hover:bg-primary/8'
|
|
25
|
+
: 'border-border/50 bg-background text-muted-foreground shadow-sm hover:border-border hover:bg-muted/30 hover:shadow hover:text-foreground'}`, children: [_jsx(Filter, { className: "h-3 w-3" }), "Filters", isActive && (_jsx("span", { className: "flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-semibold text-primary-foreground", children: activeCount }))] }), _jsx(ChartDropdownPanel, { isOpen: isOpen, onClose: () => setIsOpen(false), triggerRef: triggerRef, width: 288, className: "max-h-[420px] overflow-y-auto overscroll-contain p-3", children: _jsx(ChartFiltersPanel, {}) })] }));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=chart-filters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-filters.js","sourceRoot":"","sources":["../../src/ui/chart-filters.tsx"],"names":[],"mappings":";AAAA;;;GAGG;AAEH,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AACtC,OAAO,EAAC,MAAM,EAAC,MAAM,cAAc,CAAA;AACnC,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAC,kBAAkB,EAAC,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAC,iBAAiB,EAAC,MAAM,0BAA0B,CAAA;AAE1D;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,EAAC,SAAS,EAAuB;IAC5D,MAAM,EAAC,gBAAgB,EAAE,OAAO,EAAC,GAAG,eAAe,EAAE,CAAA;IACrD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,UAAU,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAA;IAElD,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IAE9C,MAAM,WAAW,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;IACjF,MAAM,QAAQ,GAAG,WAAW,GAAG,CAAC,CAAA;IAEhC,OAAO,CACL,eAAK,SAAS,EAAE,SAAS,aAEvB,kBACE,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,EACjC,SAAS,EAAE,+KACT,QAAQ;oBACN,CAAC,CAAC,2FAA2F;oBAC7F,CAAC,CAAC,yIACN,EAAE,aAEF,KAAC,MAAM,IAAC,SAAS,EAAC,SAAS,GAAG,aAE7B,QAAQ,IAAI,CACX,eAAM,SAAS,EAAC,6HAA6H,YAC1I,WAAW,GACP,CACR,IACM,EAGT,KAAC,kBAAkB,IACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAC/B,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,GAAG,EACV,SAAS,EAAC,sDAAsD,YAEhE,KAAC,iBAAiB,KAAG,GACF,IACjB,CACP,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GroupBy selector — premium custom dropdown replacing native <select>.
|
|
3
|
+
*/
|
|
4
|
+
/** Custom dropdown to select the groupBy column. */
|
|
5
|
+
export declare function ChartGroupBySelector({ className }: {
|
|
6
|
+
className?: string;
|
|
7
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
8
|
+
//# sourceMappingURL=chart-group-by-selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-group-by-selector.d.ts","sourceRoot":"","sources":["../../src/ui/chart-group-by-selector.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAMH,oDAAoD;AACpD,wBAAgB,oBAAoB,CAAC,EAAC,SAAS,EAAC,EAAE;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAC,kDAqBrE"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* GroupBy selector — premium custom dropdown replacing native <select>.
|
|
4
|
+
*/
|
|
5
|
+
import { CHART_TYPE_CONFIG } from '../core/chart-capabilities.js';
|
|
6
|
+
import { useChartContext } from './chart-context.js';
|
|
7
|
+
import { ChartSelect } from './chart-select.js';
|
|
8
|
+
/** Custom dropdown to select the groupBy column. */
|
|
9
|
+
export function ChartGroupBySelector({ className }) {
|
|
10
|
+
const { chartType, groupById, setGroupBy, availableGroupBys } = useChartContext();
|
|
11
|
+
if (!CHART_TYPE_CONFIG[chartType].supportsGrouping || availableGroupBys.length === 0) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const options = [
|
|
15
|
+
{ value: '', label: 'No grouping' },
|
|
16
|
+
...availableGroupBys.map((col) => ({ value: col.id, label: col.label })),
|
|
17
|
+
];
|
|
18
|
+
return (_jsx(ChartSelect, { value: groupById ?? '', options: options, onChange: (v) => setGroupBy(v || null), ariaLabel: "Group by", className: className }));
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=chart-group-by-selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-group-by-selector.js","sourceRoot":"","sources":["../../src/ui/chart-group-by-selector.tsx"],"names":[],"mappings":";AAAA;;GAEG;AAEH,OAAO,EAAC,iBAAiB,EAAC,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAC,WAAW,EAAC,MAAM,mBAAmB,CAAA;AAE7C,oDAAoD;AACpD,MAAM,UAAU,oBAAoB,CAAC,EAAC,SAAS,EAAuB;IACpE,MAAM,EAAC,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,iBAAiB,EAAC,GAAG,eAAe,EAAE,CAAA;IAE/E,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,gBAAgB,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrF,OAAO,IAAI,CAAA;IACb,CAAC;IAED,MAAM,OAAO,GAAG;QACd,EAAC,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,aAAa,EAAC;QACjC,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAC,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAC,CAAC,CAAC;KACvE,CAAA;IAED,OAAO,CACL,KAAC,WAAW,IACV,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,IAAI,CAAC,EACtC,SAAS,EAAC,UAAU,EACpB,SAAS,EAAE,SAAS,GACpB,CACH,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metric panel content — reusable by both ChartMetricSelector (inside a popover)
|
|
3
|
+
* and ChartToolbarOverflow (rendered inline).
|
|
4
|
+
*
|
|
5
|
+
* Shows a "Count" option plus grouped number columns with aggregate buttons
|
|
6
|
+
* (Sum, Avg, Min, Max) and an "Exclude zeros" toggle per column.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Metric panel content (no popover wrapper).
|
|
10
|
+
*
|
|
11
|
+
* @property onClose - Optional callback when user makes a definitive selection (e.g. "Count")
|
|
12
|
+
* @property className - Additional CSS classes
|
|
13
|
+
*/
|
|
14
|
+
export declare function ChartMetricPanel({ onClose, className }: {
|
|
15
|
+
onClose?: () => void;
|
|
16
|
+
className?: string;
|
|
17
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
//# sourceMappingURL=chart-metric-panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-metric-panel.d.ts","sourceRoot":"","sources":["../../src/ui/chart-metric-panel.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA+LH;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAAC,OAAO,EAAE,SAAS,EAAC,EAAE;IAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAC,2CAqFhG"}
|
|
@@ -0,0 +1,119 @@
|
|
|
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
|
+
}
|
|
119
|
+
//# sourceMappingURL=chart-metric-panel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-metric-panel.js","sourceRoot":"","sources":["../../src/ui/chart-metric-panel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
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
|
+
}
|
|
28
|
+
//# sourceMappingURL=chart-metric-selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-metric-selector.js","sourceRoot":"","sources":["../../src/ui/chart-metric-selector.tsx"],"names":[],"mappings":";AAAA;;;;GAIG;AAEH,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AACtC,OAAO,EAAC,WAAW,EAAE,cAAc,EAAC,MAAM,cAAc,CAAA;AACxD,OAAO,EAAC,cAAc,EAAE,iBAAiB,EAAC,MAAM,yBAAyB,CAAA;AACzE,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAC,kBAAkB,EAAC,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAA;AAExD,iFAAiF;AACjF,MAAM,UAAU,mBAAmB,CAAC,EAAC,SAAS,EAAuB;IACnE,MAAM,EAAC,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAC,GAAG,eAAe,EAAE,CAAA;IAC7D,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,UAAU,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAA;IAElD,IAAI,gBAAgB,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAE7C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,KAAK,OAAO,CAAA;IACvC,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAA;IACzB,MAAM,YAAY,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IACrF,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAE7C,OAAO,CACL,eAAK,SAAS,EAAE,SAAS,aAEvB,kBACE,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,EACjC,SAAS,EAAE,+KACT,QAAQ;oBACN,CAAC,CAAC,2FAA2F;oBAC7F,CAAC,CAAC,yIACN,EAAE,gBACS,QAAQ,aAEnB,KAAC,cAAc,IAAC,SAAS,EAAC,SAAS,GAAG,EACtC,yBAAO,KAAK,GAAQ,EACnB,QAAQ,IAAI,CAAC,YAAY,IAAI,CAC5B,eAAM,SAAS,EAAC,0EAA0E,wBAEnF,CACR,EACD,KAAC,WAAW,IACV,SAAS,EAAE,yDAAyD,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,GAChG,IACK,EAGT,KAAC,kBAAkB,IACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAC/B,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,GAAG,EACV,SAAS,EAAC,KAAK,YAEf,KAAC,gBAAgB,IAAC,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,GAAI,GAClC,IACjB,CACP,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
}
|
|
36
|
+
//# sourceMappingURL=chart-select.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-select.js","sourceRoot":"","sources":["../../src/ui/chart-select.tsx"],"names":[],"mappings":";AAAA;;;;GAIG;AAEH,OAAO,EAAC,MAAM,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AACtC,OAAO,EAAC,WAAW,EAAC,MAAM,cAAc,CAAA;AACxC,OAAO,EAAC,kBAAkB,EAAC,MAAM,qBAAqB,CAAA;AAEtD;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAmB,EAC5C,KAAK,EACL,OAAO,EACP,QAAQ,EACR,SAAS,EACT,SAAS,GAOV;IACC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,UAAU,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAA;IAClD,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAA;IAEvD,2BAA2B;IAC3B,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,SAAS,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,CAAA;IAClC,CAAC,CAAA;IAED,+CAA+C;IAC/C,MAAM,YAAY,GAAG,CAAC,WAAc,EAAE,EAAE;QACtC,QAAQ,CAAC,WAAW,CAAC,CAAA;QACrB,SAAS,CAAC,KAAK,CAAC,CAAA;IAClB,CAAC,CAAA;IAED,OAAO,CACL,eAAK,SAAS,EAAE,SAAS,aAEvB,kBACE,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,YAAY,EACrB,SAAS,EAAC,yRAAyR,gBACvR,SAAS,aAErB,eAAM,SAAS,EAAC,UAAU,YAAE,QAAQ,EAAE,KAAK,IAAI,KAAK,GAAQ,EAC5D,KAAC,WAAW,IACV,SAAS,EAAE,kEAAkE,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,GACzG,IACK,EAGT,KAAC,kBAAkB,IACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAC/B,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAC,SAAS,EAClB,SAAS,EAAC,KAAK,YAEd,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CACvB,iBAEE,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,EACzC,SAAS,EAAE,qFACT,MAAM,CAAC,KAAK,KAAK,KAAK;wBACpB,CAAC,CAAC,uCAAuC;wBACzC,CAAC,CAAC,mCACN,EAAE,YAEF,eAAM,SAAS,EAAC,UAAU,YAAE,MAAM,CAAC,KAAK,GAAQ,IAR3C,MAAM,CAAC,KAAK,CASV,CACV,CAAC,GACiB,IACjB,CACP,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data source control — adapts based on single vs multi-source.
|
|
3
|
+
*
|
|
4
|
+
* Single source: read-only badge showing source label + record count.
|
|
5
|
+
* Multi source: dropdown to switch between data sources.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Data source display/switcher.
|
|
9
|
+
*
|
|
10
|
+
* - Single source → read-only badge: "[icon] Jobs · 1,247 records"
|
|
11
|
+
* - Multi source → dropdown to switch between sources
|
|
12
|
+
*/
|
|
13
|
+
export declare function ChartSourceSwitcher({ className }: {
|
|
14
|
+
className?: string;
|
|
15
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
//# sourceMappingURL=chart-source-switcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
}
|
|
32
|
+
//# sourceMappingURL=chart-source-switcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-source-switcher.js","sourceRoot":"","sources":["../../src/ui/chart-source-switcher.tsx"],"names":[],"mappings":";AAAA;;;;;GAKG;AAEH,OAAO,EAAC,QAAQ,EAAC,MAAM,cAAc,CAAA;AACrC,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAC,WAAW,EAAC,MAAM,mBAAmB,CAAA;AAE7C,iEAAiE;AACjE,SAAS,WAAW,CAAC,CAAS;IAC5B,OAAO,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,CAAA;AAClC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAC,SAAS,EAAuB;IACnE,MAAM,EAAC,kBAAkB,EAAE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAC,GAC/E,eAAe,EAAE,CAAA;IAEnB,uCAAuC;IACvC,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,gBAAgB,CAAA;QACnD,OAAO,CACL,eACE,SAAS,EAAE,oFAAoF,SAAS,IAAI,EAAE,EAAE,aAEhH,KAAC,QAAQ,IAAC,SAAS,EAAC,kBAAkB,GAAG,EACzC,eAAM,SAAS,EAAC,6BAA6B,YAAE,KAAK,GAAQ,EAC5D,eAAM,SAAS,EAAC,0BAA0B,uBAAS,EACnD,2BAAO,WAAW,CAAC,WAAW,CAAC,gBAAgB,IAC3C,CACP,CAAA;IACH,CAAC;IAED,iCAAiC;IACjC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,WAAW,MAAM,CAAC,KAAK,EAAE,EAAC,CAAC,CAAC,CAAA;IAE/F,OAAO,CACL,KAAC,WAAW,IACV,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,EACnC,SAAS,EAAC,aAAa,EACvB,SAAS,EAAE,SAAS,GACpB,CACH,CAAA;AACH,CAAC"}
|