@conveyorhq/arrow-ds 1.165.0 → 1.166.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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@conveyorhq/arrow-ds",
3
3
  "author": "Conveyor",
4
4
  "license": "MIT",
5
- "version": "1.165.0",
5
+ "version": "1.166.0",
6
6
  "description": "Arrow Design System",
7
7
  "repository": "https://github.com/conveyor/arrow-ds",
8
8
  "publishConfig": {
@@ -1,10 +1,20 @@
1
- import React from "react";
1
+ import React, { ReactElement } from "react";
2
2
  import { PopoverTooltipSharedProps } from "../Popover";
3
3
  export interface TooltipProps extends PopoverTooltipSharedProps {
4
- delay?: number;
4
+ delay?: number | {
5
+ show?: number;
6
+ hide?: number;
7
+ };
5
8
  theme?: "light" | "dark";
6
9
  hideArrow?: boolean;
7
10
  open?: boolean;
8
11
  setOpen?(open: boolean): void;
9
12
  }
13
+ type ReferenceRenderFunction = (props: {
14
+ isOpen: boolean;
15
+ }) => ReactElement;
16
+ export declare const TooltipReference: React.ForwardRefExoticComponent<{
17
+ children: ReferenceRenderFunction | ReactElement;
18
+ } & React.RefAttributes<HTMLDivElement>>;
10
19
  export declare const Tooltip: (props: TooltipProps) => React.JSX.Element;
20
+ export {};
@@ -26,17 +26,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.Tooltip = void 0;
29
+ exports.Tooltip = exports.TooltipReference = void 0;
30
30
  const react_1 = __importStar(require("react"));
31
31
  const classnames_1 = __importDefault(require("classnames"));
32
32
  const bem_1 = require("../../utilities/bem");
33
33
  const hooks_1 = require("../../hooks");
34
+ const Box_1 = require("../Box");
34
35
  const Popover_1 = require("../Popover");
35
36
  const types_1 = require("../../types");
36
37
  const context_1 = require("./context");
38
+ const DEFAULT_DELAY = 200;
37
39
  const cn = "Tooltip";
40
+ exports.TooltipReference = react_1.default.forwardRef(({ children, ...props }, ref) => {
41
+ const { isOpen } = (0, context_1.useTooltipContext)();
42
+ return (react_1.default.createElement(Box_1.Box, { ref: ref, ...props }, typeof children === "function" ? children({ isOpen }) : children));
43
+ });
38
44
  const Tooltip = (props) => {
39
- const { isVisible: isVisibleInitial = false, open: isOpenControlled, setOpen: setOpenControlled, children, referenceElement, placement = "bottom", className, delay = 200, theme = "dark", hideArrow, style, ...rest } = props;
45
+ const { isVisible: isVisibleInitial = false, open: isOpenControlled, setOpen: setOpenControlled, children, referenceElement, placement = "bottom", className, delay, theme = "dark", hideArrow, style, ...rest } = props;
40
46
  const [isOpenUncontrolled, setOpenUncontrolled] = (0, react_1.useState)(isVisibleInitial);
41
47
  const open = isOpenControlled !== null && isOpenControlled !== void 0 ? isOpenControlled : isOpenUncontrolled;
42
48
  const setOpen = setOpenControlled !== null && setOpenControlled !== void 0 ? setOpenControlled : setOpenUncontrolled;
@@ -44,6 +50,24 @@ const Tooltip = (props) => {
44
50
  const isHoveringPopoverRef = (0, react_1.useRef)(false);
45
51
  const referenceTimoutRef = (0, react_1.useRef)(null);
46
52
  const popoverTimoutRef = (0, react_1.useRef)(null);
53
+ const showDelay = (0, react_1.useMemo)(() => {
54
+ if (typeof delay === "number") {
55
+ return delay;
56
+ }
57
+ if (typeof delay !== "undefined" && typeof delay.show === "number") {
58
+ return delay.show;
59
+ }
60
+ return DEFAULT_DELAY;
61
+ }, [delay]);
62
+ const hideDelay = (0, react_1.useMemo)(() => {
63
+ if (typeof delay === "number") {
64
+ return delay;
65
+ }
66
+ if (typeof delay !== "undefined" && typeof delay.hide === "number") {
67
+ return delay.hide;
68
+ }
69
+ return DEFAULT_DELAY;
70
+ }, [delay]);
47
71
  (0, react_1.useEffect)(() => {
48
72
  if (isVisibleInitial) {
49
73
  setOpen(true);
@@ -60,7 +84,7 @@ const Tooltip = (props) => {
60
84
  };
61
85
  });
62
86
  const close = () => {
63
- if (!isHoveringPopoverRef.current) {
87
+ if (!isHoveringPopoverRef.current && !isHoveringReferenceRef.current) {
64
88
  setOpen(false);
65
89
  }
66
90
  };
@@ -71,14 +95,14 @@ const Tooltip = (props) => {
71
95
  if (isHoveringReferenceRef.current) {
72
96
  setOpen(true);
73
97
  }
74
- }, delay);
98
+ }, showDelay);
75
99
  referenceTimoutRef.current = referenceTimeout;
76
100
  }
77
101
  };
78
102
  const handleMouseLeave = () => {
79
103
  isHoveringReferenceRef.current = false;
80
104
  if (open) {
81
- const popoverTimeout = setTimeout(close, delay);
105
+ const popoverTimeout = setTimeout(close, hideDelay);
82
106
  popoverTimoutRef.current = popoverTimeout;
83
107
  }
84
108
  };
@@ -90,7 +114,7 @@ const Tooltip = (props) => {
90
114
  const handlePopoverMouseLeave = () => {
91
115
  isHoveringPopoverRef.current = false;
92
116
  if (open) {
93
- const popoverTimeout = setTimeout(close, delay);
117
+ const popoverTimeout = setTimeout(close, hideDelay);
94
118
  popoverTimoutRef.current = popoverTimeout;
95
119
  }
96
120
  };
@@ -11,6 +11,7 @@ import { Stack } from "../Stack";
11
11
  import { Link } from "../Link";
12
12
  import { Text } from "../Text";
13
13
  import { Tooltip } from "./Tooltip";
14
+ import { TooltipLink } from "./TooltipLink";
14
15
  import { useTooltipContext } from "./context";
15
16
 
16
17
  <Meta title="Components/Popovers/Tooltip" component={Tooltip} />
@@ -323,3 +324,33 @@ export const MyButton = React.forwardRef((props, ref) => {
323
324
  </Box>
324
325
  </Story>
325
326
  </Canvas>
327
+
328
+ ## Delay
329
+
330
+ The default delay is 200ms. The delay is necessary to keep the popover open when
331
+ the mouse moves from the reference element to the popover. This is important if
332
+ the popover has a link or some other content that can be interacted with.
333
+
334
+ The delay can be a number in ms, or it can be an object with `show` and `hide`
335
+ keys. Both object keys are optional, and if either are omitted, then the default
336
+ delay will be used.
337
+
338
+ <Canvas>
339
+ <Story name="Tooltip delay">
340
+ <Box className="px-8">
341
+ <Tooltip
342
+ placement="right"
343
+ delay={{
344
+ show: 100,
345
+ hide: 1000,
346
+ }}
347
+ referenceElement={<Stack className="inline-flex p-1">Hover me</Stack>}
348
+ >
349
+ <Flex className="flex-col" style={{ width: "150px" }}>
350
+ <Flex>I have a 100ms show delay and 1000ms hide delay</Flex>
351
+ <TooltipLink href="/">This is a Tooltip link</TooltipLink>
352
+ </Flex>
353
+ </Tooltip>
354
+ </Box>
355
+ </Story>
356
+ </Canvas>
@@ -4,21 +4,28 @@ import React, {
4
4
  useEffect,
5
5
  useMemo,
6
6
  useState,
7
+ ReactElement,
7
8
  } from "react";
8
9
  import classnames from "classnames";
9
10
 
10
11
  import { bem } from "../../utilities/bem";
11
12
  import { useKeyPress } from "../../hooks";
12
13
 
14
+ import { Box } from "../Box";
13
15
  import { Popover, PopoverTooltipSharedProps } from "../Popover";
14
16
  import { KEY_CODE } from "../../types";
15
- import { TooltipContext } from "./context";
17
+ import { TooltipContext, useTooltipContext } from "./context";
16
18
 
17
19
  export interface TooltipProps extends PopoverTooltipSharedProps {
18
20
  /**
19
21
  * Number of milliseconds to delay the disclosure of the tooltip
20
22
  */
21
- delay?: number;
23
+ delay?:
24
+ | number
25
+ | {
26
+ show?: number;
27
+ hide?: number;
28
+ };
22
29
  /**
23
30
  * Controls the background and text color
24
31
  */
@@ -37,8 +44,26 @@ export interface TooltipProps extends PopoverTooltipSharedProps {
37
44
  setOpen?(open: boolean): void;
38
45
  }
39
46
 
47
+ const DEFAULT_DELAY = 200;
40
48
  const cn = "Tooltip";
41
49
 
50
+ type ReferenceRenderFunction = (props: { isOpen: boolean }) => ReactElement;
51
+
52
+ export const TooltipReference = React.forwardRef<
53
+ HTMLDivElement,
54
+ {
55
+ children: ReferenceRenderFunction | ReactElement;
56
+ }
57
+ >(({ children, ...props }, ref) => {
58
+ const { isOpen } = useTooltipContext();
59
+
60
+ return (
61
+ <Box ref={ref} {...props}>
62
+ {typeof children === "function" ? children({ isOpen }) : children}
63
+ </Box>
64
+ );
65
+ });
66
+
42
67
  export const Tooltip = (props: TooltipProps) => {
43
68
  const {
44
69
  isVisible: isVisibleInitial = false,
@@ -48,7 +73,7 @@ export const Tooltip = (props: TooltipProps) => {
48
73
  referenceElement,
49
74
  placement = "bottom",
50
75
  className,
51
- delay = 200,
76
+ delay,
52
77
  theme = "dark",
53
78
  hideArrow,
54
79
  style,
@@ -63,6 +88,30 @@ export const Tooltip = (props: TooltipProps) => {
63
88
  const referenceTimoutRef = useRef<null | NodeJS.Timeout>(null);
64
89
  const popoverTimoutRef = useRef<null | NodeJS.Timeout>(null);
65
90
 
91
+ const showDelay = useMemo(() => {
92
+ if (typeof delay === "number") {
93
+ return delay;
94
+ }
95
+
96
+ if (typeof delay !== "undefined" && typeof delay.show === "number") {
97
+ return delay.show;
98
+ }
99
+
100
+ return DEFAULT_DELAY;
101
+ }, [delay]);
102
+
103
+ const hideDelay = useMemo(() => {
104
+ if (typeof delay === "number") {
105
+ return delay;
106
+ }
107
+
108
+ if (typeof delay !== "undefined" && typeof delay.hide === "number") {
109
+ return delay.hide;
110
+ }
111
+
112
+ return DEFAULT_DELAY;
113
+ }, [delay]);
114
+
66
115
  useEffect(() => {
67
116
  if (isVisibleInitial) {
68
117
  setOpen(true);
@@ -81,7 +130,7 @@ export const Tooltip = (props: TooltipProps) => {
81
130
  });
82
131
 
83
132
  const close = () => {
84
- if (!isHoveringPopoverRef.current) {
133
+ if (!isHoveringPopoverRef.current && !isHoveringReferenceRef.current) {
85
134
  setOpen(false);
86
135
  }
87
136
  };
@@ -94,7 +143,7 @@ export const Tooltip = (props: TooltipProps) => {
94
143
  if (isHoveringReferenceRef.current) {
95
144
  setOpen(true);
96
145
  }
97
- }, delay);
146
+ }, showDelay);
98
147
  referenceTimoutRef.current = referenceTimeout;
99
148
  }
100
149
  };
@@ -103,7 +152,7 @@ export const Tooltip = (props: TooltipProps) => {
103
152
  isHoveringReferenceRef.current = false;
104
153
 
105
154
  if (open) {
106
- const popoverTimeout = setTimeout(close, delay);
155
+ const popoverTimeout = setTimeout(close, hideDelay);
107
156
  popoverTimoutRef.current = popoverTimeout;
108
157
  }
109
158
  };
@@ -118,7 +167,7 @@ export const Tooltip = (props: TooltipProps) => {
118
167
  isHoveringPopoverRef.current = false;
119
168
 
120
169
  if (open) {
121
- const popoverTimeout = setTimeout(close, delay);
170
+ const popoverTimeout = setTimeout(close, hideDelay);
122
171
  popoverTimoutRef.current = popoverTimeout;
123
172
  }
124
173
  };