@nexub/react 7.2.0 → 7.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.
- package/accessibility.json +1 -1
- package/dist/components/Accordion/Accordion.js +1 -1
- package/dist/components/Motion/Collapse.d.ts +5 -4
- package/dist/components/Motion/Collapse.js +23 -53
- package/dist/components/Motion/motion.types.d.ts +2 -0
- package/dist/components/NavigationMenu/NavigationMenu.js +3 -1
- package/dist/components/Progress/Progress.js +1 -1
- package/dist/components/Tabs/Tabs.js +13 -3
- package/dist/hooks/useSlidingIndicator.d.ts +1 -1
- package/dist/hooks/useSlidingIndicator.js +2 -0
- package/dist/styles.css +1 -1
- package/dist/utils/viewTransition.d.ts +4 -2
- package/dist/utils/viewTransition.js +10 -2
- package/package.json +6 -6
package/accessibility.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "7.
|
|
2
|
+
"version": "7.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, and on open popups (menus, listboxes, dialogs), on every pull request; a new violation fails the build.",
|
|
@@ -33,7 +33,7 @@ const Trigger = React.forwardRef(
|
|
|
33
33
|
...props,
|
|
34
34
|
children: [
|
|
35
35
|
children,
|
|
36
|
-
/* @__PURE__ */ jsx(ChevronDown, { size: "sm", className: "shrink-0 transition-transform duration-
|
|
36
|
+
/* @__PURE__ */ jsx(ChevronDown, { size: "sm", className: "shrink-0 transition-transform duration-spatial-fast ease-spatial-fast", "aria-hidden": "true" })
|
|
37
37
|
]
|
|
38
38
|
}
|
|
39
39
|
) })
|
|
@@ -4,6 +4,7 @@ export interface CollapseProps extends Omit<MotionBaseProps, 'easing'>, React.HT
|
|
|
4
4
|
/**
|
|
5
5
|
* Legacy: set it to use `--duration-*` + `--ease-{value}` instead of the
|
|
6
6
|
* spatial spring for the height transition.
|
|
7
|
+
* @deprecated since 7.3, removed in 8.0 (see MotionBaseProps.easing).
|
|
7
8
|
*/
|
|
8
9
|
easing?: MotionBaseProps['easing'];
|
|
9
10
|
/**
|
|
@@ -15,10 +16,10 @@ export interface CollapseProps extends Omit<MotionBaseProps, 'easing'>, React.HT
|
|
|
15
16
|
as?: React.ElementType;
|
|
16
17
|
}
|
|
17
18
|
/**
|
|
18
|
-
* Collapse —
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* Collapse — reveals / hides content on the spatial spring by animating a
|
|
20
|
+
* one-row grid from `0fr` to `1fr`, so the browser sizes it: no height is
|
|
21
|
+
* measured in JS and content that grows while open just grows. Reduced motion
|
|
22
|
+
* snaps instead of animating.
|
|
22
23
|
*
|
|
23
24
|
* ```tsx
|
|
24
25
|
* <Collapse in={isOpen}>
|
|
@@ -13,63 +13,30 @@ const Collapse = React.forwardRef(function Collapse2({
|
|
|
13
13
|
as: Tag = "div",
|
|
14
14
|
...rest
|
|
15
15
|
}, ref) {
|
|
16
|
-
const innerRef = React.useRef(null);
|
|
17
16
|
const reduced = usePrefersReducedMotion();
|
|
18
17
|
const legacy = easing !== void 0;
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const [overflow, setOverflow] = React.useState(
|
|
22
|
-
visible ? "visible" : "hidden"
|
|
23
|
-
);
|
|
18
|
+
const instant = duration === "instant" || reduced;
|
|
19
|
+
const settleMs = instant ? 0 : legacy ? DURATION_MS[duration] : SPRING_MS.spatial[SPRING_SPEED[duration]];
|
|
24
20
|
const [mounted, setMounted] = React.useState(unmountOnExit ? visible : true);
|
|
21
|
+
const [expanded, setExpanded] = React.useState(visible);
|
|
22
|
+
const [settled, setSettled] = React.useState(true);
|
|
25
23
|
const prevVisible = React.useRef(visible);
|
|
26
24
|
React.useEffect(() => {
|
|
27
|
-
|
|
25
|
+
if (prevVisible.current === visible) return;
|
|
28
26
|
prevVisible.current = visible;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
setMounted(true);
|
|
34
|
-
raf1 = requestAnimationFrame(() => {
|
|
35
|
-
const el = innerRef.current;
|
|
36
|
-
if (el) {
|
|
37
|
-
setHeight(el.scrollHeight);
|
|
38
|
-
setOverflow("hidden");
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
} else {
|
|
42
|
-
const el = innerRef.current;
|
|
43
|
-
if (el) {
|
|
44
|
-
setHeight(el.scrollHeight);
|
|
45
|
-
setOverflow("hidden");
|
|
46
|
-
raf1 = requestAnimationFrame(() => {
|
|
47
|
-
raf2 = requestAnimationFrame(() => {
|
|
48
|
-
setHeight(typeof collapsedHeight === "number" ? collapsedHeight : 0);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
}
|
|
27
|
+
setSettled(false);
|
|
28
|
+
if (!visible) {
|
|
29
|
+
setExpanded(false);
|
|
30
|
+
return;
|
|
52
31
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}, [visible, collapsedHeight]);
|
|
32
|
+
setMounted(true);
|
|
33
|
+
const raf = requestAnimationFrame(() => setExpanded(true));
|
|
34
|
+
return () => cancelAnimationFrame(raf);
|
|
35
|
+
}, [visible]);
|
|
58
36
|
const finish = React.useCallback(() => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
setOverflow("visible");
|
|
62
|
-
} else if (unmountOnExit) {
|
|
63
|
-
setMounted(false);
|
|
64
|
-
}
|
|
37
|
+
setSettled(true);
|
|
38
|
+
if (!visible && unmountOnExit) setMounted(false);
|
|
65
39
|
}, [visible, unmountOnExit]);
|
|
66
|
-
const handleTransitionEnd = React.useCallback(
|
|
67
|
-
(e) => {
|
|
68
|
-
if (e.target !== e.currentTarget || e.propertyName !== "max-height") return;
|
|
69
|
-
finish();
|
|
70
|
-
},
|
|
71
|
-
[finish]
|
|
72
|
-
);
|
|
73
40
|
const firstRender = React.useRef(true);
|
|
74
41
|
React.useEffect(() => {
|
|
75
42
|
if (firstRender.current) {
|
|
@@ -80,20 +47,23 @@ const Collapse = React.forwardRef(function Collapse2({
|
|
|
80
47
|
return () => clearTimeout(t);
|
|
81
48
|
}, [visible, settleMs, finish]);
|
|
82
49
|
if (!mounted) return null;
|
|
83
|
-
const
|
|
50
|
+
const overflow = expanded && settled ? "visible" : "hidden";
|
|
84
51
|
return /* @__PURE__ */ jsx(
|
|
85
52
|
Tag,
|
|
86
53
|
{
|
|
87
54
|
ref,
|
|
88
55
|
style: {
|
|
89
|
-
|
|
56
|
+
display: "grid",
|
|
57
|
+
gridTemplateRows: expanded ? "1fr" : "0fr",
|
|
90
58
|
overflow,
|
|
91
|
-
transition:
|
|
59
|
+
transition: instant ? "none" : legacy ? `grid-template-rows var(--duration-${duration}) var(--ease-${easing})` : spring("grid-template-rows", "spatial", SPRING_SPEED[duration]),
|
|
92
60
|
...style
|
|
93
61
|
},
|
|
94
|
-
onTransitionEnd:
|
|
62
|
+
onTransitionEnd: (e) => {
|
|
63
|
+
if (e.target === e.currentTarget && e.propertyName === "grid-template-rows") finish();
|
|
64
|
+
},
|
|
95
65
|
...rest,
|
|
96
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
66
|
+
children: /* @__PURE__ */ jsx("div", { style: { minHeight: collapsedHeight, overflow }, children })
|
|
97
67
|
}
|
|
98
68
|
);
|
|
99
69
|
});
|
|
@@ -12,6 +12,8 @@ export interface MotionBaseProps {
|
|
|
12
12
|
/**
|
|
13
13
|
* Legacy: set it to use the old `--duration-*` + `--ease-{value}` tokens
|
|
14
14
|
* instead of springs. Omit it to ride the spring tokens.
|
|
15
|
+
* @deprecated since 7.3: the `--duration-*` / `--ease-*` tokens (tokens/motion.json) are
|
|
16
|
+
* retired in favour of the spring tokens. Removed in 8.0.
|
|
15
17
|
*/
|
|
16
18
|
easing?: MotionEasing;
|
|
17
19
|
/**
|
|
@@ -50,7 +50,7 @@ const Trigger = React.forwardRef(
|
|
|
50
50
|
ChevronDown,
|
|
51
51
|
{
|
|
52
52
|
size: "xs",
|
|
53
|
-
className: "relative ms-1 transition duration-
|
|
53
|
+
className: "relative ms-1 transition-transform duration-spatial-fast ease-spatial-fast group-data-[state=open]:rotate-180",
|
|
54
54
|
"aria-hidden": "true"
|
|
55
55
|
}
|
|
56
56
|
)
|
|
@@ -96,6 +96,8 @@ const Viewport = React.forwardRef(
|
|
|
96
96
|
"nx-motion nx-pop origin-top relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden",
|
|
97
97
|
floatingSurface,
|
|
98
98
|
"md:w-[var(--radix-navigation-menu-viewport-width)]",
|
|
99
|
+
// Resize between items on the spatial spring instead of snapping.
|
|
100
|
+
"transition-[width,height] duration-spatial-default ease-spatial-default motion-reduce:transition-none",
|
|
99
101
|
className
|
|
100
102
|
),
|
|
101
103
|
...props
|
|
@@ -20,7 +20,7 @@ const progressTrackVariants = cva(
|
|
|
20
20
|
}
|
|
21
21
|
);
|
|
22
22
|
const progressFillVariants = cva(
|
|
23
|
-
"h-full rounded-full transition-all duration-
|
|
23
|
+
"h-full rounded-full transition-all duration-spatial-default ease-spatial-default",
|
|
24
24
|
{
|
|
25
25
|
variants: {
|
|
26
26
|
tone: {
|
|
@@ -6,7 +6,7 @@ import { cn } from "../../utils/cn.js";
|
|
|
6
6
|
import { useMergedRefs } from "../../hooks/useMergedRefs.js";
|
|
7
7
|
import { useSlidingIndicator } from "../../hooks/useSlidingIndicator.js";
|
|
8
8
|
const Root = React.forwardRef(
|
|
9
|
-
({ className, ...props }, ref) => /* @__PURE__ */ jsx(RadixTabs.Root, { ref, className: cn("flex flex-col gap-3", className), ...props })
|
|
9
|
+
({ className, ...props }, ref) => /* @__PURE__ */ jsx(RadixTabs.Root, { ref, className: cn("flex flex-col gap-3 data-[orientation=vertical]:flex-row", className), ...props })
|
|
10
10
|
);
|
|
11
11
|
Root.displayName = "Tabs.Root";
|
|
12
12
|
const List = React.forwardRef(
|
|
@@ -18,8 +18,12 @@ const List = React.forwardRef(
|
|
|
18
18
|
{
|
|
19
19
|
ref: useMergedRefs(ref, forwardedRef),
|
|
20
20
|
className: cn(
|
|
21
|
-
"relative flex w-full items-stretch justify-start overflow-x-auto",
|
|
21
|
+
"group/tabs relative flex w-full items-stretch justify-start overflow-x-auto",
|
|
22
22
|
"border-b border-[var(--color-outline-variant)]",
|
|
23
|
+
// Vertical: a column with the rule on the inline-end side.
|
|
24
|
+
"data-[orientation=vertical]:w-auto data-[orientation=vertical]:shrink-0 data-[orientation=vertical]:flex-col",
|
|
25
|
+
"data-[orientation=vertical]:overflow-x-visible data-[orientation=vertical]:overflow-y-auto",
|
|
26
|
+
"data-[orientation=vertical]:border-b-0 data-[orientation=vertical]:border-e",
|
|
23
27
|
className
|
|
24
28
|
),
|
|
25
29
|
...props,
|
|
@@ -32,7 +36,10 @@ const List = React.forwardRef(
|
|
|
32
36
|
className: cn(
|
|
33
37
|
"pointer-events-none absolute bottom-0 left-0 h-[3px] rounded-t-full bg-[var(--color-primary)]",
|
|
34
38
|
"w-[var(--nx-ind-w,0px)] translate-x-[var(--nx-ind-x,0px)] opacity-[var(--nx-ind-o,0)]",
|
|
35
|
-
"
|
|
39
|
+
"group-data-[orientation=vertical]/tabs:top-0 group-data-[orientation=vertical]/tabs:bottom-auto group-data-[orientation=vertical]/tabs:left-auto group-data-[orientation=vertical]/tabs:end-0",
|
|
40
|
+
"group-data-[orientation=vertical]/tabs:h-[var(--nx-ind-h,0px)] group-data-[orientation=vertical]/tabs:w-[3px] group-data-[orientation=vertical]/tabs:rounded-none group-data-[orientation=vertical]/tabs:rounded-s-full",
|
|
41
|
+
"group-data-[orientation=vertical]/tabs:translate-x-0 group-data-[orientation=vertical]/tabs:translate-y-[var(--nx-ind-y,0px)]",
|
|
42
|
+
"[[data-nx-indicator=ready]>&]:transition-[transform,width,height] [[data-nx-indicator=ready]>&]:duration-spatial-default [[data-nx-indicator=ready]>&]:ease-spatial-default"
|
|
36
43
|
)
|
|
37
44
|
}
|
|
38
45
|
)
|
|
@@ -52,6 +59,7 @@ const Trigger = React.forwardRef(
|
|
|
52
59
|
"nx-state-layer relative inline-flex h-control-md items-center justify-center whitespace-nowrap rounded-t-[var(--shape-field)] px-4 text-label-lg select-none",
|
|
53
60
|
"text-[var(--color-on-surface-variant)] transition-colors duration-effects-fast ease-effects-fast",
|
|
54
61
|
"data-[state=active]:text-[var(--color-primary)]",
|
|
62
|
+
"group-data-[orientation=vertical]/tabs:justify-start group-data-[orientation=vertical]/tabs:rounded-none group-data-[orientation=vertical]/tabs:rounded-s-[var(--shape-field)]",
|
|
55
63
|
"disabled:pointer-events-none disabled:text-[var(--color-text-disabled)]",
|
|
56
64
|
className
|
|
57
65
|
),
|
|
@@ -66,6 +74,8 @@ const Content = React.forwardRef(
|
|
|
66
74
|
{
|
|
67
75
|
ref,
|
|
68
76
|
className: cn(
|
|
77
|
+
// Crossfade in on the effects spring (@starting-style, @nexub/themes/base).
|
|
78
|
+
"nx-tab-panel",
|
|
69
79
|
className,
|
|
70
80
|
// Radix hides inactive panels with the `hidden` attribute, which any
|
|
71
81
|
// display class (`flex`, `md:grid`…) overrides. !important always wins.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type * as React from 'react';
|
|
2
2
|
/**
|
|
3
3
|
* One indicator that slides to the active item (SegmentedControl thumb, Tabs
|
|
4
|
-
* underline). Writes --nx-ind-x / -w / -o (opacity) on the (position: relative) root;
|
|
4
|
+
* underline). Writes --nx-ind-x / -w / -y / -h / -o (opacity) on the (position: relative) root;
|
|
5
5
|
* CSS transitions do the motion. Sets data-nx-indicator="ready" one frame after
|
|
6
6
|
* the first measure so the indicator doesn't animate in on mount.
|
|
7
7
|
*/
|
|
@@ -10,6 +10,8 @@ function useSlidingIndicator(ref, activeSelector) {
|
|
|
10
10
|
if (!el) return;
|
|
11
11
|
root.style.setProperty("--nx-ind-x", `${el.offsetLeft}px`);
|
|
12
12
|
root.style.setProperty("--nx-ind-w", `${el.offsetWidth}px`);
|
|
13
|
+
root.style.setProperty("--nx-ind-y", `${el.offsetTop}px`);
|
|
14
|
+
root.style.setProperty("--nx-ind-h", `${el.offsetHeight}px`);
|
|
13
15
|
};
|
|
14
16
|
update();
|
|
15
17
|
const frame = requestAnimationFrame(() => root.dataset.nxIndicator = "ready");
|