@nexub/react 4.2.0 → 4.3.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.2.0",
2
+ "version": "4.3.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.",
@@ -73,7 +73,7 @@
73
73
  "slug": "aurora",
74
74
  "name": "Aurora",
75
75
  "package": "@nexub/react",
76
- "automated": "not covered",
76
+ "automated": "pass",
77
77
  "exceptions": [],
78
78
  "keyboard": [],
79
79
  "screenReader": [
@@ -194,6 +194,17 @@
194
194
  "Prefer CardLink over wrapping the whole card in `<a>`: the link’s accessible name stays the title instead of every word on the card."
195
195
  ]
196
196
  },
197
+ {
198
+ "slug": "celebrate",
199
+ "name": "Celebrate",
200
+ "package": "@nexub/react",
201
+ "automated": "pass",
202
+ "exceptions": [],
203
+ "keyboard": [],
204
+ "screenReader": [
205
+ "Decorative (`aria-hidden`). Announce the win in text, for example in a Toast or a status message."
206
+ ]
207
+ },
197
208
  {
198
209
  "slug": "checkbox-card",
199
210
  "name": "Checkbox Card",
@@ -26,5 +26,8 @@ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
26
26
  leadingIcon?: React.ReactNode;
27
27
  trailingIcon?: React.ReactNode;
28
28
  asChild?: boolean;
29
+ /** 4.3: the button drifts a few pixels toward the pointer on hover. For one key action per screen.
30
+ * Off for touch and reduced motion. */
31
+ magnetic?: boolean;
29
32
  }
30
33
  export declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
@@ -4,6 +4,7 @@ import * as React from "react";
4
4
  import { Slot } from "@radix-ui/react-slot";
5
5
  import { Loader2 } from "@nexub/icons";
6
6
  import { cva } from "class-variance-authority";
7
+ import { usePointerSheen } from "../../hooks/usePointerSheen.js";
7
8
  import { cn } from "../../utils/cn.js";
8
9
  import { disabledContainer, disabledText, pressable } from "../../utils/control.js";
9
10
  import { glassSurfaceClass } from "../../utils/glass.js";
@@ -81,19 +82,24 @@ const Button = React.forwardRef(
81
82
  leadingIcon,
82
83
  trailingIcon,
83
84
  asChild = false,
85
+ magnetic = false,
84
86
  disabled,
85
87
  onClick,
88
+ onPointerMove,
86
89
  children,
87
90
  ...props
88
91
  }, ref) => {
89
92
  const status = statusProp ?? (loading ? "loading" : "idle");
93
+ const handlePointerMove = usePointerSheen(magnetic, onPointerMove);
90
94
  const sharedProps = {
91
95
  className: cn(
92
96
  buttonVariants({ variant, size, fullWidth }),
93
97
  tone ? toneClasses[tone] : "",
94
98
  !asChild && status === "error" && "nx-shake",
99
+ magnetic && "nx-magnetic",
95
100
  className
96
101
  ),
102
+ onPointerMove: handlePointerMove,
97
103
  "data-tone": tone,
98
104
  // Styling hook for opt-in layers (vivid, marketing); no styles depend on it by default.
99
105
  "data-variant": variant ?? "primary",
@@ -8,8 +8,9 @@ export declare const cardVariants: (props?: ({
8
8
  export interface CardProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof cardVariants> {
9
9
  tone?: ToneValue;
10
10
  surface?: 'solid' | 'glass';
11
- /** `sheen`: a soft light follows the pointer (opt-in; off for touch and reduced motion). */
12
- effect?: 'none' | 'sheen';
11
+ /** `sheen`: a soft light follows the pointer. `tilt` (4.3): the card also leans toward the pointer in 3D.
12
+ * Opt-in; off for touch and reduced motion. */
13
+ effect?: 'none' | 'sheen' | 'tilt';
13
14
  /** Product accent for `variant="showcase"`: a coloured top edge and tint in marketing mode. Sets `data-product`. */
14
15
  accent?: 'leap' | 'bookub' | 'payub' | 'founderub';
15
16
  asChild?: boolean;
@@ -52,13 +52,13 @@ const Card = React.forwardRef(
52
52
  ({ className, variant = "flat", surface = "solid", effect = "none", tone, accent, asChild = false, onPointerMove, children, ...props }, ref) => {
53
53
  const Comp = asChild ? Slot : "div";
54
54
  const toneStyle = tone ? toneBorderMap[tone] : "";
55
- const sheen = effect === "sheen";
55
+ const sheen = effect === "sheen" || effect === "tilt";
56
56
  const handlePointerMove = usePointerSheen(sheen, onPointerMove);
57
57
  return /* @__PURE__ */ jsx(
58
58
  Comp,
59
59
  {
60
60
  ref,
61
- className: cn(cardVariants({ variant, surface }), toneStyle, sheen && "nx-sheen", className),
61
+ className: cn(cardVariants({ variant, surface }), toneStyle, sheen && "nx-sheen", effect === "tilt" && "nx-tilt", className),
62
62
  onPointerMove: handlePointerMove,
63
63
  "data-tone": tone,
64
64
  "data-variant": variant ?? "flat",
@@ -0,0 +1,9 @@
1
+ import * as React from 'react';
2
+ export interface CelebrateProps {
3
+ /** Bursts each time this goes from false to true. */
4
+ active: boolean;
5
+ /** Number of pieces. @default 28 */
6
+ count?: number;
7
+ className?: string;
8
+ }
9
+ export declare function Celebrate({ active, count, className }: CelebrateProps): React.JSX.Element | null;
@@ -0,0 +1,31 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../../utils/cn.js";
5
+ const COLORS = ["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 Celebrate({ active, count = 28, className }) {
7
+ const ref = React.useRef(null);
8
+ const [burst, setBurst] = React.useState(0);
9
+ const was = React.useRef(false);
10
+ React.useEffect(() => {
11
+ if (active && !was.current) setBurst((b) => b + 1);
12
+ was.current = active;
13
+ }, [active]);
14
+ React.useLayoutEffect(() => {
15
+ const el = ref.current;
16
+ if (!burst || !el) return;
17
+ for (const piece of Array.from(el.children)) {
18
+ const angle = Math.random() * Math.PI * 2;
19
+ const distance = 60 + Math.random() * 90;
20
+ piece.style.setProperty("--x", `${Math.cos(angle) * distance}px`);
21
+ piece.style.setProperty("--y", `${Math.sin(angle) * distance + 40}px`);
22
+ piece.style.setProperty("--r", `${Math.random() * 540 - 270}deg`);
23
+ piece.style.setProperty("--d", `${Math.random() * 90}ms`);
24
+ }
25
+ }, [burst]);
26
+ if (!burst) return null;
27
+ return /* @__PURE__ */ jsx("div", { ref, "aria-hidden": "true", className: cn("nx-celebrate", className), children: Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx("span", { className: COLORS[i % COLORS.length] }, i)) }, burst);
28
+ }
29
+ export {
30
+ Celebrate
31
+ };
@@ -0,0 +1,2 @@
1
+ export { Celebrate } from './Celebrate.js';
2
+ export type { CelebrateProps } from './Celebrate.js';
@@ -0,0 +1,4 @@
1
+ import { Celebrate } from "./Celebrate.js";
2
+ export {
3
+ Celebrate
4
+ };
@@ -14,6 +14,8 @@ function usePointerSheen(enabled, onPointerMove) {
14
14
  const r = el.getBoundingClientRect();
15
15
  el.style.setProperty("--nx-mx", `${clientX - r.left}px`);
16
16
  el.style.setProperty("--nx-my", `${clientY - r.top}px`);
17
+ el.style.setProperty("--nx-px", String(r.width ? (clientX - r.left) / r.width : 0.5));
18
+ el.style.setProperty("--nx-py", String(r.height ? (clientY - r.top) / r.height : 0.5));
17
19
  });
18
20
  },
19
21
  [onPointerMove]
package/dist/index.d.ts CHANGED
@@ -36,6 +36,8 @@ export type { NumberInputProps } from './components/NumberInput/index.js';
36
36
  export { MoneyInput } from './components/MoneyInput/index.js';
37
37
  export type { MoneyInputProps } from './components/MoneyInput/index.js';
38
38
  export { Amount } from './components/Amount/index.js';
39
+ export { Celebrate } from './components/Celebrate/index.js';
40
+ export type { CelebrateProps } from './components/Celebrate/index.js';
39
41
  export { Aurora } from './components/Aurora/index.js';
40
42
  export type { AuroraProps } from './components/Aurora/index.js';
41
43
  export { BarChart, LineChart, DonutChart, Sparkline, ChartLegend, niceMax, niceDomain } from './components/Chart/index.js';
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ import { Textarea, textareaVariants } from "./components/Textarea/index.js";
21
21
  import { NumberInput } from "./components/NumberInput/index.js";
22
22
  import { MoneyInput } from "./components/MoneyInput/index.js";
23
23
  import { Amount } from "./components/Amount/index.js";
24
+ import { Celebrate } from "./components/Celebrate/index.js";
24
25
  import { Aurora } from "./components/Aurora/index.js";
25
26
  import { BarChart, LineChart, DonutChart, Sparkline, ChartLegend, niceMax, niceDomain } from "./components/Chart/index.js";
26
27
  import { NumberTicker } from "./components/NumberTicker/index.js";
@@ -131,6 +132,7 @@ export {
131
132
  ButtonGroup,
132
133
  Card,
133
134
  CardLink,
135
+ Celebrate,
134
136
  ChartLegend,
135
137
  CheckList,
136
138
  CheckListItem,