@godxjp/ui 13.17.3 → 14.0.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/dist/components/charts/area-chart.d.ts +8 -0
- package/dist/components/charts/area-chart.js +8 -0
- package/dist/components/charts/bar-chart.d.ts +8 -0
- package/dist/components/charts/bar-chart.js +8 -0
- package/dist/components/charts/chart-cartesian.d.ts +31 -0
- package/dist/components/charts/chart-cartesian.js +178 -0
- package/dist/components/charts/chart-frame.d.ts +44 -0
- package/dist/components/charts/chart-frame.js +72 -0
- package/dist/components/charts/chart-summary.d.ts +21 -0
- package/dist/components/charts/chart-summary.js +23 -0
- package/dist/components/charts/index.d.ts +16 -0
- package/dist/components/charts/index.js +12 -0
- package/dist/components/charts/line-chart.d.ts +8 -0
- package/dist/components/charts/line-chart.js +8 -0
- package/dist/components/charts/pie-chart.d.ts +8 -0
- package/dist/components/charts/pie-chart.js +73 -0
- package/dist/components/data-display/card.d.ts +2 -1
- package/dist/components/data-display/index.d.ts +2 -0
- package/dist/components/data-display/index.js +2 -0
- package/dist/components/data-display/list-row.d.ts +24 -0
- package/dist/components/data-display/list-row.js +31 -0
- package/dist/components/data-entry/command.d.ts +10 -10
- package/dist/components/data-entry/transfer.js +1 -1
- package/dist/components/general/button.d.ts +1 -0
- package/dist/components/general/button.js +3 -0
- package/dist/components/general/index.d.ts +2 -0
- package/dist/components/general/index.js +4 -1
- package/dist/components/general/logo.d.ts +28 -0
- package/dist/components/general/logo.js +45 -0
- package/dist/components/layout/index.d.ts +1 -1
- package/dist/components/layout/sidebar.js +32 -24
- package/dist/components/layout/topbar.d.ts +19 -2
- package/dist/components/layout/topbar.js +7 -128
- package/dist/i18n/messages/en.json +5 -0
- package/dist/i18n/messages/ja.json +5 -0
- package/dist/i18n/messages/vi.json +5 -0
- package/dist/props/components/charts.prop.d.ts +89 -0
- package/dist/props/components/charts.prop.js +0 -0
- package/dist/props/components/general.prop.d.ts +5 -0
- package/dist/props/components/index.d.ts +2 -1
- package/dist/props/components/layout.prop.d.ts +16 -33
- package/dist/props/registry.d.ts +170 -11
- package/dist/props/registry.js +112 -11
- package/dist/styles/card-layout.css +5 -3
- package/dist/styles/chart-layout.css +37 -0
- package/dist/styles/data-display-layout.css +38 -0
- package/dist/styles/index.css +1 -0
- package/dist/styles/shell-layout.css +39 -0
- package/dist/styles/text-layout.css +3 -0
- package/dist/tokens/base.css +2 -0
- package/dist/tokens/components/card.css +5 -0
- package/dist/tokens/components/list-row.css +9 -0
- package/dist/tokens/components/logo.css +11 -0
- package/dist/tokens/foundation.css +13 -0
- package/package.json +42 -7
- package/scripts/_agent-setup.mjs +145 -0
- package/scripts/audit-hook.mjs +66 -0
- package/scripts/cli.mjs +26 -0
- package/scripts/init-agent-kit.mjs +52 -0
- package/scripts/postinstall.mjs +31 -0
- package/scripts/ui-audit.mjs +165 -3
- package/scripts/visual-audit-rules.mjs +119 -0
- package/scripts/visual-audit.mjs +261 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AreaChartProp } from "../../props/components/charts.prop";
|
|
2
|
+
export type { AreaChartProp, AreaChartProp as AreaChartProps, } from "../../props/components/charts.prop";
|
|
3
|
+
/**
|
|
4
|
+
* Area chart — magnitude over an ordered category axis. `stacked` accumulates
|
|
5
|
+
* series; `curved` smooths the line. Import from the tree-shaken
|
|
6
|
+
* `@godxjp/ui/charts` entry; requires the `recharts` optional peer.
|
|
7
|
+
*/
|
|
8
|
+
export declare function AreaChart(props: AreaChartProp): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BarChartProp } from "../../props/components/charts.prop";
|
|
2
|
+
export type { BarChartProp, BarChartProp as BarChartProps, } from "../../props/components/charts.prop";
|
|
3
|
+
/**
|
|
4
|
+
* Bar chart — compare a value across categories. `stacked` stacks series into one
|
|
5
|
+
* bar; `horizontal` puts the category axis on the left. Import from the
|
|
6
|
+
* tree-shaken `@godxjp/ui/charts` entry; requires the `recharts` optional peer.
|
|
7
|
+
*/
|
|
8
|
+
export declare function BarChart(props: BarChartProp): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { ChartDatum, ChartSeriesProp } from "../../props/components/charts.prop";
|
|
3
|
+
/**
|
|
4
|
+
* Shared cartesian renderer for Line / Bar / Area. Internal — the filename pascal
|
|
5
|
+
* (`ChartCartesian`) is intentionally NOT exported, so this is not a catalog entry.
|
|
6
|
+
*/
|
|
7
|
+
type CartesianKind = "line" | "bar" | "area";
|
|
8
|
+
type CartesianChartProps = {
|
|
9
|
+
kind: CartesianKind;
|
|
10
|
+
data: ChartDatum[];
|
|
11
|
+
series: ChartSeriesProp[];
|
|
12
|
+
categoryKey: string;
|
|
13
|
+
label: React.ReactNode;
|
|
14
|
+
description?: React.ReactNode;
|
|
15
|
+
size?: "xs" | "sm" | "md" | "lg";
|
|
16
|
+
height?: number;
|
|
17
|
+
showLegend?: boolean;
|
|
18
|
+
showGrid?: boolean;
|
|
19
|
+
numberFormat?: Intl.NumberFormatOptions;
|
|
20
|
+
emptyMessage?: string;
|
|
21
|
+
className?: string;
|
|
22
|
+
id?: string;
|
|
23
|
+
/** line/area */
|
|
24
|
+
curved?: boolean;
|
|
25
|
+
/** bar/area */
|
|
26
|
+
stacked?: boolean;
|
|
27
|
+
/** bar */
|
|
28
|
+
horizontal?: boolean;
|
|
29
|
+
};
|
|
30
|
+
export declare function CartesianChart({ kind, data, series, categoryKey, label, description, size, height, showLegend, showGrid, numberFormat, emptyMessage, className, id, curved, stacked, horizontal, }: CartesianChartProps): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import {
|
|
4
|
+
Area,
|
|
5
|
+
AreaChart as RAreaChart,
|
|
6
|
+
Bar,
|
|
7
|
+
BarChart as RBarChart,
|
|
8
|
+
CartesianGrid,
|
|
9
|
+
Legend,
|
|
10
|
+
Line,
|
|
11
|
+
LineChart as RLineChart,
|
|
12
|
+
ResponsiveContainer,
|
|
13
|
+
Tooltip,
|
|
14
|
+
XAxis,
|
|
15
|
+
YAxis
|
|
16
|
+
} from "recharts";
|
|
17
|
+
import { EmptyState } from "../data-display/empty-state";
|
|
18
|
+
import { useTranslation } from "../../i18n/use-translation";
|
|
19
|
+
import {
|
|
20
|
+
ChartFrame,
|
|
21
|
+
chartColor,
|
|
22
|
+
chartHeight,
|
|
23
|
+
useChartNumberFormat
|
|
24
|
+
} from "./chart-frame";
|
|
25
|
+
import { buildCartesianSummary } from "./chart-summary";
|
|
26
|
+
function CartesianChart({
|
|
27
|
+
kind,
|
|
28
|
+
data,
|
|
29
|
+
series,
|
|
30
|
+
categoryKey,
|
|
31
|
+
label,
|
|
32
|
+
description,
|
|
33
|
+
size = "md",
|
|
34
|
+
height,
|
|
35
|
+
showLegend = true,
|
|
36
|
+
showGrid = true,
|
|
37
|
+
numberFormat,
|
|
38
|
+
emptyMessage,
|
|
39
|
+
className,
|
|
40
|
+
id,
|
|
41
|
+
curved = false,
|
|
42
|
+
stacked = false,
|
|
43
|
+
horizontal = false
|
|
44
|
+
}) {
|
|
45
|
+
const { t, locale } = useTranslation();
|
|
46
|
+
const fmt = useChartNumberFormat(numberFormat);
|
|
47
|
+
const list = React.useMemo(
|
|
48
|
+
() => new Intl.ListFormat(locale, { style: "narrow", type: "unit" }),
|
|
49
|
+
[locale]
|
|
50
|
+
);
|
|
51
|
+
const hasData = data.length > 0 && series.length > 0;
|
|
52
|
+
const summary = buildCartesianSummary(
|
|
53
|
+
data,
|
|
54
|
+
series,
|
|
55
|
+
categoryKey,
|
|
56
|
+
fmt,
|
|
57
|
+
list,
|
|
58
|
+
(c) => t("chart.summaryCartesian", { series: fmt.format(c.series), points: fmt.format(c.points) })
|
|
59
|
+
);
|
|
60
|
+
const resolvedHeight = chartHeight(size, height);
|
|
61
|
+
const tickFormatter = (value) => fmt.format(value);
|
|
62
|
+
const curve = curved ? "monotone" : "linear";
|
|
63
|
+
const axes = (numberAxisVertical) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
64
|
+
showGrid ? /* @__PURE__ */ jsx(CartesianGrid, { strokeDasharray: "3 3", stroke: "hsl(var(--border))" }) : null,
|
|
65
|
+
numberAxisVertical ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
66
|
+
/* @__PURE__ */ jsx(
|
|
67
|
+
XAxis,
|
|
68
|
+
{
|
|
69
|
+
dataKey: categoryKey,
|
|
70
|
+
tickLine: false,
|
|
71
|
+
stroke: "hsl(var(--muted-foreground))",
|
|
72
|
+
fontSize: 12
|
|
73
|
+
}
|
|
74
|
+
),
|
|
75
|
+
/* @__PURE__ */ jsx(
|
|
76
|
+
YAxis,
|
|
77
|
+
{
|
|
78
|
+
tickFormatter,
|
|
79
|
+
tickLine: false,
|
|
80
|
+
stroke: "hsl(var(--muted-foreground))",
|
|
81
|
+
fontSize: 12
|
|
82
|
+
}
|
|
83
|
+
)
|
|
84
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
85
|
+
/* @__PURE__ */ jsx(
|
|
86
|
+
XAxis,
|
|
87
|
+
{
|
|
88
|
+
type: "number",
|
|
89
|
+
tickFormatter,
|
|
90
|
+
tickLine: false,
|
|
91
|
+
stroke: "hsl(var(--muted-foreground))",
|
|
92
|
+
fontSize: 12
|
|
93
|
+
}
|
|
94
|
+
),
|
|
95
|
+
/* @__PURE__ */ jsx(
|
|
96
|
+
YAxis,
|
|
97
|
+
{
|
|
98
|
+
type: "category",
|
|
99
|
+
dataKey: categoryKey,
|
|
100
|
+
tickLine: false,
|
|
101
|
+
stroke: "hsl(var(--muted-foreground))",
|
|
102
|
+
fontSize: 12
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
] }),
|
|
106
|
+
/* @__PURE__ */ jsx(Tooltip, { formatter: (value) => fmt.format(Number(value)) }),
|
|
107
|
+
showLegend ? /* @__PURE__ */ jsx(Legend, {}) : null
|
|
108
|
+
] });
|
|
109
|
+
const chart = () => {
|
|
110
|
+
if (kind === "line") {
|
|
111
|
+
return /* @__PURE__ */ jsxs(RLineChart, { data, children: [
|
|
112
|
+
axes(true),
|
|
113
|
+
series.map((s, i) => /* @__PURE__ */ jsx(
|
|
114
|
+
Line,
|
|
115
|
+
{
|
|
116
|
+
type: curve,
|
|
117
|
+
dataKey: s.dataKey,
|
|
118
|
+
name: s.label ?? s.dataKey,
|
|
119
|
+
stroke: chartColor(i, s.color),
|
|
120
|
+
strokeWidth: 2,
|
|
121
|
+
dot: false
|
|
122
|
+
},
|
|
123
|
+
s.dataKey
|
|
124
|
+
))
|
|
125
|
+
] });
|
|
126
|
+
}
|
|
127
|
+
if (kind === "area") {
|
|
128
|
+
return /* @__PURE__ */ jsxs(RAreaChart, { data, children: [
|
|
129
|
+
axes(true),
|
|
130
|
+
series.map((s, i) => /* @__PURE__ */ jsx(
|
|
131
|
+
Area,
|
|
132
|
+
{
|
|
133
|
+
type: curve,
|
|
134
|
+
dataKey: s.dataKey,
|
|
135
|
+
name: s.label ?? s.dataKey,
|
|
136
|
+
stackId: stacked ? "stack" : void 0,
|
|
137
|
+
stroke: chartColor(i, s.color),
|
|
138
|
+
fill: chartColor(i, s.color),
|
|
139
|
+
fillOpacity: 0.2,
|
|
140
|
+
strokeWidth: 2
|
|
141
|
+
},
|
|
142
|
+
s.dataKey
|
|
143
|
+
))
|
|
144
|
+
] });
|
|
145
|
+
}
|
|
146
|
+
return /* @__PURE__ */ jsxs(RBarChart, { data, layout: horizontal ? "vertical" : "horizontal", children: [
|
|
147
|
+
axes(!horizontal),
|
|
148
|
+
series.map((s, i) => /* @__PURE__ */ jsx(
|
|
149
|
+
Bar,
|
|
150
|
+
{
|
|
151
|
+
dataKey: s.dataKey,
|
|
152
|
+
name: s.label ?? s.dataKey,
|
|
153
|
+
stackId: stacked ? "stack" : void 0,
|
|
154
|
+
fill: chartColor(i, s.color),
|
|
155
|
+
radius: 2
|
|
156
|
+
},
|
|
157
|
+
s.dataKey
|
|
158
|
+
))
|
|
159
|
+
] });
|
|
160
|
+
};
|
|
161
|
+
return /* @__PURE__ */ jsx(
|
|
162
|
+
ChartFrame,
|
|
163
|
+
{
|
|
164
|
+
label,
|
|
165
|
+
description,
|
|
166
|
+
summaryRows: summary.rows,
|
|
167
|
+
imgSummary: summary.img,
|
|
168
|
+
hasData,
|
|
169
|
+
height: resolvedHeight,
|
|
170
|
+
className,
|
|
171
|
+
id,
|
|
172
|
+
children: hasData ? /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: chart() }) : /* @__PURE__ */ jsx(EmptyState, { title: emptyMessage ?? t("chart.empty") })
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
export {
|
|
177
|
+
CartesianChart
|
|
178
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Shared chart chrome — owns the cross-cutting concerns every chart needs so the
|
|
4
|
+
* individual chart wrappers stay tiny:
|
|
5
|
+
* - a11y: a `<figure>` with a visible `<figcaption>` title and a screen-reader
|
|
6
|
+
* text alternative (WCAG 1.1.1) describing the plotted data, with the SVG
|
|
7
|
+
* itself marked `role="img"` so AT announces one labelled graphic.
|
|
8
|
+
* - i18n: a locale-aware `Intl.NumberFormat` shared by axis ticks + tooltips.
|
|
9
|
+
* - tokens: the `--chart-1..6` palette + size→height tiers.
|
|
10
|
+
*
|
|
11
|
+
* Internal — NOT a public catalog primitive (re-exported only through the chart
|
|
12
|
+
* wrappers). See check-mcp-orphans ALLOWLIST.
|
|
13
|
+
*/
|
|
14
|
+
/** Canonical decorative chart palette (foundation tokens). */
|
|
15
|
+
export declare const CHART_COLORS: readonly ["var(--chart-1)", "var(--chart-2)", "var(--chart-3)", "var(--chart-4)", "var(--chart-5)", "var(--chart-6)"];
|
|
16
|
+
/** Resolve a series/slice colour: explicit wins, else cycle the palette by index. */
|
|
17
|
+
export declare function chartColor(index: number, explicit?: string): string;
|
|
18
|
+
/** Resolve the canvas height: explicit px overrides the `size` tier. */
|
|
19
|
+
export declare function chartHeight(size?: "xs" | "sm" | "md" | "lg", height?: number): number;
|
|
20
|
+
/** A locale-bound number formatter for the active app locale. */
|
|
21
|
+
export declare function useChartNumberFormat(options?: Intl.NumberFormatOptions): Intl.NumberFormat;
|
|
22
|
+
type ChartFrameProps = {
|
|
23
|
+
/** Visible caption; also the accessible name via `aria-labelledby` → `<figcaption>`. */
|
|
24
|
+
label: React.ReactNode;
|
|
25
|
+
/** Extra context appended to the screen-reader description. */
|
|
26
|
+
description?: React.ReactNode;
|
|
27
|
+
/** Pre-formatted "category: value" rows for the screen-reader text alternative. */
|
|
28
|
+
summaryRows: string[];
|
|
29
|
+
/** Concise summary read on the `role="img"` SVG wrapper. */
|
|
30
|
+
imgSummary: string;
|
|
31
|
+
/** True when there is data to plot (otherwise children render an empty state). */
|
|
32
|
+
hasData: boolean;
|
|
33
|
+
height: number;
|
|
34
|
+
className?: string;
|
|
35
|
+
id?: string;
|
|
36
|
+
children: React.ReactNode;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* The accessible figure wrapper. The recharts SVG passed as `children` is wrapped
|
|
40
|
+
* in a `role="img"` element with a short `aria-label`; the full data is exposed as
|
|
41
|
+
* a sibling visually-hidden list referenced by the figure's `aria-describedby`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function ChartFrame({ label, description, summaryRows, imgSummary, hasData, height, className, id, children, }: ChartFrameProps): import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
import { useTranslation } from "../../i18n/use-translation";
|
|
5
|
+
const CHART_COLORS = [
|
|
6
|
+
"var(--chart-1)",
|
|
7
|
+
"var(--chart-2)",
|
|
8
|
+
"var(--chart-3)",
|
|
9
|
+
"var(--chart-4)",
|
|
10
|
+
"var(--chart-5)",
|
|
11
|
+
"var(--chart-6)"
|
|
12
|
+
];
|
|
13
|
+
function chartColor(index, explicit) {
|
|
14
|
+
return explicit ?? CHART_COLORS[index % CHART_COLORS.length];
|
|
15
|
+
}
|
|
16
|
+
const SIZE_HEIGHT = {
|
|
17
|
+
xs: 160,
|
|
18
|
+
sm: 220,
|
|
19
|
+
md: 300,
|
|
20
|
+
lg: 400
|
|
21
|
+
};
|
|
22
|
+
function chartHeight(size = "md", height) {
|
|
23
|
+
return height ?? SIZE_HEIGHT[size];
|
|
24
|
+
}
|
|
25
|
+
function useChartNumberFormat(options) {
|
|
26
|
+
const { locale } = useTranslation();
|
|
27
|
+
return React.useMemo(() => new Intl.NumberFormat(locale, options), [locale, options]);
|
|
28
|
+
}
|
|
29
|
+
function ChartFrame({
|
|
30
|
+
label,
|
|
31
|
+
description,
|
|
32
|
+
summaryRows,
|
|
33
|
+
imgSummary,
|
|
34
|
+
hasData,
|
|
35
|
+
height,
|
|
36
|
+
className,
|
|
37
|
+
id,
|
|
38
|
+
children
|
|
39
|
+
}) {
|
|
40
|
+
const reactId = React.useId();
|
|
41
|
+
const titleId = `${id ?? reactId}-title`;
|
|
42
|
+
const descId = `${id ?? reactId}-desc`;
|
|
43
|
+
return /* @__PURE__ */ jsxs(
|
|
44
|
+
"figure",
|
|
45
|
+
{
|
|
46
|
+
id,
|
|
47
|
+
"data-slot": "chart",
|
|
48
|
+
className: cn("ui-chart", className),
|
|
49
|
+
"aria-labelledby": titleId,
|
|
50
|
+
"aria-describedby": descId,
|
|
51
|
+
children: [
|
|
52
|
+
/* @__PURE__ */ jsx("figcaption", { id: titleId, className: "ui-chart-title", children: label }),
|
|
53
|
+
/* @__PURE__ */ jsx("div", { className: "ui-chart-canvas", style: { height }, role: "img", "aria-label": imgSummary, children }),
|
|
54
|
+
/* @__PURE__ */ jsxs("p", { id: descId, className: "sr-only", children: [
|
|
55
|
+
description ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
56
|
+
description,
|
|
57
|
+
" "
|
|
58
|
+
] }) : null,
|
|
59
|
+
hasData ? imgSummary : null
|
|
60
|
+
] }),
|
|
61
|
+
hasData ? /* @__PURE__ */ jsx("ul", { className: "sr-only", children: summaryRows.map((row, i) => /* @__PURE__ */ jsx("li", { children: row }, i)) }) : null
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
export {
|
|
67
|
+
CHART_COLORS,
|
|
68
|
+
ChartFrame,
|
|
69
|
+
chartColor,
|
|
70
|
+
chartHeight,
|
|
71
|
+
useChartNumberFormat
|
|
72
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers that turn chart data into a localized screen-reader text
|
|
3
|
+
* alternative (WCAG 1.1.1). No JSX — filename pascal is intentionally NOT
|
|
4
|
+
* exported, so this is not a catalog primitive.
|
|
5
|
+
*/
|
|
6
|
+
import type { ChartDatum, ChartSeriesProp } from "../../props/components/charts.prop";
|
|
7
|
+
type Formatter = Intl.NumberFormat;
|
|
8
|
+
export type ChartSummary = {
|
|
9
|
+
rows: string[];
|
|
10
|
+
img: string;
|
|
11
|
+
};
|
|
12
|
+
/** Build the per-category rows + a one-line summary for a cartesian chart. */
|
|
13
|
+
export declare function buildCartesianSummary(data: ChartDatum[], series: ChartSeriesProp[], categoryKey: string, fmt: Formatter, list: Intl.ListFormat, summaryLine: (counts: {
|
|
14
|
+
series: number;
|
|
15
|
+
points: number;
|
|
16
|
+
}) => string): ChartSummary;
|
|
17
|
+
/** Build the per-slice rows + a one-line summary for a pie chart. */
|
|
18
|
+
export declare function buildPieSummary(data: ChartDatum[], dataKey: string, nameKey: string, fmt: Formatter, summaryLine: (counts: {
|
|
19
|
+
slices: number;
|
|
20
|
+
}) => string): ChartSummary;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
function numeric(value) {
|
|
2
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
3
|
+
}
|
|
4
|
+
function buildCartesianSummary(data, series, categoryKey, fmt, list, summaryLine) {
|
|
5
|
+
const rows = data.map((datum) => {
|
|
6
|
+
const category = String(datum[categoryKey] ?? "");
|
|
7
|
+
const parts = series.map(
|
|
8
|
+
(s) => `${s.label ?? s.dataKey}: ${fmt.format(numeric(datum[s.dataKey]))}`
|
|
9
|
+
);
|
|
10
|
+
return `${category} \u2014 ${list.format(parts)}`;
|
|
11
|
+
});
|
|
12
|
+
return { rows, img: summaryLine({ series: series.length, points: data.length }) };
|
|
13
|
+
}
|
|
14
|
+
function buildPieSummary(data, dataKey, nameKey, fmt, summaryLine) {
|
|
15
|
+
const rows = data.map(
|
|
16
|
+
(datum) => `${String(datum[nameKey] ?? "")}: ${fmt.format(numeric(datum[dataKey]))}`
|
|
17
|
+
);
|
|
18
|
+
return { rows, img: summaryLine({ slices: data.length }) };
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
buildCartesianSummary,
|
|
22
|
+
buildPieSummary
|
|
23
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Charts entry — `@godxjp/ui/charts`. Isolated from the main barrel so the
|
|
3
|
+
* `recharts` dependency is only pulled in when a consumer imports a chart
|
|
4
|
+
* (tree-shaking: `sideEffects: false` + a dedicated tsup entry + recharts as an
|
|
5
|
+
* optional peer dependency).
|
|
6
|
+
*/
|
|
7
|
+
export { LineChart } from "./line-chart";
|
|
8
|
+
export type { LineChartProp, LineChartProps } from "./line-chart";
|
|
9
|
+
export { BarChart } from "./bar-chart";
|
|
10
|
+
export type { BarChartProp, BarChartProps } from "./bar-chart";
|
|
11
|
+
export { AreaChart } from "./area-chart";
|
|
12
|
+
export type { AreaChartProp, AreaChartProps } from "./area-chart";
|
|
13
|
+
export { PieChart } from "./pie-chart";
|
|
14
|
+
export type { PieChartProp, PieChartProps } from "./pie-chart";
|
|
15
|
+
export type { ChartSeriesProp, ChartDatum } from "../../props/components/charts.prop";
|
|
16
|
+
export { CHART_COLORS } from "./chart-frame";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { LineChart } from "./line-chart";
|
|
2
|
+
import { BarChart } from "./bar-chart";
|
|
3
|
+
import { AreaChart } from "./area-chart";
|
|
4
|
+
import { PieChart } from "./pie-chart";
|
|
5
|
+
import { CHART_COLORS } from "./chart-frame";
|
|
6
|
+
export {
|
|
7
|
+
AreaChart,
|
|
8
|
+
BarChart,
|
|
9
|
+
CHART_COLORS,
|
|
10
|
+
LineChart,
|
|
11
|
+
PieChart
|
|
12
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LineChartProp } from "../../props/components/charts.prop";
|
|
2
|
+
export type { LineChartProp, LineChartProp as LineChartProps, } from "../../props/components/charts.prop";
|
|
3
|
+
/**
|
|
4
|
+
* Line chart — trends over an ordered category axis (one or more series).
|
|
5
|
+
* Import from the tree-shaken `@godxjp/ui/charts` entry; requires the `recharts`
|
|
6
|
+
* optional peer dependency.
|
|
7
|
+
*/
|
|
8
|
+
export declare function LineChart(props: LineChartProp): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PieChartProp } from "../../props/components/charts.prop";
|
|
2
|
+
export type { PieChartProp, PieChartProp as PieChartProps, } from "../../props/components/charts.prop";
|
|
3
|
+
/**
|
|
4
|
+
* Pie / donut chart — part-to-whole composition across a small set of slices.
|
|
5
|
+
* Import from the tree-shaken `@godxjp/ui/charts` entry; requires the `recharts`
|
|
6
|
+
* optional peer dependency.
|
|
7
|
+
*/
|
|
8
|
+
export declare function PieChart({ data, dataKey, nameKey, colors, label, description, size, height, showLegend, numberFormat, donut, emptyMessage, className, id, }: PieChartProp): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import {
|
|
3
|
+
Cell,
|
|
4
|
+
Legend,
|
|
5
|
+
Pie,
|
|
6
|
+
PieChart as RPieChart,
|
|
7
|
+
ResponsiveContainer,
|
|
8
|
+
Tooltip
|
|
9
|
+
} from "recharts";
|
|
10
|
+
import { EmptyState } from "../data-display/empty-state";
|
|
11
|
+
import { useTranslation } from "../../i18n/use-translation";
|
|
12
|
+
import { ChartFrame, chartColor, chartHeight, useChartNumberFormat } from "./chart-frame";
|
|
13
|
+
import { buildPieSummary } from "./chart-summary";
|
|
14
|
+
function PieChart({
|
|
15
|
+
data,
|
|
16
|
+
dataKey,
|
|
17
|
+
nameKey,
|
|
18
|
+
colors,
|
|
19
|
+
label,
|
|
20
|
+
description,
|
|
21
|
+
size = "md",
|
|
22
|
+
height,
|
|
23
|
+
showLegend = true,
|
|
24
|
+
numberFormat,
|
|
25
|
+
donut = false,
|
|
26
|
+
emptyMessage,
|
|
27
|
+
className,
|
|
28
|
+
id
|
|
29
|
+
}) {
|
|
30
|
+
const { t } = useTranslation();
|
|
31
|
+
const fmt = useChartNumberFormat(numberFormat);
|
|
32
|
+
const hasData = data.length > 0;
|
|
33
|
+
const summary = buildPieSummary(
|
|
34
|
+
data,
|
|
35
|
+
dataKey,
|
|
36
|
+
nameKey,
|
|
37
|
+
fmt,
|
|
38
|
+
(c) => t("chart.summaryPie", { slices: fmt.format(c.slices) })
|
|
39
|
+
);
|
|
40
|
+
const resolvedHeight = chartHeight(size, height);
|
|
41
|
+
return /* @__PURE__ */ jsx(
|
|
42
|
+
ChartFrame,
|
|
43
|
+
{
|
|
44
|
+
label,
|
|
45
|
+
description,
|
|
46
|
+
summaryRows: summary.rows,
|
|
47
|
+
imgSummary: summary.img,
|
|
48
|
+
hasData,
|
|
49
|
+
height: resolvedHeight,
|
|
50
|
+
className,
|
|
51
|
+
id,
|
|
52
|
+
children: hasData ? /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(RPieChart, { children: [
|
|
53
|
+
/* @__PURE__ */ jsx(
|
|
54
|
+
Pie,
|
|
55
|
+
{
|
|
56
|
+
data,
|
|
57
|
+
dataKey,
|
|
58
|
+
nameKey,
|
|
59
|
+
innerRadius: donut ? "55%" : 0,
|
|
60
|
+
outerRadius: "80%",
|
|
61
|
+
paddingAngle: donut ? 2 : 0,
|
|
62
|
+
children: data.map((_, i) => /* @__PURE__ */ jsx(Cell, { fill: chartColor(i, colors?.[i]) }, i))
|
|
63
|
+
}
|
|
64
|
+
),
|
|
65
|
+
/* @__PURE__ */ jsx(Tooltip, { formatter: (value) => fmt.format(Number(value)) }),
|
|
66
|
+
showLegend ? /* @__PURE__ */ jsx(Legend, {}) : null
|
|
67
|
+
] }) }) : /* @__PURE__ */ jsx(EmptyState, { title: emptyMessage ?? t("chart.empty") })
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
PieChart
|
|
73
|
+
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
3
|
type CardSize = "md" | "compact";
|
|
4
|
-
/** Semantic
|
|
4
|
+
/** Semantic leading-edge accent stripe (border-inline-start; width via the
|
|
5
|
+
* --card-accent-rail-width token, default 6px). */
|
|
5
6
|
type CardAccent = "primary" | "success" | "warning" | "info" | "attention" | "destructive";
|
|
6
7
|
/** Surface fill — plain card, muted band, borderless outline, or emphasized featured ring. */
|
|
7
8
|
type CardVariant = "default" | "muted" | "outline" | "featured";
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { Badge } from "./badge";
|
|
2
2
|
export type { BadgeProps } from "./badge";
|
|
3
|
+
export { ListRow } from "./list-row";
|
|
4
|
+
export type { ListRowProps } from "./list-row";
|
|
3
5
|
export { Avatar, AvatarImage, AvatarFallback } from "./avatar";
|
|
4
6
|
export { Card, CardBar, CardContent, CardCover, CardDescription, CardFooter, CardHeader, CardTitle, CardAction, StatCard, } from "./card";
|
|
5
7
|
export type { StatCardProps, CardBarProps } from "./card";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Badge } from "./badge";
|
|
2
|
+
import { ListRow } from "./list-row";
|
|
2
3
|
import { Avatar, AvatarImage, AvatarFallback } from "./avatar";
|
|
3
4
|
import {
|
|
4
5
|
Card,
|
|
@@ -74,6 +75,7 @@ export {
|
|
|
74
75
|
HoverCard,
|
|
75
76
|
HoverCardContent,
|
|
76
77
|
HoverCardTrigger,
|
|
78
|
+
ListRow,
|
|
77
79
|
Popover,
|
|
78
80
|
PopoverAnchor,
|
|
79
81
|
PopoverContent,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* ListRow — a single-line entity row (leading · title/description · trailing) for SHORT lists
|
|
4
|
+
* inside a Card: active sessions, API tokens, linked accounts, passkeys, MFA factors, invitations.
|
|
5
|
+
* Use it INSTEAD of a hand-rolled `<div className="flex items-center justify-between border-b …">`.
|
|
6
|
+
* DataTable is too heavy for a 2–4 item list, and nesting a Card per row would be card-in-card —
|
|
7
|
+
* ListRow is the in-between surface. Drop rows into a `<Card><CardContent flush>…` and they stack
|
|
8
|
+
* with a quiet divider; the trailing slot holds the row's action (Button / DropdownMenu / Switch).
|
|
9
|
+
*/
|
|
10
|
+
export interface ListRowProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
|
|
11
|
+
/** Render element — `div` (default) or `li` when the parent is a `<ul>`/`<ol>`. */
|
|
12
|
+
as?: "div" | "li";
|
|
13
|
+
/** Leading slot — a decorative icon or an Avatar. Mark a purely decorative icon `aria-hidden`. */
|
|
14
|
+
leading?: React.ReactNode;
|
|
15
|
+
/** Primary line — rendered in medium weight; truncates to a single line. */
|
|
16
|
+
title: React.ReactNode;
|
|
17
|
+
/** Secondary line under the title (muted, xs); truncates to a single line. */
|
|
18
|
+
description?: React.ReactNode;
|
|
19
|
+
/** Trailing slot — the row action(s): a Button / DropdownMenu trigger, a Badge, or a Switch. */
|
|
20
|
+
trailing?: React.ReactNode;
|
|
21
|
+
/** Cross-axis alignment of the columns — `center` (default) or `start` for multi-line content. */
|
|
22
|
+
align?: "center" | "start";
|
|
23
|
+
}
|
|
24
|
+
export declare const ListRow: React.ForwardRefExoticComponent<ListRowProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
import { Text } from "../general/typography";
|
|
5
|
+
const ListRow = React.forwardRef(
|
|
6
|
+
({ as = "div", leading, title, description, trailing, align = "center", className, ...props }, ref) => {
|
|
7
|
+
const Comp = as;
|
|
8
|
+
return /* @__PURE__ */ jsxs(
|
|
9
|
+
Comp,
|
|
10
|
+
{
|
|
11
|
+
ref,
|
|
12
|
+
"data-slot": "list-row",
|
|
13
|
+
"data-align": align === "start" ? "start" : void 0,
|
|
14
|
+
className: cn("ui-list-row", className),
|
|
15
|
+
...props,
|
|
16
|
+
children: [
|
|
17
|
+
leading != null ? /* @__PURE__ */ jsx("span", { "data-slot": "list-row-leading", children: leading }) : null,
|
|
18
|
+
/* @__PURE__ */ jsxs("span", { "data-slot": "list-row-body", children: [
|
|
19
|
+
/* @__PURE__ */ jsx(Text, { weight: "medium", truncate: true, children: title }),
|
|
20
|
+
description != null ? /* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", truncate: true, children: description }) : null
|
|
21
|
+
] }),
|
|
22
|
+
trailing != null ? /* @__PURE__ */ jsx("span", { "data-slot": "list-row-trailing", children: trailing }) : null
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
ListRow.displayName = "ListRow";
|
|
29
|
+
export {
|
|
30
|
+
ListRow
|
|
31
|
+
};
|