@nexub/react 4.5.0 → 4.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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.5.0",
2
+ "version": "4.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 on every pull request; a new violation fails the build.",
@@ -205,6 +205,19 @@
205
205
  "Decorative (`aria-hidden`). Announce the win in text, for example in a Toast or a status message."
206
206
  ]
207
207
  },
208
+ {
209
+ "slug": "chart-toggle",
210
+ "name": "Chart Toggle",
211
+ "package": "@nexub/react",
212
+ "automated": "pass",
213
+ "exceptions": [],
214
+ "keyboard": [
215
+ "Tab / Space: Move between series and switch one on or off."
216
+ ],
217
+ "screenReader": [
218
+ "Each series is a toggle button with `aria-pressed`. The last visible series cannot be switched off."
219
+ ]
220
+ },
208
221
  {
209
222
  "slug": "checkbox-card",
210
223
  "name": "Checkbox Card",
@@ -4,7 +4,7 @@ import type { ToneValue } from '@nexub/core';
4
4
  export type { ToneValue };
5
5
  export { toneTextClasses } from '../../utils/control.js';
6
6
  export declare const buttonVariants: (props?: ({
7
- variant?: "accent" | "text" | "link" | "outline" | "glass" | "ghost" | "subtle" | "filled" | "tonal" | "outlined" | "hero" | "primary" | "secondary" | "destructive" | null | undefined;
7
+ variant?: "accent" | "text" | "link" | "outline" | "primary" | "glass" | "ghost" | "subtle" | "filled" | "tonal" | "outlined" | "hero" | "secondary" | "destructive" | null | undefined;
8
8
  size?: "xs" | "sm" | "md" | "lg" | "xl" | null | undefined;
9
9
  fullWidth?: boolean | null | undefined;
10
10
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
@@ -0,0 +1,11 @@
1
+ import * as React from 'react';
2
+ import type { ChartSeries } from './Chart.js';
3
+ export interface ChartToggleProps {
4
+ series: ChartSeries[];
5
+ /** Renders the chart with the series that are switched on. */
6
+ children: (visible: ChartSeries[]) => React.ReactNode;
7
+ /** Accessible name for the group of toggles. @default 'Series' */
8
+ label?: string;
9
+ className?: string;
10
+ }
11
+ export declare function ChartToggle({ series, children, label, className }: ChartToggleProps): 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 { cn } from "../../utils/cn.js";
5
+ const BG = ["bg-chart-1", "bg-chart-2", "bg-chart-3", "bg-chart-4", "bg-chart-5", "bg-chart-6", "bg-chart-7", "bg-chart-8"];
6
+ function ChartToggle({ series, children, label = "Series", className }) {
7
+ const [hidden, setHidden] = React.useState(() => /* @__PURE__ */ new Set());
8
+ const coloured = series.map((s, i) => ({ ...s, color: s.color ?? i % 8 + 1 }));
9
+ const visible = coloured.filter((s) => !hidden.has(s.key));
10
+ const toggle = (key) => setHidden((prev) => {
11
+ const next = new Set(prev);
12
+ if (next.has(key)) next.delete(key);
13
+ else if (series.length - next.size > 1) next.add(key);
14
+ return next;
15
+ });
16
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3", className), children: [
17
+ /* @__PURE__ */ jsx("div", { role: "group", "aria-label": label, className: "flex flex-wrap gap-2", children: coloured.map((s) => {
18
+ const on = !hidden.has(s.key);
19
+ return /* @__PURE__ */ jsxs(
20
+ "button",
21
+ {
22
+ type: "button",
23
+ "aria-pressed": on,
24
+ onClick: () => toggle(s.key),
25
+ className: cn(
26
+ "nx-state-layer inline-flex h-control-xs items-center gap-1.5 rounded-full border px-2.5 text-label-md",
27
+ on ? "border-[var(--color-outline-variant)] text-[var(--color-on-surface)]" : "border-dashed border-[var(--color-outline-variant)] text-[var(--color-on-surface-variant)] line-through"
28
+ ),
29
+ children: [
30
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: cn("size-2.5 rounded-full", on ? BG[(s.color - 1) % 8] : "bg-[var(--color-outline-variant)]") }),
31
+ s.label ?? s.key
32
+ ]
33
+ },
34
+ s.key
35
+ );
36
+ }) }),
37
+ children(visible)
38
+ ] });
39
+ }
40
+ export {
41
+ ChartToggle
42
+ };
@@ -1,4 +1,6 @@
1
1
  export { BarChart, LineChart, DonutChart, Sparkline, ChartLegend, niceMax, niceDomain } from './Chart.js';
2
2
  export { Gauge, Heatmap, Funnel, KpiTile } from './MoreCharts.js';
3
+ export { ChartToggle } from './ChartToggle.js';
4
+ export type { ChartToggleProps } from './ChartToggle.js';
3
5
  export type { GaugeProps, HeatmapProps, FunnelProps, KpiTileProps } from './MoreCharts.js';
4
6
  export type { BarChartProps, LineChartProps, DonutChartProps, SparklineProps, ChartLegendProps, ChartSeries, ChartColor } from './Chart.js';
@@ -1,8 +1,10 @@
1
1
  import { BarChart, LineChart, DonutChart, Sparkline, ChartLegend, niceMax, niceDomain } from "./Chart.js";
2
2
  import { Gauge, Heatmap, Funnel, KpiTile } from "./MoreCharts.js";
3
+ import { ChartToggle } from "./ChartToggle.js";
3
4
  export {
4
5
  BarChart,
5
6
  ChartLegend,
7
+ ChartToggle,
6
8
  DonutChart,
7
9
  Funnel,
8
10
  Gauge,
@@ -1,2 +1,2 @@
1
- import { useLayoutEffect } from 'react';
2
- export declare const useIsomorphicLayoutEffect: typeof useLayoutEffect;
1
+ import { useEffect } from 'react';
2
+ export declare const useIsomorphicLayoutEffect: typeof useEffect;
@@ -0,0 +1,11 @@
1
+ import * as React from 'react';
2
+ /**
3
+ * 4.7: recolours one element (and everything inside it) from a brand seed, like
4
+ * <ThemeProvider seed> but scoped, e.g. to preview a customer's brand on one
5
+ * card or section. Writes the seeded role variables through the CSSOM (strict-
6
+ * CSP safe) and removes them when the seed is cleared or the component unmounts.
7
+ * Lazy-loads @nexub/tokens/seed, so the colour library stays out of the main bundle.
8
+ */
9
+ export declare function useScopedSeed<T extends HTMLElement>(ref: React.RefObject<T | null>, seed: string | null | undefined, options?: {
10
+ target?: 'primary' | 'tertiary';
11
+ }): void;
@@ -0,0 +1,24 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ function useScopedSeed(ref, seed, options = {}) {
4
+ const { target = "primary" } = options;
5
+ React.useEffect(() => {
6
+ const el = ref.current;
7
+ if (!el || !seed) return;
8
+ let applied = [];
9
+ let cancelled = false;
10
+ import("@nexub/tokens/seed").then(({ createSeedTheme }) => {
11
+ if (cancelled) return;
12
+ const vars = createSeedTheme(seed, { target });
13
+ for (const [k, v] of Object.entries(vars)) el.style.setProperty(k, v);
14
+ applied = Object.keys(vars);
15
+ });
16
+ return () => {
17
+ cancelled = true;
18
+ for (const k of applied) el.style.removeProperty(k);
19
+ };
20
+ }, [ref, seed, target]);
21
+ }
22
+ export {
23
+ useScopedSeed
24
+ };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { cn } from './utils/cn.js';
2
2
  export type { Size } from './utils/control.js';
3
3
  export { startViewTransition } from './utils/viewTransition.js';
4
+ export { useScopedSeed } from './hooks/useScopedSeed.js';
4
5
  export { useControllableState } from './hooks/useControllableState.js';
5
6
  export { useDisclosure } from './hooks/useDisclosure.js';
6
7
  export { useIsomorphicLayoutEffect } from './hooks/useIsomorphicLayoutEffect.js';
@@ -48,6 +49,8 @@ export { Aurora } from './components/Aurora/index.js';
48
49
  export type { AuroraProps } from './components/Aurora/index.js';
49
50
  export { BarChart, LineChart, DonutChart, Sparkline, ChartLegend, niceMax, niceDomain } from './components/Chart/index.js';
50
51
  export { Gauge, Heatmap, Funnel, KpiTile } from './components/Chart/index.js';
52
+ export { ChartToggle } from './components/Chart/index.js';
53
+ export type { ChartToggleProps } from './components/Chart/index.js';
51
54
  export type { GaugeProps, HeatmapProps, FunnelProps, KpiTileProps } from './components/Chart/index.js';
52
55
  export type { BarChartProps, LineChartProps, DonutChartProps, SparklineProps, ChartLegendProps, ChartSeries, ChartColor } from './components/Chart/index.js';
53
56
  export type { AmountProps } from './components/Amount/index.js';
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { cn } from "./utils/cn.js";
2
2
  import { startViewTransition } from "./utils/viewTransition.js";
3
+ import { useScopedSeed } from "./hooks/useScopedSeed.js";
3
4
  import { useControllableState } from "./hooks/useControllableState.js";
4
5
  import { useDisclosure } from "./hooks/useDisclosure.js";
5
6
  import { useIsomorphicLayoutEffect } from "./hooks/useIsomorphicLayoutEffect.js";
@@ -28,6 +29,7 @@ import { Celebrate } from "./components/Celebrate/index.js";
28
29
  import { Aurora } from "./components/Aurora/index.js";
29
30
  import { BarChart, LineChart, DonutChart, Sparkline, ChartLegend, niceMax, niceDomain } from "./components/Chart/index.js";
30
31
  import { Gauge, Heatmap, Funnel, KpiTile } from "./components/Chart/index.js";
32
+ import { ChartToggle } from "./components/Chart/index.js";
31
33
  import { NumberTicker } from "./components/NumberTicker/index.js";
32
34
  import { SearchInput } from "./components/SearchInput/index.js";
33
35
  import { PasswordInput } from "./components/PasswordInput/index.js";
@@ -138,6 +140,7 @@ export {
138
140
  CardLink,
139
141
  Celebrate,
140
142
  ChartLegend,
143
+ ChartToggle,
141
144
  CheckList,
142
145
  CheckListItem,
143
146
  Checkbox,
@@ -295,6 +298,7 @@ export {
295
298
  useNexubMessages,
296
299
  usePointerSheen,
297
300
  usePrefersReducedMotion,
301
+ useScopedSeed,
298
302
  useTheme,
299
303
  useToastStore
300
304
  };