@charcuterie/ui 4.16.0 → 4.17.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/README.md +1 -1
- package/dist/Chart/Chart.d.ts +4 -1
- package/dist/Chart/Chart.d.ts.map +1 -1
- package/dist/Chart/Chart.js +13 -7
- package/dist/Chart/Chart.js.map +1 -1
- package/package.json +2 -2
- package/src/Chart/Chart.mdx +10 -1
- package/src/Chart/Chart.stories.tsx +51 -1
- package/src/Chart/Chart.test.tsx +30 -1
- package/src/Chart/Chart.tsx +38 -7
- package/src/sourceRules.test.ts +28 -0
package/README.md
CHANGED
|
@@ -328,4 +328,4 @@ rename breaks only the rendered page).
|
|
|
328
328
|
board. `sourceRules.test.ts` now derives the container-declaring components from
|
|
329
329
|
source and fails on this, so the component M4 adds joins the rule automatically.
|
|
330
330
|
|
|
331
|
-
**`Chart`** provides responsive bar and line plots, negative values, gaps for missing data, and an optional semantic values table.
|
|
331
|
+
**`Chart`** provides responsive bar and line plots, negative values, gaps for missing data, and an optional semantic values table. TanStack provides hover/touch tooltips, keyboard navigation, and transitions with reduced-motion support. Set `renderer="portable"` for the lightweight fallback. The `@charcuterie/logic/charts`, `/charts/preact`, and `/charts/react` subpaths expose static and framework-specific surfaces; `/core` remains dependency-free. Apps supply their own series, labels, and semantic colors.
|
package/dist/Chart/Chart.d.ts
CHANGED
|
@@ -4,7 +4,10 @@ export type ChartProps = ChartOptions & {
|
|
|
4
4
|
className?: string;
|
|
5
5
|
/** A text table exposes every value without relying on color, hover, or SVG. */
|
|
6
6
|
isTableVisible?: boolean;
|
|
7
|
+
/** The portable renderer is an explicit fallback for constrained environments. */
|
|
8
|
+
renderer?: "tanstack" | "portable";
|
|
9
|
+
isAnimated?: boolean;
|
|
7
10
|
};
|
|
8
11
|
/** The same escaped SVG renderer is available without React for kiosk/image consumers. */
|
|
9
|
-
export declare const Chart: ({ className, isTableVisible, ...options }: ChartProps) => ReactNode;
|
|
12
|
+
export declare const Chart: ({ className, isTableVisible, renderer, isAnimated, ...options }: ChartProps) => ReactNode;
|
|
10
13
|
//# sourceMappingURL=Chart.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chart.d.ts","sourceRoot":"","sources":["../../src/Chart/Chart.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Chart.d.ts","sourceRoot":"","sources":["../../src/Chart/Chart.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,YAAY,EAElB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAEL,KAAK,SAAS,EAIf,MAAM,OAAO,CAAA;AAGd,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gFAAgF;IAChF,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,UAAU,GAAG,UAAU,CAAA;IAClC,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAED,0FAA0F;AAC1F,eAAO,MAAM,KAAK,GAAI,iEAMnB,UAAU,KAAG,SA+Hf,CAAA"}
|
package/dist/Chart/Chart.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// biome-ignore-all lint/security/noDangerouslySetInnerHtml: The portable renderer escapes text and restricts color references; security tests cover this boundary.
|
|
3
|
+
import { ChartPlot } from "@charcuterie/logic/charts/react";
|
|
3
4
|
import { renderChartSvg, } from "@charcuterie/logic/core";
|
|
4
5
|
import { useEffect, useRef, useState, } from "react";
|
|
5
6
|
import { toClassName } from "../toClassName.js";
|
|
6
7
|
/** The same escaped SVG renderer is available without React for kiosk/image consumers. */
|
|
7
|
-
export const Chart = ({ className, isTableVisible = false, ...options }) => {
|
|
8
|
+
export const Chart = ({ className, isTableVisible = false, renderer = "tanstack", isAnimated = true, ...options }) => {
|
|
8
9
|
const container = useRef(null);
|
|
9
10
|
const [measuredWidth, setMeasuredWidth] = useState(options.width ?? 640);
|
|
10
11
|
useEffect(() => {
|
|
@@ -26,12 +27,17 @@ export const Chart = ({ className, isTableVisible = false, ...options }) => {
|
|
|
26
27
|
cancelAnimationFrame(frame.id);
|
|
27
28
|
};
|
|
28
29
|
}, [options.width]);
|
|
29
|
-
return (_jsxs("figure", {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
return (_jsxs("figure", { style: {
|
|
31
|
+
"--ts-chart-tooltip-background": "var(--color-surface-raised)",
|
|
32
|
+
"--ts-chart-tooltip-color": "var(--color-content-primary)",
|
|
33
|
+
"--ts-chart-tooltip-border": "1px solid var(--color-border-subtle)",
|
|
34
|
+
"--ts-chart-tooltip-font": "inherit",
|
|
35
|
+
}, className: toClassName("min-w-0 text-content-primary", className), children: [_jsx("figcaption", { className: "mb-2 text-sm font-semibold", children: options.title }), _jsx("div", { ref: container, style: { height: options.height ?? 240 }, children: renderer === "portable" ? (_jsx("div", { style: { height: "100%" }, dangerouslySetInnerHTML: {
|
|
36
|
+
__html: renderChartSvg({
|
|
37
|
+
...options,
|
|
38
|
+
width: options.width ?? measuredWidth,
|
|
39
|
+
}),
|
|
40
|
+
} })) : (_jsx(ChartPlot, { ...options, width: options.width ?? measuredWidth, isAnimated: isAnimated })) }), _jsx("ul", { "aria-label": `${options.title} legend`, className: "mt-2 flex flex-wrap gap-3 text-xs", children: options.series.map((entry, index) => (_jsxs("li", { className: "min-w-0 wrap-anywhere", children: [_jsx("span", { "aria-hidden": "true", style: {
|
|
35
41
|
color: entry.color ?? "currentColor",
|
|
36
42
|
borderTop: `3px ${index % 3 === 0 ? "solid" : index % 3 === 1 ? "dashed" : "dotted"} currentColor`,
|
|
37
43
|
display: "inline-block",
|
package/dist/Chart/Chart.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chart.js","sourceRoot":"","sources":["../../src/Chart/Chart.tsx"],"names":[],"mappings":";AAAA,mKAAmK;
|
|
1
|
+
{"version":3,"file":"Chart.js","sourceRoot":"","sources":["../../src/Chart/Chart.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@charcuterie/ui",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.17.0",
|
|
4
4
|
"description": "The Charcuterie components. Tokens for look, @charcuterie/logic for state, ARIA that agents can actually drive.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"typecheck": "tsc --noEmit"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@charcuterie/logic": "2.
|
|
56
|
+
"@charcuterie/logic": "2.9.0",
|
|
57
57
|
"@charcuterie/tokens": "1.10.2",
|
|
58
58
|
"@floating-ui/react": "^0.27.20",
|
|
59
59
|
"@tanstack/react-virtual": "^3.13.12",
|
package/src/Chart/Chart.mdx
CHANGED
|
@@ -7,10 +7,19 @@ import * as stories from "./Chart.stories.tsx"
|
|
|
7
7
|
|
|
8
8
|
Bar and line plots with a zero baseline, negative values, explicit missing samples, and an optional values table. The app owns the data and its meaning. Null means unavailable, never zero. Color is optional; mark titles, labels, and the table preserve the information without it.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
TanStack Charts 0.18.0 is the primary renderer. Hover, tap, or focus the plot and use arrow keys, Home, and End to inspect values. Tooltips show every series for the selected label, including unavailable samples. Positive and negative contributions stack independently with `barLayout="stacked"`; grouped bars remain the default. `isAnimated={false}` disables motion, and changes to `prefers-reduced-motion` are honored while mounted.
|
|
11
|
+
|
|
12
|
+
Use `renderer="portable"` for the existing lightweight SVG fallback. Its static output and the optional semantic values table remain available. Neither renderer fetches data.
|
|
13
|
+
|
|
14
|
+
`@charcuterie/logic/charts` exports `createChartDefinition` and a standalone `renderChartSvg` with explicit image dimensions. `@charcuterie/logic/charts/preact` exports native `ChartPlot` without React or a compatibility layer. `@charcuterie/logic/core` keeps the dependency-free portable renderer for constrained consumers. Static consumers supply resolved colors rather than browser CSS variables.
|
|
15
|
+
|
|
16
|
+
TanStack remains alpha and is pinned exactly. Upgrades require the interaction and export checks recorded in the decision and evaluation.
|
|
11
17
|
|
|
12
18
|
<Canvas of={stories.Playground} />
|
|
13
19
|
<Canvas of={stories.AllVariants} />
|
|
14
20
|
<Canvas of={stories.AllStates} />
|
|
15
21
|
<Canvas of={stories.Responsive} />
|
|
16
22
|
<Canvas of={stories.Interactive} />
|
|
23
|
+
|
|
24
|
+
<Canvas of={stories.StackedDaily} />
|
|
25
|
+
<Canvas of={stories.PortableFallback} />
|
|
@@ -78,15 +78,65 @@ export const Interactive: Story = {
|
|
|
78
78
|
render: (props) => {
|
|
79
79
|
const [isTableVisible, setIsTableVisible] =
|
|
80
80
|
useState(false)
|
|
81
|
+
const [isUpdated, setIsUpdated] = useState(false)
|
|
81
82
|
return (
|
|
82
83
|
<>
|
|
84
|
+
<Button onClick={() => setIsUpdated(!isUpdated)}>
|
|
85
|
+
Update values
|
|
86
|
+
</Button>
|
|
83
87
|
<Button
|
|
84
88
|
onClick={() => setIsTableVisible(!isTableVisible)}
|
|
85
89
|
>
|
|
86
90
|
{isTableVisible ? "Hide values" : "Show values"}
|
|
87
91
|
</Button>
|
|
88
|
-
<Chart
|
|
92
|
+
<Chart
|
|
93
|
+
{...props}
|
|
94
|
+
series={props.series.map((entry) => ({
|
|
95
|
+
...entry,
|
|
96
|
+
values: entry.values.map((value) =>
|
|
97
|
+
value === null
|
|
98
|
+
? null
|
|
99
|
+
: value + (isUpdated ? 100 : 0),
|
|
100
|
+
),
|
|
101
|
+
}))}
|
|
102
|
+
isTableVisible={isTableVisible}
|
|
103
|
+
/>
|
|
89
104
|
</>
|
|
90
105
|
)
|
|
91
106
|
},
|
|
92
107
|
}
|
|
108
|
+
|
|
109
|
+
export const StackedDaily: Story = {
|
|
110
|
+
args: {
|
|
111
|
+
barLayout: "stacked",
|
|
112
|
+
series: [
|
|
113
|
+
{
|
|
114
|
+
id: "tasks",
|
|
115
|
+
label: "Tasks",
|
|
116
|
+
values: [200, 280, 180, 260, 300],
|
|
117
|
+
color: "var(--color-intent-accent-solid)",
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: "bonuses",
|
|
121
|
+
label: "Bonuses",
|
|
122
|
+
values: [10, 20, 0, 10, 0],
|
|
123
|
+
color: "var(--color-intent-success-solid)",
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: "penalties",
|
|
127
|
+
label: "Penalties",
|
|
128
|
+
values: [0, -50, -50, 0, 0],
|
|
129
|
+
color: "var(--color-intent-danger-solid)",
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: "reversals",
|
|
133
|
+
label: "Reversals",
|
|
134
|
+
values: [0, -10, 0, 0, 0],
|
|
135
|
+
color: "var(--color-content-muted)",
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
}
|
|
140
|
+
export const PortableFallback: Story = {
|
|
141
|
+
args: { renderer: "portable" },
|
|
142
|
+
}
|
package/src/Chart/Chart.test.tsx
CHANGED
|
@@ -5,7 +5,8 @@ import { mountStory } from "../mountStory.testHelpers.ts"
|
|
|
5
5
|
import { expectAgentDrivable } from "../testing/index.ts"
|
|
6
6
|
import * as stories from "./Chart.stories.tsx"
|
|
7
7
|
|
|
8
|
-
const { Playground, Interactive } =
|
|
8
|
+
const { Playground, Interactive, StackedDaily } =
|
|
9
|
+
composeStories(stories)
|
|
9
10
|
test("the plot has an accessible name and a named legend", async () => {
|
|
10
11
|
const { canvas } = await mountStory(Playground)
|
|
11
12
|
expectAgentDrivable(canvas, {
|
|
@@ -35,3 +36,31 @@ test("the keyboard exposes all values, including missing data, in a real table",
|
|
|
35
36
|
).toBeVisible()
|
|
36
37
|
await expect(within(table).getByText("-50")).toBeVisible()
|
|
37
38
|
})
|
|
39
|
+
|
|
40
|
+
test("keyboard point navigation exposes the day's original category amounts", async () => {
|
|
41
|
+
const { canvas } = await mountStory(StackedDaily)
|
|
42
|
+
const plot = expectAgentDrivable(canvas, {
|
|
43
|
+
role: "img",
|
|
44
|
+
name: "Daily progress",
|
|
45
|
+
})
|
|
46
|
+
plot.focus()
|
|
47
|
+
await userEvent.keyboard("{Home}")
|
|
48
|
+
const body = within(document.body)
|
|
49
|
+
await expect(body.getByRole("status")).toBeVisible()
|
|
50
|
+
await expect(
|
|
51
|
+
within(body.getByRole("status")).getByText("Tasks"),
|
|
52
|
+
).toBeVisible()
|
|
53
|
+
await expect(
|
|
54
|
+
within(body.getByRole("status")).getByText("200"),
|
|
55
|
+
).toBeVisible()
|
|
56
|
+
await expect(
|
|
57
|
+
within(body.getByRole("status")).getByText("10"),
|
|
58
|
+
).toBeVisible()
|
|
59
|
+
await userEvent.keyboard("{End}")
|
|
60
|
+
await expect(
|
|
61
|
+
within(body.getByRole("status")).getByText("Fri"),
|
|
62
|
+
).toBeVisible()
|
|
63
|
+
await expect(
|
|
64
|
+
within(body.getByRole("status")).getByText("300"),
|
|
65
|
+
).toBeVisible()
|
|
66
|
+
})
|
package/src/Chart/Chart.tsx
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
// biome-ignore-all lint/security/noDangerouslySetInnerHtml: The portable renderer escapes text and restricts color references; security tests cover this boundary.
|
|
2
|
+
|
|
3
|
+
import { ChartPlot } from "@charcuterie/logic/charts/react"
|
|
2
4
|
import {
|
|
3
5
|
type ChartOptions,
|
|
4
6
|
renderChartSvg,
|
|
5
7
|
} from "@charcuterie/logic/core"
|
|
6
8
|
import {
|
|
9
|
+
type CSSProperties,
|
|
7
10
|
type ReactNode,
|
|
8
11
|
useEffect,
|
|
9
12
|
useRef,
|
|
@@ -15,12 +18,17 @@ export type ChartProps = ChartOptions & {
|
|
|
15
18
|
className?: string
|
|
16
19
|
/** A text table exposes every value without relying on color, hover, or SVG. */
|
|
17
20
|
isTableVisible?: boolean
|
|
21
|
+
/** The portable renderer is an explicit fallback for constrained environments. */
|
|
22
|
+
renderer?: "tanstack" | "portable"
|
|
23
|
+
isAnimated?: boolean
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
/** The same escaped SVG renderer is available without React for kiosk/image consumers. */
|
|
21
27
|
export const Chart = ({
|
|
22
28
|
className,
|
|
23
29
|
isTableVisible = false,
|
|
30
|
+
renderer = "tanstack",
|
|
31
|
+
isAnimated = true,
|
|
24
32
|
...options
|
|
25
33
|
}: ChartProps): ReactNode => {
|
|
26
34
|
const container = useRef<HTMLDivElement>(null)
|
|
@@ -47,6 +55,17 @@ export const Chart = ({
|
|
|
47
55
|
}, [options.width])
|
|
48
56
|
return (
|
|
49
57
|
<figure
|
|
58
|
+
style={
|
|
59
|
+
{
|
|
60
|
+
"--ts-chart-tooltip-background":
|
|
61
|
+
"var(--color-surface-raised)",
|
|
62
|
+
"--ts-chart-tooltip-color":
|
|
63
|
+
"var(--color-content-primary)",
|
|
64
|
+
"--ts-chart-tooltip-border":
|
|
65
|
+
"1px solid var(--color-border-subtle)",
|
|
66
|
+
"--ts-chart-tooltip-font": "inherit",
|
|
67
|
+
} as CSSProperties
|
|
68
|
+
}
|
|
50
69
|
className={toClassName(
|
|
51
70
|
"min-w-0 text-content-primary",
|
|
52
71
|
className,
|
|
@@ -58,13 +77,25 @@ export const Chart = ({
|
|
|
58
77
|
<div
|
|
59
78
|
ref={container}
|
|
60
79
|
style={{ height: options.height ?? 240 }}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
80
|
+
>
|
|
81
|
+
{renderer === "portable" ? (
|
|
82
|
+
<div
|
|
83
|
+
style={{ height: "100%" }}
|
|
84
|
+
dangerouslySetInnerHTML={{
|
|
85
|
+
__html: renderChartSvg({
|
|
86
|
+
...options,
|
|
87
|
+
width: options.width ?? measuredWidth,
|
|
88
|
+
}),
|
|
89
|
+
}}
|
|
90
|
+
/>
|
|
91
|
+
) : (
|
|
92
|
+
<ChartPlot
|
|
93
|
+
{...options}
|
|
94
|
+
width={options.width ?? measuredWidth}
|
|
95
|
+
isAnimated={isAnimated}
|
|
96
|
+
/>
|
|
97
|
+
)}
|
|
98
|
+
</div>
|
|
68
99
|
<ul
|
|
69
100
|
aria-label={`${options.title} legend`}
|
|
70
101
|
className="mt-2 flex flex-wrap gap-3 text-xs"
|
package/src/sourceRules.test.ts
CHANGED
|
@@ -700,6 +700,33 @@ const ENTRY_POINT_RUNTIMES: Record<
|
|
|
700
700
|
// into `core` — which is why `ColorSchemeApplier` lives in the
|
|
701
701
|
// core rather than beside the hook, so this entry never pulls
|
|
702
702
|
// `react`.
|
|
703
|
+
"./charts": [
|
|
704
|
+
"@tanstack/charts",
|
|
705
|
+
"@tanstack/charts/scales/band",
|
|
706
|
+
"@tanstack/charts/scales/linear",
|
|
707
|
+
"@tanstack/charts/svg",
|
|
708
|
+
],
|
|
709
|
+
"./charts/preact": [
|
|
710
|
+
"@tanstack/charts",
|
|
711
|
+
"@tanstack/charts/adapter/renderer",
|
|
712
|
+
"@tanstack/charts/motion",
|
|
713
|
+
"@tanstack/charts/scales/band",
|
|
714
|
+
"@tanstack/charts/scales/linear",
|
|
715
|
+
"@tanstack/charts/svg/renderer",
|
|
716
|
+
"@tanstack/charts/tooltip",
|
|
717
|
+
"preact",
|
|
718
|
+
"preact/hooks",
|
|
719
|
+
],
|
|
720
|
+
"./charts/react": [
|
|
721
|
+
"@tanstack/charts",
|
|
722
|
+
"@tanstack/charts/motion",
|
|
723
|
+
"@tanstack/charts/react/core",
|
|
724
|
+
"@tanstack/charts/scales/band",
|
|
725
|
+
"@tanstack/charts/scales/linear",
|
|
726
|
+
"@tanstack/charts/svg/renderer",
|
|
727
|
+
"@tanstack/charts/tooltip",
|
|
728
|
+
"react",
|
|
729
|
+
],
|
|
703
730
|
"./browser": [],
|
|
704
731
|
"./core": [],
|
|
705
732
|
"./jotai": ["jotai"],
|
|
@@ -733,6 +760,7 @@ const ENTRY_POINT_RUNTIMES: Record<
|
|
|
733
760
|
// browser, and it does so through this subpath so the coupling
|
|
734
761
|
// is named rather than smuggled in through the main entry.
|
|
735
762
|
"@charcuterie/logic/browser",
|
|
763
|
+
"@charcuterie/logic/charts/react",
|
|
736
764
|
"@charcuterie/logic/core",
|
|
737
765
|
"@charcuterie/tokens",
|
|
738
766
|
"@floating-ui/react",
|