@smwb/ui-react 2.3.0 → 2.4.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.
@@ -7,7 +7,7 @@ export type MenuSubmenuProps = Pick<MenuFloatingProps, "placement" | "onClose">
7
7
  /** Open the submenu on pointer hover in addition to click. */
8
8
  openOnHover?: boolean;
9
9
  };
10
- export declare const MenuSubmenu: React.ForwardRefExoticComponent<Pick<MenuFloatingProps, "onClose" | "placement"> & React.HTMLAttributes<HTMLDivElement> & {
10
+ export declare const MenuSubmenu: React.ForwardRefExoticComponent<Pick<MenuFloatingProps, "placement" | "onClose"> & React.HTMLAttributes<HTMLDivElement> & {
11
11
  toggleElement?: React.ReactElement;
12
12
  /** Items and/or nested `MenuSubmenu` elements (multi-level supported). */
13
13
  children: React.ReactNode;
@@ -0,0 +1,117 @@
1
+ import { useState as k, useRef as m, useMemo as _, useCallback as e, useEffect as S } from "react";
2
+ import { offset as z, flip as B, shift as G, useFloating as V, autoUpdate as j } from "@floating-ui/react";
3
+ import { resolvePlacement as q } from "../utils/floating.js";
4
+ const J = "bottom-start", K = 4, Q = 8, W = ({ x: l, y: r }) => ({
5
+ x: l,
6
+ y: r,
7
+ top: r,
8
+ left: l,
9
+ right: l,
10
+ bottom: r,
11
+ width: 0,
12
+ height: 0
13
+ });
14
+ function H(l = {}) {
15
+ const {
16
+ placement: r = J,
17
+ offsetPx: T = K,
18
+ openDelay: M = 0,
19
+ closeDelay: R = 0,
20
+ middleware: a
21
+ } = l, [p, c] = k(!1), A = m({ x: 0, y: 0 }), F = m({ x: 0, y: 0 }), h = m(null), P = m(null), s = m(null), E = q(r), X = _(
22
+ () => [
23
+ z({ mainAxis: T, crossAxis: T }),
24
+ ...E.autoMiddleware ? [E.autoMiddleware] : [B()],
25
+ G({ padding: Q }),
26
+ ...a != null ? a : []
27
+ ],
28
+ [T, E.autoMiddleware, a]
29
+ ), { refs: g, floatingStyles: w, update: y } = V({
30
+ open: p,
31
+ placement: E.placement,
32
+ whileElementsMounted: j,
33
+ middleware: X
34
+ }), x = _(
35
+ () => ({ getBoundingClientRect: () => W(F.current) }),
36
+ []
37
+ ), o = e(() => {
38
+ P.current !== null && (clearTimeout(P.current), P.current = null), s.current !== null && (clearTimeout(s.current), s.current = null);
39
+ }, []);
40
+ S(() => () => o(), [o]), S(() => {
41
+ var t;
42
+ p && (g.setPositionReference((t = h.current) != null ? t : x), y());
43
+ }, [p, g, y, x]);
44
+ const f = e(() => {
45
+ h.current === null && (F.current = A.current);
46
+ }, []), b = e(() => {
47
+ o(), f(), c(!0);
48
+ }, [o, f]), v = e(() => {
49
+ if (o(), M <= 0) {
50
+ f(), c(!0);
51
+ return;
52
+ }
53
+ P.current = setTimeout(() => {
54
+ f(), c(!0);
55
+ }, M);
56
+ }, [o, f, M]), u = e(() => {
57
+ if (o(), R <= 0) {
58
+ c(!1);
59
+ return;
60
+ }
61
+ s.current = setTimeout(() => c(!1), R);
62
+ }, [o, R]), N = e(() => {
63
+ o(), c(!1);
64
+ }, [o]), O = e((t) => {
65
+ h.current = null, F.current = t;
66
+ }, []), U = e((t) => {
67
+ h.current = t;
68
+ }, []), D = e(
69
+ (t) => {
70
+ A.current = { x: t.clientX, y: t.clientY }, v();
71
+ },
72
+ [v]
73
+ ), L = e((t) => {
74
+ A.current = { x: t.clientX, y: t.clientY };
75
+ }, []), I = e(
76
+ (t) => ({
77
+ onPointerEnter: (i) => {
78
+ var n;
79
+ (n = t == null ? void 0 : t.onPointerEnter) == null || n.call(t, i), D(i);
80
+ },
81
+ onPointerMove: (i) => {
82
+ var n;
83
+ (n = t == null ? void 0 : t.onPointerMove) == null || n.call(t, i), L(i);
84
+ },
85
+ onPointerLeave: (i) => {
86
+ var n;
87
+ (n = t == null ? void 0 : t.onPointerLeave) == null || n.call(t, i), u();
88
+ }
89
+ }),
90
+ [D, L, u]
91
+ ), C = e(() => {
92
+ o(), c(!0);
93
+ }, [o]), Y = e(
94
+ (t) => ({
95
+ ref: g.setFloating,
96
+ style: { ...w, ...t == null ? void 0 : t.style },
97
+ onPointerEnter: C,
98
+ onPointerLeave: u
99
+ }),
100
+ [g, w, C, u]
101
+ );
102
+ return {
103
+ open: p,
104
+ getReferenceProps: I,
105
+ getFloatingProps: Y,
106
+ setAnchorEl: U,
107
+ setVirtualAnchor: O,
108
+ openNow: b,
109
+ scheduleOpen: v,
110
+ scheduleClose: u,
111
+ close: N
112
+ };
113
+ }
114
+ export {
115
+ H as useHoverPopover
116
+ };
117
+ //# sourceMappingURL=useHoverPopover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useHoverPopover.js","sources":["../../../src/hooks/useHoverPopover.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { CSSProperties, PointerEvent as ReactPointerEvent } from \"react\";\nimport { autoUpdate, flip, offset, shift, useFloating } from \"@floating-ui/react\";\nimport type { Middleware, VirtualElement } from \"@floating-ui/react\";\nimport { resolvePlacement } from \"../utils/floating\";\nimport type { Placement } from \"../utils/floating\";\n\nexport interface UseHoverPopoverParams {\n /** Placement of the popover relative to its anchor. Default `\"bottom-start\"`. */\n placement?: Placement;\n /** Offset (px) applied on both axes between the anchor and the popover. Default `4`. */\n offsetPx?: number;\n /** Delay (ms) before opening after pointer enter. Default `0`. */\n openDelay?: number;\n /** Delay (ms) before closing after pointer leave. Default `0`. */\n closeDelay?: number;\n /** Extra floating-ui middleware appended after the smwb defaults. */\n middleware?: Middleware[];\n}\n\n/** A pointer position in viewport (client) coordinates. */\nexport interface HoverPopoverPoint {\n x: number;\n y: number;\n}\n\nexport interface HoverPopoverReferenceProps {\n onPointerEnter: (event: ReactPointerEvent) => void;\n onPointerMove: (event: ReactPointerEvent) => void;\n onPointerLeave: (event: ReactPointerEvent) => void;\n}\n\nexport interface HoverPopoverFloatingProps {\n ref: (node: HTMLElement | null) => void;\n style: CSSProperties;\n onPointerEnter: () => void;\n onPointerLeave: () => void;\n}\n\nexport interface UseHoverPopoverResult {\n /** Whether the popover is currently open. */\n open: boolean;\n /**\n * Pointer handlers for the trigger element(s). Spread on a single anchor, or\n * on EVERY row of a list/table to share one popover across many triggers. By\n * default the popover is anchored to the cursor position frozen when it opens.\n * Pass your own handlers to compose them (e.g. to mark which row is active).\n */\n getReferenceProps: (userHandlers?: Partial<HoverPopoverReferenceProps>) => HoverPopoverReferenceProps;\n /** Props for the single floating element; keeps it open while it is hovered. */\n getFloatingProps: (userProps?: { style?: CSSProperties }) => HoverPopoverFloatingProps;\n /** Anchor the popover to a real element instead of the cursor (`null` clears it). */\n setAnchorEl: (element: Element | null) => void;\n /** Anchor the popover to an explicit point, e.g. an external cursor source. */\n setVirtualAnchor: (point: HoverPopoverPoint) => void;\n /** Open immediately, ignoring `openDelay`. */\n openNow: () => void;\n /** Open after `openDelay`. */\n scheduleOpen: () => void;\n /** Close after `closeDelay`. */\n scheduleClose: () => void;\n /** Close immediately. */\n close: () => void;\n}\n\nconst DEFAULT_PLACEMENT: Placement = \"bottom-start\";\nconst DEFAULT_OFFSET_PX = 4;\nconst SHIFT_PADDING_PX = 8;\n\nconst rectFromPoint = ({ x, y }: HoverPopoverPoint) => ({\n x,\n y,\n top: y,\n left: x,\n right: x,\n bottom: y,\n width: 0,\n height: 0,\n});\n\n/**\n * Headless hover-popover positioning.\n *\n * Wraps floating-ui with the smwb placement / offset / flip / shift conventions\n * but imposes NO DOM structure: spread `getReferenceProps()` on any trigger\n * (including a `<tr>`, which the wrapper-based `<Tooltip>` cannot do) and\n * `getFloatingProps()` on a single floating element you render yourself.\n *\n * The default anchor is the cursor point frozen when the popover opens (a\n * floating-ui virtual element), so ONE instance can serve a whole table/list —\n * call `getReferenceProps()` on every row and render one shared popover instead\n * of mounting one floating engine per row. Use `setAnchorEl` to anchor to a\n * real element instead.\n */\nexport function useHoverPopover(params: UseHoverPopoverParams = {}): UseHoverPopoverResult {\n const {\n placement = DEFAULT_PLACEMENT,\n offsetPx = DEFAULT_OFFSET_PX,\n openDelay = 0,\n closeDelay = 0,\n middleware,\n } = params;\n\n const [open, setOpen] = useState(false);\n\n const cursorRef = useRef<HoverPopoverPoint>({ x: 0, y: 0 });\n const anchorRef = useRef<HoverPopoverPoint>({ x: 0, y: 0 });\n const anchorElRef = useRef<Element | null>(null);\n const openTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const resolved = resolvePlacement(placement);\n\n const floatingMiddleware = useMemo<Middleware[]>(\n () => [\n offset({ mainAxis: offsetPx, crossAxis: offsetPx }),\n ...(resolved.autoMiddleware ? [resolved.autoMiddleware] : [flip()]),\n shift({ padding: SHIFT_PADDING_PX }),\n ...(middleware ?? []),\n ],\n [offsetPx, resolved.autoMiddleware, middleware]\n );\n\n const { refs, floatingStyles, update } = useFloating({\n open,\n placement: resolved.placement,\n whileElementsMounted: autoUpdate,\n middleware: floatingMiddleware,\n });\n\n const virtualReference = useMemo<VirtualElement>(\n () => ({ getBoundingClientRect: () => rectFromPoint(anchorRef.current) }),\n []\n );\n\n const clearTimers = useCallback(() => {\n if (openTimerRef.current !== null) {\n clearTimeout(openTimerRef.current);\n openTimerRef.current = null;\n }\n if (closeTimerRef.current !== null) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n }, []);\n\n useEffect(() => () => clearTimers(), [clearTimers]);\n\n // Apply the active anchor (element or frozen cursor) whenever the popover\n // opens; autoUpdate keeps it positioned while the floating element is mounted.\n useEffect(() => {\n if (!open) return;\n refs.setPositionReference(anchorElRef.current ?? virtualReference);\n void update();\n }, [open, refs, update, virtualReference]);\n\n const freezeAnchor = useCallback(() => {\n if (anchorElRef.current === null) anchorRef.current = cursorRef.current;\n }, []);\n\n const openNow = useCallback(() => {\n clearTimers();\n freezeAnchor();\n setOpen(true);\n }, [clearTimers, freezeAnchor]);\n\n const scheduleOpen = useCallback(() => {\n clearTimers();\n if (openDelay <= 0) {\n freezeAnchor();\n setOpen(true);\n return;\n }\n openTimerRef.current = setTimeout(() => {\n freezeAnchor();\n setOpen(true);\n }, openDelay);\n }, [clearTimers, freezeAnchor, openDelay]);\n\n const scheduleClose = useCallback(() => {\n clearTimers();\n if (closeDelay <= 0) {\n setOpen(false);\n return;\n }\n closeTimerRef.current = setTimeout(() => setOpen(false), closeDelay);\n }, [clearTimers, closeDelay]);\n\n const close = useCallback(() => {\n clearTimers();\n setOpen(false);\n }, [clearTimers]);\n\n const setVirtualAnchor = useCallback((point: HoverPopoverPoint) => {\n anchorElRef.current = null;\n anchorRef.current = point;\n }, []);\n\n const setAnchorEl = useCallback((element: Element | null) => {\n anchorElRef.current = element;\n }, []);\n\n const handleEnter = useCallback(\n (event: ReactPointerEvent) => {\n cursorRef.current = { x: event.clientX, y: event.clientY };\n scheduleOpen();\n },\n [scheduleOpen]\n );\n\n const handleMove = useCallback((event: ReactPointerEvent) => {\n cursorRef.current = { x: event.clientX, y: event.clientY };\n }, []);\n\n const getReferenceProps = useCallback<UseHoverPopoverResult[\"getReferenceProps\"]>(\n (userHandlers) => ({\n onPointerEnter: (event) => {\n userHandlers?.onPointerEnter?.(event);\n handleEnter(event);\n },\n onPointerMove: (event) => {\n userHandlers?.onPointerMove?.(event);\n handleMove(event);\n },\n onPointerLeave: (event) => {\n userHandlers?.onPointerLeave?.(event);\n scheduleClose();\n },\n }),\n [handleEnter, handleMove, scheduleClose]\n );\n\n const cancelClose = useCallback(() => {\n clearTimers();\n setOpen(true);\n }, [clearTimers]);\n\n const getFloatingProps = useCallback<UseHoverPopoverResult[\"getFloatingProps\"]>(\n (userProps) => ({\n ref: refs.setFloating,\n style: { ...floatingStyles, ...userProps?.style },\n onPointerEnter: cancelClose,\n onPointerLeave: scheduleClose,\n }),\n [refs, floatingStyles, cancelClose, scheduleClose]\n );\n\n return {\n open,\n getReferenceProps,\n getFloatingProps,\n setAnchorEl,\n setVirtualAnchor,\n openNow,\n scheduleOpen,\n scheduleClose,\n close,\n };\n}\n"],"names":["DEFAULT_PLACEMENT","DEFAULT_OFFSET_PX","SHIFT_PADDING_PX","rectFromPoint","x","y","useHoverPopover","params","placement","offsetPx","openDelay","closeDelay","middleware","open","setOpen","useState","cursorRef","useRef","anchorRef","anchorElRef","openTimerRef","closeTimerRef","resolved","resolvePlacement","floatingMiddleware","useMemo","offset","flip","shift","refs","floatingStyles","update","useFloating","autoUpdate","virtualReference","clearTimers","useCallback","useEffect","_a","freezeAnchor","openNow","scheduleOpen","scheduleClose","close","setVirtualAnchor","point","setAnchorEl","element","handleEnter","event","handleMove","getReferenceProps","userHandlers","cancelClose","getFloatingProps","userProps"],"mappings":"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"}