@kinetixui/ui 0.4.2 → 0.5.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/index.d.ts +14 -0
- package/dist/index.js +55 -2
- package/package.json +2 -2
- package/src/components/chart.tsx +106 -2
- package/tailwind.config.ts +3 -0
package/dist/index.d.ts
CHANGED
|
@@ -482,6 +482,20 @@ declare const ChartContainer: React$1.ForwardRefExoticComponent<Omit<React$1.Cla
|
|
|
482
482
|
* primitive for keyboard data-point navigation.
|
|
483
483
|
*/
|
|
484
484
|
label?: string;
|
|
485
|
+
/**
|
|
486
|
+
* Render a placeholder in place of the chart. `"loading"` shows a shimmer,
|
|
487
|
+
* `"empty"` / `"error"` show a message (override with `stateMessage`).
|
|
488
|
+
*/
|
|
489
|
+
state?: "loading" | "empty" | "error";
|
|
490
|
+
stateMessage?: string;
|
|
491
|
+
/**
|
|
492
|
+
* Visually-hidden `<table>` rendered after the chart so a screen reader can
|
|
493
|
+
* read the underlying numbers. Pair with a concise `label`.
|
|
494
|
+
*/
|
|
495
|
+
srTable?: {
|
|
496
|
+
columns: React$1.ReactNode[];
|
|
497
|
+
rows: React$1.ReactNode[][];
|
|
498
|
+
};
|
|
485
499
|
}, "ref"> & React$1.RefAttributes<HTMLDivElement>>;
|
|
486
500
|
declare const ChartStyle: ({ id, config }: {
|
|
487
501
|
id: string;
|
package/dist/index.js
CHANGED
|
@@ -1545,7 +1545,19 @@ function useChart() {
|
|
|
1545
1545
|
if (!context) throw new Error("useChart must be used within a <ChartContainer />");
|
|
1546
1546
|
return context;
|
|
1547
1547
|
}
|
|
1548
|
-
var ChartContainer = React32.forwardRef(({
|
|
1548
|
+
var ChartContainer = React32.forwardRef(({
|
|
1549
|
+
id,
|
|
1550
|
+
className,
|
|
1551
|
+
children,
|
|
1552
|
+
config,
|
|
1553
|
+
label,
|
|
1554
|
+
state,
|
|
1555
|
+
stateMessage,
|
|
1556
|
+
srTable,
|
|
1557
|
+
role,
|
|
1558
|
+
"aria-label": ariaLabel,
|
|
1559
|
+
...props
|
|
1560
|
+
}, ref) => {
|
|
1549
1561
|
const uniqueId = React32.useId();
|
|
1550
1562
|
const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
|
|
1551
1563
|
const name = ariaLabel ?? label ?? "Chart";
|
|
@@ -1584,12 +1596,53 @@ var ChartContainer = React32.forwardRef(({ id, className, children, config, labe
|
|
|
1584
1596
|
...props,
|
|
1585
1597
|
children: [
|
|
1586
1598
|
/* @__PURE__ */ jsx37(ChartStyle, { id: chartId, config }),
|
|
1587
|
-
/* @__PURE__ */ jsx37(RechartsPrimitive.ResponsiveContainer, { children })
|
|
1599
|
+
state ? /* @__PURE__ */ jsx37(ChartState, { state, message: stateMessage }) : /* @__PURE__ */ jsx37(RechartsPrimitive.ResponsiveContainer, { children }),
|
|
1600
|
+
srTable && !state ? /* @__PURE__ */ jsx37(ChartSrTable, { ...srTable }) : null
|
|
1588
1601
|
]
|
|
1589
1602
|
}
|
|
1590
1603
|
) });
|
|
1591
1604
|
});
|
|
1592
1605
|
ChartContainer.displayName = "Chart";
|
|
1606
|
+
var STATE_COPY = {
|
|
1607
|
+
loading: "Loading chart\u2026",
|
|
1608
|
+
empty: "No data to show",
|
|
1609
|
+
error: "Couldn't load this chart"
|
|
1610
|
+
};
|
|
1611
|
+
function ChartState({
|
|
1612
|
+
state,
|
|
1613
|
+
message
|
|
1614
|
+
}) {
|
|
1615
|
+
return /* @__PURE__ */ jsxs15(
|
|
1616
|
+
"div",
|
|
1617
|
+
{
|
|
1618
|
+
role: state === "error" ? "alert" : "status",
|
|
1619
|
+
className: cn(
|
|
1620
|
+
"flex h-full w-full flex-col items-center justify-center gap-2 rounded-md border border-dashed p-6 text-center text-xs",
|
|
1621
|
+
state === "error" ? "border-destructive/40 text-destructive" : "border-border text-muted-foreground"
|
|
1622
|
+
),
|
|
1623
|
+
children: [
|
|
1624
|
+
state === "loading" ? /* @__PURE__ */ jsx37("div", { "aria-hidden": true, className: "flex w-full max-w-[220px] items-end justify-between gap-1.5", children: [40, 72, 56, 88, 48, 64, 80].map((h, i) => /* @__PURE__ */ jsx37(
|
|
1625
|
+
"span",
|
|
1626
|
+
{
|
|
1627
|
+
className: "w-full animate-pulse rounded-sm bg-muted",
|
|
1628
|
+
style: { height: `${h}px`, animationDelay: `${i * 90}ms` }
|
|
1629
|
+
},
|
|
1630
|
+
i
|
|
1631
|
+
)) }) : /* @__PURE__ */ jsx37("svg", { "aria-hidden": true, viewBox: "0 0 24 24", className: "size-5", fill: "none", stroke: "currentColor", strokeWidth: 1.5, children: state === "empty" ? /* @__PURE__ */ jsx37("path", { d: "M3 3v18h18M7 15l4-4 3 3 5-6", strokeLinecap: "round", strokeLinejoin: "round" }) : /* @__PURE__ */ jsx37("path", { d: "M12 9v4m0 4h.01M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.7 3.86a2 2 0 0 0-3.42 0Z", strokeLinecap: "round", strokeLinejoin: "round" }) }),
|
|
1632
|
+
/* @__PURE__ */ jsx37("span", { children: message ?? STATE_COPY[state] })
|
|
1633
|
+
]
|
|
1634
|
+
}
|
|
1635
|
+
);
|
|
1636
|
+
}
|
|
1637
|
+
function ChartSrTable({
|
|
1638
|
+
columns,
|
|
1639
|
+
rows
|
|
1640
|
+
}) {
|
|
1641
|
+
return /* @__PURE__ */ jsxs15("table", { className: "sr-only", children: [
|
|
1642
|
+
/* @__PURE__ */ jsx37("thead", { children: /* @__PURE__ */ jsx37("tr", { children: columns.map((c, i) => /* @__PURE__ */ jsx37("th", { scope: "col", children: c }, i)) }) }),
|
|
1643
|
+
/* @__PURE__ */ jsx37("tbody", { children: rows.map((r, i) => /* @__PURE__ */ jsx37("tr", { children: r.map((cell, j) => /* @__PURE__ */ jsx37("td", { children: cell }, j)) }, i)) })
|
|
1644
|
+
] });
|
|
1645
|
+
}
|
|
1593
1646
|
var ChartStyle = ({ id, config }) => {
|
|
1594
1647
|
const colorConfig = Object.entries(config).filter(([, c]) => c.theme || c.color);
|
|
1595
1648
|
if (!colorConfig.length) return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kinetixui/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "KinetixUI React components — CVA + Radix + Tailwind on the KinetixUI token contract. Also distributed via the kinetixui CLI as a component registry.",
|
|
6
6
|
"keywords": [
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"react-dom": ">=18"
|
|
90
90
|
},
|
|
91
91
|
"devDependencies": {
|
|
92
|
-
"@kinetixui/tokens": "0.
|
|
92
|
+
"@kinetixui/tokens": "0.5.0",
|
|
93
93
|
"@testing-library/jest-dom": "^6.6.3",
|
|
94
94
|
"@testing-library/react": "^16.1.0",
|
|
95
95
|
"@testing-library/user-event": "^14.5.2",
|
package/src/components/chart.tsx
CHANGED
|
@@ -35,8 +35,31 @@ const ChartContainer = React.forwardRef<
|
|
|
35
35
|
* primitive for keyboard data-point navigation.
|
|
36
36
|
*/
|
|
37
37
|
label?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Render a placeholder in place of the chart. `"loading"` shows a shimmer,
|
|
40
|
+
* `"empty"` / `"error"` show a message (override with `stateMessage`).
|
|
41
|
+
*/
|
|
42
|
+
state?: "loading" | "empty" | "error";
|
|
43
|
+
stateMessage?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Visually-hidden `<table>` rendered after the chart so a screen reader can
|
|
46
|
+
* read the underlying numbers. Pair with a concise `label`.
|
|
47
|
+
*/
|
|
48
|
+
srTable?: { columns: React.ReactNode[]; rows: React.ReactNode[][] };
|
|
38
49
|
}
|
|
39
|
-
>(({
|
|
50
|
+
>(({
|
|
51
|
+
id,
|
|
52
|
+
className,
|
|
53
|
+
children,
|
|
54
|
+
config,
|
|
55
|
+
label,
|
|
56
|
+
state,
|
|
57
|
+
stateMessage,
|
|
58
|
+
srTable,
|
|
59
|
+
role,
|
|
60
|
+
"aria-label": ariaLabel,
|
|
61
|
+
...props
|
|
62
|
+
}, ref) => {
|
|
40
63
|
const uniqueId = React.useId();
|
|
41
64
|
const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
|
|
42
65
|
const name = ariaLabel ?? label ?? "Chart";
|
|
@@ -83,13 +106,94 @@ const ChartContainer = React.forwardRef<
|
|
|
83
106
|
{...props}
|
|
84
107
|
>
|
|
85
108
|
<ChartStyle id={chartId} config={config} />
|
|
86
|
-
|
|
109
|
+
{state ? (
|
|
110
|
+
<ChartState state={state} message={stateMessage} />
|
|
111
|
+
) : (
|
|
112
|
+
<RechartsPrimitive.ResponsiveContainer>{children}</RechartsPrimitive.ResponsiveContainer>
|
|
113
|
+
)}
|
|
114
|
+
{srTable && !state ? <ChartSrTable {...srTable} /> : null}
|
|
87
115
|
</div>
|
|
88
116
|
</ChartContext.Provider>
|
|
89
117
|
);
|
|
90
118
|
});
|
|
91
119
|
ChartContainer.displayName = "Chart";
|
|
92
120
|
|
|
121
|
+
const STATE_COPY = {
|
|
122
|
+
loading: "Loading chart…",
|
|
123
|
+
empty: "No data to show",
|
|
124
|
+
error: "Couldn't load this chart",
|
|
125
|
+
} as const;
|
|
126
|
+
|
|
127
|
+
function ChartState({
|
|
128
|
+
state,
|
|
129
|
+
message,
|
|
130
|
+
}: {
|
|
131
|
+
state: "loading" | "empty" | "error";
|
|
132
|
+
message?: string;
|
|
133
|
+
}) {
|
|
134
|
+
return (
|
|
135
|
+
<div
|
|
136
|
+
role={state === "error" ? "alert" : "status"}
|
|
137
|
+
className={cn(
|
|
138
|
+
"flex h-full w-full flex-col items-center justify-center gap-2 rounded-md border border-dashed p-6 text-center text-xs",
|
|
139
|
+
state === "error" ? "border-destructive/40 text-destructive" : "border-border text-muted-foreground",
|
|
140
|
+
)}
|
|
141
|
+
>
|
|
142
|
+
{state === "loading" ? (
|
|
143
|
+
<div aria-hidden className="flex w-full max-w-[220px] items-end justify-between gap-1.5">
|
|
144
|
+
{[40, 72, 56, 88, 48, 64, 80].map((h, i) => (
|
|
145
|
+
<span
|
|
146
|
+
key={i}
|
|
147
|
+
className="w-full animate-pulse rounded-sm bg-muted"
|
|
148
|
+
style={{ height: `${h}px`, animationDelay: `${i * 90}ms` }}
|
|
149
|
+
/>
|
|
150
|
+
))}
|
|
151
|
+
</div>
|
|
152
|
+
) : (
|
|
153
|
+
<svg aria-hidden viewBox="0 0 24 24" className="size-5" fill="none" stroke="currentColor" strokeWidth={1.5}>
|
|
154
|
+
{state === "empty" ? (
|
|
155
|
+
<path d="M3 3v18h18M7 15l4-4 3 3 5-6" strokeLinecap="round" strokeLinejoin="round" />
|
|
156
|
+
) : (
|
|
157
|
+
<path d="M12 9v4m0 4h.01M10.3 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.7 3.86a2 2 0 0 0-3.42 0Z" strokeLinecap="round" strokeLinejoin="round" />
|
|
158
|
+
)}
|
|
159
|
+
</svg>
|
|
160
|
+
)}
|
|
161
|
+
<span>{message ?? STATE_COPY[state]}</span>
|
|
162
|
+
</div>
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function ChartSrTable({
|
|
167
|
+
columns,
|
|
168
|
+
rows,
|
|
169
|
+
}: {
|
|
170
|
+
columns: React.ReactNode[];
|
|
171
|
+
rows: React.ReactNode[][];
|
|
172
|
+
}) {
|
|
173
|
+
return (
|
|
174
|
+
<table className="sr-only">
|
|
175
|
+
<thead>
|
|
176
|
+
<tr>
|
|
177
|
+
{columns.map((c, i) => (
|
|
178
|
+
<th key={i} scope="col">
|
|
179
|
+
{c}
|
|
180
|
+
</th>
|
|
181
|
+
))}
|
|
182
|
+
</tr>
|
|
183
|
+
</thead>
|
|
184
|
+
<tbody>
|
|
185
|
+
{rows.map((r, i) => (
|
|
186
|
+
<tr key={i}>
|
|
187
|
+
{r.map((cell, j) => (
|
|
188
|
+
<td key={j}>{cell}</td>
|
|
189
|
+
))}
|
|
190
|
+
</tr>
|
|
191
|
+
))}
|
|
192
|
+
</tbody>
|
|
193
|
+
</table>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
93
197
|
const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
|
|
94
198
|
const colorConfig = Object.entries(config).filter(([, c]) => c.theme || c.color);
|
|
95
199
|
if (!colorConfig.length) return null;
|