@tangle-network/ui 11.51.10 → 11.51.11
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 +4 -0
- package/dist/primitives/hover-card.js +19 -9
- package/package.json +1 -1
- package/src/primitives/hover-card.tsx +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
## 11.51.11
|
|
2
|
+
|
|
3
|
+
- Keep tool-row actions and navigation reachable after a hover preview. HoverCard uses its anchor for placement, preserves keyboard inspection, and dismisses previews when a nested control commits an action. Touch actions do not become hover intent.
|
|
4
|
+
|
|
1
5
|
## 11.51.10
|
|
2
6
|
|
|
3
7
|
- Render Runtime’s recorded `down` outcome as Failed; cancellation and no-winner remain Stopped.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cn } from "../lib/utils.js";
|
|
2
|
-
import { Popover, PopoverAnchor, PopoverContent
|
|
2
|
+
import { Popover, PopoverAnchor, PopoverContent } from "./popover.js";
|
|
3
3
|
import { Slot } from "@radix-ui/react-slot";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -7,7 +7,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
7
7
|
const HoverIntent = React.createContext({
|
|
8
8
|
enter: (_target) => {},
|
|
9
9
|
leave: () => {},
|
|
10
|
-
restore: () => {}
|
|
10
|
+
restore: () => {},
|
|
11
|
+
press: () => {}
|
|
11
12
|
});
|
|
12
13
|
/** One hover policy and Popover's keyboard/focus behavior; delays follow the trigger's fast token. */
|
|
13
14
|
function HoverCard({ anchor, open: controlled, defaultOpen = false, onOpenChange, openDelay, closeDelay, children, ...props }) {
|
|
@@ -31,12 +32,12 @@ function HoverCard({ anchor, open: controlled, defaultOpen = false, onOpenChange
|
|
|
31
32
|
element
|
|
32
33
|
]);
|
|
33
34
|
const delay = (target) => {
|
|
34
|
-
if (typeof document === "undefined") return 0;
|
|
35
35
|
const value = getComputedStyle(target ?? document.documentElement).getPropertyValue("--duration-fast").trim();
|
|
36
36
|
return (parseFloat(value) || 0) * (value.endsWith("ms") ? 1 : 1e3);
|
|
37
37
|
};
|
|
38
38
|
const enter = React.useCallback((target) => {
|
|
39
|
-
if (intent.current.restoring) return;
|
|
39
|
+
if (intent.current.restoring || intent.current.pressed && target.closest("[data-hover-card]")) return;
|
|
40
|
+
intent.current.pressed = false;
|
|
40
41
|
if (!target.closest("[data-hover-card]")) intent.current.target = target;
|
|
41
42
|
clearTimeout(intent.current.timer);
|
|
42
43
|
intent.current.timer = setTimeout(() => change(true), openDelay ?? delay(target));
|
|
@@ -82,7 +83,11 @@ function HoverCard({ anchor, open: controlled, defaultOpen = false, onOpenChange
|
|
|
82
83
|
value: {
|
|
83
84
|
enter,
|
|
84
85
|
leave,
|
|
85
|
-
restore
|
|
86
|
+
restore,
|
|
87
|
+
press: () => {
|
|
88
|
+
intent.current.pressed = true;
|
|
89
|
+
change(false);
|
|
90
|
+
}
|
|
86
91
|
},
|
|
87
92
|
children: /* @__PURE__ */ jsxs(Popover, {
|
|
88
93
|
...props,
|
|
@@ -92,9 +97,9 @@ function HoverCard({ anchor, open: controlled, defaultOpen = false, onOpenChange
|
|
|
92
97
|
})
|
|
93
98
|
});
|
|
94
99
|
}
|
|
95
|
-
const HoverCardTrigger = React.forwardRef(({ className, onPointerEnter, onPointerLeave, onFocus, onBlur, asChild, ...props }, ref) => {
|
|
100
|
+
const HoverCardTrigger = React.forwardRef(({ className, onPointerEnter, onPointerLeave, onFocus, onBlur, onClickCapture, asChild, ...props }, ref) => {
|
|
96
101
|
const intent = React.useContext(HoverIntent);
|
|
97
|
-
return /* @__PURE__ */ jsx(
|
|
102
|
+
return /* @__PURE__ */ jsx(PopoverAnchor, {
|
|
98
103
|
asChild: true,
|
|
99
104
|
children: /* @__PURE__ */ jsx(asChild ? Slot : "a", {
|
|
100
105
|
ref,
|
|
@@ -102,7 +107,7 @@ const HoverCardTrigger = React.forwardRef(({ className, onPointerEnter, onPointe
|
|
|
102
107
|
className: cn("cursor-pointer underline-offset-4 hover:underline", className),
|
|
103
108
|
onPointerEnter: (event) => {
|
|
104
109
|
onPointerEnter?.(event);
|
|
105
|
-
if (!event.defaultPrevented) intent.enter(event.currentTarget);
|
|
110
|
+
if (!event.defaultPrevented && event.pointerType !== "touch") intent.enter(event.currentTarget);
|
|
106
111
|
},
|
|
107
112
|
onPointerLeave: (event) => {
|
|
108
113
|
onPointerLeave?.(event);
|
|
@@ -110,7 +115,12 @@ const HoverCardTrigger = React.forwardRef(({ className, onPointerEnter, onPointe
|
|
|
110
115
|
},
|
|
111
116
|
onFocus: (event) => {
|
|
112
117
|
onFocus?.(event);
|
|
113
|
-
if (!event.defaultPrevented) intent.enter(event.currentTarget);
|
|
118
|
+
if (!event.defaultPrevented && event.target.matches(":focus-visible")) intent.enter(event.currentTarget);
|
|
119
|
+
},
|
|
120
|
+
onClickCapture: (event) => {
|
|
121
|
+
onClickCapture?.(event);
|
|
122
|
+
const action = event.target instanceof Element ? event.target.closest("a,button,input,select,textarea,[role=\"button\"]") : null;
|
|
123
|
+
if (!event.defaultPrevented && action && action !== event.currentTarget) intent.press();
|
|
114
124
|
},
|
|
115
125
|
onBlur: (event) => {
|
|
116
126
|
onBlur?.(event);
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { cn } from "../lib/utils";
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { Slot } from "@radix-ui/react-slot";
|
|
4
|
-
import { Popover, PopoverAnchor, PopoverContent
|
|
4
|
+
import { Popover, PopoverAnchor, PopoverContent } from "./popover";
|
|
5
5
|
|
|
6
|
-
const HoverIntent = React.createContext({ enter: (_target: Element) => {}, leave: () => {}, restore: () => {} });
|
|
6
|
+
const HoverIntent = React.createContext({ enter: (_target: Element) => {}, leave: () => {}, restore: () => {}, press: () => {} });
|
|
7
7
|
type HoverCardProps = React.ComponentProps<typeof Popover> & {
|
|
8
8
|
/** Existing DOM trigger for delegated canvas or virtual-list previews. */
|
|
9
9
|
anchor?: HTMLElement | { getBoundingClientRect: () => DOMRect; contextElement: HTMLElement } | null;
|
|
@@ -15,15 +15,14 @@ type HoverCardProps = React.ComponentProps<typeof Popover> & {
|
|
|
15
15
|
export function HoverCard({ anchor, open: controlled, defaultOpen = false, onOpenChange, openDelay, closeDelay, children, ...props }: HoverCardProps) {
|
|
16
16
|
const element = anchor && ("contextElement" in anchor ? anchor.contextElement : anchor);
|
|
17
17
|
const [own, setOwn] = React.useState({ anchor: element, open: defaultOpen });
|
|
18
|
-
const intent = React.useRef<{ timer?: ReturnType<typeof setTimeout>; target?: Element; restoring?: boolean }>({});
|
|
18
|
+
const intent = React.useRef<{ timer?: ReturnType<typeof setTimeout>; target?: Element; restoring?: boolean; pressed?: boolean }>({});
|
|
19
19
|
if (element) intent.current.target = element;
|
|
20
20
|
const change = React.useCallback((next: boolean) => { clearTimeout(intent.current.timer); if (controlled === undefined) setOwn({ anchor: element, open: next }); onOpenChange?.(next); }, [controlled, onOpenChange, element]);
|
|
21
21
|
const delay = (target: Element | null | undefined) => {
|
|
22
|
-
if (typeof document === "undefined") return 0;
|
|
23
22
|
const value = getComputedStyle(target ?? document.documentElement).getPropertyValue("--duration-fast").trim();
|
|
24
23
|
return (parseFloat(value) || 0) * (value.endsWith("ms") ? 1 : 1000);
|
|
25
24
|
};
|
|
26
|
-
const enter = React.useCallback((target: Element) => { if (intent.current.restoring) return; if (!target.closest("[data-hover-card]")) intent.current.target = target; clearTimeout(intent.current.timer); intent.current.timer = setTimeout(() => change(true), openDelay ?? delay(target)); }, [change, openDelay]);
|
|
25
|
+
const enter = React.useCallback((target: Element) => { if (intent.current.restoring || (intent.current.pressed && target.closest("[data-hover-card]"))) return; intent.current.pressed = false; if (!target.closest("[data-hover-card]")) intent.current.target = target; clearTimeout(intent.current.timer); intent.current.timer = setTimeout(() => change(true), openDelay ?? delay(target)); }, [change, openDelay]);
|
|
27
26
|
const leave = React.useCallback(() => { clearTimeout(intent.current.timer); intent.current.timer = setTimeout(() => change(false), closeDelay ?? delay(element ?? intent.current.target)); }, [change, closeDelay, element]);
|
|
28
27
|
React.useEffect(() => {
|
|
29
28
|
if (!element) return () => clearTimeout(intent.current.timer);
|
|
@@ -36,20 +35,21 @@ export function HoverCard({ anchor, open: controlled, defaultOpen = false, onOpe
|
|
|
36
35
|
if (document.activeElement === document.body && intent.current.target instanceof HTMLElement) intent.current.target.focus({ preventScroll: true });
|
|
37
36
|
queueMicrotask(() => { intent.current.restoring = false; });
|
|
38
37
|
};
|
|
39
|
-
return <HoverIntent.Provider value={{ enter, leave, restore }}><Popover {...props} open={anchor === null ? false : controlled ?? (own.anchor === element && own.open)} onOpenChange={change}>
|
|
38
|
+
return <HoverIntent.Provider value={{ enter, leave, restore, press: () => { intent.current.pressed = true; change(false); } }}><Popover {...props} open={anchor === null ? false : controlled ?? (own.anchor === element && own.open)} onOpenChange={change}>
|
|
40
39
|
{anchor && <PopoverAnchor virtualRef={{ current: anchor }} />}{children}
|
|
41
40
|
</Popover></HoverIntent.Provider>;
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
export const HoverCardTrigger = React.forwardRef<HTMLAnchorElement, React.AnchorHTMLAttributes<HTMLAnchorElement> & { asChild?: boolean }>(
|
|
45
|
-
({ className, onPointerEnter, onPointerLeave, onFocus, onBlur, asChild, ...props }, ref) => {
|
|
44
|
+
({ className, onPointerEnter, onPointerLeave, onFocus, onBlur, onClickCapture, asChild, ...props }, ref) => {
|
|
46
45
|
const intent = React.useContext(HoverIntent);
|
|
47
46
|
const Trigger = asChild ? Slot : "a";
|
|
48
|
-
return <
|
|
49
|
-
onPointerEnter={event => { onPointerEnter?.(event); if (!event.defaultPrevented) intent.enter(event.currentTarget); }}
|
|
47
|
+
return <PopoverAnchor asChild><Trigger ref={ref} tabIndex={0} className={cn("cursor-pointer underline-offset-4 hover:underline", className)}
|
|
48
|
+
onPointerEnter={event => { onPointerEnter?.(event); if (!event.defaultPrevented && event.pointerType !== "touch") intent.enter(event.currentTarget); }}
|
|
50
49
|
onPointerLeave={event => { onPointerLeave?.(event); if (!event.defaultPrevented) intent.leave(); }}
|
|
51
|
-
onFocus={event => { onFocus?.(event); if (!event.defaultPrevented) intent.enter(event.currentTarget); }}
|
|
52
|
-
|
|
50
|
+
onFocus={event => { onFocus?.(event); if (!event.defaultPrevented && event.target.matches(":focus-visible")) intent.enter(event.currentTarget); }}
|
|
51
|
+
onClickCapture={event => { onClickCapture?.(event); const action = event.target instanceof Element ? event.target.closest('a,button,input,select,textarea,[role="button"]') : null; if (!event.defaultPrevented && action && action !== event.currentTarget) intent.press(); }}
|
|
52
|
+
onBlur={event => { onBlur?.(event); if (!event.defaultPrevented && !(event.relatedTarget instanceof Element && event.relatedTarget.closest("[data-hover-card]"))) intent.leave(); }} {...props} /></PopoverAnchor>;
|
|
53
53
|
},
|
|
54
54
|
);
|
|
55
55
|
HoverCardTrigger.displayName = "HoverCardTrigger";
|