@tangle-network/ui 11.38.0 → 11.38.2
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/CHANGELOG.md +12 -0
- package/dist/lib/surface-motion.js +11 -2
- package/dist/primitives/tooltip.d.ts +4 -1
- package/dist/primitives/tooltip.js +12 -1
- package/package.json +1 -1
- package/src/lib/surface-motion.tsx +15 -3
- package/src/primitives/tooltip.tsx +15 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @tangle-network/ui
|
|
2
2
|
|
|
3
|
+
## 11.38.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- b33914e: Keep accepted Tooltip reopens open while exit content is retained. Preserve controlled/defaultOpen APIs, native disabled-trigger descriptions and sibling-tooltip dismissal through the shared Root owner.
|
|
8
|
+
|
|
9
|
+
## 11.38.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- c049dc4: Bound shared surface dismissal by its scoped role deadline so missing CSS animation events cannot strand Radix cleanup or focus return. Preserve retained motion values on reopen.
|
|
14
|
+
|
|
3
15
|
## 11.38.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
|
@@ -4,9 +4,10 @@ import * as React from "react";
|
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
import { animate, motionValue, styleEffect } from "motion";
|
|
6
6
|
//#region src/lib/surface-motion.tsx
|
|
7
|
-
/** Radix owns state
|
|
7
|
+
/** Radix owns state and focus; visual retirement cannot wait for a CSS event. */
|
|
8
8
|
const SurfaceMotion = React.forwardRef(({ kind, side = "right", asChild, "data-state": state, ...props }, forwardedRef) => {
|
|
9
9
|
const element = React.useRef(null);
|
|
10
|
+
const [retired, setRetired] = React.useState(false);
|
|
10
11
|
const values = React.useRef(null);
|
|
11
12
|
const controls = React.useRef([]);
|
|
12
13
|
const ref = React.useCallback((node) => {
|
|
@@ -24,7 +25,10 @@ const SurfaceMotion = React.forwardRef(({ kind, side = "right", asChild, "data-s
|
|
|
24
25
|
if (!node) return;
|
|
25
26
|
const preference = typeof matchMedia === "function" ? matchMedia("(prefers-reduced-motion: reduce)") : void 0;
|
|
26
27
|
let cancelRender;
|
|
28
|
+
let retirement;
|
|
27
29
|
const run = () => {
|
|
30
|
+
clearTimeout(retirement);
|
|
31
|
+
setRetired(false);
|
|
28
32
|
const closed = state === "closed";
|
|
29
33
|
const bounds = node.getBoundingClientRect();
|
|
30
34
|
const hidden = {
|
|
@@ -46,6 +50,10 @@ const SurfaceMotion = React.forwardRef(({ kind, side = "right", asChild, "data-s
|
|
|
46
50
|
node.style.opacity = String(value.opacity);
|
|
47
51
|
node.style.transform = `translateX(${value.x}px) translateY(${value.y}px) scale(${value.scale})`;
|
|
48
52
|
};
|
|
53
|
+
if (closed) {
|
|
54
|
+
if (preference?.matches || seconds <= 0 || style.animationName === "none") setRetired(true);
|
|
55
|
+
else retirement = setTimeout(() => setRetired(true), seconds * 1e3);
|
|
56
|
+
}
|
|
49
57
|
if (preference?.matches || seconds <= 0 || style.animationName === "none") {
|
|
50
58
|
controls.current.forEach((control) => control.stop());
|
|
51
59
|
if (values.current) for (const key of [
|
|
@@ -84,6 +92,7 @@ const SurfaceMotion = React.forwardRef(({ kind, side = "right", asChild, "data-s
|
|
|
84
92
|
run();
|
|
85
93
|
preference?.addEventListener("change", run);
|
|
86
94
|
return () => {
|
|
95
|
+
clearTimeout(retirement);
|
|
87
96
|
preference?.removeEventListener("change", run);
|
|
88
97
|
cancelRender?.();
|
|
89
98
|
};
|
|
@@ -94,7 +103,7 @@ const SurfaceMotion = React.forwardRef(({ kind, side = "right", asChild, "data-s
|
|
|
94
103
|
props.style?.animation
|
|
95
104
|
]);
|
|
96
105
|
React.useEffect(() => () => controls.current.forEach((control) => control.stop()), []);
|
|
97
|
-
return /* @__PURE__ */ jsx(asChild ? Slot : "div", {
|
|
106
|
+
return state === "closed" && retired ? null : /* @__PURE__ */ jsx(asChild ? Slot : "div", {
|
|
98
107
|
...props,
|
|
99
108
|
"data-state": state,
|
|
100
109
|
ref
|
|
@@ -5,7 +5,10 @@ declare function TooltipProvider({ delayDuration, skipDelayDuration, ...props }:
|
|
|
5
5
|
declare namespace TooltipProvider {
|
|
6
6
|
var displayName: string;
|
|
7
7
|
}
|
|
8
|
-
declare
|
|
8
|
+
declare function Tooltip({ open, defaultOpen, onOpenChange, ...props }: React.ComponentProps<typeof TooltipPrimitive.Root>): React.JSX.Element;
|
|
9
|
+
declare namespace Tooltip {
|
|
10
|
+
var displayName: string;
|
|
11
|
+
}
|
|
9
12
|
declare const TooltipTrigger: React.ForwardRefExoticComponent<TooltipPrimitive.TooltipTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
10
13
|
/**
|
|
11
14
|
* Inverse-surface label for a control whose name is otherwise only an icon.
|
|
@@ -17,7 +17,18 @@ const TooltipProvider = ({ delayDuration = 400, skipDelayDuration = 300, ...prop
|
|
|
17
17
|
...props
|
|
18
18
|
});
|
|
19
19
|
TooltipProvider.displayName = "TooltipProvider";
|
|
20
|
-
const Tooltip =
|
|
20
|
+
const Tooltip = ({ open, defaultOpen = false, onOpenChange, ...props }) => {
|
|
21
|
+
const [localOpen, setLocalOpen] = React.useState(defaultOpen);
|
|
22
|
+
return /* @__PURE__ */ jsx(TooltipPrimitive.Root, {
|
|
23
|
+
...props,
|
|
24
|
+
open: open ?? localOpen,
|
|
25
|
+
onOpenChange: (next) => {
|
|
26
|
+
if (open === void 0) setLocalOpen(next);
|
|
27
|
+
onOpenChange?.(next);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
Tooltip.displayName = "Tooltip";
|
|
21
32
|
const TooltipTrigger = TooltipPrimitive.Trigger;
|
|
22
33
|
/**
|
|
23
34
|
* Inverse-surface label for a control whose name is otherwise only an icon.
|
package/package.json
CHANGED
|
@@ -12,10 +12,11 @@ type SurfaceProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
|
12
12
|
"data-state"?: string;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
/** Radix owns state
|
|
15
|
+
/** Radix owns state and focus; visual retirement cannot wait for a CSS event. */
|
|
16
16
|
export const SurfaceMotion = React.forwardRef<HTMLDivElement, SurfaceProps>(
|
|
17
17
|
({ kind, side = "right", asChild, "data-state": state, ...props }, forwardedRef) => {
|
|
18
18
|
const element = React.useRef<HTMLDivElement | null>(null);
|
|
19
|
+
const [retired, setRetired] = React.useState(false);
|
|
19
20
|
const values = React.useRef<Record<"opacity" | "scale" | "x" | "y", MotionValue<number>> | null>(null);
|
|
20
21
|
const controls = React.useRef<Array<ReturnType<typeof animate>>>([]);
|
|
21
22
|
const ref = React.useCallback<React.RefCallback<HTMLDivElement>>((node) => {
|
|
@@ -31,7 +32,10 @@ export const SurfaceMotion = React.forwardRef<HTMLDivElement, SurfaceProps>(
|
|
|
31
32
|
if (!node) return;
|
|
32
33
|
const preference = typeof matchMedia === "function" ? matchMedia("(prefers-reduced-motion: reduce)") : undefined;
|
|
33
34
|
let cancelRender: (() => void) | undefined;
|
|
35
|
+
let retirement: ReturnType<typeof setTimeout> | undefined;
|
|
34
36
|
const run = () => {
|
|
37
|
+
clearTimeout(retirement);
|
|
38
|
+
setRetired(false);
|
|
35
39
|
const closed = state === "closed";
|
|
36
40
|
const bounds = node.getBoundingClientRect();
|
|
37
41
|
const hidden = {
|
|
@@ -49,6 +53,14 @@ export const SurfaceMotion = React.forwardRef<HTMLDivElement, SurfaceProps>(
|
|
|
49
53
|
node.style.opacity = String(value.opacity);
|
|
50
54
|
node.style.transform = `translateX(${value.x}px) translateY(${value.y}px) scale(${value.scale})`;
|
|
51
55
|
};
|
|
56
|
+
// Radix may retain an exit until animationend. Retire this DOM node at
|
|
57
|
+
// the scoped deadline even when keyframes/events are missing or paused;
|
|
58
|
+
// its null ref lets Radix release presence, focus and modal resources.
|
|
59
|
+
// Reopen cancels retirement and keeps the same node and Motion values.
|
|
60
|
+
if (closed) {
|
|
61
|
+
if (preference?.matches || seconds <= 0 || style.animationName === "none") setRetired(true);
|
|
62
|
+
else retirement = setTimeout(() => setRetired(true), seconds * 1000);
|
|
63
|
+
}
|
|
52
64
|
// Missing styles and reduced motion settle synchronously. No semantic
|
|
53
65
|
// transition waits for a JavaScript completion callback.
|
|
54
66
|
if (preference?.matches || seconds <= 0 || style.animationName === "none") {
|
|
@@ -73,13 +85,13 @@ export const SurfaceMotion = React.forwardRef<HTMLDivElement, SurfaceProps>(
|
|
|
73
85
|
};
|
|
74
86
|
run();
|
|
75
87
|
preference?.addEventListener("change", run);
|
|
76
|
-
return () => { preference?.removeEventListener("change", run); cancelRender?.(); };
|
|
88
|
+
return () => { clearTimeout(retirement); preference?.removeEventListener("change", run); cancelRender?.(); };
|
|
77
89
|
// Radix Popper temporarily suppresses animation until placement resolves.
|
|
78
90
|
// Start the same retained values when that inline override clears.
|
|
79
91
|
}, [state, kind, side, props.style?.animation]);
|
|
80
92
|
React.useEffect(() => () => controls.current.forEach(control => control.stop()), []);
|
|
81
93
|
const Component = asChild ? Slot : "div";
|
|
82
|
-
return <Component {...props} data-state={state} ref={ref} />;
|
|
94
|
+
return state === "closed" && retired ? null : <Component {...props} data-state={state} ref={ref} />;
|
|
83
95
|
},
|
|
84
96
|
);
|
|
85
97
|
SurfaceMotion.displayName = "SurfaceMotion";
|
|
@@ -24,7 +24,21 @@ const TooltipProvider = ({
|
|
|
24
24
|
);
|
|
25
25
|
TooltipProvider.displayName = "TooltipProvider";
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
// Keep Radix on its controlled path even for the public uncontrolled API.
|
|
28
|
+
// Its global tooltip.open event then runs before the new open state commits:
|
|
29
|
+
// a retained content listener cannot turn its own accepted reopen into Close.
|
|
30
|
+
const Tooltip = ({ open, defaultOpen = false, onOpenChange, ...props }: React.ComponentProps<typeof TooltipPrimitive.Root>) => {
|
|
31
|
+
const [localOpen, setLocalOpen] = React.useState(defaultOpen);
|
|
32
|
+
return <TooltipPrimitive.Root
|
|
33
|
+
{...props}
|
|
34
|
+
open={open ?? localOpen}
|
|
35
|
+
onOpenChange={(next) => {
|
|
36
|
+
if (open === undefined) setLocalOpen(next);
|
|
37
|
+
onOpenChange?.(next);
|
|
38
|
+
}}
|
|
39
|
+
/>;
|
|
40
|
+
};
|
|
41
|
+
Tooltip.displayName = "Tooltip";
|
|
28
42
|
|
|
29
43
|
const TooltipTrigger = TooltipPrimitive.Trigger;
|
|
30
44
|
|