@nexub/react 6.5.0 → 6.7.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/accessibility.json +21 -1
- package/dist/components/ChartZoom/ChartZoom.d.ts +18 -0
- package/dist/components/ChartZoom/ChartZoom.js +42 -0
- package/dist/components/ChartZoom/index.d.ts +2 -0
- package/dist/components/ChartZoom/index.js +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/utils/csv.d.ts +11 -0
- package/dist/utils/csv.js +17 -0
- package/package.json +6 -6
package/accessibility.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "6.
|
|
2
|
+
"version": "6.7.0",
|
|
3
3
|
"standard": "WCAG 2.2 Level AA",
|
|
4
4
|
"method": {
|
|
5
5
|
"automated": "axe-core rules tagged wcag2a, wcag2aa, wcag21a, wcag21aa and wcag22aa, run on every Storybook story in light and dark, and on open popups (menus, listboxes, dialogs), on every pull request; a new violation fails the build.",
|
|
@@ -238,6 +238,17 @@
|
|
|
238
238
|
"Each series is a toggle button with `aria-pressed`. The last visible series cannot be switched off."
|
|
239
239
|
]
|
|
240
240
|
},
|
|
241
|
+
{
|
|
242
|
+
"slug": "chart-zoom",
|
|
243
|
+
"name": "Chart Zoom",
|
|
244
|
+
"package": "@nexub/react",
|
|
245
|
+
"automated": "pass",
|
|
246
|
+
"exceptions": [],
|
|
247
|
+
"keyboard": [
|
|
248
|
+
"Arrow keys / Home / End: Move the focused thumb."
|
|
249
|
+
],
|
|
250
|
+
"screenReader": []
|
|
251
|
+
},
|
|
241
252
|
{
|
|
242
253
|
"slug": "checkbox-card",
|
|
243
254
|
"name": "Checkbox Card",
|
|
@@ -1430,6 +1441,15 @@
|
|
|
1430
1441
|
"keyboard": [],
|
|
1431
1442
|
"screenReader": []
|
|
1432
1443
|
},
|
|
1444
|
+
{
|
|
1445
|
+
"slug": "notification-center",
|
|
1446
|
+
"name": "NotificationCenter",
|
|
1447
|
+
"package": "@nexub/patterns",
|
|
1448
|
+
"automated": "pass",
|
|
1449
|
+
"exceptions": [],
|
|
1450
|
+
"keyboard": [],
|
|
1451
|
+
"screenReader": []
|
|
1452
|
+
},
|
|
1433
1453
|
{
|
|
1434
1454
|
"slug": "notification-item",
|
|
1435
1455
|
"name": "NotificationItem",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface ChartZoomProps<T> {
|
|
3
|
+
data: T[];
|
|
4
|
+
/** The category key, shown as the range's ends. */
|
|
5
|
+
index: keyof T;
|
|
6
|
+
/** Render the chart for the visible slice (charts stay server-friendly; only this wrapper is client). */
|
|
7
|
+
children: (slice: T[]) => React.ReactNode;
|
|
8
|
+
/** Start and end indexes. @default the whole range */
|
|
9
|
+
defaultRange?: [number, number];
|
|
10
|
+
/** Fewest categories shown. @default 2 */
|
|
11
|
+
minSpan?: number;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Zoom a chart to part of its range with a two-thumb slider under it (keyboard
|
|
16
|
+
* and touch friendly), and reset to the whole range.
|
|
17
|
+
*/
|
|
18
|
+
export declare function ChartZoom<T>({ data, index, children, defaultRange, minSpan, className }: ChartZoomProps<T>): React.JSX.Element;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Slider } from "../Slider/Slider.js";
|
|
5
|
+
import { Button } from "../Button/Button.js";
|
|
6
|
+
import { cn } from "../../utils/cn.js";
|
|
7
|
+
import { useNexubMessages } from "../NexubProvider/NexubProvider.js";
|
|
8
|
+
function ChartZoom({ data, index, children, defaultRange, minSpan = 2, className }) {
|
|
9
|
+
const t = useNexubMessages();
|
|
10
|
+
const full = [0, Math.max(0, data.length - 1)];
|
|
11
|
+
const [range, setRange] = React.useState(defaultRange ?? full);
|
|
12
|
+
const [a, b] = [Math.max(0, range[0]), Math.min(full[1], range[1])];
|
|
13
|
+
const zoomed = a > 0 || b < full[1];
|
|
14
|
+
const label = (i) => String(data[i]?.[index] ?? "");
|
|
15
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3", className), children: [
|
|
16
|
+
children(data.slice(a, b + 1)),
|
|
17
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
18
|
+
/* @__PURE__ */ jsx(
|
|
19
|
+
Slider,
|
|
20
|
+
{
|
|
21
|
+
min: 0,
|
|
22
|
+
max: full[1],
|
|
23
|
+
step: 1,
|
|
24
|
+
minStepsBetweenThumbs: Math.max(1, minSpan - 1),
|
|
25
|
+
value: [a, b],
|
|
26
|
+
onValueChange: (v) => setRange([v[0], v[1]]),
|
|
27
|
+
thumbLabels: [`${t.zoomStart}: ${label(a)}`, `${t.zoomEnd}: ${label(b)}`],
|
|
28
|
+
className: "flex-1"
|
|
29
|
+
}
|
|
30
|
+
),
|
|
31
|
+
/* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: "min-w-max text-label-md tabular-nums text-[var(--color-on-surface-muted)]", children: [
|
|
32
|
+
label(a),
|
|
33
|
+
" \u2013 ",
|
|
34
|
+
label(b)
|
|
35
|
+
] }),
|
|
36
|
+
/* @__PURE__ */ jsx(Button, { variant: "text", size: "sm", disabled: !zoomed, onClick: () => setRange(full), children: t.resetZoom })
|
|
37
|
+
] })
|
|
38
|
+
] });
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
ChartZoom
|
|
42
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -53,6 +53,8 @@ export type { AuroraProps } from './components/Aurora/index.js';
|
|
|
53
53
|
export { BarChart, LineChart, DonutChart, Sparkline, ChartLegend, niceMax, niceDomain } from './components/Chart/index.js';
|
|
54
54
|
export { Gauge, Heatmap, Funnel, KpiTile } from './components/Chart/index.js';
|
|
55
55
|
export { ChartToggle } from './components/Chart/index.js';
|
|
56
|
+
export { ChartZoom } from './components/ChartZoom/index.js';
|
|
57
|
+
export type { ChartZoomProps } from './components/ChartZoom/index.js';
|
|
56
58
|
export type { ChartToggleProps } from './components/Chart/index.js';
|
|
57
59
|
export type { GaugeProps, HeatmapProps, FunnelProps, KpiTileProps } from './components/Chart/index.js';
|
|
58
60
|
export type { BarChartProps, LineChartProps, DonutChartProps, SparklineProps, ChartLegendProps, ChartSeries, ChartColor } from './components/Chart/index.js';
|
|
@@ -238,6 +240,8 @@ export { Sortable } from './components/Sortable/index.js';
|
|
|
238
240
|
export type { SortableProps } from './components/Sortable/index.js';
|
|
239
241
|
export { Kanban } from './components/Kanban/index.js';
|
|
240
242
|
export type { KanbanProps, KanbanColumn } from './components/Kanban/index.js';
|
|
243
|
+
export { toCSV } from './utils/csv.js';
|
|
244
|
+
export type { CSVColumn } from './utils/csv.js';
|
|
241
245
|
export type { OTPInputProps } from './components/OTPInput/index.js';
|
|
242
246
|
export { DatePicker } from './components/DatePicker/index.js';
|
|
243
247
|
export type { DatePickerProps } from './components/DatePicker/index.js';
|
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ import { Aurora } from "./components/Aurora/index.js";
|
|
|
32
32
|
import { BarChart, LineChart, DonutChart, Sparkline, ChartLegend, niceMax, niceDomain } from "./components/Chart/index.js";
|
|
33
33
|
import { Gauge, Heatmap, Funnel, KpiTile } from "./components/Chart/index.js";
|
|
34
34
|
import { ChartToggle } from "./components/Chart/index.js";
|
|
35
|
+
import { ChartZoom } from "./components/ChartZoom/index.js";
|
|
35
36
|
import { NumberTicker } from "./components/NumberTicker/index.js";
|
|
36
37
|
import { SearchInput } from "./components/SearchInput/index.js";
|
|
37
38
|
import { PasswordInput } from "./components/PasswordInput/index.js";
|
|
@@ -133,6 +134,7 @@ import { Stepper } from "./components/Stepper/index.js";
|
|
|
133
134
|
import { ActionBar } from "./components/ActionBar/index.js";
|
|
134
135
|
import { Sortable } from "./components/Sortable/index.js";
|
|
135
136
|
import { Kanban } from "./components/Kanban/index.js";
|
|
137
|
+
import { toCSV } from "./utils/csv.js";
|
|
136
138
|
import { DatePicker } from "./components/DatePicker/index.js";
|
|
137
139
|
import { DateRangePicker } from "./components/DateRangePicker/index.js";
|
|
138
140
|
import { todayIn } from "./components/DateRangePicker/index.js";
|
|
@@ -162,6 +164,7 @@ export {
|
|
|
162
164
|
Celebrate,
|
|
163
165
|
ChartLegend,
|
|
164
166
|
ChartToggle,
|
|
167
|
+
ChartZoom,
|
|
165
168
|
CheckList,
|
|
166
169
|
CheckListItem,
|
|
167
170
|
Checkbox,
|
|
@@ -331,6 +334,7 @@ export {
|
|
|
331
334
|
startViewTransition,
|
|
332
335
|
textVariants,
|
|
333
336
|
textareaVariants,
|
|
337
|
+
toCSV,
|
|
334
338
|
toast,
|
|
335
339
|
todayIn,
|
|
336
340
|
toggleVariants,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CSVColumn<T> {
|
|
2
|
+
header: string;
|
|
3
|
+
/** A key of the row, or a function returning the cell's value. */
|
|
4
|
+
value: keyof T | ((row: T) => unknown);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Rows to CSV text (RFC 4180, CRLF line ends). Text that starts like a formula
|
|
8
|
+
* gets a leading `'` so spreadsheets show it instead of running it. Pass the
|
|
9
|
+
* rows and columns the person sees, e.g. after sorting and hiding columns.
|
|
10
|
+
*/
|
|
11
|
+
export declare function toCSV<T>(rows: T[], columns: CSVColumn<T>[]): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const FORMULA = /^[=+\-@\t\r]/;
|
|
2
|
+
function cell(value) {
|
|
3
|
+
if (value == null) return "";
|
|
4
|
+
let text = value instanceof Date ? value.toISOString() : String(value);
|
|
5
|
+
if (typeof value !== "number" && FORMULA.test(text)) text = `'${text}`;
|
|
6
|
+
return /[",\r\n]/.test(text) || text !== text.trim() ? `"${text.replace(/"/g, '""')}"` : text;
|
|
7
|
+
}
|
|
8
|
+
function toCSV(rows, columns) {
|
|
9
|
+
const lines = [columns.map((c) => cell(c.header)).join(",")];
|
|
10
|
+
for (const row of rows) {
|
|
11
|
+
lines.push(columns.map((c) => cell(typeof c.value === "function" ? c.value(row) : row[c.value])).join(","));
|
|
12
|
+
}
|
|
13
|
+
return lines.join("\r\n") + "\r\n";
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
toCSV
|
|
17
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexub/react",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.7.0",
|
|
4
4
|
"description": "React component library for Nexub Design System — 90+ accessible, themeable UI components built on Radix UI primitives.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -81,14 +81,14 @@
|
|
|
81
81
|
"date-fns": "^4.4.0",
|
|
82
82
|
"react-day-picker": "^10.0.2",
|
|
83
83
|
"tailwind-merge": "^3.7.0",
|
|
84
|
-
"@nexub/core": "6.
|
|
85
|
-
"@nexub/icons": "6.
|
|
84
|
+
"@nexub/core": "6.7.0",
|
|
85
|
+
"@nexub/icons": "6.7.0"
|
|
86
86
|
},
|
|
87
87
|
"peerDependencies": {
|
|
88
88
|
"react": ">=19 <20",
|
|
89
89
|
"react-dom": ">=19 <20",
|
|
90
90
|
"@tanstack/react-virtual": "^3.14.22",
|
|
91
|
-
"@nexub/tokens": "^6.
|
|
91
|
+
"@nexub/tokens": "^6.7.0"
|
|
92
92
|
},
|
|
93
93
|
"peerDependenciesMeta": {
|
|
94
94
|
"@tanstack/react-virtual": {
|
|
@@ -120,8 +120,8 @@
|
|
|
120
120
|
"vaul": "1.1.2",
|
|
121
121
|
"vite": "^8.3.5",
|
|
122
122
|
"vitest": "^5.0.5",
|
|
123
|
-
"@nexub/themes": "6.
|
|
124
|
-
"@nexub/tokens": "6.
|
|
123
|
+
"@nexub/themes": "6.7.0",
|
|
124
|
+
"@nexub/tokens": "6.7.0"
|
|
125
125
|
},
|
|
126
126
|
"scripts": {
|
|
127
127
|
"build": "rm -rf dist && tsup && tsc -p tsconfig.build.json && rm -f dist/vendor/*.d.ts && node scripts/check-dts.mjs && tailwindcss -i src/styles.css -o dist/styles.css --minify && cp -R ../themes/src/fonts dist/fonts",
|