@matthieumordrel/chart-studio-ui 0.5.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 +35 -0
- package/dist/index.d.mts +19 -0
- package/dist/index.mjs +18 -0
- package/dist/theme.css +67 -0
- package/dist/ui/chart-axis-ticks.mjs +65 -0
- package/dist/ui/chart-canvas.d.mts +40 -0
- package/dist/ui/chart-canvas.mjs +872 -0
- package/dist/ui/chart-context.d.mts +101 -0
- package/dist/ui/chart-context.mjs +117 -0
- package/dist/ui/chart-date-range-badge.d.mts +20 -0
- 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 +126 -0
- package/dist/ui/chart-date-range.d.mts +20 -0
- package/dist/ui/chart-date-range.mjs +67 -0
- package/dist/ui/chart-debug.d.mts +21 -0
- package/dist/ui/chart-debug.mjs +172 -0
- package/dist/ui/chart-dropdown.mjs +92 -0
- package/dist/ui/chart-filters-panel.d.mts +26 -0
- package/dist/ui/chart-filters-panel.mjs +258 -0
- package/dist/ui/chart-filters.d.mts +18 -0
- package/dist/ui/chart-filters.mjs +48 -0
- package/dist/ui/chart-group-by-selector.d.mts +16 -0
- package/dist/ui/chart-group-by-selector.mjs +32 -0
- package/dist/ui/chart-metric-panel.d.mts +25 -0
- 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 +61 -0
- package/dist/ui/chart-source-switcher.d.mts +24 -0
- package/dist/ui/chart-source-switcher.mjs +56 -0
- package/dist/ui/chart-time-bucket-selector.d.mts +17 -0
- package/dist/ui/chart-time-bucket-selector.mjs +37 -0
- package/dist/ui/chart-toolbar-overflow.d.mts +28 -0
- package/dist/ui/chart-toolbar-overflow.mjs +223 -0
- package/dist/ui/chart-toolbar.d.mts +33 -0
- package/dist/ui/chart-toolbar.mjs +60 -0
- package/dist/ui/chart-type-selector.d.mts +19 -0
- package/dist/ui/chart-type-selector.mjs +173 -0
- package/dist/ui/chart-x-axis-selector.d.mts +16 -0
- package/dist/ui/chart-x-axis-selector.mjs +28 -0
- package/dist/ui/index.d.mts +18 -0
- package/dist/ui/percent-stacked.mjs +36 -0
- package/dist/ui/toolbar-types.d.mts +7 -0
- package/dist/ui/toolbar-types.mjs +83 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# @matthieumordrel/chart-studio-ui
|
|
2
|
+
|
|
3
|
+
> Early alpha. Active work in progress. Not recommended for production use yet.
|
|
4
|
+
|
|
5
|
+
Optional React UI primitives for `@matthieumordrel/chart-studio`.
|
|
6
|
+
|
|
7
|
+
This package contains the ready-made controls, context provider, and Recharts canvas. It depends on the headless core package and requires Tailwind CSS v4 for the shipped theme contract.
|
|
8
|
+
|
|
9
|
+
Your app still needs a normal Tailwind CSS v4 integration such as `@tailwindcss/vite`, the PostCSS plugin, or the Tailwind CLI.
|
|
10
|
+
|
|
11
|
+
Install:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bun add @matthieumordrel/chart-studio@alpha @matthieumordrel/chart-studio-ui@alpha react react-dom recharts lucide-react tailwindcss
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Current prereleases are published under the `alpha` dist-tag on npm.
|
|
18
|
+
|
|
19
|
+
Import from:
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import {useChart} from '@matthieumordrel/chart-studio'
|
|
23
|
+
import {Chart, ChartCanvas, ChartToolbar} from '@matthieumordrel/chart-studio-ui'
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Theme import:
|
|
27
|
+
|
|
28
|
+
```css
|
|
29
|
+
@import 'tailwindcss';
|
|
30
|
+
@import '@matthieumordrel/chart-studio-ui/theme.css';
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Special thanks to the teams behind TanStack Table and Recharts.
|
|
34
|
+
|
|
35
|
+
Full documentation: <https://github.com/MatthieuMordrel/chart-studio#readme>
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Chart, useChartContext, useTypedChartContext } from "./ui/chart-context.mjs";
|
|
2
|
+
import { ChartCanvas } from "./ui/chart-canvas.mjs";
|
|
3
|
+
import { ControlId } from "./ui/toolbar-types.mjs";
|
|
4
|
+
import { ChartToolbar } from "./ui/chart-toolbar.mjs";
|
|
5
|
+
import { ChartToolbarOverflow } from "./ui/chart-toolbar-overflow.mjs";
|
|
6
|
+
import { ChartSourceSwitcher } from "./ui/chart-source-switcher.mjs";
|
|
7
|
+
import { ChartTypeSelector } from "./ui/chart-type-selector.mjs";
|
|
8
|
+
import { ChartGroupBySelector } from "./ui/chart-group-by-selector.mjs";
|
|
9
|
+
import { ChartTimeBucketSelector } from "./ui/chart-time-bucket-selector.mjs";
|
|
10
|
+
import { ChartMetricSelector } from "./ui/chart-metric-selector.mjs";
|
|
11
|
+
import { ChartMetricPanel } from "./ui/chart-metric-panel.mjs";
|
|
12
|
+
import { ChartXAxisSelector } from "./ui/chart-x-axis-selector.mjs";
|
|
13
|
+
import { ChartDateRange } from "./ui/chart-date-range.mjs";
|
|
14
|
+
import { ChartDateRangeBadge } from "./ui/chart-date-range-badge.mjs";
|
|
15
|
+
import { ChartDateRangePanel } from "./ui/chart-date-range-panel.mjs";
|
|
16
|
+
import { ChartFilters } from "./ui/chart-filters.mjs";
|
|
17
|
+
import { ChartFiltersPanel } from "./ui/chart-filters-panel.mjs";
|
|
18
|
+
import { ChartDebug } from "./ui/chart-debug.mjs";
|
|
19
|
+
export { Chart, ChartCanvas, ChartDateRange, ChartDateRangeBadge, ChartDateRangePanel, ChartDebug, ChartFilters, ChartFiltersPanel, ChartGroupBySelector, ChartMetricPanel, ChartMetricSelector, ChartSourceSwitcher, ChartTimeBucketSelector, ChartToolbar, ChartToolbarOverflow, ChartTypeSelector, ChartXAxisSelector, ControlId, useChartContext, useTypedChartContext };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Chart, useChartContext, useTypedChartContext } from "./ui/chart-context.mjs";
|
|
2
|
+
import { ChartCanvas } from "./ui/chart-canvas.mjs";
|
|
3
|
+
import { ChartDateRangePanel } from "./ui/chart-date-range-panel.mjs";
|
|
4
|
+
import { ChartFiltersPanel } from "./ui/chart-filters-panel.mjs";
|
|
5
|
+
import { ChartMetricPanel } from "./ui/chart-metric-panel.mjs";
|
|
6
|
+
import { ChartDateRange } from "./ui/chart-date-range.mjs";
|
|
7
|
+
import { ChartFilters } from "./ui/chart-filters.mjs";
|
|
8
|
+
import { ChartGroupBySelector } from "./ui/chart-group-by-selector.mjs";
|
|
9
|
+
import { ChartMetricSelector } from "./ui/chart-metric-selector.mjs";
|
|
10
|
+
import { ChartSourceSwitcher } from "./ui/chart-source-switcher.mjs";
|
|
11
|
+
import { ChartTimeBucketSelector } from "./ui/chart-time-bucket-selector.mjs";
|
|
12
|
+
import { ChartTypeSelector } from "./ui/chart-type-selector.mjs";
|
|
13
|
+
import { ChartXAxisSelector } from "./ui/chart-x-axis-selector.mjs";
|
|
14
|
+
import { ChartToolbarOverflow } from "./ui/chart-toolbar-overflow.mjs";
|
|
15
|
+
import { ChartToolbar } from "./ui/chart-toolbar.mjs";
|
|
16
|
+
import { ChartDateRangeBadge } from "./ui/chart-date-range-badge.mjs";
|
|
17
|
+
import { ChartDebug } from "./ui/chart-debug.mjs";
|
|
18
|
+
export { Chart, ChartCanvas, ChartDateRange, ChartDateRangeBadge, ChartDateRangePanel, ChartDebug, ChartFilters, ChartFiltersPanel, ChartGroupBySelector, ChartMetricPanel, ChartMetricSelector, ChartSourceSwitcher, ChartTimeBucketSelector, ChartToolbar, ChartToolbarOverflow, ChartTypeSelector, ChartXAxisSelector, useChartContext, useTypedChartContext };
|
package/dist/theme.css
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
@source "./";
|
|
2
|
+
|
|
3
|
+
@theme inline {
|
|
4
|
+
--color-background: var(--cs-background);
|
|
5
|
+
--color-foreground: var(--cs-foreground);
|
|
6
|
+
--color-card: var(--cs-card);
|
|
7
|
+
--color-card-foreground: var(--cs-card-foreground);
|
|
8
|
+
--color-popover: var(--cs-popover);
|
|
9
|
+
--color-popover-foreground: var(--cs-popover-foreground);
|
|
10
|
+
--color-primary: var(--cs-primary);
|
|
11
|
+
--color-primary-foreground: var(--cs-primary-foreground);
|
|
12
|
+
--color-muted: var(--cs-muted);
|
|
13
|
+
--color-muted-foreground: var(--cs-muted-foreground);
|
|
14
|
+
--color-border: var(--cs-border);
|
|
15
|
+
--color-input: var(--cs-input);
|
|
16
|
+
--color-ring: var(--cs-ring);
|
|
17
|
+
--radius-sm: max(0px, calc(var(--cs-radius) - 4px));
|
|
18
|
+
--radius-md: max(0px, calc(var(--cs-radius) - 2px));
|
|
19
|
+
--radius-lg: var(--cs-radius);
|
|
20
|
+
--radius-xl: calc(var(--cs-radius) + clamp(0px, var(--cs-radius), 4px));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
:root {
|
|
24
|
+
color-scheme: light;
|
|
25
|
+
--cs-radius: var(--radius, 0.25rem);
|
|
26
|
+
--cs-background: var(--background, oklch(0.980 0.002 264.545));
|
|
27
|
+
--cs-foreground: var(--foreground, oklch(0.128 0.027 261.594));
|
|
28
|
+
--cs-card: var(--card, oklch(1.000 0 0));
|
|
29
|
+
--cs-card-foreground: var(--card-foreground, oklch(0.128 0.027 261.594));
|
|
30
|
+
--cs-popover: var(--popover, oklch(1.000 0 0));
|
|
31
|
+
--cs-popover-foreground: var(--popover-foreground, oklch(0.128 0.027 261.594));
|
|
32
|
+
--cs-primary: var(--primary, oklch(0.501 0.228 277.992));
|
|
33
|
+
--cs-primary-foreground: var(--primary-foreground, oklch(1.000 0 0));
|
|
34
|
+
--cs-muted: var(--muted, oklch(0.948 0.004 264.536));
|
|
35
|
+
--cs-muted-foreground: var(--muted-foreground, oklch(0.550 0.023 264.362));
|
|
36
|
+
--cs-border: var(--border, oklch(0.920 0.006 264.529));
|
|
37
|
+
--cs-input: var(--input, oklch(0.920 0.006 264.529));
|
|
38
|
+
--cs-ring: var(--ring, oklch(0.501 0.228 277.992));
|
|
39
|
+
--cs-chart-1: oklch(0.501 0.228 277.992);
|
|
40
|
+
--cs-chart-2: oklch(0.550 0.235 302.715);
|
|
41
|
+
--cs-chart-3: oklch(0.609 0.206 354.673);
|
|
42
|
+
--cs-chart-4: oklch(0.635 0.109 178.228);
|
|
43
|
+
--cs-chart-5: oklch(0.732 0.166 58.213);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
:root[data-theme='dark'],
|
|
47
|
+
.dark {
|
|
48
|
+
color-scheme: dark;
|
|
49
|
+
--cs-background: var(--background, oklch(0.171 0.015 273.761));
|
|
50
|
+
--cs-foreground: var(--foreground, oklch(0.944 0.005 264.534));
|
|
51
|
+
--cs-card: var(--card, oklch(0.203 0.018 273.739));
|
|
52
|
+
--cs-card-foreground: var(--card-foreground, oklch(0.944 0.005 264.534));
|
|
53
|
+
--cs-popover: var(--popover, oklch(0.224 0.019 273.793));
|
|
54
|
+
--cs-popover-foreground: var(--popover-foreground, oklch(0.944 0.005 264.534));
|
|
55
|
+
--cs-primary: var(--primary, oklch(0.597 0.196 282.474));
|
|
56
|
+
--cs-primary-foreground: var(--primary-foreground, oklch(1.000 0 0));
|
|
57
|
+
--cs-muted: var(--muted, oklch(0.246 0.018 274.033));
|
|
58
|
+
--cs-muted-foreground: var(--muted-foreground, oklch(0.618 0.025 264.372));
|
|
59
|
+
--cs-border: var(--border, oklch(0.258 0.016 274.161));
|
|
60
|
+
--cs-input: var(--input, oklch(0.287 0.019 274.112));
|
|
61
|
+
--cs-ring: var(--ring, oklch(0.597 0.196 282.474));
|
|
62
|
+
--cs-chart-1: oklch(0.625 0.188 283.272);
|
|
63
|
+
--cs-chart-2: oklch(0.660 0.198 305.491);
|
|
64
|
+
--cs-chart-3: oklch(0.785 0.132 215.571);
|
|
65
|
+
--cs-chart-4: oklch(0.789 0.176 158.514);
|
|
66
|
+
--cs-chart-5: oklch(0.815 0.143 77.593);
|
|
67
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
//#region src/ui/chart-axis-ticks.ts
|
|
2
|
+
/**
|
|
3
|
+
* Default horizontal breathing room kept between two rendered tick labels.
|
|
4
|
+
*/
|
|
5
|
+
const DEFAULT_MINIMUM_TICK_GAP = 8;
|
|
6
|
+
/**
|
|
7
|
+
* Select visible X-axis tick values so labels stay readable, the first and last
|
|
8
|
+
* values always remain visible, and any unavoidable wider gaps are pushed away
|
|
9
|
+
* from the chart edges.
|
|
10
|
+
*/
|
|
11
|
+
function selectVisibleXAxisTicks({ values, labels, plotWidth, minimumTickGap = DEFAULT_MINIMUM_TICK_GAP, measureLabelWidth = measureLabelWidthByCharacterCount }) {
|
|
12
|
+
if (values.length <= 2) return [...values];
|
|
13
|
+
const minimumStep = estimateMinimumTickStep(labels, plotWidth, minimumTickGap, measureLabelWidth);
|
|
14
|
+
return buildVisibleTickIndices(values.length, minimumStep).map((index) => values[index]);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Estimate the minimum index distance required between rendered labels so they
|
|
18
|
+
* can fit inside the available plot width without overlapping.
|
|
19
|
+
*/
|
|
20
|
+
function estimateMinimumTickStep(labels, plotWidth, minimumTickGap, measureLabelWidth) {
|
|
21
|
+
if (labels.length <= 1) return 1;
|
|
22
|
+
const widestLabel = labels.reduce((maxWidth, label) => Math.max(maxWidth, measureLabelWidth(label)), 0);
|
|
23
|
+
const slotWidth = plotWidth / Math.max(labels.length - 1, 1);
|
|
24
|
+
return Math.max(1, Math.ceil((widestLabel + minimumTickGap) / Math.max(slotWidth, 1)));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build the visible tick indices for a given point count and minimum step.
|
|
28
|
+
*
|
|
29
|
+
* The selector keeps the first and last tick, shows as many intermediate ticks
|
|
30
|
+
* as possible, and places any wider fallback gaps near the center so the edges
|
|
31
|
+
* stay visually balanced.
|
|
32
|
+
*/
|
|
33
|
+
function buildVisibleTickIndices(pointCount, minimumStep) {
|
|
34
|
+
if (pointCount <= 0) return [];
|
|
35
|
+
if (pointCount <= 2) return Array.from({ length: pointCount }, (_, index) => index);
|
|
36
|
+
const safeMinimumStep = Math.max(1, Math.floor(minimumStep));
|
|
37
|
+
if (safeMinimumStep === 1) return Array.from({ length: pointCount }, (_, index) => index);
|
|
38
|
+
const gapCount = Math.floor((pointCount - 1) / safeMinimumStep);
|
|
39
|
+
if (gapCount === 0) return [0, pointCount - 1];
|
|
40
|
+
const gaps = Array.from({ length: gapCount }, () => safeMinimumStep);
|
|
41
|
+
const remainder = pointCount - 1 - safeMinimumStep * gapCount;
|
|
42
|
+
for (const gapIndex of getCenteredGapOrder(gapCount).slice(0, remainder)) {
|
|
43
|
+
const gap = gaps[gapIndex];
|
|
44
|
+
if (gap !== void 0) gaps[gapIndex] = gap + 1;
|
|
45
|
+
}
|
|
46
|
+
const visibleIndices = [0];
|
|
47
|
+
for (const gap of gaps) visibleIndices.push(visibleIndices[visibleIndices.length - 1] + gap);
|
|
48
|
+
return visibleIndices;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Order gap positions from the center outward so any larger fallback gaps land
|
|
52
|
+
* away from the chart edges.
|
|
53
|
+
*/
|
|
54
|
+
function getCenteredGapOrder(gapCount) {
|
|
55
|
+
const center = (gapCount - 1) / 2;
|
|
56
|
+
return Array.from({ length: gapCount }, (_, index) => index).sort((left, right) => Math.abs(left - center) - Math.abs(right - center) || left - right);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Lightweight default width estimate used by tests and non-DOM callers.
|
|
60
|
+
*/
|
|
61
|
+
function measureLabelWidthByCharacterCount(label) {
|
|
62
|
+
return label.length;
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { selectVisibleXAxisTicks };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
2
|
+
|
|
3
|
+
//#region src/ui/chart-canvas.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Chart canvas — renders the actual recharts chart based on the current state.
|
|
6
|
+
*
|
|
7
|
+
* Supports: bar, grouped-bar, percent-bar, line, area, percent-area (time-series), bar, grouped-bar, percent-bar, pie, donut (categorical).
|
|
8
|
+
* Automatically switches between chart types based on the chart instance state.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Props for ChartCanvas.
|
|
12
|
+
*
|
|
13
|
+
* @property height - Chart height in pixels (default: 300)
|
|
14
|
+
* @property className - Additional CSS classes
|
|
15
|
+
* @property showDataLabels - Control data label visibility: `true`/`false` for explicit control,
|
|
16
|
+
* or `'auto'` (default) to let {@link DATA_LABEL_DEFAULTS} decide per chart type and time bucket.
|
|
17
|
+
*/
|
|
18
|
+
type ChartCanvasProps = {
|
|
19
|
+
/** Chart height in pixels (default: 300) */height?: number; /** Additional CSS classes */
|
|
20
|
+
className?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Control data label visibility.
|
|
23
|
+
* - `true` — always show
|
|
24
|
+
* - `false` — always hide
|
|
25
|
+
* - `'auto'` — resolved from {@link DATA_LABEL_DEFAULTS} per chart type and time bucket
|
|
26
|
+
*/
|
|
27
|
+
showDataLabels?: boolean | 'auto';
|
|
28
|
+
};
|
|
29
|
+
/** Renders the appropriate recharts chart based on the chart instance state.
|
|
30
|
+
* @param height - Chart height in pixels (default: 300)
|
|
31
|
+
* @param className - Additional CSS classes
|
|
32
|
+
* @param showDataLabels - Control data label visibility: `true`/`false` for explicit control, or `'auto'` (default) to let {@link DATA_LABEL_DEFAULTS} decide per chart type and time bucket.
|
|
33
|
+
*/
|
|
34
|
+
declare function ChartCanvas({
|
|
35
|
+
height,
|
|
36
|
+
className,
|
|
37
|
+
showDataLabels
|
|
38
|
+
}: ChartCanvasProps): react_jsx_runtime0.JSX.Element;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { ChartCanvas };
|