@vuu-ui/vuu-ui-controls 4.0.0-beta.3 → 4.0.0-beta.5

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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.0.0-beta.3",
2
+ "version": "4.0.0-beta.5",
3
3
  "description": "VUU UI Controls",
4
4
  "main": "./src/index.js",
5
5
  "author": "heswell",
@@ -10,17 +10,17 @@
10
10
  "type-defs": "node ../../scripts/build-type-defs.mjs"
11
11
  },
12
12
  "devDependencies": {
13
- "@vuu-ui/vuu-data-types": "4.0.0-beta.3",
14
- "@vuu-ui/vuu-protocol-types": "4.0.0-beta.3",
15
- "@vuu-ui/vuu-table-types": "4.0.0-beta.3"
13
+ "@vuu-ui/vuu-data-types": "4.0.0-beta.5",
14
+ "@vuu-ui/vuu-protocol-types": "4.0.0-beta.5",
15
+ "@vuu-ui/vuu-table-types": "4.0.0-beta.5"
16
16
  },
17
17
  "dependencies": {
18
- "@vuu-ui/vuu-context-menu": "4.0.0-beta.3",
19
- "@vuu-ui/vuu-data-react": "4.0.0-beta.3",
20
- "@vuu-ui/vuu-layout": "4.0.0-beta.3",
21
- "@vuu-ui/vuu-popups": "4.0.0-beta.3",
22
- "@vuu-ui/vuu-table": "4.0.0-beta.3",
23
- "@vuu-ui/vuu-utils": "4.0.0-beta.3",
18
+ "@vuu-ui/vuu-context-menu": "4.0.0-beta.5",
19
+ "@vuu-ui/vuu-data-react": "4.0.0-beta.5",
20
+ "@vuu-ui/vuu-layout": "4.0.0-beta.5",
21
+ "@vuu-ui/vuu-popups": "4.0.0-beta.5",
22
+ "@vuu-ui/vuu-table": "4.0.0-beta.5",
23
+ "@vuu-ui/vuu-utils": "4.0.0-beta.5",
24
24
  "@salt-ds/core": "1.72.0",
25
25
  "@salt-ds/icons": "1.18.3",
26
26
  "@salt-ds/styles": "0.4.1",
@@ -0,0 +1,8 @@
1
+ const css = `
2
+ .vuuHoverOverlay-panel {
3
+ --saltOverlay-borderColor: var(--salt-container-primary-borderColor);
4
+ }
5
+
6
+
7
+ `;
8
+ export default css;
@@ -1,11 +1,38 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { Overlay, OverlayPanel, OverlayPanelContent, OverlayTrigger } from "@salt-ds/core";
3
+ import { useComponentCssInjection } from "@salt-ds/styles";
4
+ import { useWindow } from "@salt-ds/window";
5
+ import { containsPoint } from "@vuu-ui/vuu-utils";
3
6
  import { useCallback, useEffect, useRef, useState } from "react";
4
- const HoverOverlay = ({ children, open: openProp = false, onOpenChange, placement = "right", trigger })=>{
7
+ import HoverOverlay from "./HoverOverlay.css";
8
+ const classBase = "vuuHoverOverlay";
9
+ const OPEN_DELAY = 400;
10
+ const CLOSE_DELAY = 300;
11
+ const HoverOverlay_HoverOverlay = ({ children, open: openProp = false, onOpenChange, openOn = "hover", placement = "right", trigger })=>{
12
+ const targetWindow = useWindow();
13
+ useComponentCssInjection({
14
+ testId: "vuu-hover-overlay",
15
+ css: HoverOverlay,
16
+ window: targetWindow
17
+ });
5
18
  const [open, _setOpen] = useState(openProp);
6
19
  const isOpen = useRef(false);
7
20
  const showHandle = useRef(void 0);
8
21
  const hideHandle = useRef(void 0);
22
+ const triggerRef = useRef(null);
23
+ const panelRef = useRef(null);
24
+ const clearShowTimer = useCallback(()=>{
25
+ if (showHandle.current) {
26
+ clearTimeout(showHandle.current);
27
+ showHandle.current = void 0;
28
+ }
29
+ }, []);
30
+ const clearHideTimer = useCallback(()=>{
31
+ if (hideHandle.current) {
32
+ clearTimeout(hideHandle.current);
33
+ hideHandle.current = void 0;
34
+ }
35
+ }, []);
9
36
  const setOpen = useCallback((open)=>{
10
37
  if (open !== isOpen.current) {
11
38
  isOpen.current = open;
@@ -15,78 +42,100 @@ const HoverOverlay = ({ children, open: openProp = false, onOpenChange, placemen
15
42
  }, [
16
43
  onOpenChange
17
44
  ]);
45
+ const startHideTimer = useCallback(()=>{
46
+ if (void 0 === hideHandle.current) hideHandle.current = setTimeout(()=>{
47
+ hideHandle.current = void 0;
48
+ setOpen(false);
49
+ }, CLOSE_DELAY);
50
+ }, [
51
+ setOpen
52
+ ]);
18
53
  useEffect(()=>{
19
54
  if (openProp !== isOpen.current) setOpen(openProp);
20
55
  }, [
21
56
  openProp,
22
57
  setOpen
23
58
  ]);
24
- const handleOverlayMouseEnter = useCallback(()=>{
25
- if (hideHandle.current) {
26
- clearTimeout(hideHandle.current);
27
- hideHandle.current = void 0;
59
+ useEffect(()=>()=>{
60
+ clearShowTimer();
61
+ clearHideTimer();
62
+ }, [
63
+ clearHideTimer,
64
+ clearShowTimer
65
+ ]);
66
+ useEffect(()=>{
67
+ if (open && "hover" === openOn) {
68
+ const doc = triggerRef.current?.ownerDocument ?? document;
69
+ const handlePointerMove = ({ clientX, clientY })=>{
70
+ if (containsPoint(triggerRef.current, clientX, clientY) || containsPoint(panelRef.current, clientX, clientY)) clearHideTimer();
71
+ else startHideTimer();
72
+ };
73
+ doc.addEventListener("pointermove", handlePointerMove);
74
+ doc.documentElement.addEventListener("mouseleave", startHideTimer);
75
+ return ()=>{
76
+ doc.removeEventListener("pointermove", handlePointerMove);
77
+ doc.documentElement.removeEventListener("mouseleave", startHideTimer);
78
+ clearHideTimer();
79
+ };
28
80
  }
29
- }, []);
30
- const handleOverlayMouseLeave = useCallback(()=>{
31
- hideHandle.current = setTimeout(()=>{
32
- setOpen(false);
33
- hideHandle.current = void 0;
34
- }, 300);
35
81
  }, [
36
- setOpen
82
+ clearHideTimer,
83
+ open,
84
+ openOn,
85
+ startHideTimer
37
86
  ]);
38
87
  const handleMouseEnter = useCallback(()=>{
39
- showHandle.current = setTimeout(()=>{
40
- setOpen(true);
88
+ if (!isOpen.current && void 0 === showHandle.current) showHandle.current = setTimeout(()=>{
41
89
  showHandle.current = void 0;
42
- }, 400);
43
- if (hideHandle.current) {
44
- clearTimeout(hideHandle.current);
45
- hideHandle.current = void 0;
46
- }
90
+ setOpen(true);
91
+ }, OPEN_DELAY);
47
92
  }, [
48
93
  setOpen
49
94
  ]);
50
95
  const handleMouseLeave = useCallback(()=>{
51
- if (showHandle.current) {
52
- clearTimeout(showHandle.current);
53
- showHandle.current = void 0;
54
- } else if (isOpen.current) hideHandle.current = setTimeout(()=>{
55
- setOpen(false);
56
- hideHandle.current = void 0;
57
- }, 300);
96
+ clearShowTimer();
58
97
  }, [
59
- setOpen
98
+ clearShowTimer
60
99
  ]);
61
100
  const handleClick = useCallback(()=>{
62
- if (showHandle.current) {
63
- clearTimeout(showHandle.current);
64
- showHandle.current = void 0;
65
- } else if (isOpen.current) setOpen(false);
101
+ clearShowTimer();
102
+ }, [
103
+ clearShowTimer
104
+ ]);
105
+ const handleOpenChange = useCallback((open)=>{
106
+ clearShowTimer();
107
+ clearHideTimer();
108
+ setOpen(open);
66
109
  }, [
110
+ clearHideTimer,
111
+ clearShowTimer,
67
112
  setOpen
68
113
  ]);
114
+ const triggerProps = "hover" === openOn ? {
115
+ onClick: handleClick,
116
+ onMouseEnter: handleMouseEnter,
117
+ onMouseLeave: handleMouseLeave
118
+ } : void 0;
69
119
  return /*#__PURE__*/ jsxs(Overlay, {
70
120
  placement: placement,
71
- onOpenChange: onOpenChange,
121
+ onOpenChange: handleOpenChange,
72
122
  open: open,
73
123
  children: [
74
124
  /*#__PURE__*/ jsx(OverlayTrigger, {
75
125
  children: /*#__PURE__*/ jsx("div", {
76
- onClick: handleClick,
77
- onMouseEnter: handleMouseEnter,
78
- onMouseLeave: handleMouseLeave,
126
+ ...triggerProps,
127
+ ref: triggerRef,
79
128
  children: trigger
80
129
  })
81
130
  }),
82
131
  /*#__PURE__*/ jsx(OverlayPanel, {
132
+ className: `${classBase}-panel`,
133
+ ref: panelRef,
83
134
  children: /*#__PURE__*/ jsx(OverlayPanelContent, {
84
- onMouseEnter: handleOverlayMouseEnter,
85
- onMouseLeave: handleOverlayMouseLeave,
86
135
  children: children
87
136
  })
88
137
  })
89
138
  ]
90
139
  });
91
140
  };
92
- export { HoverOverlay };
141
+ export { HoverOverlay_HoverOverlay as HoverOverlay };
@@ -3,6 +3,12 @@ import { ReactNode } from "react";
3
3
  export interface HoverOverlayProps extends Pick<OverlayProps, "placement" | "onOpenChange"> {
4
4
  children: ReactNode;
5
5
  open?: boolean;
6
+ /**
7
+ * hover (default) opens the overlay after a short delay when pointer
8
+ * enters trigger and closes it when pointer leaves both trigger and
9
+ * overlay. click leaves open/close entirely to Salt Overlay.
10
+ */
11
+ openOn?: "hover" | "click";
6
12
  trigger: ReactNode;
7
13
  }
8
- export declare const HoverOverlay: ({ children, open: openProp, onOpenChange, placement, trigger, }: HoverOverlayProps) => import("react/jsx-runtime").JSX.Element;
14
+ export declare const HoverOverlay: ({ children, open: openProp, onOpenChange, openOn, placement, trigger, }: HoverOverlayProps) => import("react/jsx-runtime").JSX.Element;
package/types/index.d.ts CHANGED
@@ -9,7 +9,7 @@ export * from "./drag-drop";
9
9
  export * from "./editable";
10
10
  export * from "./editable-label";
11
11
  export * from "./expando-input";
12
- export { HoverOverlay } from "./hover-overlay/HoverOverlay";
12
+ export { HoverOverlay, type HoverOverlayProps, } from "./hover-overlay/HoverOverlay";
13
13
  export * from "./icon-button";
14
14
  export * from "./instrument-picker";
15
15
  export { ItemPicker, type ItemPickerProps } from "./item-picker/ItemPicker";